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-builder.h"
6 
7 #include "src/globals.h"
8 #include "src/interpreter/bytecode-array-writer.h"
9 #include "src/interpreter/bytecode-dead-code-optimizer.h"
10 #include "src/interpreter/bytecode-label.h"
11 #include "src/interpreter/bytecode-peephole-optimizer.h"
12 #include "src/interpreter/bytecode-register-optimizer.h"
13 #include "src/interpreter/interpreter-intrinsics.h"
14 
15 namespace v8 {
16 namespace internal {
17 namespace interpreter {
18 
BytecodeArrayBuilder(Isolate * isolate,Zone * zone,int parameter_count,int context_count,int locals_count,FunctionLiteral * literal,SourcePositionTableBuilder::RecordingMode source_position_mode)19 BytecodeArrayBuilder::BytecodeArrayBuilder(
20     Isolate* isolate, Zone* zone, int parameter_count, int context_count,
21     int locals_count, FunctionLiteral* literal,
22     SourcePositionTableBuilder::RecordingMode source_position_mode)
23     : zone_(zone),
24       bytecode_generated_(false),
25       constant_array_builder_(zone, isolate->factory()->the_hole_value()),
26       handler_table_builder_(zone),
27       return_seen_in_block_(false),
28       parameter_count_(parameter_count),
29       local_register_count_(locals_count),
30       context_register_count_(context_count),
31       register_allocator_(fixed_register_count()),
32       bytecode_array_writer_(zone, &constant_array_builder_,
33                              source_position_mode),
34       pipeline_(&bytecode_array_writer_),
35       register_optimizer_(nullptr) {
36   DCHECK_GE(parameter_count_, 0);
37   DCHECK_GE(context_register_count_, 0);
38   DCHECK_GE(local_register_count_, 0);
39 
40   if (FLAG_ignition_deadcode) {
41     pipeline_ = new (zone) BytecodeDeadCodeOptimizer(pipeline_);
42   }
43 
44   if (FLAG_ignition_peephole) {
45     pipeline_ = new (zone) BytecodePeepholeOptimizer(pipeline_);
46   }
47 
48   if (FLAG_ignition_reo) {
49     register_optimizer_ = new (zone) BytecodeRegisterOptimizer(
50         zone, &register_allocator_, fixed_register_count(), parameter_count,
51         pipeline_);
52   }
53 
54   return_position_ = literal ? literal->return_position() : kNoSourcePosition;
55 }
56 
first_context_register() const57 Register BytecodeArrayBuilder::first_context_register() const {
58   DCHECK_GT(context_register_count_, 0);
59   return Register(local_register_count_);
60 }
61 
last_context_register() const62 Register BytecodeArrayBuilder::last_context_register() const {
63   DCHECK_GT(context_register_count_, 0);
64   return Register(local_register_count_ + context_register_count_ - 1);
65 }
66 
Parameter(int parameter_index) const67 Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
68   DCHECK_GE(parameter_index, 0);
69   return Register::FromParameterIndex(parameter_index, parameter_count());
70 }
71 
ToBytecodeArray(Isolate * isolate)72 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) {
73   DCHECK(return_seen_in_block_);
74   DCHECK(!bytecode_generated_);
75   bytecode_generated_ = true;
76 
77   int register_count = total_register_count();
78 
79   if (register_optimizer_) {
80     register_optimizer_->Flush();
81     register_count = register_optimizer_->maxiumum_register_index() + 1;
82   }
83 
84   Handle<FixedArray> handler_table =
85       handler_table_builder()->ToHandlerTable(isolate);
86   return pipeline_->ToBytecodeArray(isolate, register_count, parameter_count(),
87                                     handler_table);
88 }
89 
CurrentSourcePosition(Bytecode bytecode)90 BytecodeSourceInfo BytecodeArrayBuilder::CurrentSourcePosition(
91     Bytecode bytecode) {
92   BytecodeSourceInfo source_position;
93   if (latest_source_info_.is_valid()) {
94     // Statement positions need to be emitted immediately.  Expression
95     // positions can be pushed back until a bytecode is found that can
96     // throw (if expression position filtering is turned on). We only
97     // invalidate the existing source position information if it is used.
98     if (latest_source_info_.is_statement() ||
99         !FLAG_ignition_filter_expression_positions ||
100         !Bytecodes::IsWithoutExternalSideEffects(bytecode)) {
101       source_position = latest_source_info_;
102       latest_source_info_.set_invalid();
103     }
104   }
105   return source_position;
106 }
107 
108 namespace {
109 
110 template <OperandTypeInfo type_info>
111 class UnsignedOperandHelper {
112  public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,size_t value))113   INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, size_t value)) {
114     DCHECK(IsValid(value));
115     return static_cast<uint32_t>(value);
116   }
117 
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,int value))118   INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, int value)) {
119     DCHECK_GE(value, 0);
120     return Convert(builder, static_cast<size_t>(value));
121   }
122 
123  private:
IsValid(size_t value)124   static bool IsValid(size_t value) {
125     switch (type_info) {
126       case OperandTypeInfo::kFixedUnsignedByte:
127         return value <= kMaxUInt8;
128       case OperandTypeInfo::kFixedUnsignedShort:
129         return value <= kMaxUInt16;
130       case OperandTypeInfo::kScalableUnsignedByte:
131         return value <= kMaxUInt32;
132       default:
133         UNREACHABLE();
134         return false;
135     }
136   }
137 };
138 
139 template <OperandType>
140 class OperandHelper {};
141 
142 #define DEFINE_UNSIGNED_OPERAND_HELPER(Name, Type) \
143   template <>                                      \
144   class OperandHelper<OperandType::k##Name>        \
145       : public UnsignedOperandHelper<Type> {};
146 UNSIGNED_SCALAR_OPERAND_TYPE_LIST(DEFINE_UNSIGNED_OPERAND_HELPER)
147 #undef DEFINE_UNSIGNED_OPERAND_HELPER
148 
149 template <>
150 class OperandHelper<OperandType::kImm> {
151  public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,int value))152   INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, int value)) {
153     return static_cast<uint32_t>(value);
154   }
155 };
156 
157 template <>
158 class OperandHelper<OperandType::kReg> {
159  public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,Register reg))160   INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, Register reg)) {
161     return builder->GetInputRegisterOperand(reg);
162   }
163 };
164 
165 template <>
166 class OperandHelper<OperandType::kRegList> {
167  public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,RegisterList reg_list))168   INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder,
169                                  RegisterList reg_list)) {
170     return builder->GetInputRegisterListOperand(reg_list);
171   }
172 };
173 
174 template <>
175 class OperandHelper<OperandType::kRegPair> {
176  public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,RegisterList reg_list))177   INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder,
178                                  RegisterList reg_list)) {
179     DCHECK_EQ(reg_list.register_count(), 2);
180     return builder->GetInputRegisterListOperand(reg_list);
181   }
182 };
183 
184 template <>
185 class OperandHelper<OperandType::kRegOut> {
186  public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,Register reg))187   INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder, Register reg)) {
188     return builder->GetOutputRegisterOperand(reg);
189   }
190 };
191 
192 template <>
193 class OperandHelper<OperandType::kRegOutPair> {
194  public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,RegisterList reg_list))195   INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder,
196                                  RegisterList reg_list)) {
197     DCHECK_EQ(2, reg_list.register_count());
198     return builder->GetOutputRegisterListOperand(reg_list);
199   }
200 };
201 
202 template <>
203 class OperandHelper<OperandType::kRegOutTriple> {
204  public:
INLINE(static uint32_t Convert (BytecodeArrayBuilder * builder,RegisterList reg_list))205   INLINE(static uint32_t Convert(BytecodeArrayBuilder* builder,
206                                  RegisterList reg_list)) {
207     DCHECK_EQ(3, reg_list.register_count());
208     return builder->GetOutputRegisterListOperand(reg_list);
209   }
210 };
211 
212 }  // namespace
213 
214 template <OperandType... operand_types>
215 class BytecodeNodeBuilder {
216  public:
217   template <typename... Operands>
INLINE(static BytecodeNode Make (BytecodeArrayBuilder * builder,BytecodeSourceInfo source_info,Bytecode bytecode,Operands...operands))218   INLINE(static BytecodeNode Make(BytecodeArrayBuilder* builder,
219                                   BytecodeSourceInfo source_info,
220                                   Bytecode bytecode, Operands... operands)) {
221     builder->PrepareToOutputBytecode(bytecode);
222     // The "OperandHelper<operand_types>::Convert(builder, operands)..." will
223     // expand both the OperandType... and Operands... parameter packs e.g. for:
224     //   BytecodeNodeBuilder<OperandType::kReg, OperandType::kImm>::Make<
225     //       Register, int>(..., Register reg, int immediate)
226     // the code will expand into:
227     //    OperandHelper<OperandType::kReg>::Convert(builder, reg),
228     //    OperandHelper<OperandType::kImm>::Convert(builder, immediate),
229     return BytecodeNode(
230         bytecode, OperandHelper<operand_types>::Convert(builder, operands)...,
231         source_info);
232   }
233 };
234 
235 #define DEFINE_BYTECODE_OUTPUT(name, accumulator_use, ...)                 \
236   template <typename... Operands>                                          \
237   void BytecodeArrayBuilder::Output##name(Operands... operands) {          \
238     BytecodeNode node(BytecodeNodeBuilder<__VA_ARGS__>::Make<Operands...>( \
239         this, CurrentSourcePosition(Bytecode::k##name), Bytecode::k##name, \
240         operands...));                                                     \
241     pipeline()->Write(&node);                                              \
242   }                                                                        \
243                                                                            \
244   template <typename... Operands>                                          \
245   void BytecodeArrayBuilder::Output##name(BytecodeLabel* label,            \
246                                           Operands... operands) {          \
247     DCHECK(Bytecodes::IsJump(Bytecode::k##name));                          \
248     BytecodeNode node(BytecodeNodeBuilder<__VA_ARGS__>::Make<Operands...>( \
249         this, CurrentSourcePosition(Bytecode::k##name), Bytecode::k##name, \
250         operands...));                                                     \
251     pipeline()->WriteJump(&node, label);                                   \
252     LeaveBasicBlock();                                                     \
253   }
BYTECODE_LIST(DEFINE_BYTECODE_OUTPUT)254 BYTECODE_LIST(DEFINE_BYTECODE_OUTPUT)
255 #undef DEFINE_BYTECODE_OUTPUT
256 
257 BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op,
258                                                             Register reg,
259                                                             int feedback_slot) {
260   switch (op) {
261     case Token::Value::ADD:
262       OutputAdd(reg, feedback_slot);
263       break;
264     case Token::Value::SUB:
265       OutputSub(reg, feedback_slot);
266       break;
267     case Token::Value::MUL:
268       OutputMul(reg, feedback_slot);
269       break;
270     case Token::Value::DIV:
271       OutputDiv(reg, feedback_slot);
272       break;
273     case Token::Value::MOD:
274       OutputMod(reg, feedback_slot);
275       break;
276     case Token::Value::BIT_OR:
277       OutputBitwiseOr(reg, feedback_slot);
278       break;
279     case Token::Value::BIT_XOR:
280       OutputBitwiseXor(reg, feedback_slot);
281       break;
282     case Token::Value::BIT_AND:
283       OutputBitwiseAnd(reg, feedback_slot);
284       break;
285     case Token::Value::SHL:
286       OutputShiftLeft(reg, feedback_slot);
287       break;
288     case Token::Value::SAR:
289       OutputShiftRight(reg, feedback_slot);
290       break;
291     case Token::Value::SHR:
292       OutputShiftRightLogical(reg, feedback_slot);
293       break;
294     default:
295       UNREACHABLE();
296   }
297   return *this;
298 }
299 
CountOperation(Token::Value op,int feedback_slot)300 BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op,
301                                                            int feedback_slot) {
302   if (op == Token::Value::ADD) {
303     OutputInc(feedback_slot);
304   } else {
305     DCHECK_EQ(op, Token::Value::SUB);
306     OutputDec(feedback_slot);
307   }
308   return *this;
309 }
310 
LogicalNot()311 BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() {
312   OutputToBooleanLogicalNot();
313   return *this;
314 }
315 
TypeOf()316 BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() {
317   OutputTypeOf();
318   return *this;
319 }
320 
CompareOperation(Token::Value op,Register reg,int feedback_slot)321 BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(
322     Token::Value op, Register reg, int feedback_slot) {
323   switch (op) {
324     case Token::Value::EQ:
325       OutputTestEqual(reg, feedback_slot);
326       break;
327     case Token::Value::NE:
328       OutputTestNotEqual(reg, feedback_slot);
329       break;
330     case Token::Value::EQ_STRICT:
331       OutputTestEqualStrict(reg, feedback_slot);
332       break;
333     case Token::Value::LT:
334       OutputTestLessThan(reg, feedback_slot);
335       break;
336     case Token::Value::GT:
337       OutputTestGreaterThan(reg, feedback_slot);
338       break;
339     case Token::Value::LTE:
340       OutputTestLessThanOrEqual(reg, feedback_slot);
341       break;
342     case Token::Value::GTE:
343       OutputTestGreaterThanOrEqual(reg, feedback_slot);
344       break;
345     case Token::Value::INSTANCEOF:
346       OutputTestInstanceOf(reg);
347       break;
348     case Token::Value::IN:
349       OutputTestIn(reg);
350       break;
351     default:
352       UNREACHABLE();
353   }
354   return *this;
355 }
356 
LoadConstantPoolEntry(size_t entry)357 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadConstantPoolEntry(
358     size_t entry) {
359   OutputLdaConstant(entry);
360   return *this;
361 }
362 
LoadLiteral(v8::internal::Smi * smi)363 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
364     v8::internal::Smi* smi) {
365   int32_t raw_smi = smi->value();
366   if (raw_smi == 0) {
367     OutputLdaZero();
368   } else {
369     OutputLdaSmi(raw_smi);
370   }
371   return *this;
372 }
373 
LoadLiteral(Handle<Object> object)374 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) {
375   size_t entry = GetConstantPoolEntry(object);
376   OutputLdaConstant(entry);
377   return *this;
378 }
379 
LoadUndefined()380 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadUndefined() {
381   OutputLdaUndefined();
382   return *this;
383 }
384 
LoadNull()385 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNull() {
386   OutputLdaNull();
387   return *this;
388 }
389 
LoadTheHole()390 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTheHole() {
391   OutputLdaTheHole();
392   return *this;
393 }
394 
LoadTrue()395 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadTrue() {
396   OutputLdaTrue();
397   return *this;
398 }
399 
LoadFalse()400 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() {
401   OutputLdaFalse();
402   return *this;
403 }
404 
LoadAccumulatorWithRegister(Register reg)405 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister(
406     Register reg) {
407   if (register_optimizer_) {
408     register_optimizer_->DoLdar(reg, CurrentSourcePosition(Bytecode::kLdar));
409   } else {
410     OutputLdar(reg);
411   }
412   return *this;
413 }
414 
StoreAccumulatorInRegister(Register reg)415 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
416     Register reg) {
417   if (register_optimizer_) {
418     register_optimizer_->DoStar(reg, CurrentSourcePosition(Bytecode::kStar));
419   } else {
420     OutputStar(reg);
421   }
422   return *this;
423 }
424 
MoveRegister(Register from,Register to)425 BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from,
426                                                          Register to) {
427   DCHECK(from != to);
428   if (register_optimizer_) {
429     register_optimizer_->DoMov(from, to, CurrentSourcePosition(Bytecode::kMov));
430   } else {
431     OutputMov(from, to);
432   }
433   return *this;
434 }
435 
LoadGlobal(int feedback_slot,TypeofMode typeof_mode)436 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(int feedback_slot,
437                                                        TypeofMode typeof_mode) {
438   if (typeof_mode == INSIDE_TYPEOF) {
439     OutputLdaGlobalInsideTypeof(feedback_slot);
440   } else {
441     DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF);
442     OutputLdaGlobal(feedback_slot);
443   }
444   return *this;
445 }
446 
StoreGlobal(const Handle<String> name,int feedback_slot,LanguageMode language_mode)447 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal(
448     const Handle<String> name, int feedback_slot, LanguageMode language_mode) {
449   size_t name_index = GetConstantPoolEntry(name);
450   if (language_mode == SLOPPY) {
451     OutputStaGlobalSloppy(name_index, feedback_slot);
452   } else {
453     DCHECK_EQ(language_mode, STRICT);
454     OutputStaGlobalStrict(name_index, feedback_slot);
455   }
456   return *this;
457 }
458 
LoadContextSlot(Register context,int slot_index,int depth)459 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context,
460                                                             int slot_index,
461                                                             int depth) {
462   if (context.is_current_context() && depth == 0) {
463     OutputLdaCurrentContextSlot(slot_index);
464   } else {
465     OutputLdaContextSlot(context, slot_index, depth);
466   }
467   return *this;
468 }
469 
StoreContextSlot(Register context,int slot_index,int depth)470 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context,
471                                                              int slot_index,
472                                                              int depth) {
473   if (context.is_current_context() && depth == 0) {
474     OutputStaCurrentContextSlot(slot_index);
475   } else {
476     OutputStaContextSlot(context, slot_index, depth);
477   }
478   return *this;
479 }
480 
LoadLookupSlot(const Handle<String> name,TypeofMode typeof_mode)481 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot(
482     const Handle<String> name, TypeofMode typeof_mode) {
483   size_t name_index = GetConstantPoolEntry(name);
484   if (typeof_mode == INSIDE_TYPEOF) {
485     OutputLdaLookupSlotInsideTypeof(name_index);
486   } else {
487     DCHECK_EQ(typeof_mode, NOT_INSIDE_TYPEOF);
488     OutputLdaLookupSlot(name_index);
489   }
490   return *this;
491 }
492 
LoadLookupContextSlot(const Handle<String> name,TypeofMode typeof_mode,int slot_index,int depth)493 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupContextSlot(
494     const Handle<String> name, TypeofMode typeof_mode, int slot_index,
495     int depth) {
496   size_t name_index = GetConstantPoolEntry(name);
497   if (typeof_mode == INSIDE_TYPEOF) {
498     OutputLdaLookupContextSlotInsideTypeof(name_index, slot_index, depth);
499   } else {
500     DCHECK(typeof_mode == NOT_INSIDE_TYPEOF);
501     OutputLdaLookupContextSlot(name_index, slot_index, depth);
502   }
503   return *this;
504 }
505 
LoadLookupGlobalSlot(const Handle<String> name,TypeofMode typeof_mode,int feedback_slot,int depth)506 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupGlobalSlot(
507     const Handle<String> name, TypeofMode typeof_mode, int feedback_slot,
508     int depth) {
509   size_t name_index = GetConstantPoolEntry(name);
510   if (typeof_mode == INSIDE_TYPEOF) {
511     OutputLdaLookupGlobalSlotInsideTypeof(name_index, feedback_slot, depth);
512   } else {
513     DCHECK(typeof_mode == NOT_INSIDE_TYPEOF);
514     OutputLdaLookupGlobalSlot(name_index, feedback_slot, depth);
515   }
516   return *this;
517 }
518 
StoreLookupSlot(const Handle<String> name,LanguageMode language_mode)519 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot(
520     const Handle<String> name, LanguageMode language_mode) {
521   size_t name_index = GetConstantPoolEntry(name);
522   if (language_mode == SLOPPY) {
523     OutputStaLookupSlotSloppy(name_index);
524   } else {
525     DCHECK_EQ(language_mode, STRICT);
526     OutputStaLookupSlotStrict(name_index);
527   }
528   return *this;
529 }
530 
LoadNamedProperty(Register object,const Handle<Name> name,int feedback_slot)531 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
532     Register object, const Handle<Name> name, int feedback_slot) {
533   size_t name_index = GetConstantPoolEntry(name);
534   OutputLdaNamedProperty(object, name_index, feedback_slot);
535   return *this;
536 }
537 
LoadKeyedProperty(Register object,int feedback_slot)538 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty(
539     Register object, int feedback_slot) {
540   OutputLdaKeyedProperty(object, feedback_slot);
541   return *this;
542 }
543 
StoreNamedProperty(Register object,const Handle<Name> name,int feedback_slot,LanguageMode language_mode)544 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty(
545     Register object, const Handle<Name> name, int feedback_slot,
546     LanguageMode language_mode) {
547   size_t name_index = GetConstantPoolEntry(name);
548   if (language_mode == SLOPPY) {
549     OutputStaNamedPropertySloppy(object, name_index, feedback_slot);
550   } else {
551     DCHECK_EQ(language_mode, STRICT);
552     OutputStaNamedPropertyStrict(object, name_index, feedback_slot);
553   }
554   return *this;
555 }
556 
StoreKeyedProperty(Register object,Register key,int feedback_slot,LanguageMode language_mode)557 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
558     Register object, Register key, int feedback_slot,
559     LanguageMode language_mode) {
560   if (language_mode == SLOPPY) {
561     OutputStaKeyedPropertySloppy(object, key, feedback_slot);
562   } else {
563     DCHECK_EQ(language_mode, STRICT);
564     OutputStaKeyedPropertyStrict(object, key, feedback_slot);
565   }
566   return *this;
567 }
568 
CreateClosure(size_t entry,int flags)569 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(size_t entry,
570                                                           int flags) {
571   OutputCreateClosure(entry, flags);
572   return *this;
573 }
574 
CreateBlockContext(Handle<ScopeInfo> scope_info)575 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateBlockContext(
576     Handle<ScopeInfo> scope_info) {
577   size_t entry = GetConstantPoolEntry(scope_info);
578   OutputCreateBlockContext(entry);
579   return *this;
580 }
581 
CreateCatchContext(Register exception,Handle<String> name,Handle<ScopeInfo> scope_info)582 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateCatchContext(
583     Register exception, Handle<String> name, Handle<ScopeInfo> scope_info) {
584   size_t name_index = GetConstantPoolEntry(name);
585   size_t scope_info_index = GetConstantPoolEntry(scope_info);
586   OutputCreateCatchContext(exception, name_index, scope_info_index);
587   return *this;
588 }
589 
CreateFunctionContext(int slots)590 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateFunctionContext(int slots) {
591   OutputCreateFunctionContext(slots);
592   return *this;
593 }
594 
CreateWithContext(Register object,Handle<ScopeInfo> scope_info)595 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateWithContext(
596     Register object, Handle<ScopeInfo> scope_info) {
597   size_t scope_info_index = GetConstantPoolEntry(scope_info);
598   OutputCreateWithContext(object, scope_info_index);
599   return *this;
600 }
601 
CreateArguments(CreateArgumentsType type)602 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments(
603     CreateArgumentsType type) {
604   switch (type) {
605     case CreateArgumentsType::kMappedArguments:
606       OutputCreateMappedArguments();
607       break;
608     case CreateArgumentsType::kUnmappedArguments:
609       OutputCreateUnmappedArguments();
610       break;
611     case CreateArgumentsType::kRestParameter:
612       OutputCreateRestParameter();
613       break;
614     default:
615       UNREACHABLE();
616   }
617   return *this;
618 }
619 
CreateRegExpLiteral(Handle<String> pattern,int literal_index,int flags)620 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral(
621     Handle<String> pattern, int literal_index, int flags) {
622   size_t pattern_entry = GetConstantPoolEntry(pattern);
623   OutputCreateRegExpLiteral(pattern_entry, literal_index, flags);
624   return *this;
625 }
626 
CreateArrayLiteral(Handle<FixedArray> constant_elements,int literal_index,int flags)627 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral(
628     Handle<FixedArray> constant_elements, int literal_index, int flags) {
629   size_t constant_elements_entry = GetConstantPoolEntry(constant_elements);
630   OutputCreateArrayLiteral(constant_elements_entry, literal_index, flags);
631   return *this;
632 }
633 
CreateObjectLiteral(Handle<FixedArray> constant_properties,int literal_index,int flags,Register output)634 BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral(
635     Handle<FixedArray> constant_properties, int literal_index, int flags,
636     Register output) {
637   size_t constant_properties_entry = GetConstantPoolEntry(constant_properties);
638   OutputCreateObjectLiteral(constant_properties_entry, literal_index, flags,
639                             output);
640   return *this;
641 }
642 
PushContext(Register context)643 BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
644   OutputPushContext(context);
645   return *this;
646 }
647 
PopContext(Register context)648 BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
649   OutputPopContext(context);
650   return *this;
651 }
652 
ConvertAccumulatorToObject(Register out)653 BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToObject(
654     Register out) {
655   OutputToObject(out);
656   return *this;
657 }
658 
ConvertAccumulatorToName(Register out)659 BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToName(
660     Register out) {
661   OutputToName(out);
662   return *this;
663 }
664 
ConvertAccumulatorToNumber(Register out)665 BytecodeArrayBuilder& BytecodeArrayBuilder::ConvertAccumulatorToNumber(
666     Register out) {
667   OutputToNumber(out);
668   return *this;
669 }
670 
Bind(BytecodeLabel * label)671 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
672   // Flush the register optimizer when binding a label to ensure all
673   // expected registers are valid when jumping to this label.
674   if (register_optimizer_) register_optimizer_->Flush();
675   pipeline_->BindLabel(label);
676   LeaveBasicBlock();
677   return *this;
678 }
679 
Bind(const BytecodeLabel & target,BytecodeLabel * label)680 BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target,
681                                                  BytecodeLabel* label) {
682   pipeline_->BindLabel(target, label);
683   LeaveBasicBlock();
684   return *this;
685 }
686 
Jump(BytecodeLabel * label)687 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) {
688   OutputJump(label, 0);
689   return *this;
690 }
691 
JumpIfTrue(BytecodeLabel * label)692 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) {
693   // The peephole optimizer attempts to simplify JumpIfToBooleanTrue
694   // to JumpIfTrue.
695   OutputJumpIfToBooleanTrue(label, 0);
696   return *this;
697 }
698 
JumpIfFalse(BytecodeLabel * label)699 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) {
700   OutputJumpIfToBooleanFalse(label, 0);
701   return *this;
702 }
703 
JumpIfNull(BytecodeLabel * label)704 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) {
705   OutputJumpIfNull(label, 0);
706   return *this;
707 }
708 
JumpIfUndefined(BytecodeLabel * label)709 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined(
710     BytecodeLabel* label) {
711   OutputJumpIfUndefined(label, 0);
712   return *this;
713 }
714 
JumpIfNotHole(BytecodeLabel * label)715 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotHole(
716     BytecodeLabel* label) {
717   OutputJumpIfNotHole(label, 0);
718   return *this;
719 }
720 
JumpLoop(BytecodeLabel * label,int loop_depth)721 BytecodeArrayBuilder& BytecodeArrayBuilder::JumpLoop(BytecodeLabel* label,
722                                                      int loop_depth) {
723   OutputJumpLoop(label, 0, loop_depth);
724   return *this;
725 }
726 
StackCheck(int position)727 BytecodeArrayBuilder& BytecodeArrayBuilder::StackCheck(int position) {
728   if (position != kNoSourcePosition) {
729     // We need to attach a non-breakable source position to a stack
730     // check, so we simply add it as expression position. There can be
731     // a prior statement position from constructs like:
732     //
733     //    do var x;  while (false);
734     //
735     // A Nop could be inserted for empty statements, but since no code
736     // is associated with these positions, instead we force the stack
737     // check's expression position which eliminates the empty
738     // statement's position.
739     latest_source_info_.ForceExpressionPosition(position);
740   }
741   OutputStackCheck();
742   return *this;
743 }
744 
Throw()745 BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() {
746   OutputThrow();
747   return *this;
748 }
749 
ReThrow()750 BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() {
751   OutputReThrow();
752   return *this;
753 }
754 
Return()755 BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
756   SetReturnPosition();
757   OutputReturn();
758   return_seen_in_block_ = true;
759   return *this;
760 }
761 
Debugger()762 BytecodeArrayBuilder& BytecodeArrayBuilder::Debugger() {
763   OutputDebugger();
764   return *this;
765 }
766 
ForInPrepare(Register receiver,RegisterList cache_info_triple)767 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare(
768     Register receiver, RegisterList cache_info_triple) {
769   DCHECK_EQ(3, cache_info_triple.register_count());
770   OutputForInPrepare(receiver, cache_info_triple);
771   return *this;
772 }
773 
ForInContinue(Register index,Register cache_length)774 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInContinue(
775     Register index, Register cache_length) {
776   OutputForInContinue(index, cache_length);
777   return *this;
778 }
779 
ForInNext(Register receiver,Register index,RegisterList cache_type_array_pair,int feedback_slot)780 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext(
781     Register receiver, Register index, RegisterList cache_type_array_pair,
782     int feedback_slot) {
783   DCHECK_EQ(2, cache_type_array_pair.register_count());
784   OutputForInNext(receiver, index, cache_type_array_pair, feedback_slot);
785   return *this;
786 }
787 
ForInStep(Register index)788 BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) {
789   OutputForInStep(index);
790   return *this;
791 }
792 
StoreModuleVariable(int cell_index,int depth)793 BytecodeArrayBuilder& BytecodeArrayBuilder::StoreModuleVariable(int cell_index,
794                                                                 int depth) {
795   OutputStaModuleVariable(cell_index, depth);
796   return *this;
797 }
798 
LoadModuleVariable(int cell_index,int depth)799 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadModuleVariable(int cell_index,
800                                                                int depth) {
801   OutputLdaModuleVariable(cell_index, depth);
802   return *this;
803 }
804 
SuspendGenerator(Register generator)805 BytecodeArrayBuilder& BytecodeArrayBuilder::SuspendGenerator(
806     Register generator) {
807   OutputSuspendGenerator(generator);
808   return *this;
809 }
810 
ResumeGenerator(Register generator)811 BytecodeArrayBuilder& BytecodeArrayBuilder::ResumeGenerator(
812     Register generator) {
813   OutputResumeGenerator(generator);
814   return *this;
815 }
816 
MarkHandler(int handler_id,HandlerTable::CatchPrediction catch_prediction)817 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkHandler(
818     int handler_id, HandlerTable::CatchPrediction catch_prediction) {
819   BytecodeLabel handler;
820   Bind(&handler);
821   handler_table_builder()->SetHandlerTarget(handler_id, handler.offset());
822   handler_table_builder()->SetPrediction(handler_id, catch_prediction);
823   return *this;
824 }
825 
MarkTryBegin(int handler_id,Register context)826 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryBegin(int handler_id,
827                                                          Register context) {
828   BytecodeLabel try_begin;
829   Bind(&try_begin);
830   handler_table_builder()->SetTryRegionStart(handler_id, try_begin.offset());
831   handler_table_builder()->SetContextRegister(handler_id, context);
832   return *this;
833 }
834 
MarkTryEnd(int handler_id)835 BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) {
836   BytecodeLabel try_end;
837   Bind(&try_end);
838   handler_table_builder()->SetTryRegionEnd(handler_id, try_end.offset());
839   return *this;
840 }
841 
Call(Register callable,RegisterList args,int feedback_slot,Call::CallType call_type,TailCallMode tail_call_mode)842 BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
843                                                  RegisterList args,
844                                                  int feedback_slot,
845                                                  Call::CallType call_type,
846                                                  TailCallMode tail_call_mode) {
847   if (tail_call_mode == TailCallMode::kDisallow) {
848     if (call_type == Call::NAMED_PROPERTY_CALL ||
849         call_type == Call::KEYED_PROPERTY_CALL) {
850       OutputCallProperty(callable, args, args.register_count(), feedback_slot);
851     } else {
852       OutputCall(callable, args, args.register_count(), feedback_slot);
853     }
854   } else {
855     DCHECK(tail_call_mode == TailCallMode::kAllow);
856     OutputTailCall(callable, args, args.register_count(), feedback_slot);
857   }
858   return *this;
859 }
860 
New(Register constructor,RegisterList args,int feedback_slot_id)861 BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
862                                                 RegisterList args,
863                                                 int feedback_slot_id) {
864   OutputNew(constructor, args, args.register_count(), feedback_slot_id);
865   return *this;
866 }
867 
CallRuntime(Runtime::FunctionId function_id,RegisterList args)868 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
869     Runtime::FunctionId function_id, RegisterList args) {
870   DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size);
871   DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort);
872   if (IntrinsicsHelper::IsSupported(function_id)) {
873     IntrinsicsHelper::IntrinsicId intrinsic_id =
874         IntrinsicsHelper::FromRuntimeId(function_id);
875     OutputInvokeIntrinsic(static_cast<int>(intrinsic_id), args,
876                           args.register_count());
877   } else {
878     OutputCallRuntime(static_cast<int>(function_id), args,
879                       args.register_count());
880   }
881   return *this;
882 }
883 
CallRuntime(Runtime::FunctionId function_id,Register arg)884 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
885     Runtime::FunctionId function_id, Register arg) {
886   return CallRuntime(function_id, RegisterList(arg.index(), 1));
887 }
888 
CallRuntime(Runtime::FunctionId function_id)889 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
890     Runtime::FunctionId function_id) {
891   return CallRuntime(function_id, RegisterList());
892 }
893 
CallRuntimeForPair(Runtime::FunctionId function_id,RegisterList args,RegisterList return_pair)894 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
895     Runtime::FunctionId function_id, RegisterList args,
896     RegisterList return_pair) {
897   DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size);
898   DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort);
899   DCHECK_EQ(2, return_pair.register_count());
900   OutputCallRuntimeForPair(static_cast<uint16_t>(function_id), args,
901                            args.register_count(), return_pair);
902   return *this;
903 }
904 
CallRuntimeForPair(Runtime::FunctionId function_id,Register arg,RegisterList return_pair)905 BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
906     Runtime::FunctionId function_id, Register arg, RegisterList return_pair) {
907   return CallRuntimeForPair(function_id, RegisterList(arg.index(), 1),
908                             return_pair);
909 }
910 
CallJSRuntime(int context_index,RegisterList args)911 BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(int context_index,
912                                                           RegisterList args) {
913   OutputCallJSRuntime(context_index, args, args.register_count());
914   return *this;
915 }
916 
Delete(Register object,LanguageMode language_mode)917 BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object,
918                                                    LanguageMode language_mode) {
919   if (language_mode == SLOPPY) {
920     OutputDeletePropertySloppy(object);
921   } else {
922     DCHECK_EQ(language_mode, STRICT);
923     OutputDeletePropertyStrict(object);
924   }
925   return *this;
926 }
927 
GetConstantPoolEntry(Handle<Object> object)928 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) {
929   return constant_array_builder()->Insert(object);
930 }
931 
AllocateConstantPoolEntry()932 size_t BytecodeArrayBuilder::AllocateConstantPoolEntry() {
933   return constant_array_builder()->AllocateEntry();
934 }
935 
InsertConstantPoolEntryAt(size_t entry,Handle<Object> object)936 void BytecodeArrayBuilder::InsertConstantPoolEntryAt(size_t entry,
937                                                      Handle<Object> object) {
938   constant_array_builder()->InsertAllocatedEntry(entry, object);
939 }
940 
SetReturnPosition()941 void BytecodeArrayBuilder::SetReturnPosition() {
942   if (return_position_ == kNoSourcePosition) return;
943   latest_source_info_.MakeStatementPosition(return_position_);
944 }
945 
RegisterIsValid(Register reg) const946 bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const {
947   if (!reg.is_valid()) {
948     return false;
949   }
950 
951   if (reg.is_current_context() || reg.is_function_closure() ||
952       reg.is_new_target()) {
953     return true;
954   } else if (reg.is_parameter()) {
955     int parameter_index = reg.ToParameterIndex(parameter_count());
956     return parameter_index >= 0 && parameter_index < parameter_count();
957   } else if (reg.index() < fixed_register_count()) {
958     return true;
959   } else {
960     return register_allocator()->RegisterIsLive(reg);
961   }
962 }
963 
RegisterListIsValid(RegisterList reg_list) const964 bool BytecodeArrayBuilder::RegisterListIsValid(RegisterList reg_list) const {
965   if (reg_list.register_count() == 0) {
966     return reg_list.first_register() == Register(0);
967   } else {
968     int first_reg_index = reg_list.first_register().index();
969     for (int i = 0; i < reg_list.register_count(); i++) {
970       if (!RegisterIsValid(Register(first_reg_index + i))) {
971         return false;
972       }
973     }
974     return true;
975   }
976 }
977 
PrepareToOutputBytecode(Bytecode bytecode)978 void BytecodeArrayBuilder::PrepareToOutputBytecode(Bytecode bytecode) {
979   if (register_optimizer_) register_optimizer_->PrepareForBytecode(bytecode);
980 }
981 
GetInputRegisterOperand(Register reg)982 uint32_t BytecodeArrayBuilder::GetInputRegisterOperand(Register reg) {
983   DCHECK(RegisterIsValid(reg));
984   if (register_optimizer_) reg = register_optimizer_->GetInputRegister(reg);
985   return static_cast<uint32_t>(reg.ToOperand());
986 }
987 
GetOutputRegisterOperand(Register reg)988 uint32_t BytecodeArrayBuilder::GetOutputRegisterOperand(Register reg) {
989   DCHECK(RegisterIsValid(reg));
990   if (register_optimizer_) register_optimizer_->PrepareOutputRegister(reg);
991   return static_cast<uint32_t>(reg.ToOperand());
992 }
993 
GetInputRegisterListOperand(RegisterList reg_list)994 uint32_t BytecodeArrayBuilder::GetInputRegisterListOperand(
995     RegisterList reg_list) {
996   DCHECK(RegisterListIsValid(reg_list));
997   if (register_optimizer_)
998     reg_list = register_optimizer_->GetInputRegisterList(reg_list);
999   return static_cast<uint32_t>(reg_list.first_register().ToOperand());
1000 }
1001 
GetOutputRegisterListOperand(RegisterList reg_list)1002 uint32_t BytecodeArrayBuilder::GetOutputRegisterListOperand(
1003     RegisterList reg_list) {
1004   DCHECK(RegisterListIsValid(reg_list));
1005   if (register_optimizer_)
1006     register_optimizer_->PrepareOutputRegisterList(reg_list);
1007   return static_cast<uint32_t>(reg_list.first_register().ToOperand());
1008 }
1009 
1010 }  // namespace interpreter
1011 }  // namespace internal
1012 }  // namespace v8
1013