• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/api-inl.h"
8 #include "src/heap/local-factory-inl.h"
9 #include "src/interpreter/bytecode-jump-table.h"
10 #include "src/interpreter/bytecode-label.h"
11 #include "src/interpreter/bytecode-node.h"
12 #include "src/interpreter/bytecode-register.h"
13 #include "src/interpreter/bytecode-source-info.h"
14 #include "src/interpreter/constant-array-builder.h"
15 #include "src/interpreter/handler-table-builder.h"
16 #include "src/objects/objects-inl.h"
17 
18 namespace v8 {
19 namespace internal {
20 namespace interpreter {
21 
22 STATIC_CONST_MEMBER_DEFINITION const size_t
23     BytecodeArrayWriter::kMaxSizeOfPackedBytecode;
24 
BytecodeArrayWriter(Zone * zone,ConstantArrayBuilder * constant_array_builder,SourcePositionTableBuilder::RecordingMode source_position_mode)25 BytecodeArrayWriter::BytecodeArrayWriter(
26     Zone* zone, ConstantArrayBuilder* constant_array_builder,
27     SourcePositionTableBuilder::RecordingMode source_position_mode)
28     : bytecodes_(zone),
29       unbound_jumps_(0),
30       source_position_table_builder_(zone, source_position_mode),
31       constant_array_builder_(constant_array_builder),
32       last_bytecode_(Bytecode::kIllegal),
33       last_bytecode_offset_(0),
34       last_bytecode_had_source_info_(false),
35       elide_noneffectful_bytecodes_(FLAG_ignition_elide_noneffectful_bytecodes),
36       exit_seen_in_block_(false) {
37   bytecodes_.reserve(512);  // Derived via experimentation.
38 }
39 
40 template <typename IsolateT>
ToBytecodeArray(IsolateT * isolate,int register_count,int parameter_count,Handle<ByteArray> handler_table)41 Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
42     IsolateT* isolate, int register_count, int parameter_count,
43     Handle<ByteArray> handler_table) {
44   DCHECK_EQ(0, unbound_jumps_);
45 
46   int bytecode_size = static_cast<int>(bytecodes()->size());
47   int frame_size = register_count * kSystemPointerSize;
48   Handle<FixedArray> constant_pool =
49       constant_array_builder()->ToFixedArray(isolate);
50   Handle<BytecodeArray> bytecode_array = isolate->factory()->NewBytecodeArray(
51       bytecode_size, &bytecodes()->front(), frame_size, parameter_count,
52       constant_pool);
53   bytecode_array->set_handler_table(*handler_table);
54   return bytecode_array;
55 }
56 
57 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
58     Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
59         Isolate* isolate, int register_count, int parameter_count,
60         Handle<ByteArray> handler_table);
61 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
62     Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
63         LocalIsolate* isolate, int register_count, int parameter_count,
64         Handle<ByteArray> handler_table);
65 
66 template <typename IsolateT>
ToSourcePositionTable(IsolateT * isolate)67 Handle<ByteArray> BytecodeArrayWriter::ToSourcePositionTable(
68     IsolateT* isolate) {
69   DCHECK(!source_position_table_builder_.Lazy());
70   Handle<ByteArray> source_position_table =
71       source_position_table_builder_.Omit()
72           ? isolate->factory()->empty_byte_array()
73           : source_position_table_builder_.ToSourcePositionTable(isolate);
74   return source_position_table;
75 }
76 
77 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
78     Handle<ByteArray> BytecodeArrayWriter::ToSourcePositionTable(
79         Isolate* isolate);
80 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
81     Handle<ByteArray> BytecodeArrayWriter::ToSourcePositionTable(
82         LocalIsolate* isolate);
83 
84 #ifdef DEBUG
CheckBytecodeMatches(BytecodeArray bytecode)85 int BytecodeArrayWriter::CheckBytecodeMatches(BytecodeArray bytecode) {
86   int mismatches = false;
87   int bytecode_size = static_cast<int>(bytecodes()->size());
88   const byte* bytecode_ptr = &bytecodes()->front();
89   if (bytecode_size != bytecode.length()) mismatches = true;
90 
91   // If there's a mismatch only in the length of the bytecode (very unlikely)
92   // then the first mismatch will be the first extra bytecode.
93   int first_mismatch = std::min(bytecode_size, bytecode.length());
94   for (int i = 0; i < first_mismatch; ++i) {
95     if (bytecode_ptr[i] != bytecode.get(i)) {
96       mismatches = true;
97       first_mismatch = i;
98       break;
99     }
100   }
101 
102   if (mismatches) {
103     return first_mismatch;
104   }
105   return -1;
106 }
107 #endif
108 
Write(BytecodeNode * node)109 void BytecodeArrayWriter::Write(BytecodeNode* node) {
110   DCHECK(!Bytecodes::IsJump(node->bytecode()));
111 
112   if (exit_seen_in_block_) return;  // Don't emit dead code.
113   UpdateExitSeenInBlock(node->bytecode());
114   MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
115 
116   UpdateSourcePositionTable(node);
117   EmitBytecode(node);
118 }
119 
WriteJump(BytecodeNode * node,BytecodeLabel * label)120 void BytecodeArrayWriter::WriteJump(BytecodeNode* node, BytecodeLabel* label) {
121   DCHECK(Bytecodes::IsForwardJump(node->bytecode()));
122 
123   if (exit_seen_in_block_) return;  // Don't emit dead code.
124   UpdateExitSeenInBlock(node->bytecode());
125   MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
126 
127   UpdateSourcePositionTable(node);
128   EmitJump(node, label);
129 }
130 
WriteJumpLoop(BytecodeNode * node,BytecodeLoopHeader * loop_header)131 void BytecodeArrayWriter::WriteJumpLoop(BytecodeNode* node,
132                                         BytecodeLoopHeader* loop_header) {
133   DCHECK_EQ(node->bytecode(), Bytecode::kJumpLoop);
134 
135   if (exit_seen_in_block_) return;  // Don't emit dead code.
136   UpdateExitSeenInBlock(node->bytecode());
137   MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
138 
139   UpdateSourcePositionTable(node);
140   EmitJumpLoop(node, loop_header);
141 }
142 
WriteSwitch(BytecodeNode * node,BytecodeJumpTable * jump_table)143 void BytecodeArrayWriter::WriteSwitch(BytecodeNode* node,
144                                       BytecodeJumpTable* jump_table) {
145   DCHECK(Bytecodes::IsSwitch(node->bytecode()));
146 
147   if (exit_seen_in_block_) return;  // Don't emit dead code.
148   UpdateExitSeenInBlock(node->bytecode());
149   MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
150 
151   UpdateSourcePositionTable(node);
152   EmitSwitch(node, jump_table);
153 }
154 
BindLabel(BytecodeLabel * label)155 void BytecodeArrayWriter::BindLabel(BytecodeLabel* label) {
156   DCHECK(label->has_referrer_jump());
157   size_t current_offset = bytecodes()->size();
158   // Update the jump instruction's location.
159   PatchJump(current_offset, label->jump_offset());
160   label->bind();
161   StartBasicBlock();
162 }
163 
BindLoopHeader(BytecodeLoopHeader * loop_header)164 void BytecodeArrayWriter::BindLoopHeader(BytecodeLoopHeader* loop_header) {
165   size_t current_offset = bytecodes()->size();
166   loop_header->bind_to(current_offset);
167   // Don't start a basic block when the entire loop is dead.
168   if (exit_seen_in_block_) return;
169   StartBasicBlock();
170 }
171 
BindJumpTableEntry(BytecodeJumpTable * jump_table,int case_value)172 void BytecodeArrayWriter::BindJumpTableEntry(BytecodeJumpTable* jump_table,
173                                              int case_value) {
174   DCHECK(!jump_table->is_bound(case_value));
175 
176   size_t current_offset = bytecodes()->size();
177   size_t relative_jump = current_offset - jump_table->switch_bytecode_offset();
178 
179   constant_array_builder()->SetJumpTableSmi(
180       jump_table->ConstantPoolEntryFor(case_value),
181       Smi::FromInt(static_cast<int>(relative_jump)));
182   jump_table->mark_bound(case_value);
183 
184   StartBasicBlock();
185 }
186 
BindHandlerTarget(HandlerTableBuilder * handler_table_builder,int handler_id)187 void BytecodeArrayWriter::BindHandlerTarget(
188     HandlerTableBuilder* handler_table_builder, int handler_id) {
189   size_t current_offset = bytecodes()->size();
190   StartBasicBlock();
191   handler_table_builder->SetHandlerTarget(handler_id, current_offset);
192 }
193 
BindTryRegionStart(HandlerTableBuilder * handler_table_builder,int handler_id)194 void BytecodeArrayWriter::BindTryRegionStart(
195     HandlerTableBuilder* handler_table_builder, int handler_id) {
196   size_t current_offset = bytecodes()->size();
197   // Try blocks don't have to be in a separate basic block, but we do have to
198   // invalidate the bytecode to avoid eliding it and changing the offset.
199   InvalidateLastBytecode();
200   handler_table_builder->SetTryRegionStart(handler_id, current_offset);
201 }
202 
BindTryRegionEnd(HandlerTableBuilder * handler_table_builder,int handler_id)203 void BytecodeArrayWriter::BindTryRegionEnd(
204     HandlerTableBuilder* handler_table_builder, int handler_id) {
205   // Try blocks don't have to be in a separate basic block, but we do have to
206   // invalidate the bytecode to avoid eliding it and changing the offset.
207   InvalidateLastBytecode();
208   size_t current_offset = bytecodes()->size();
209   handler_table_builder->SetTryRegionEnd(handler_id, current_offset);
210 }
211 
SetFunctionEntrySourcePosition(int position)212 void BytecodeArrayWriter::SetFunctionEntrySourcePosition(int position) {
213   bool is_statement = false;
214   source_position_table_builder_.AddPosition(
215       kFunctionEntryBytecodeOffset, SourcePosition(position), is_statement);
216 }
217 
StartBasicBlock()218 void BytecodeArrayWriter::StartBasicBlock() {
219   InvalidateLastBytecode();
220   exit_seen_in_block_ = false;
221 }
222 
UpdateSourcePositionTable(const BytecodeNode * const node)223 void BytecodeArrayWriter::UpdateSourcePositionTable(
224     const BytecodeNode* const node) {
225   int bytecode_offset = static_cast<int>(bytecodes()->size());
226   const BytecodeSourceInfo& source_info = node->source_info();
227   if (source_info.is_valid()) {
228     source_position_table_builder()->AddPosition(
229         bytecode_offset, SourcePosition(source_info.source_position()),
230         source_info.is_statement());
231   }
232 }
233 
UpdateExitSeenInBlock(Bytecode bytecode)234 void BytecodeArrayWriter::UpdateExitSeenInBlock(Bytecode bytecode) {
235   switch (bytecode) {
236     case Bytecode::kReturn:
237     case Bytecode::kThrow:
238     case Bytecode::kReThrow:
239     case Bytecode::kAbort:
240     case Bytecode::kJump:
241     case Bytecode::kJumpLoop:
242     case Bytecode::kJumpConstant:
243     case Bytecode::kSuspendGenerator:
244       exit_seen_in_block_ = true;
245       break;
246     default:
247       break;
248   }
249 }
250 
MaybeElideLastBytecode(Bytecode next_bytecode,bool has_source_info)251 void BytecodeArrayWriter::MaybeElideLastBytecode(Bytecode next_bytecode,
252                                                  bool has_source_info) {
253   if (!elide_noneffectful_bytecodes_) return;
254 
255   // If the last bytecode loaded the accumulator without any external effect,
256   // and the next bytecode clobbers this load without reading the accumulator,
257   // then the previous bytecode can be elided as it has no effect.
258   if (Bytecodes::IsAccumulatorLoadWithoutEffects(last_bytecode_) &&
259       Bytecodes::GetImplicitRegisterUse(next_bytecode) ==
260           ImplicitRegisterUse::kWriteAccumulator &&
261       (!last_bytecode_had_source_info_ || !has_source_info)) {
262     DCHECK_GT(bytecodes()->size(), last_bytecode_offset_);
263     bytecodes()->resize(last_bytecode_offset_);
264     // If the last bytecode had source info we will transfer the source info
265     // to this bytecode.
266     has_source_info |= last_bytecode_had_source_info_;
267   }
268   last_bytecode_ = next_bytecode;
269   last_bytecode_had_source_info_ = has_source_info;
270   last_bytecode_offset_ = bytecodes()->size();
271 }
272 
InvalidateLastBytecode()273 void BytecodeArrayWriter::InvalidateLastBytecode() {
274   last_bytecode_ = Bytecode::kIllegal;
275 }
276 
EmitBytecode(const BytecodeNode * const node)277 void BytecodeArrayWriter::EmitBytecode(const BytecodeNode* const node) {
278   DCHECK_NE(node->bytecode(), Bytecode::kIllegal);
279 
280   Bytecode bytecode = node->bytecode();
281   OperandScale operand_scale = node->operand_scale();
282 
283   if (operand_scale != OperandScale::kSingle) {
284     Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale);
285     bytecodes()->push_back(Bytecodes::ToByte(prefix));
286   }
287   bytecodes()->push_back(Bytecodes::ToByte(bytecode));
288 
289   const uint32_t* const operands = node->operands();
290   const int operand_count = node->operand_count();
291   const OperandSize* operand_sizes =
292       Bytecodes::GetOperandSizes(bytecode, operand_scale);
293   for (int i = 0; i < operand_count; ++i) {
294     switch (operand_sizes[i]) {
295       case OperandSize::kNone:
296         UNREACHABLE();
297       case OperandSize::kByte:
298         bytecodes()->push_back(static_cast<uint8_t>(operands[i]));
299         break;
300       case OperandSize::kShort: {
301         uint16_t operand = static_cast<uint16_t>(operands[i]);
302         const uint8_t* raw_operand = reinterpret_cast<const uint8_t*>(&operand);
303         bytecodes()->push_back(raw_operand[0]);
304         bytecodes()->push_back(raw_operand[1]);
305         break;
306       }
307       case OperandSize::kQuad: {
308         const uint8_t* raw_operand =
309             reinterpret_cast<const uint8_t*>(&operands[i]);
310         bytecodes()->push_back(raw_operand[0]);
311         bytecodes()->push_back(raw_operand[1]);
312         bytecodes()->push_back(raw_operand[2]);
313         bytecodes()->push_back(raw_operand[3]);
314         break;
315       }
316     }
317   }
318 }
319 
320 // static
GetJumpWithConstantOperand(Bytecode jump_bytecode)321 Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) {
322   switch (jump_bytecode) {
323     case Bytecode::kJump:
324       return Bytecode::kJumpConstant;
325     case Bytecode::kJumpIfTrue:
326       return Bytecode::kJumpIfTrueConstant;
327     case Bytecode::kJumpIfFalse:
328       return Bytecode::kJumpIfFalseConstant;
329     case Bytecode::kJumpIfToBooleanTrue:
330       return Bytecode::kJumpIfToBooleanTrueConstant;
331     case Bytecode::kJumpIfToBooleanFalse:
332       return Bytecode::kJumpIfToBooleanFalseConstant;
333     case Bytecode::kJumpIfNull:
334       return Bytecode::kJumpIfNullConstant;
335     case Bytecode::kJumpIfNotNull:
336       return Bytecode::kJumpIfNotNullConstant;
337     case Bytecode::kJumpIfUndefined:
338       return Bytecode::kJumpIfUndefinedConstant;
339     case Bytecode::kJumpIfNotUndefined:
340       return Bytecode::kJumpIfNotUndefinedConstant;
341     case Bytecode::kJumpIfUndefinedOrNull:
342       return Bytecode::kJumpIfUndefinedOrNullConstant;
343     case Bytecode::kJumpIfJSReceiver:
344       return Bytecode::kJumpIfJSReceiverConstant;
345     default:
346       UNREACHABLE();
347   }
348 }
349 
PatchJumpWith8BitOperand(size_t jump_location,int delta)350 void BytecodeArrayWriter::PatchJumpWith8BitOperand(size_t jump_location,
351                                                    int delta) {
352   Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
353   DCHECK(Bytecodes::IsForwardJump(jump_bytecode));
354   DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
355   DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm);
356   DCHECK_GT(delta, 0);
357   size_t operand_location = jump_location + 1;
358   DCHECK_EQ(bytecodes()->at(operand_location), k8BitJumpPlaceholder);
359   if (Bytecodes::ScaleForUnsignedOperand(delta) == OperandScale::kSingle) {
360     // The jump fits within the range of an UImm8 operand, so cancel
361     // the reservation and jump directly.
362     constant_array_builder()->DiscardReservedEntry(OperandSize::kByte);
363     bytecodes()->at(operand_location) = static_cast<uint8_t>(delta);
364   } else {
365     // The jump does not fit within the range of an UImm8 operand, so
366     // commit reservation putting the offset into the constant pool,
367     // and update the jump instruction and operand.
368     size_t entry = constant_array_builder()->CommitReservedEntry(
369         OperandSize::kByte, Smi::FromInt(delta));
370     DCHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<uint32_t>(entry)),
371               OperandSize::kByte);
372     jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
373     bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
374     bytecodes()->at(operand_location) = static_cast<uint8_t>(entry);
375   }
376 }
377 
PatchJumpWith16BitOperand(size_t jump_location,int delta)378 void BytecodeArrayWriter::PatchJumpWith16BitOperand(size_t jump_location,
379                                                     int delta) {
380   Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
381   DCHECK(Bytecodes::IsForwardJump(jump_bytecode));
382   DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
383   DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm);
384   DCHECK_GT(delta, 0);
385   size_t operand_location = jump_location + 1;
386   uint8_t operand_bytes[2];
387   if (Bytecodes::ScaleForUnsignedOperand(delta) <= OperandScale::kDouble) {
388     // The jump fits within the range of an Imm16 operand, so cancel
389     // the reservation and jump directly.
390     constant_array_builder()->DiscardReservedEntry(OperandSize::kShort);
391     base::WriteUnalignedValue<uint16_t>(
392         reinterpret_cast<Address>(operand_bytes), static_cast<uint16_t>(delta));
393   } else {
394     // The jump does not fit within the range of an Imm16 operand, so
395     // commit reservation putting the offset into the constant pool,
396     // and update the jump instruction and operand.
397     size_t entry = constant_array_builder()->CommitReservedEntry(
398         OperandSize::kShort, Smi::FromInt(delta));
399     jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
400     bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
401     base::WriteUnalignedValue<uint16_t>(
402         reinterpret_cast<Address>(operand_bytes), static_cast<uint16_t>(entry));
403   }
404   DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&
405          bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder);
406   bytecodes()->at(operand_location++) = operand_bytes[0];
407   bytecodes()->at(operand_location) = operand_bytes[1];
408 }
409 
PatchJumpWith32BitOperand(size_t jump_location,int delta)410 void BytecodeArrayWriter::PatchJumpWith32BitOperand(size_t jump_location,
411                                                     int delta) {
412   DCHECK(Bytecodes::IsJumpImmediate(
413       Bytecodes::FromByte(bytecodes()->at(jump_location))));
414   constant_array_builder()->DiscardReservedEntry(OperandSize::kQuad);
415   uint8_t operand_bytes[4];
416   base::WriteUnalignedValue<uint32_t>(reinterpret_cast<Address>(operand_bytes),
417                                       static_cast<uint32_t>(delta));
418   size_t operand_location = jump_location + 1;
419   DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&
420          bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder &&
421          bytecodes()->at(operand_location + 2) == k8BitJumpPlaceholder &&
422          bytecodes()->at(operand_location + 3) == k8BitJumpPlaceholder);
423   bytecodes()->at(operand_location++) = operand_bytes[0];
424   bytecodes()->at(operand_location++) = operand_bytes[1];
425   bytecodes()->at(operand_location++) = operand_bytes[2];
426   bytecodes()->at(operand_location) = operand_bytes[3];
427 }
428 
PatchJump(size_t jump_target,size_t jump_location)429 void BytecodeArrayWriter::PatchJump(size_t jump_target, size_t jump_location) {
430   Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
431   int delta = static_cast<int>(jump_target - jump_location);
432   int prefix_offset = 0;
433   OperandScale operand_scale = OperandScale::kSingle;
434   if (Bytecodes::IsPrefixScalingBytecode(jump_bytecode)) {
435     // If a prefix scaling bytecode is emitted the target offset is one
436     // less than the case of no prefix scaling bytecode.
437     delta -= 1;
438     prefix_offset = 1;
439     operand_scale = Bytecodes::PrefixBytecodeToOperandScale(jump_bytecode);
440     jump_bytecode =
441         Bytecodes::FromByte(bytecodes()->at(jump_location + prefix_offset));
442   }
443 
444   DCHECK(Bytecodes::IsJump(jump_bytecode));
445   switch (operand_scale) {
446     case OperandScale::kSingle:
447       PatchJumpWith8BitOperand(jump_location, delta);
448       break;
449     case OperandScale::kDouble:
450       PatchJumpWith16BitOperand(jump_location + prefix_offset, delta);
451       break;
452     case OperandScale::kQuadruple:
453       PatchJumpWith32BitOperand(jump_location + prefix_offset, delta);
454       break;
455     default:
456       UNREACHABLE();
457   }
458   unbound_jumps_--;
459 }
460 
EmitJumpLoop(BytecodeNode * node,BytecodeLoopHeader * loop_header)461 void BytecodeArrayWriter::EmitJumpLoop(BytecodeNode* node,
462                                        BytecodeLoopHeader* loop_header) {
463   DCHECK_EQ(node->bytecode(), Bytecode::kJumpLoop);
464   DCHECK_EQ(0u, node->operand(0));
465 
466   size_t current_offset = bytecodes()->size();
467 
468   CHECK_GE(current_offset, loop_header->offset());
469   CHECK_LE(current_offset, static_cast<size_t>(kMaxUInt32));
470   // Label has been bound already so this is a backwards jump.
471   uint32_t delta =
472       static_cast<uint32_t>(current_offset - loop_header->offset());
473   OperandScale operand_scale = Bytecodes::ScaleForUnsignedOperand(delta);
474   if (operand_scale > OperandScale::kSingle) {
475     // Adjust for scaling byte prefix for wide jump offset.
476     delta += 1;
477   }
478   node->update_operand0(delta);
479   EmitBytecode(node);
480 }
481 
EmitJump(BytecodeNode * node,BytecodeLabel * label)482 void BytecodeArrayWriter::EmitJump(BytecodeNode* node, BytecodeLabel* label) {
483   DCHECK(Bytecodes::IsForwardJump(node->bytecode()));
484   DCHECK_EQ(0u, node->operand(0));
485 
486   size_t current_offset = bytecodes()->size();
487 
488   // The label has not yet been bound so this is a forward reference
489   // that will be patched when the label is bound. We create a
490   // reservation in the constant pool so the jump can be patched
491   // when the label is bound. The reservation means the maximum size
492   // of the operand for the constant is known and the jump can
493   // be emitted into the bytecode stream with space for the operand.
494   unbound_jumps_++;
495   label->set_referrer(current_offset);
496   OperandSize reserved_operand_size =
497       constant_array_builder()->CreateReservedEntry();
498   DCHECK_NE(Bytecode::kJumpLoop, node->bytecode());
499   switch (reserved_operand_size) {
500     case OperandSize::kNone:
501       UNREACHABLE();
502     case OperandSize::kByte:
503       node->update_operand0(k8BitJumpPlaceholder);
504       break;
505     case OperandSize::kShort:
506       node->update_operand0(k16BitJumpPlaceholder);
507       break;
508     case OperandSize::kQuad:
509       node->update_operand0(k32BitJumpPlaceholder);
510       break;
511   }
512   EmitBytecode(node);
513 }
514 
EmitSwitch(BytecodeNode * node,BytecodeJumpTable * jump_table)515 void BytecodeArrayWriter::EmitSwitch(BytecodeNode* node,
516                                      BytecodeJumpTable* jump_table) {
517   DCHECK(Bytecodes::IsSwitch(node->bytecode()));
518 
519   size_t current_offset = bytecodes()->size();
520   if (node->operand_scale() > OperandScale::kSingle) {
521     // Adjust for scaling byte prefix.
522     current_offset += 1;
523   }
524   jump_table->set_switch_bytecode_offset(current_offset);
525 
526   EmitBytecode(node);
527 }
528 
529 }  // namespace interpreter
530 }  // namespace internal
531 }  // namespace v8
532