Line data Source code
1 : // Copyright 2015 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/interpreter/bytecode-array-writer.h"
6 :
7 : #include "src/api-inl.h"
8 : #include "src/interpreter/bytecode-jump-table.h"
9 : #include "src/interpreter/bytecode-label.h"
10 : #include "src/interpreter/bytecode-node.h"
11 : #include "src/interpreter/bytecode-register.h"
12 : #include "src/interpreter/bytecode-source-info.h"
13 : #include "src/interpreter/constant-array-builder.h"
14 : #include "src/log.h"
15 : #include "src/objects-inl.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 : namespace interpreter {
20 :
21 : STATIC_CONST_MEMBER_DEFINITION const size_t
22 : BytecodeArrayWriter::kMaxSizeOfPackedBytecode;
23 :
24 2129970 : BytecodeArrayWriter::BytecodeArrayWriter(
25 : Zone* zone, ConstantArrayBuilder* constant_array_builder,
26 : SourcePositionTableBuilder::RecordingMode source_position_mode)
27 : : bytecodes_(zone),
28 : unbound_jumps_(0),
29 : source_position_table_builder_(source_position_mode),
30 : constant_array_builder_(constant_array_builder),
31 : last_bytecode_(Bytecode::kIllegal),
32 : last_bytecode_offset_(0),
33 : last_bytecode_had_source_info_(false),
34 : elide_noneffectful_bytecodes_(FLAG_ignition_elide_noneffectful_bytecodes),
35 4259940 : exit_seen_in_block_(false) {
36 2129964 : bytecodes_.reserve(512); // Derived via experimentation.
37 2129976 : }
38 :
39 2105820 : Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
40 2105834 : Isolate* isolate, int register_count, int parameter_count,
41 2105820 : Handle<ByteArray> handler_table) {
42 : DCHECK_EQ(0, unbound_jumps_);
43 :
44 4211640 : int bytecode_size = static_cast<int>(bytecodes()->size());
45 2105820 : int frame_size = register_count * kSystemPointerSize;
46 : Handle<FixedArray> constant_pool =
47 2105820 : constant_array_builder()->ToFixedArray(isolate);
48 : Handle<ByteArray> source_position_table =
49 2105828 : source_position_table_builder()->ToSourcePositionTable(isolate);
50 : Handle<BytecodeArray> bytecode_array = isolate->factory()->NewBytecodeArray(
51 : bytecode_size, &bytecodes()->front(), frame_size, parameter_count,
52 2105815 : constant_pool);
53 2105820 : bytecode_array->set_handler_table(*handler_table);
54 4211658 : bytecode_array->set_source_position_table(*source_position_table);
55 2106150 : LOG_CODE_EVENT(isolate, CodeLinePosInfoRecordEvent(
56 : bytecode_array->GetFirstBytecodeAddress(),
57 : *source_position_table));
58 2105828 : return bytecode_array;
59 : }
60 :
61 231993406 : void BytecodeArrayWriter::Write(BytecodeNode* node) {
62 : DCHECK(!Bytecodes::IsJump(node->bytecode()));
63 :
64 154958195 : if (exit_seen_in_block_) return; // Don't emit dead code.
65 : UpdateExitSeenInBlock(node->bytecode());
66 231774345 : MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
67 :
68 77273584 : UpdateSourcePositionTable(node);
69 77280339 : EmitBytecode(node);
70 : }
71 :
72 6226568 : void BytecodeArrayWriter::WriteJump(BytecodeNode* node, BytecodeLabel* label) {
73 : DCHECK(Bytecodes::IsJump(node->bytecode()));
74 :
75 : // TODO(rmcilroy): For forward jumps we could also mark the label as dead,
76 : // thereby avoiding emitting dead code when we bind the label.
77 4166802 : if (exit_seen_in_block_) return; // Don't emit dead code.
78 : UpdateExitSeenInBlock(node->bytecode());
79 6214806 : MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
80 :
81 2071665 : UpdateSourcePositionTable(node);
82 2071692 : EmitJump(node, label);
83 : }
84 :
85 59445 : void BytecodeArrayWriter::WriteSwitch(BytecodeNode* node,
86 : BytecodeJumpTable* jump_table) {
87 : DCHECK(Bytecodes::IsSwitch(node->bytecode()));
88 :
89 : // TODO(rmcilroy): For jump tables we could also mark the table as dead,
90 : // thereby avoiding emitting dead code when we bind the entries.
91 40122 : if (exit_seen_in_block_) return; // Don't emit dead code.
92 : UpdateExitSeenInBlock(node->bytecode());
93 59076 : MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
94 :
95 19691 : UpdateSourcePositionTable(node);
96 : EmitSwitch(node, jump_table);
97 : }
98 :
99 2701486 : void BytecodeArrayWriter::BindLabel(BytecodeLabel* label) {
100 2701486 : size_t current_offset = bytecodes()->size();
101 2701486 : if (label->is_forward_target()) {
102 : // An earlier jump instruction refers to this label. Update it's location.
103 1815248 : PatchJump(current_offset, label->offset());
104 : // Now treat as if the label will only be back referred to.
105 : }
106 : label->bind_to(current_offset);
107 : InvalidateLastBytecode();
108 2701478 : exit_seen_in_block_ = false; // Starting a new basic block.
109 2701478 : }
110 :
111 0 : void BytecodeArrayWriter::BindLabel(const BytecodeLabel& target,
112 : BytecodeLabel* label) {
113 : DCHECK(!label->is_bound());
114 : DCHECK(target.is_bound());
115 0 : if (label->is_forward_target()) {
116 : // An earlier jump instruction refers to this label. Update it's location.
117 0 : PatchJump(target.offset(), label->offset());
118 : // Now treat as if the label will only be back referred to.
119 : }
120 : label->bind_to(target.offset());
121 : InvalidateLastBytecode();
122 : // exit_seen_in_block_ was reset when target was bound, so shouldn't be
123 : // changed here.
124 0 : }
125 :
126 140199 : void BytecodeArrayWriter::BindJumpTableEntry(BytecodeJumpTable* jump_table,
127 46733 : int case_value) {
128 : DCHECK(!jump_table->is_bound(case_value));
129 :
130 46733 : size_t current_offset = bytecodes()->size();
131 46733 : size_t relative_jump = current_offset - jump_table->switch_bytecode_offset();
132 :
133 : constant_array_builder()->SetJumpTableSmi(
134 : jump_table->ConstantPoolEntryFor(case_value),
135 93466 : Smi::FromInt(static_cast<int>(relative_jump)));
136 : jump_table->mark_bound(case_value);
137 :
138 : InvalidateLastBytecode();
139 46734 : exit_seen_in_block_ = false; // Starting a new basic block.
140 46734 : }
141 :
142 79362835 : void BytecodeArrayWriter::UpdateSourcePositionTable(
143 : const BytecodeNode* const node) {
144 158725670 : int bytecode_offset = static_cast<int>(bytecodes()->size());
145 111172470 : const BytecodeSourceInfo& source_info = node->source_info();
146 79362835 : if (source_info.is_valid()) {
147 : source_position_table_builder()->AddPosition(
148 : bytecode_offset, SourcePosition(source_info.source_position()),
149 63619270 : source_info.is_statement());
150 : }
151 79362861 : }
152 :
153 0 : void BytecodeArrayWriter::UpdateExitSeenInBlock(Bytecode bytecode) {
154 : switch (bytecode) {
155 : case Bytecode::kReturn:
156 : case Bytecode::kThrow:
157 : case Bytecode::kReThrow:
158 : case Bytecode::kAbort:
159 : case Bytecode::kJump:
160 : case Bytecode::kJumpConstant:
161 : case Bytecode::kSuspendGenerator:
162 2958190 : exit_seen_in_block_ = true;
163 0 : break;
164 : default:
165 : break;
166 : }
167 0 : }
168 :
169 79348000 : void BytecodeArrayWriter::MaybeElideLastBytecode(Bytecode next_bytecode,
170 : bool has_source_info) {
171 158713539 : if (!elide_noneffectful_bytecodes_) return;
172 :
173 : // If the last bytecode loaded the accumulator without any external effect,
174 : // and the next bytecode clobbers this load without reading the accumulator,
175 : // then the previous bytecode can be elided as it has no effect.
176 177591539 : if (Bytecodes::IsAccumulatorLoadWithoutEffects(last_bytecode_) &&
177 79697134 : Bytecodes::GetAccumulatorUse(next_bytecode) == AccumulatorUse::kWrite &&
178 332579 : (!last_bytecode_had_source_info_ || !has_source_info)) {
179 : DCHECK_GT(bytecodes()->size(), last_bytecode_offset_);
180 329585 : bytecodes()->resize(last_bytecode_offset_);
181 : // If the last bytecode had source info we will transfer the source info
182 : // to this bytecode.
183 329585 : has_source_info |= last_bytecode_had_source_info_;
184 : }
185 79366174 : last_bytecode_ = next_bytecode;
186 79366174 : last_bytecode_had_source_info_ = has_source_info;
187 158732348 : last_bytecode_offset_ = bytecodes()->size();
188 : }
189 :
190 0 : void BytecodeArrayWriter::InvalidateLastBytecode() {
191 2748212 : last_bytecode_ = Bytecode::kIllegal;
192 0 : }
193 :
194 158737385 : void BytecodeArrayWriter::EmitBytecode(const BytecodeNode* const node) {
195 : DCHECK_NE(node->bytecode(), Bytecode::kIllegal);
196 :
197 : Bytecode bytecode = node->bytecode();
198 : OperandScale operand_scale = node->operand_scale();
199 :
200 79371739 : if (operand_scale != OperandScale::kSingle) {
201 10099635 : Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale);
202 20199222 : bytecodes()->push_back(Bytecodes::ToByte(prefix));
203 : }
204 158737352 : bytecodes()->push_back(Bytecodes::ToByte(bytecode));
205 :
206 79365646 : const uint32_t* const operands = node->operands();
207 : const int operand_count = node->operand_count();
208 : const OperandSize* operand_sizes =
209 : Bytecodes::GetOperandSizes(bytecode, operand_scale);
210 186093604 : for (int i = 0; i < operand_count; ++i) {
211 106741813 : switch (operand_sizes[i]) {
212 : case OperandSize::kNone:
213 74 : UNREACHABLE();
214 : break;
215 : case OperandSize::kByte:
216 183267828 : bytecodes()->push_back(static_cast<uint8_t>(operands[i]));
217 91627023 : break;
218 : case OperandSize::kShort: {
219 10515828 : uint16_t operand = static_cast<uint16_t>(operands[i]);
220 : const uint8_t* raw_operand = reinterpret_cast<const uint8_t*>(&operand);
221 10515828 : bytecodes()->push_back(raw_operand[0]);
222 10515904 : bytecodes()->push_back(raw_operand[1]);
223 : break;
224 : }
225 : case OperandSize::kQuad: {
226 : const uint8_t* raw_operand =
227 4593023 : reinterpret_cast<const uint8_t*>(&operands[i]);
228 4593023 : bytecodes()->push_back(raw_operand[0]);
229 4593031 : bytecodes()->push_back(raw_operand[1]);
230 4593029 : bytecodes()->push_back(raw_operand[2]);
231 4593028 : bytecodes()->push_back(raw_operand[3]);
232 4593032 : break;
233 : }
234 : }
235 : }
236 79351791 : }
237 :
238 : // static
239 24854 : Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) {
240 24854 : switch (jump_bytecode) {
241 : case Bytecode::kJump:
242 : return Bytecode::kJumpConstant;
243 : case Bytecode::kJumpIfTrue:
244 9331 : return Bytecode::kJumpIfTrueConstant;
245 : case Bytecode::kJumpIfFalse:
246 4126 : return Bytecode::kJumpIfFalseConstant;
247 : case Bytecode::kJumpIfToBooleanTrue:
248 5561 : return Bytecode::kJumpIfToBooleanTrueConstant;
249 : case Bytecode::kJumpIfToBooleanFalse:
250 102 : return Bytecode::kJumpIfToBooleanFalseConstant;
251 : case Bytecode::kJumpIfNull:
252 211 : return Bytecode::kJumpIfNullConstant;
253 : case Bytecode::kJumpIfNotNull:
254 1 : return Bytecode::kJumpIfNotNullConstant;
255 : case Bytecode::kJumpIfUndefined:
256 359 : return Bytecode::kJumpIfUndefinedConstant;
257 : case Bytecode::kJumpIfNotUndefined:
258 11 : return Bytecode::kJumpIfNotUndefinedConstant;
259 : case Bytecode::kJumpIfJSReceiver:
260 1 : return Bytecode::kJumpIfJSReceiverConstant;
261 : default:
262 0 : UNREACHABLE();
263 : }
264 : }
265 :
266 1799160 : void BytecodeArrayWriter::PatchJumpWith8BitOperand(size_t jump_location,
267 1799160 : int delta) {
268 1799160 : Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
269 : DCHECK(Bytecodes::IsForwardJump(jump_bytecode));
270 : DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
271 : DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm);
272 : DCHECK_GT(delta, 0);
273 1799160 : size_t operand_location = jump_location + 1;
274 : DCHECK_EQ(bytecodes()->at(operand_location), k8BitJumpPlaceholder);
275 3598320 : if (Bytecodes::ScaleForUnsignedOperand(delta) == OperandScale::kSingle) {
276 : // The jump fits within the range of an UImm8 operand, so cancel
277 : // the reservation and jump directly.
278 1774304 : constant_array_builder()->DiscardReservedEntry(OperandSize::kByte);
279 1774338 : bytecodes()->at(operand_location) = static_cast<uint8_t>(delta);
280 : } else {
281 : // The jump does not fit within the range of an UImm8 operand, so
282 : // commit reservation putting the offset into the constant pool,
283 : // and update the jump instruction and operand.
284 : size_t entry = constant_array_builder()->CommitReservedEntry(
285 24856 : OperandSize::kByte, Smi::FromInt(delta));
286 : DCHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<uint32_t>(entry)),
287 : OperandSize::kByte);
288 24849 : jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
289 24841 : bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
290 24841 : bytecodes()->at(operand_location) = static_cast<uint8_t>(entry);
291 : }
292 1799179 : }
293 :
294 16047 : void BytecodeArrayWriter::PatchJumpWith16BitOperand(size_t jump_location,
295 16047 : int delta) {
296 16047 : Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
297 : DCHECK(Bytecodes::IsForwardJump(jump_bytecode));
298 : DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
299 : DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm);
300 : DCHECK_GT(delta, 0);
301 16047 : size_t operand_location = jump_location + 1;
302 : uint8_t operand_bytes[2];
303 32094 : if (Bytecodes::ScaleForUnsignedOperand(delta) <= OperandScale::kDouble) {
304 : // The jump fits within the range of an Imm16 operand, so cancel
305 : // the reservation and jump directly.
306 16042 : constant_array_builder()->DiscardReservedEntry(OperandSize::kShort);
307 : WriteUnalignedUInt16(reinterpret_cast<Address>(operand_bytes),
308 16042 : static_cast<uint16_t>(delta));
309 : } else {
310 : // The jump does not fit within the range of an Imm16 operand, so
311 : // commit reservation putting the offset into the constant pool,
312 : // and update the jump instruction and operand.
313 : size_t entry = constant_array_builder()->CommitReservedEntry(
314 5 : OperandSize::kShort, Smi::FromInt(delta));
315 5 : jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
316 5 : bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
317 : WriteUnalignedUInt16(reinterpret_cast<Address>(operand_bytes),
318 5 : static_cast<uint16_t>(entry));
319 : }
320 : DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&
321 : bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder);
322 32094 : bytecodes()->at(operand_location++) = operand_bytes[0];
323 16047 : bytecodes()->at(operand_location) = operand_bytes[1];
324 16047 : }
325 :
326 5 : void BytecodeArrayWriter::PatchJumpWith32BitOperand(size_t jump_location,
327 5 : int delta) {
328 : DCHECK(Bytecodes::IsJumpImmediate(
329 : Bytecodes::FromByte(bytecodes()->at(jump_location))));
330 5 : constant_array_builder()->DiscardReservedEntry(OperandSize::kQuad);
331 : uint8_t operand_bytes[4];
332 : WriteUnalignedUInt32(reinterpret_cast<Address>(operand_bytes),
333 5 : static_cast<uint32_t>(delta));
334 5 : size_t operand_location = jump_location + 1;
335 : DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&
336 : bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder &&
337 : bytecodes()->at(operand_location + 2) == k8BitJumpPlaceholder &&
338 : bytecodes()->at(operand_location + 3) == k8BitJumpPlaceholder);
339 10 : bytecodes()->at(operand_location++) = operand_bytes[0];
340 10 : bytecodes()->at(operand_location++) = operand_bytes[1];
341 10 : bytecodes()->at(operand_location++) = operand_bytes[2];
342 5 : bytecodes()->at(operand_location) = operand_bytes[3];
343 5 : }
344 :
345 1815237 : void BytecodeArrayWriter::PatchJump(size_t jump_target, size_t jump_location) {
346 1815237 : Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
347 1815237 : int delta = static_cast<int>(jump_target - jump_location);
348 : int prefix_offset = 0;
349 : OperandScale operand_scale = OperandScale::kSingle;
350 1815237 : if (Bytecodes::IsPrefixScalingBytecode(jump_bytecode)) {
351 : // If a prefix scaling bytecode is emitted the target offset is one
352 : // less than the case of no prefix scaling bytecode.
353 16052 : delta -= 1;
354 : prefix_offset = 1;
355 16052 : operand_scale = Bytecodes::PrefixBytecodeToOperandScale(jump_bytecode);
356 : jump_bytecode =
357 16052 : Bytecodes::FromByte(bytecodes()->at(jump_location + prefix_offset));
358 : }
359 :
360 : DCHECK(Bytecodes::IsJump(jump_bytecode));
361 1815237 : switch (operand_scale) {
362 : case OperandScale::kSingle:
363 1799185 : PatchJumpWith8BitOperand(jump_location, delta);
364 1799185 : break;
365 : case OperandScale::kDouble:
366 16047 : PatchJumpWith16BitOperand(jump_location + prefix_offset, delta);
367 16047 : break;
368 : case OperandScale::kQuadruple:
369 5 : PatchJumpWith32BitOperand(jump_location + prefix_offset, delta);
370 5 : break;
371 : default:
372 0 : UNREACHABLE();
373 : }
374 1815237 : unbound_jumps_--;
375 1815237 : }
376 :
377 6214974 : void BytecodeArrayWriter::EmitJump(BytecodeNode* node, BytecodeLabel* label) {
378 : DCHECK(Bytecodes::IsJump(node->bytecode()));
379 : DCHECK_EQ(0u, node->operand(0));
380 :
381 2071658 : size_t current_offset = bytecodes()->size();
382 :
383 2071658 : if (label->is_bound()) {
384 256425 : CHECK_GE(current_offset, label->offset());
385 256425 : CHECK_LE(current_offset, static_cast<size_t>(kMaxUInt32));
386 : // Label has been bound already so this is a backwards jump.
387 256425 : uint32_t delta = static_cast<uint32_t>(current_offset - label->offset());
388 : OperandScale operand_scale = Bytecodes::ScaleForUnsignedOperand(delta);
389 256425 : if (operand_scale > OperandScale::kSingle) {
390 : // Adjust for scaling byte prefix for wide jump offset.
391 8816 : delta += 1;
392 : }
393 : DCHECK_EQ(Bytecode::kJumpLoop, node->bytecode());
394 256425 : node->update_operand0(delta);
395 : } else {
396 : // The label has not yet been bound so this is a forward reference
397 : // that will be patched when the label is bound. We create a
398 : // reservation in the constant pool so the jump can be patched
399 : // when the label is bound. The reservation means the maximum size
400 : // of the operand for the constant is known and the jump can
401 : // be emitted into the bytecode stream with space for the operand.
402 1815233 : unbound_jumps_++;
403 : label->set_referrer(current_offset);
404 : OperandSize reserved_operand_size =
405 1815233 : constant_array_builder()->CreateReservedEntry();
406 : DCHECK_NE(Bytecode::kJumpLoop, node->bytecode());
407 1815220 : switch (reserved_operand_size) {
408 : case OperandSize::kNone:
409 0 : UNREACHABLE();
410 : break;
411 : case OperandSize::kByte:
412 1799177 : node->update_operand0(k8BitJumpPlaceholder);
413 1799232 : break;
414 : case OperandSize::kShort:
415 16047 : node->update_operand0(k16BitJumpPlaceholder);
416 16047 : break;
417 : case OperandSize::kQuad:
418 5 : node->update_operand0(k32BitJumpPlaceholder);
419 5 : break;
420 : }
421 : }
422 2071685 : EmitBytecode(node);
423 2071672 : }
424 :
425 19692 : void BytecodeArrayWriter::EmitSwitch(BytecodeNode* node,
426 : BytecodeJumpTable* jump_table) {
427 : DCHECK(Bytecodes::IsSwitch(node->bytecode()));
428 :
429 19692 : size_t current_offset = bytecodes()->size();
430 19692 : if (node->operand_scale() > OperandScale::kSingle) {
431 : // Adjust for scaling byte prefix.
432 122 : current_offset += 1;
433 : }
434 : jump_table->set_switch_bytecode_offset(current_offset);
435 :
436 19692 : EmitBytecode(node);
437 0 : }
438 :
439 : } // namespace interpreter
440 : } // namespace internal
441 183867 : } // namespace v8
|