• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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/interpreter-generator.h"
6 
7 #include <array>
8 #include <tuple>
9 
10 #include "src/builtins/builtins-constructor-gen.h"
11 #include "src/builtins/builtins-iterator-gen.h"
12 #include "src/builtins/profile-data-reader.h"
13 #include "src/codegen/code-factory.h"
14 #include "src/debug/debug.h"
15 #include "src/ic/accessor-assembler.h"
16 #include "src/ic/binary-op-assembler.h"
17 #include "src/ic/ic.h"
18 #include "src/ic/unary-op-assembler.h"
19 #include "src/interpreter/bytecode-flags.h"
20 #include "src/interpreter/bytecodes.h"
21 #include "src/interpreter/interpreter-assembler.h"
22 #include "src/interpreter/interpreter-intrinsics-generator.h"
23 #include "src/objects/cell.h"
24 #include "src/objects/js-generator.h"
25 #include "src/objects/objects-inl.h"
26 #include "src/objects/oddball.h"
27 #include "src/objects/shared-function-info.h"
28 #include "src/objects/source-text-module.h"
29 #include "src/utils/ostreams.h"
30 #include "torque-generated/exported-macros-assembler.h"
31 
32 namespace v8 {
33 namespace internal {
34 namespace interpreter {
35 
36 namespace {
37 
38 using compiler::CodeAssemblerState;
39 using Label = CodeStubAssembler::Label;
40 
41 #define IGNITION_HANDLER(Name, BaseAssembler)                         \
42   class Name##Assembler : public BaseAssembler {                      \
43    public:                                                            \
44     explicit Name##Assembler(compiler::CodeAssemblerState* state,     \
45                              Bytecode bytecode, OperandScale scale)   \
46         : BaseAssembler(state, bytecode, scale) {}                    \
47     Name##Assembler(const Name##Assembler&) = delete;                 \
48     Name##Assembler& operator=(const Name##Assembler&) = delete;      \
49     static void Generate(compiler::CodeAssemblerState* state,         \
50                          OperandScale scale);                         \
51                                                                       \
52    private:                                                           \
53     void GenerateImpl();                                              \
54   };                                                                  \
55   void Name##Assembler::Generate(compiler::CodeAssemblerState* state, \
56                                  OperandScale scale) {                \
57     Name##Assembler assembler(state, Bytecode::k##Name, scale);       \
58     state->SetInitialDebugInformation(#Name, __FILE__, __LINE__);     \
59     assembler.GenerateImpl();                                         \
60   }                                                                   \
61   void Name##Assembler::GenerateImpl()
62 
63 // LdaZero
64 //
65 // Load literal '0' into the accumulator.
IGNITION_HANDLER(LdaZero,InterpreterAssembler)66 IGNITION_HANDLER(LdaZero, InterpreterAssembler) {
67   TNode<Number> zero_value = NumberConstant(0.0);
68   SetAccumulator(zero_value);
69   Dispatch();
70 }
71 
72 // LdaSmi <imm>
73 //
74 // Load an integer literal into the accumulator as a Smi.
IGNITION_HANDLER(LdaSmi,InterpreterAssembler)75 IGNITION_HANDLER(LdaSmi, InterpreterAssembler) {
76   TNode<Smi> smi_int = BytecodeOperandImmSmi(0);
77   SetAccumulator(smi_int);
78   Dispatch();
79 }
80 
81 // LdaConstant <idx>
82 //
83 // Load constant literal at |idx| in the constant pool into the accumulator.
IGNITION_HANDLER(LdaConstant,InterpreterAssembler)84 IGNITION_HANDLER(LdaConstant, InterpreterAssembler) {
85   TNode<Object> constant = LoadConstantPoolEntryAtOperandIndex(0);
86   SetAccumulator(constant);
87   Dispatch();
88 }
89 
90 // LdaUndefined
91 //
92 // Load Undefined into the accumulator.
IGNITION_HANDLER(LdaUndefined,InterpreterAssembler)93 IGNITION_HANDLER(LdaUndefined, InterpreterAssembler) {
94   SetAccumulator(UndefinedConstant());
95   Dispatch();
96 }
97 
98 // LdaNull
99 //
100 // Load Null into the accumulator.
IGNITION_HANDLER(LdaNull,InterpreterAssembler)101 IGNITION_HANDLER(LdaNull, InterpreterAssembler) {
102   SetAccumulator(NullConstant());
103   Dispatch();
104 }
105 
106 // LdaTheHole
107 //
108 // Load TheHole into the accumulator.
IGNITION_HANDLER(LdaTheHole,InterpreterAssembler)109 IGNITION_HANDLER(LdaTheHole, InterpreterAssembler) {
110   SetAccumulator(TheHoleConstant());
111   Dispatch();
112 }
113 
114 // LdaTrue
115 //
116 // Load True into the accumulator.
IGNITION_HANDLER(LdaTrue,InterpreterAssembler)117 IGNITION_HANDLER(LdaTrue, InterpreterAssembler) {
118   SetAccumulator(TrueConstant());
119   Dispatch();
120 }
121 
122 // LdaFalse
123 //
124 // Load False into the accumulator.
IGNITION_HANDLER(LdaFalse,InterpreterAssembler)125 IGNITION_HANDLER(LdaFalse, InterpreterAssembler) {
126   SetAccumulator(FalseConstant());
127   Dispatch();
128 }
129 
130 // Ldar <src>
131 //
132 // Load accumulator with value from register <src>.
IGNITION_HANDLER(Ldar,InterpreterAssembler)133 IGNITION_HANDLER(Ldar, InterpreterAssembler) {
134   TNode<Object> value = LoadRegisterAtOperandIndex(0);
135   SetAccumulator(value);
136   Dispatch();
137 }
138 
139 // Star <dst>
140 //
141 // Store accumulator to register <dst>.
IGNITION_HANDLER(Star,InterpreterAssembler)142 IGNITION_HANDLER(Star, InterpreterAssembler) {
143   TNode<Object> accumulator = GetAccumulator();
144   StoreRegisterAtOperandIndex(accumulator, 0);
145   Dispatch();
146 }
147 
148 // Star0 - StarN
149 //
150 // Store accumulator to one of a special batch of registers, without using a
151 // second byte to specify the destination.
152 //
153 // Even though this handler is declared as Star0, multiple entries in
154 // the jump table point to this handler.
IGNITION_HANDLER(Star0,InterpreterAssembler)155 IGNITION_HANDLER(Star0, InterpreterAssembler) {
156   TNode<Object> accumulator = GetAccumulator();
157   TNode<WordT> opcode = LoadBytecode(BytecodeOffset());
158   StoreRegisterForShortStar(accumulator, opcode);
159   Dispatch();
160 }
161 
162 // Mov <src> <dst>
163 //
164 // Stores the value of register <src> to register <dst>.
IGNITION_HANDLER(Mov,InterpreterAssembler)165 IGNITION_HANDLER(Mov, InterpreterAssembler) {
166   TNode<Object> src_value = LoadRegisterAtOperandIndex(0);
167   StoreRegisterAtOperandIndex(src_value, 1);
168   Dispatch();
169 }
170 
171 class InterpreterLoadGlobalAssembler : public InterpreterAssembler {
172  public:
InterpreterLoadGlobalAssembler(CodeAssemblerState * state,Bytecode bytecode,OperandScale operand_scale)173   InterpreterLoadGlobalAssembler(CodeAssemblerState* state, Bytecode bytecode,
174                                  OperandScale operand_scale)
175       : InterpreterAssembler(state, bytecode, operand_scale) {}
176 
LdaGlobal(int slot_operand_index,int name_operand_index,TypeofMode typeof_mode)177   void LdaGlobal(int slot_operand_index, int name_operand_index,
178                  TypeofMode typeof_mode) {
179     TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
180 
181     AccessorAssembler accessor_asm(state());
182     ExitPoint exit_point(this, [=](TNode<Object> result) {
183       SetAccumulator(result);
184       Dispatch();
185     });
186 
187     LazyNode<TaggedIndex> lazy_slot = [=] {
188       return BytecodeOperandIdxTaggedIndex(slot_operand_index);
189     };
190 
191     LazyNode<Context> lazy_context = [=] { return GetContext(); };
192 
193     LazyNode<Name> lazy_name = [=] {
194       TNode<Name> name =
195           CAST(LoadConstantPoolEntryAtOperandIndex(name_operand_index));
196       return name;
197     };
198 
199     accessor_asm.LoadGlobalIC(maybe_feedback_vector, lazy_slot, lazy_context,
200                               lazy_name, typeof_mode, &exit_point);
201   }
202 };
203 
204 // LdaGlobal <name_index> <slot>
205 //
206 // Load the global with name in constant pool entry <name_index> into the
207 // accumulator using FeedBackVector slot <slot> outside of a typeof.
IGNITION_HANDLER(LdaGlobal,InterpreterLoadGlobalAssembler)208 IGNITION_HANDLER(LdaGlobal, InterpreterLoadGlobalAssembler) {
209   static const int kNameOperandIndex = 0;
210   static const int kSlotOperandIndex = 1;
211 
212   LdaGlobal(kSlotOperandIndex, kNameOperandIndex, TypeofMode::kNotInside);
213 }
214 
215 // LdaGlobalInsideTypeof <name_index> <slot>
216 //
217 // Load the global with name in constant pool entry <name_index> into the
218 // accumulator using FeedBackVector slot <slot> inside of a typeof.
IGNITION_HANDLER(LdaGlobalInsideTypeof,InterpreterLoadGlobalAssembler)219 IGNITION_HANDLER(LdaGlobalInsideTypeof, InterpreterLoadGlobalAssembler) {
220   static const int kNameOperandIndex = 0;
221   static const int kSlotOperandIndex = 1;
222 
223   LdaGlobal(kSlotOperandIndex, kNameOperandIndex, TypeofMode::kInside);
224 }
225 
226 // StaGlobal <name_index> <slot>
227 //
228 // Store the value in the accumulator into the global with name in constant pool
229 // entry <name_index> using FeedBackVector slot <slot>.
IGNITION_HANDLER(StaGlobal,InterpreterAssembler)230 IGNITION_HANDLER(StaGlobal, InterpreterAssembler) {
231   TNode<Context> context = GetContext();
232 
233   // Store the global via the StoreGlobalIC.
234   TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
235   TNode<Object> value = GetAccumulator();
236   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
237   TNode<HeapObject> maybe_vector = LoadFeedbackVector();
238 
239   TNode<Object> result = CallBuiltin(Builtin::kStoreGlobalIC, context, name,
240                                      value, slot, maybe_vector);
241   // To avoid special logic in the deoptimizer to re-materialize the value in
242   // the accumulator, we overwrite the accumulator after the IC call. It
243   // doesn't really matter what we write to the accumulator here, since we
244   // restore to the correct value on the outside. Storing the result means we
245   // don't need to keep unnecessary state alive across the callstub.
246   SetAccumulator(result);
247 
248   Dispatch();
249 }
250 
251 // LdaContextSlot <context> <slot_index> <depth>
252 //
253 // Load the object in |slot_index| of the context at |depth| in the context
254 // chain starting at |context| into the accumulator.
IGNITION_HANDLER(LdaContextSlot,InterpreterAssembler)255 IGNITION_HANDLER(LdaContextSlot, InterpreterAssembler) {
256   TNode<Context> context = CAST(LoadRegisterAtOperandIndex(0));
257   TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(1));
258   TNode<Uint32T> depth = BytecodeOperandUImm(2);
259   TNode<Context> slot_context = GetContextAtDepth(context, depth);
260   TNode<Object> result = LoadContextElement(slot_context, slot_index);
261   SetAccumulator(result);
262   Dispatch();
263 }
264 
265 // LdaImmutableContextSlot <context> <slot_index> <depth>
266 //
267 // Load the object in |slot_index| of the context at |depth| in the context
268 // chain starting at |context| into the accumulator.
IGNITION_HANDLER(LdaImmutableContextSlot,InterpreterAssembler)269 IGNITION_HANDLER(LdaImmutableContextSlot, InterpreterAssembler) {
270   TNode<Context> context = CAST(LoadRegisterAtOperandIndex(0));
271   TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(1));
272   TNode<Uint32T> depth = BytecodeOperandUImm(2);
273   TNode<Context> slot_context = GetContextAtDepth(context, depth);
274   TNode<Object> result = LoadContextElement(slot_context, slot_index);
275   SetAccumulator(result);
276   Dispatch();
277 }
278 
279 // LdaCurrentContextSlot <slot_index>
280 //
281 // Load the object in |slot_index| of the current context into the accumulator.
IGNITION_HANDLER(LdaCurrentContextSlot,InterpreterAssembler)282 IGNITION_HANDLER(LdaCurrentContextSlot, InterpreterAssembler) {
283   TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(0));
284   TNode<Context> slot_context = GetContext();
285   TNode<Object> result = LoadContextElement(slot_context, slot_index);
286   SetAccumulator(result);
287   Dispatch();
288 }
289 
290 // LdaImmutableCurrentContextSlot <slot_index>
291 //
292 // Load the object in |slot_index| of the current context into the accumulator.
IGNITION_HANDLER(LdaImmutableCurrentContextSlot,InterpreterAssembler)293 IGNITION_HANDLER(LdaImmutableCurrentContextSlot, InterpreterAssembler) {
294   TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(0));
295   TNode<Context> slot_context = GetContext();
296   TNode<Object> result = LoadContextElement(slot_context, slot_index);
297   SetAccumulator(result);
298   Dispatch();
299 }
300 
301 // StaContextSlot <context> <slot_index> <depth>
302 //
303 // Stores the object in the accumulator into |slot_index| of the context at
304 // |depth| in the context chain starting at |context|.
IGNITION_HANDLER(StaContextSlot,InterpreterAssembler)305 IGNITION_HANDLER(StaContextSlot, InterpreterAssembler) {
306   TNode<Object> value = GetAccumulator();
307   TNode<Context> context = CAST(LoadRegisterAtOperandIndex(0));
308   TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(1));
309   TNode<Uint32T> depth = BytecodeOperandUImm(2);
310   TNode<Context> slot_context = GetContextAtDepth(context, depth);
311   StoreContextElement(slot_context, slot_index, value);
312   Dispatch();
313 }
314 
315 // StaCurrentContextSlot <slot_index>
316 //
317 // Stores the object in the accumulator into |slot_index| of the current
318 // context.
IGNITION_HANDLER(StaCurrentContextSlot,InterpreterAssembler)319 IGNITION_HANDLER(StaCurrentContextSlot, InterpreterAssembler) {
320   TNode<Object> value = GetAccumulator();
321   TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(0));
322   TNode<Context> slot_context = GetContext();
323   StoreContextElement(slot_context, slot_index, value);
324   Dispatch();
325 }
326 
327 // LdaLookupSlot <name_index>
328 //
329 // Lookup the object with the name in constant pool entry |name_index|
330 // dynamically.
IGNITION_HANDLER(LdaLookupSlot,InterpreterAssembler)331 IGNITION_HANDLER(LdaLookupSlot, InterpreterAssembler) {
332   TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
333   TNode<Context> context = GetContext();
334   TNode<Object> result = CallRuntime(Runtime::kLoadLookupSlot, context, name);
335   SetAccumulator(result);
336   Dispatch();
337 }
338 
339 // LdaLookupSlotInsideTypeof <name_index>
340 //
341 // Lookup the object with the name in constant pool entry |name_index|
342 // dynamically without causing a NoReferenceError.
IGNITION_HANDLER(LdaLookupSlotInsideTypeof,InterpreterAssembler)343 IGNITION_HANDLER(LdaLookupSlotInsideTypeof, InterpreterAssembler) {
344   TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
345   TNode<Context> context = GetContext();
346   TNode<Object> result =
347       CallRuntime(Runtime::kLoadLookupSlotInsideTypeof, context, name);
348   SetAccumulator(result);
349   Dispatch();
350 }
351 
352 class InterpreterLookupContextSlotAssembler : public InterpreterAssembler {
353  public:
InterpreterLookupContextSlotAssembler(CodeAssemblerState * state,Bytecode bytecode,OperandScale operand_scale)354   InterpreterLookupContextSlotAssembler(CodeAssemblerState* state,
355                                         Bytecode bytecode,
356                                         OperandScale operand_scale)
357       : InterpreterAssembler(state, bytecode, operand_scale) {}
358 
LookupContextSlot(Runtime::FunctionId function_id)359   void LookupContextSlot(Runtime::FunctionId function_id) {
360     TNode<Context> context = GetContext();
361     TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(1));
362     TNode<Uint32T> depth = BytecodeOperandUImm(2);
363 
364     Label slowpath(this, Label::kDeferred);
365 
366     // Check for context extensions to allow the fast path.
367     TNode<Context> slot_context =
368         GotoIfHasContextExtensionUpToDepth(context, depth, &slowpath);
369 
370     // Fast path does a normal load context.
371     {
372       TNode<Object> result = LoadContextElement(slot_context, slot_index);
373       SetAccumulator(result);
374       Dispatch();
375     }
376 
377     // Slow path when we have to call out to the runtime.
378     BIND(&slowpath);
379     {
380       TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
381       TNode<Object> result = CallRuntime(function_id, context, name);
382       SetAccumulator(result);
383       Dispatch();
384     }
385   }
386 };
387 
388 // LdaLookupContextSlot <name_index>
389 //
390 // Lookup the object with the name in constant pool entry |name_index|
391 // dynamically.
IGNITION_HANDLER(LdaLookupContextSlot,InterpreterLookupContextSlotAssembler)392 IGNITION_HANDLER(LdaLookupContextSlot, InterpreterLookupContextSlotAssembler) {
393   LookupContextSlot(Runtime::kLoadLookupSlot);
394 }
395 
396 // LdaLookupContextSlotInsideTypeof <name_index>
397 //
398 // Lookup the object with the name in constant pool entry |name_index|
399 // dynamically without causing a NoReferenceError.
IGNITION_HANDLER(LdaLookupContextSlotInsideTypeof,InterpreterLookupContextSlotAssembler)400 IGNITION_HANDLER(LdaLookupContextSlotInsideTypeof,
401                  InterpreterLookupContextSlotAssembler) {
402   LookupContextSlot(Runtime::kLoadLookupSlotInsideTypeof);
403 }
404 
405 class InterpreterLookupGlobalAssembler : public InterpreterLoadGlobalAssembler {
406  public:
InterpreterLookupGlobalAssembler(CodeAssemblerState * state,Bytecode bytecode,OperandScale operand_scale)407   InterpreterLookupGlobalAssembler(CodeAssemblerState* state, Bytecode bytecode,
408                                    OperandScale operand_scale)
409       : InterpreterLoadGlobalAssembler(state, bytecode, operand_scale) {}
410 
LookupGlobalSlot(Runtime::FunctionId function_id)411   void LookupGlobalSlot(Runtime::FunctionId function_id) {
412     TNode<Context> context = GetContext();
413     TNode<Uint32T> depth = BytecodeOperandUImm(2);
414 
415     Label slowpath(this, Label::kDeferred);
416 
417     // Check for context extensions to allow the fast path
418     GotoIfHasContextExtensionUpToDepth(context, depth, &slowpath);
419 
420     // Fast path does a normal load global
421     {
422       static const int kNameOperandIndex = 0;
423       static const int kSlotOperandIndex = 1;
424 
425       TypeofMode typeof_mode =
426           function_id == Runtime::kLoadLookupSlotInsideTypeof
427               ? TypeofMode::kInside
428               : TypeofMode::kNotInside;
429 
430       LdaGlobal(kSlotOperandIndex, kNameOperandIndex, typeof_mode);
431     }
432 
433     // Slow path when we have to call out to the runtime
434     BIND(&slowpath);
435     {
436       TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
437       TNode<Object> result = CallRuntime(function_id, context, name);
438       SetAccumulator(result);
439       Dispatch();
440     }
441   }
442 };
443 
444 // LdaLookupGlobalSlot <name_index> <feedback_slot> <depth>
445 //
446 // Lookup the object with the name in constant pool entry |name_index|
447 // dynamically.
IGNITION_HANDLER(LdaLookupGlobalSlot,InterpreterLookupGlobalAssembler)448 IGNITION_HANDLER(LdaLookupGlobalSlot, InterpreterLookupGlobalAssembler) {
449   LookupGlobalSlot(Runtime::kLoadLookupSlot);
450 }
451 
452 // LdaLookupGlobalSlotInsideTypeof <name_index> <feedback_slot> <depth>
453 //
454 // Lookup the object with the name in constant pool entry |name_index|
455 // dynamically without causing a NoReferenceError.
IGNITION_HANDLER(LdaLookupGlobalSlotInsideTypeof,InterpreterLookupGlobalAssembler)456 IGNITION_HANDLER(LdaLookupGlobalSlotInsideTypeof,
457                  InterpreterLookupGlobalAssembler) {
458   LookupGlobalSlot(Runtime::kLoadLookupSlotInsideTypeof);
459 }
460 
461 // StaLookupSlot <name_index> <flags>
462 //
463 // Store the object in accumulator to the object with the name in constant
464 // pool entry |name_index|.
IGNITION_HANDLER(StaLookupSlot,InterpreterAssembler)465 IGNITION_HANDLER(StaLookupSlot, InterpreterAssembler) {
466   TNode<Object> value = GetAccumulator();
467   TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
468   TNode<Uint32T> bytecode_flags = BytecodeOperandFlag(1);
469   TNode<Context> context = GetContext();
470   TVARIABLE(Object, var_result);
471 
472   Label sloppy(this), strict(this), end(this);
473   DCHECK_EQ(0, LanguageMode::kSloppy);
474   DCHECK_EQ(1, LanguageMode::kStrict);
475   DCHECK_EQ(0, static_cast<int>(LookupHoistingMode::kNormal));
476   DCHECK_EQ(1, static_cast<int>(LookupHoistingMode::kLegacySloppy));
477   Branch(IsSetWord32<StoreLookupSlotFlags::LanguageModeBit>(bytecode_flags),
478          &strict, &sloppy);
479 
480   BIND(&strict);
481   {
482     CSA_DCHECK(this, IsClearWord32<StoreLookupSlotFlags::LookupHoistingModeBit>(
483                          bytecode_flags));
484     var_result =
485         CallRuntime(Runtime::kStoreLookupSlot_Strict, context, name, value);
486     Goto(&end);
487   }
488 
489   BIND(&sloppy);
490   {
491     Label hoisting(this), ordinary(this);
492     Branch(IsSetWord32<StoreLookupSlotFlags::LookupHoistingModeBit>(
493                bytecode_flags),
494            &hoisting, &ordinary);
495 
496     BIND(&hoisting);
497     {
498       var_result = CallRuntime(Runtime::kStoreLookupSlot_SloppyHoisting,
499                                context, name, value);
500       Goto(&end);
501     }
502 
503     BIND(&ordinary);
504     {
505       var_result =
506           CallRuntime(Runtime::kStoreLookupSlot_Sloppy, context, name, value);
507       Goto(&end);
508     }
509   }
510 
511   BIND(&end);
512   {
513     SetAccumulator(var_result.value());
514     Dispatch();
515   }
516 }
517 
518 // GetNamedProperty <object> <name_index> <slot>
519 //
520 // Calls the LoadIC at FeedBackVector slot <slot> for <object> and the name at
521 // constant pool entry <name_index>.
IGNITION_HANDLER(GetNamedProperty,InterpreterAssembler)522 IGNITION_HANDLER(GetNamedProperty, InterpreterAssembler) {
523   TNode<HeapObject> feedback_vector = LoadFeedbackVector();
524 
525   // Load receiver.
526   TNode<Object> recv = LoadRegisterAtOperandIndex(0);
527 
528   // Load the name and context lazily.
529   LazyNode<TaggedIndex> lazy_slot = [=] {
530     return BytecodeOperandIdxTaggedIndex(2);
531   };
532   LazyNode<Name> lazy_name = [=] {
533     return CAST(LoadConstantPoolEntryAtOperandIndex(1));
534   };
535   LazyNode<Context> lazy_context = [=] { return GetContext(); };
536 
537   Label done(this);
538   TVARIABLE(Object, var_result);
539   ExitPoint exit_point(this, &done, &var_result);
540 
541   AccessorAssembler::LazyLoadICParameters params(lazy_context, recv, lazy_name,
542                                                  lazy_slot, feedback_vector);
543   AccessorAssembler accessor_asm(state());
544   accessor_asm.LoadIC_BytecodeHandler(&params, &exit_point);
545 
546   BIND(&done);
547   {
548     SetAccumulator(var_result.value());
549     Dispatch();
550   }
551 }
552 
553 // GetNamedPropertyFromSuper <receiver> <name_index> <slot>
554 //
555 // Calls the LoadSuperIC at FeedBackVector slot <slot> for <receiver>, home
556 // object's prototype (home object in the accumulator) and the name at constant
557 // pool entry <name_index>.
IGNITION_HANDLER(GetNamedPropertyFromSuper,InterpreterAssembler)558 IGNITION_HANDLER(GetNamedPropertyFromSuper, InterpreterAssembler) {
559   TNode<Object> receiver = LoadRegisterAtOperandIndex(0);
560   TNode<HeapObject> home_object = CAST(GetAccumulator());
561   TNode<Object> home_object_prototype = LoadMapPrototype(LoadMap(home_object));
562   TNode<Object> name = LoadConstantPoolEntryAtOperandIndex(1);
563   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(2);
564   TNode<HeapObject> feedback_vector = LoadFeedbackVector();
565   TNode<Context> context = GetContext();
566 
567   TNode<Object> result =
568       CallBuiltin(Builtin::kLoadSuperIC, context, receiver,
569                   home_object_prototype, name, slot, feedback_vector);
570   SetAccumulator(result);
571   Dispatch();
572 }
573 
574 // GetKeyedProperty <object> <slot>
575 //
576 // Calls the KeyedLoadIC at FeedBackVector slot <slot> for <object> and the key
577 // in the accumulator.
IGNITION_HANDLER(GetKeyedProperty,InterpreterAssembler)578 IGNITION_HANDLER(GetKeyedProperty, InterpreterAssembler) {
579   TNode<Object> object = LoadRegisterAtOperandIndex(0);
580   TNode<Object> name = GetAccumulator();
581   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
582   TNode<HeapObject> feedback_vector = LoadFeedbackVector();
583   TNode<Context> context = GetContext();
584 
585   TVARIABLE(Object, var_result);
586   var_result = CallBuiltin(Builtin::kKeyedLoadIC, context, object, name, slot,
587                            feedback_vector);
588   SetAccumulator(var_result.value());
589   Dispatch();
590 }
591 
592 class InterpreterSetNamedPropertyAssembler : public InterpreterAssembler {
593  public:
InterpreterSetNamedPropertyAssembler(CodeAssemblerState * state,Bytecode bytecode,OperandScale operand_scale)594   InterpreterSetNamedPropertyAssembler(CodeAssemblerState* state,
595                                        Bytecode bytecode,
596                                        OperandScale operand_scale)
597       : InterpreterAssembler(state, bytecode, operand_scale) {}
598 
SetNamedProperty(Callable ic,NamedPropertyType property_type)599   void SetNamedProperty(Callable ic, NamedPropertyType property_type) {
600     TNode<Object> object = LoadRegisterAtOperandIndex(0);
601     TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(1));
602     TNode<Object> value = GetAccumulator();
603     TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(2);
604     TNode<HeapObject> maybe_vector = LoadFeedbackVector();
605     TNode<Context> context = GetContext();
606 
607     TNode<Object> result =
608         CallStub(ic, context, object, name, value, slot, maybe_vector);
609     // To avoid special logic in the deoptimizer to re-materialize the value in
610     // the accumulator, we overwrite the accumulator after the IC call. It
611     // doesn't really matter what we write to the accumulator here, since we
612     // restore to the correct value on the outside. Storing the result means we
613     // don't need to keep unnecessary state alive across the callstub.
614     SetAccumulator(result);
615     Dispatch();
616   }
617 };
618 
619 // SetNamedProperty <object> <name_index> <slot>
620 //
621 // Calls the StoreIC at FeedBackVector slot <slot> for <object> and
622 // the name in constant pool entry <name_index> with the value in the
623 // accumulator.
IGNITION_HANDLER(SetNamedProperty,InterpreterSetNamedPropertyAssembler)624 IGNITION_HANDLER(SetNamedProperty, InterpreterSetNamedPropertyAssembler) {
625   // StoreIC is currently a base class for multiple property store operations
626   // and contains mixed logic for named and keyed, set and define operations,
627   // the paths are controlled by feedback.
628   // TODO(v8:12548): refactor SetNamedIC as a subclass of StoreIC, which can be
629   // called here.
630   Callable ic = Builtins::CallableFor(isolate(), Builtin::kStoreIC);
631   SetNamedProperty(ic, NamedPropertyType::kNotOwn);
632 }
633 
634 // DefineNamedOwnProperty <object> <name_index> <slot>
635 //
636 // Calls the DefineNamedOwnIC at FeedBackVector slot <slot> for <object> and
637 // the name in constant pool entry <name_index> with the value in the
638 // accumulator.
IGNITION_HANDLER(DefineNamedOwnProperty,InterpreterSetNamedPropertyAssembler)639 IGNITION_HANDLER(DefineNamedOwnProperty, InterpreterSetNamedPropertyAssembler) {
640   Callable ic = Builtins::CallableFor(isolate(), Builtin::kDefineNamedOwnIC);
641   SetNamedProperty(ic, NamedPropertyType::kOwn);
642 }
643 
644 // SetKeyedProperty <object> <key> <slot>
645 //
646 // Calls the KeyedStoreIC at FeedbackVector slot <slot> for <object> and
647 // the key <key> with the value in the accumulator. This could trigger
648 // the setter and the set traps if necessary.
IGNITION_HANDLER(SetKeyedProperty,InterpreterAssembler)649 IGNITION_HANDLER(SetKeyedProperty, InterpreterAssembler) {
650   TNode<Object> object = LoadRegisterAtOperandIndex(0);
651   TNode<Object> name = LoadRegisterAtOperandIndex(1);
652   TNode<Object> value = GetAccumulator();
653   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(2);
654   TNode<HeapObject> maybe_vector = LoadFeedbackVector();
655   TNode<Context> context = GetContext();
656 
657   // KeyedStoreIC is currently a base class for multiple keyed property store
658   // operations and contains mixed logic for set and define operations,
659   // the paths are controlled by feedback.
660   // TODO(v8:12548): refactor SetKeyedIC as a subclass of KeyedStoreIC, which
661   // can be called here.
662   TNode<Object> result = CallBuiltin(Builtin::kKeyedStoreIC, context, object,
663                                      name, value, slot, maybe_vector);
664   // To avoid special logic in the deoptimizer to re-materialize the value in
665   // the accumulator, we overwrite the accumulator after the IC call. It
666   // doesn't really matter what we write to the accumulator here, since we
667   // restore to the correct value on the outside. Storing the result means we
668   // don't need to keep unnecessary state alive across the callstub.
669   SetAccumulator(result);
670   Dispatch();
671 }
672 
673 // DefineKeyedOwnProperty <object> <key> <slot>
674 //
675 // Calls the DefineKeyedOwnIC at FeedbackVector slot <slot> for <object> and
676 // the key <key> with the value in the accumulator.
677 //
678 // This is similar to SetKeyedProperty, but avoids checking the prototype
679 // chain, and in the case of private names, throws if the private name already
680 // exists.
IGNITION_HANDLER(DefineKeyedOwnProperty,InterpreterAssembler)681 IGNITION_HANDLER(DefineKeyedOwnProperty, InterpreterAssembler) {
682   TNode<Object> object = LoadRegisterAtOperandIndex(0);
683   TNode<Object> name = LoadRegisterAtOperandIndex(1);
684   TNode<Object> value = GetAccumulator();
685   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(2);
686   TNode<HeapObject> maybe_vector = LoadFeedbackVector();
687   TNode<Context> context = GetContext();
688 
689   TVARIABLE(Object, var_result);
690   var_result = CallBuiltin(Builtin::kDefineKeyedOwnIC, context, object, name,
691                            value, slot, maybe_vector);
692   // To avoid special logic in the deoptimizer to re-materialize the value in
693   // the accumulator, we overwrite the accumulator after the IC call. It
694   // doesn't really matter what we write to the accumulator here, since we
695   // restore to the correct value on the outside. Storing the result means we
696   // don't need to keep unnecessary state alive across the callstub.
697   SetAccumulator(var_result.value());
698   Dispatch();
699 }
700 
701 // StaInArrayLiteral <array> <index> <slot>
702 //
703 // Calls the StoreInArrayLiteralIC at FeedbackVector slot <slot> for <array> and
704 // the key <index> with the value in the accumulator.
IGNITION_HANDLER(StaInArrayLiteral,InterpreterAssembler)705 IGNITION_HANDLER(StaInArrayLiteral, InterpreterAssembler) {
706   TNode<Object> array = LoadRegisterAtOperandIndex(0);
707   TNode<Object> index = LoadRegisterAtOperandIndex(1);
708   TNode<Object> value = GetAccumulator();
709   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(2);
710   TNode<HeapObject> feedback_vector = LoadFeedbackVector();
711   TNode<Context> context = GetContext();
712 
713   TNode<Object> result =
714       CallBuiltin(Builtin::kStoreInArrayLiteralIC, context, array, index, value,
715                   slot, feedback_vector);
716   // To avoid special logic in the deoptimizer to re-materialize the value in
717   // the accumulator, we overwrite the accumulator after the IC call. It
718   // doesn't really matter what we write to the accumulator here, since we
719   // restore to the correct value on the outside. Storing the result means we
720   // don't need to keep unnecessary state alive across the callstub.
721   SetAccumulator(result);
722   Dispatch();
723 }
724 
725 // DefineKeyedOwnPropertyInLiteral <object> <name> <flags> <slot>
726 //
727 // Define a property <name> with value from the accumulator in <object>.
728 // Property attributes and whether set_function_name are stored in
729 // DefineKeyedOwnPropertyInLiteralFlags <flags>.
730 //
731 // This definition is not observable and is used only for definitions
732 // in object or class literals.
IGNITION_HANDLER(DefineKeyedOwnPropertyInLiteral,InterpreterAssembler)733 IGNITION_HANDLER(DefineKeyedOwnPropertyInLiteral, InterpreterAssembler) {
734   TNode<Object> object = LoadRegisterAtOperandIndex(0);
735   TNode<Object> name = LoadRegisterAtOperandIndex(1);
736   TNode<Object> value = GetAccumulator();
737   TNode<Smi> flags =
738       SmiFromInt32(UncheckedCast<Int32T>(BytecodeOperandFlag(2)));
739   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(3);
740 
741   TNode<HeapObject> feedback_vector = LoadFeedbackVector();
742   TNode<Context> context = GetContext();
743 
744   CallRuntime(Runtime::kDefineKeyedOwnPropertyInLiteral, context, object, name,
745               value, flags, feedback_vector, slot);
746   Dispatch();
747 }
748 
IGNITION_HANDLER(CollectTypeProfile,InterpreterAssembler)749 IGNITION_HANDLER(CollectTypeProfile, InterpreterAssembler) {
750   TNode<Smi> position = BytecodeOperandImmSmi(0);
751   TNode<Object> value = GetAccumulator();
752 
753   TNode<HeapObject> feedback_vector = LoadFeedbackVector();
754   TNode<Context> context = GetContext();
755 
756   CallRuntime(Runtime::kCollectTypeProfile, context, position, value,
757               feedback_vector);
758   Dispatch();
759 }
760 
761 // LdaModuleVariable <cell_index> <depth>
762 //
763 // Load the contents of a module variable into the accumulator.  The variable is
764 // identified by <cell_index>.  <depth> is the depth of the current context
765 // relative to the module context.
IGNITION_HANDLER(LdaModuleVariable,InterpreterAssembler)766 IGNITION_HANDLER(LdaModuleVariable, InterpreterAssembler) {
767   TNode<IntPtrT> cell_index = BytecodeOperandImmIntPtr(0);
768   TNode<Uint32T> depth = BytecodeOperandUImm(1);
769 
770   TNode<Context> module_context = GetContextAtDepth(GetContext(), depth);
771   TNode<SourceTextModule> module =
772       CAST(LoadContextElement(module_context, Context::EXTENSION_INDEX));
773 
774   Label if_export(this), if_import(this), end(this);
775   Branch(IntPtrGreaterThan(cell_index, IntPtrConstant(0)), &if_export,
776          &if_import);
777 
778   BIND(&if_export);
779   {
780     TNode<FixedArray> regular_exports = LoadObjectField<FixedArray>(
781         module, SourceTextModule::kRegularExportsOffset);
782     // The actual array index is (cell_index - 1).
783     TNode<IntPtrT> export_index = IntPtrSub(cell_index, IntPtrConstant(1));
784     TNode<Cell> cell =
785         CAST(LoadFixedArrayElement(regular_exports, export_index));
786     SetAccumulator(LoadObjectField(cell, Cell::kValueOffset));
787     Goto(&end);
788   }
789 
790   BIND(&if_import);
791   {
792     TNode<FixedArray> regular_imports = LoadObjectField<FixedArray>(
793         module, SourceTextModule::kRegularImportsOffset);
794     // The actual array index is (-cell_index - 1).
795     TNode<IntPtrT> import_index = IntPtrSub(IntPtrConstant(-1), cell_index);
796     TNode<Cell> cell =
797         CAST(LoadFixedArrayElement(regular_imports, import_index));
798     SetAccumulator(LoadObjectField(cell, Cell::kValueOffset));
799     Goto(&end);
800   }
801 
802   BIND(&end);
803   Dispatch();
804 }
805 
806 // StaModuleVariable <cell_index> <depth>
807 //
808 // Store accumulator to the module variable identified by <cell_index>.
809 // <depth> is the depth of the current context relative to the module context.
IGNITION_HANDLER(StaModuleVariable,InterpreterAssembler)810 IGNITION_HANDLER(StaModuleVariable, InterpreterAssembler) {
811   TNode<Object> value = GetAccumulator();
812   TNode<IntPtrT> cell_index = BytecodeOperandImmIntPtr(0);
813   TNode<Uint32T> depth = BytecodeOperandUImm(1);
814 
815   TNode<Context> module_context = GetContextAtDepth(GetContext(), depth);
816   TNode<SourceTextModule> module =
817       CAST(LoadContextElement(module_context, Context::EXTENSION_INDEX));
818 
819   Label if_export(this), if_import(this), end(this);
820   Branch(IntPtrGreaterThan(cell_index, IntPtrConstant(0)), &if_export,
821          &if_import);
822 
823   BIND(&if_export);
824   {
825     TNode<FixedArray> regular_exports = LoadObjectField<FixedArray>(
826         module, SourceTextModule::kRegularExportsOffset);
827     // The actual array index is (cell_index - 1).
828     TNode<IntPtrT> export_index = IntPtrSub(cell_index, IntPtrConstant(1));
829     TNode<HeapObject> cell =
830         CAST(LoadFixedArrayElement(regular_exports, export_index));
831     StoreObjectField(cell, Cell::kValueOffset, value);
832     Goto(&end);
833   }
834 
835   BIND(&if_import);
836   {
837     // Not supported (probably never).
838     Abort(AbortReason::kUnsupportedModuleOperation);
839     Goto(&end);
840   }
841 
842   BIND(&end);
843   Dispatch();
844 }
845 
846 // PushContext <context>
847 //
848 // Saves the current context in <context>, and pushes the accumulator as the
849 // new current context.
IGNITION_HANDLER(PushContext,InterpreterAssembler)850 IGNITION_HANDLER(PushContext, InterpreterAssembler) {
851   TNode<Context> new_context = CAST(GetAccumulator());
852   TNode<Context> old_context = GetContext();
853   StoreRegisterAtOperandIndex(old_context, 0);
854   SetContext(new_context);
855   Dispatch();
856 }
857 
858 // PopContext <context>
859 //
860 // Pops the current context and sets <context> as the new context.
IGNITION_HANDLER(PopContext,InterpreterAssembler)861 IGNITION_HANDLER(PopContext, InterpreterAssembler) {
862   TNode<Context> context = CAST(LoadRegisterAtOperandIndex(0));
863   SetContext(context);
864   Dispatch();
865 }
866 
867 class InterpreterBinaryOpAssembler : public InterpreterAssembler {
868  public:
InterpreterBinaryOpAssembler(CodeAssemblerState * state,Bytecode bytecode,OperandScale operand_scale)869   InterpreterBinaryOpAssembler(CodeAssemblerState* state, Bytecode bytecode,
870                                OperandScale operand_scale)
871       : InterpreterAssembler(state, bytecode, operand_scale) {}
872 
873   using BinaryOpGenerator = TNode<Object> (BinaryOpAssembler::*)(
874       const LazyNode<Context>& context, TNode<Object> left, TNode<Object> right,
875       TNode<UintPtrT> slot, const LazyNode<HeapObject>& maybe_feedback_vector,
876       UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi);
877 
BinaryOpWithFeedback(BinaryOpGenerator generator)878   void BinaryOpWithFeedback(BinaryOpGenerator generator) {
879     TNode<Object> lhs = LoadRegisterAtOperandIndex(0);
880     TNode<Object> rhs = GetAccumulator();
881     TNode<Context> context = GetContext();
882     TNode<UintPtrT> slot_index = BytecodeOperandIdx(1);
883     TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
884 
885     BinaryOpAssembler binop_asm(state());
886     TNode<Object> result =
887         (binop_asm.*generator)([=] { return context; }, lhs, rhs, slot_index,
888                                [=] { return maybe_feedback_vector; },
889                                UpdateFeedbackMode::kOptionalFeedback, false);
890     SetAccumulator(result);
891     Dispatch();
892   }
893 
BinaryOpSmiWithFeedback(BinaryOpGenerator generator)894   void BinaryOpSmiWithFeedback(BinaryOpGenerator generator) {
895     TNode<Object> lhs = GetAccumulator();
896     TNode<Smi> rhs = BytecodeOperandImmSmi(0);
897     TNode<Context> context = GetContext();
898     TNode<UintPtrT> slot_index = BytecodeOperandIdx(1);
899     TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
900 
901     BinaryOpAssembler binop_asm(state());
902     TNode<Object> result =
903         (binop_asm.*generator)([=] { return context; }, lhs, rhs, slot_index,
904                                [=] { return maybe_feedback_vector; },
905                                UpdateFeedbackMode::kOptionalFeedback, true);
906     SetAccumulator(result);
907     Dispatch();
908   }
909 };
910 
911 // Add <src>
912 //
913 // Add register <src> to accumulator.
IGNITION_HANDLER(Add,InterpreterBinaryOpAssembler)914 IGNITION_HANDLER(Add, InterpreterBinaryOpAssembler) {
915   BinaryOpWithFeedback(&BinaryOpAssembler::Generate_AddWithFeedback);
916 }
917 
918 // Sub <src>
919 //
920 // Subtract register <src> from accumulator.
IGNITION_HANDLER(Sub,InterpreterBinaryOpAssembler)921 IGNITION_HANDLER(Sub, InterpreterBinaryOpAssembler) {
922   BinaryOpWithFeedback(&BinaryOpAssembler::Generate_SubtractWithFeedback);
923 }
924 
925 // Mul <src>
926 //
927 // Multiply accumulator by register <src>.
IGNITION_HANDLER(Mul,InterpreterBinaryOpAssembler)928 IGNITION_HANDLER(Mul, InterpreterBinaryOpAssembler) {
929   BinaryOpWithFeedback(&BinaryOpAssembler::Generate_MultiplyWithFeedback);
930 }
931 
932 // Div <src>
933 //
934 // Divide register <src> by accumulator.
IGNITION_HANDLER(Div,InterpreterBinaryOpAssembler)935 IGNITION_HANDLER(Div, InterpreterBinaryOpAssembler) {
936   BinaryOpWithFeedback(&BinaryOpAssembler::Generate_DivideWithFeedback);
937 }
938 
939 // Mod <src>
940 //
941 // Modulo register <src> by accumulator.
IGNITION_HANDLER(Mod,InterpreterBinaryOpAssembler)942 IGNITION_HANDLER(Mod, InterpreterBinaryOpAssembler) {
943   BinaryOpWithFeedback(&BinaryOpAssembler::Generate_ModulusWithFeedback);
944 }
945 
946 // Exp <src>
947 //
948 // Exponentiate register <src> (base) with accumulator (exponent).
IGNITION_HANDLER(Exp,InterpreterBinaryOpAssembler)949 IGNITION_HANDLER(Exp, InterpreterBinaryOpAssembler) {
950   BinaryOpWithFeedback(&BinaryOpAssembler::Generate_ExponentiateWithFeedback);
951 }
952 
953 // AddSmi <imm>
954 //
955 // Adds an immediate value <imm> to the value in the accumulator.
IGNITION_HANDLER(AddSmi,InterpreterBinaryOpAssembler)956 IGNITION_HANDLER(AddSmi, InterpreterBinaryOpAssembler) {
957   BinaryOpSmiWithFeedback(&BinaryOpAssembler::Generate_AddWithFeedback);
958 }
959 
960 // SubSmi <imm>
961 //
962 // Subtracts an immediate value <imm> from the value in the accumulator.
IGNITION_HANDLER(SubSmi,InterpreterBinaryOpAssembler)963 IGNITION_HANDLER(SubSmi, InterpreterBinaryOpAssembler) {
964   BinaryOpSmiWithFeedback(&BinaryOpAssembler::Generate_SubtractWithFeedback);
965 }
966 
967 // MulSmi <imm>
968 //
969 // Multiplies an immediate value <imm> to the value in the accumulator.
IGNITION_HANDLER(MulSmi,InterpreterBinaryOpAssembler)970 IGNITION_HANDLER(MulSmi, InterpreterBinaryOpAssembler) {
971   BinaryOpSmiWithFeedback(&BinaryOpAssembler::Generate_MultiplyWithFeedback);
972 }
973 
974 // DivSmi <imm>
975 //
976 // Divides the value in the accumulator by immediate value <imm>.
IGNITION_HANDLER(DivSmi,InterpreterBinaryOpAssembler)977 IGNITION_HANDLER(DivSmi, InterpreterBinaryOpAssembler) {
978   BinaryOpSmiWithFeedback(&BinaryOpAssembler::Generate_DivideWithFeedback);
979 }
980 
981 // ModSmi <imm>
982 //
983 // Modulo accumulator by immediate value <imm>.
IGNITION_HANDLER(ModSmi,InterpreterBinaryOpAssembler)984 IGNITION_HANDLER(ModSmi, InterpreterBinaryOpAssembler) {
985   BinaryOpSmiWithFeedback(&BinaryOpAssembler::Generate_ModulusWithFeedback);
986 }
987 
988 // ExpSmi <imm>
989 //
990 // Exponentiate accumulator (base) with immediate value <imm> (exponent).
IGNITION_HANDLER(ExpSmi,InterpreterBinaryOpAssembler)991 IGNITION_HANDLER(ExpSmi, InterpreterBinaryOpAssembler) {
992   BinaryOpSmiWithFeedback(
993       &BinaryOpAssembler::Generate_ExponentiateWithFeedback);
994 }
995 
996 class InterpreterBitwiseBinaryOpAssembler : public InterpreterAssembler {
997  public:
InterpreterBitwiseBinaryOpAssembler(CodeAssemblerState * state,Bytecode bytecode,OperandScale operand_scale)998   InterpreterBitwiseBinaryOpAssembler(CodeAssemblerState* state,
999                                       Bytecode bytecode,
1000                                       OperandScale operand_scale)
1001       : InterpreterAssembler(state, bytecode, operand_scale) {}
1002 
BitwiseBinaryOpWithFeedback(Operation bitwise_op)1003   void BitwiseBinaryOpWithFeedback(Operation bitwise_op) {
1004     TNode<Object> left = LoadRegisterAtOperandIndex(0);
1005     TNode<Object> right = GetAccumulator();
1006     TNode<Context> context = GetContext();
1007     TNode<UintPtrT> slot_index = BytecodeOperandIdx(1);
1008     TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1009 
1010     BinaryOpAssembler binop_asm(state());
1011     TNode<Object> result = binop_asm.Generate_BitwiseBinaryOpWithFeedback(
1012         bitwise_op, left, right, [=] { return context; }, slot_index,
1013         [=] { return maybe_feedback_vector; },
1014         UpdateFeedbackMode::kOptionalFeedback, false);
1015 
1016     SetAccumulator(result);
1017     Dispatch();
1018   }
1019 
BitwiseBinaryOpWithSmi(Operation bitwise_op)1020   void BitwiseBinaryOpWithSmi(Operation bitwise_op) {
1021     TNode<Object> left = GetAccumulator();
1022     TNode<Smi> right = BytecodeOperandImmSmi(0);
1023     TNode<UintPtrT> slot_index = BytecodeOperandIdx(1);
1024     TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1025     TNode<Context> context = GetContext();
1026 
1027     BinaryOpAssembler binop_asm(state());
1028     TNode<Object> result = binop_asm.Generate_BitwiseBinaryOpWithFeedback(
1029         bitwise_op, left, right, [=] { return context; }, slot_index,
1030         [=] { return maybe_feedback_vector; },
1031         UpdateFeedbackMode::kOptionalFeedback, true);
1032 
1033     SetAccumulator(result);
1034     Dispatch();
1035   }
1036 };
1037 
1038 // BitwiseOr <src>
1039 //
1040 // BitwiseOr register <src> to accumulator.
IGNITION_HANDLER(BitwiseOr,InterpreterBitwiseBinaryOpAssembler)1041 IGNITION_HANDLER(BitwiseOr, InterpreterBitwiseBinaryOpAssembler) {
1042   BitwiseBinaryOpWithFeedback(Operation::kBitwiseOr);
1043 }
1044 
1045 // BitwiseXor <src>
1046 //
1047 // BitwiseXor register <src> to accumulator.
IGNITION_HANDLER(BitwiseXor,InterpreterBitwiseBinaryOpAssembler)1048 IGNITION_HANDLER(BitwiseXor, InterpreterBitwiseBinaryOpAssembler) {
1049   BitwiseBinaryOpWithFeedback(Operation::kBitwiseXor);
1050 }
1051 
1052 // BitwiseAnd <src>
1053 //
1054 // BitwiseAnd register <src> to accumulator.
IGNITION_HANDLER(BitwiseAnd,InterpreterBitwiseBinaryOpAssembler)1055 IGNITION_HANDLER(BitwiseAnd, InterpreterBitwiseBinaryOpAssembler) {
1056   BitwiseBinaryOpWithFeedback(Operation::kBitwiseAnd);
1057 }
1058 
1059 // ShiftLeft <src>
1060 //
1061 // Left shifts register <src> by the count specified in the accumulator.
1062 // Register <src> is converted to an int32 and the accumulator to uint32
1063 // before the operation. 5 lsb bits from the accumulator are used as count
1064 // i.e. <src> << (accumulator & 0x1F).
IGNITION_HANDLER(ShiftLeft,InterpreterBitwiseBinaryOpAssembler)1065 IGNITION_HANDLER(ShiftLeft, InterpreterBitwiseBinaryOpAssembler) {
1066   BitwiseBinaryOpWithFeedback(Operation::kShiftLeft);
1067 }
1068 
1069 // ShiftRight <src>
1070 //
1071 // Right shifts register <src> by the count specified in the accumulator.
1072 // Result is sign extended. Register <src> is converted to an int32 and the
1073 // accumulator to uint32 before the operation. 5 lsb bits from the accumulator
1074 // are used as count i.e. <src> >> (accumulator & 0x1F).
IGNITION_HANDLER(ShiftRight,InterpreterBitwiseBinaryOpAssembler)1075 IGNITION_HANDLER(ShiftRight, InterpreterBitwiseBinaryOpAssembler) {
1076   BitwiseBinaryOpWithFeedback(Operation::kShiftRight);
1077 }
1078 
1079 // ShiftRightLogical <src>
1080 //
1081 // Right Shifts register <src> by the count specified in the accumulator.
1082 // Result is zero-filled. The accumulator and register <src> are converted to
1083 // uint32 before the operation 5 lsb bits from the accumulator are used as
1084 // count i.e. <src> << (accumulator & 0x1F).
IGNITION_HANDLER(ShiftRightLogical,InterpreterBitwiseBinaryOpAssembler)1085 IGNITION_HANDLER(ShiftRightLogical, InterpreterBitwiseBinaryOpAssembler) {
1086   BitwiseBinaryOpWithFeedback(Operation::kShiftRightLogical);
1087 }
1088 
1089 // BitwiseOrSmi <imm>
1090 //
1091 // BitwiseOrSmi accumulator with <imm>.
IGNITION_HANDLER(BitwiseOrSmi,InterpreterBitwiseBinaryOpAssembler)1092 IGNITION_HANDLER(BitwiseOrSmi, InterpreterBitwiseBinaryOpAssembler) {
1093   BitwiseBinaryOpWithSmi(Operation::kBitwiseOr);
1094 }
1095 
1096 // BitwiseXorSmi <imm>
1097 //
1098 // BitwiseXorSmi accumulator with <imm>.
IGNITION_HANDLER(BitwiseXorSmi,InterpreterBitwiseBinaryOpAssembler)1099 IGNITION_HANDLER(BitwiseXorSmi, InterpreterBitwiseBinaryOpAssembler) {
1100   BitwiseBinaryOpWithSmi(Operation::kBitwiseXor);
1101 }
1102 
1103 // BitwiseAndSmi <imm>
1104 //
1105 // BitwiseAndSmi accumulator with <imm>.
IGNITION_HANDLER(BitwiseAndSmi,InterpreterBitwiseBinaryOpAssembler)1106 IGNITION_HANDLER(BitwiseAndSmi, InterpreterBitwiseBinaryOpAssembler) {
1107   BitwiseBinaryOpWithSmi(Operation::kBitwiseAnd);
1108 }
1109 
1110 // BitwiseNot <feedback_slot>
1111 //
1112 // Perform bitwise-not on the accumulator.
IGNITION_HANDLER(BitwiseNot,InterpreterAssembler)1113 IGNITION_HANDLER(BitwiseNot, InterpreterAssembler) {
1114   TNode<Object> value = GetAccumulator();
1115   TNode<Context> context = GetContext();
1116   TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
1117   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1118 
1119   UnaryOpAssembler unary_op_asm(state());
1120   TNode<Object> result = unary_op_asm.Generate_BitwiseNotWithFeedback(
1121       context, value, slot_index, maybe_feedback_vector,
1122       UpdateFeedbackMode::kOptionalFeedback);
1123 
1124   SetAccumulator(result);
1125   Dispatch();
1126 }
1127 
1128 // ShiftLeftSmi <imm>
1129 //
1130 // Left shifts accumulator by the count specified in <imm>.
1131 // The accumulator is converted to an int32 before the operation. The 5
1132 // lsb bits from <imm> are used as count i.e. <src> << (<imm> & 0x1F).
IGNITION_HANDLER(ShiftLeftSmi,InterpreterBitwiseBinaryOpAssembler)1133 IGNITION_HANDLER(ShiftLeftSmi, InterpreterBitwiseBinaryOpAssembler) {
1134   BitwiseBinaryOpWithSmi(Operation::kShiftLeft);
1135 }
1136 
1137 // ShiftRightSmi <imm>
1138 //
1139 // Right shifts accumulator by the count specified in <imm>. Result is sign
1140 // extended. The accumulator is converted to an int32 before the operation. The
1141 // 5 lsb bits from <imm> are used as count i.e. <src> >> (<imm> & 0x1F).
IGNITION_HANDLER(ShiftRightSmi,InterpreterBitwiseBinaryOpAssembler)1142 IGNITION_HANDLER(ShiftRightSmi, InterpreterBitwiseBinaryOpAssembler) {
1143   BitwiseBinaryOpWithSmi(Operation::kShiftRight);
1144 }
1145 
1146 // ShiftRightLogicalSmi <imm>
1147 //
1148 // Right shifts accumulator by the count specified in <imm>. Result is zero
1149 // extended. The accumulator is converted to an int32 before the operation. The
1150 // 5 lsb bits from <imm> are used as count i.e. <src> >>> (<imm> & 0x1F).
IGNITION_HANDLER(ShiftRightLogicalSmi,InterpreterBitwiseBinaryOpAssembler)1151 IGNITION_HANDLER(ShiftRightLogicalSmi, InterpreterBitwiseBinaryOpAssembler) {
1152   BitwiseBinaryOpWithSmi(Operation::kShiftRightLogical);
1153 }
1154 
1155 // Negate <feedback_slot>
1156 //
1157 // Perform arithmetic negation on the accumulator.
IGNITION_HANDLER(Negate,InterpreterAssembler)1158 IGNITION_HANDLER(Negate, InterpreterAssembler) {
1159   TNode<Object> value = GetAccumulator();
1160   TNode<Context> context = GetContext();
1161   TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
1162   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1163 
1164   UnaryOpAssembler unary_op_asm(state());
1165   TNode<Object> result = unary_op_asm.Generate_NegateWithFeedback(
1166       context, value, slot_index, maybe_feedback_vector,
1167       UpdateFeedbackMode::kOptionalFeedback);
1168 
1169   SetAccumulator(result);
1170   Dispatch();
1171 }
1172 
1173 // ToName <dst>
1174 //
1175 // Convert the object referenced by the accumulator to a name.
IGNITION_HANDLER(ToName,InterpreterAssembler)1176 IGNITION_HANDLER(ToName, InterpreterAssembler) {
1177   TNode<Object> object = GetAccumulator();
1178   TNode<Context> context = GetContext();
1179   TNode<Object> result = CallBuiltin(Builtin::kToName, context, object);
1180   StoreRegisterAtOperandIndex(result, 0);
1181   Dispatch();
1182 }
1183 
1184 // ToNumber <slot>
1185 //
1186 // Convert the object referenced by the accumulator to a number.
IGNITION_HANDLER(ToNumber,InterpreterAssembler)1187 IGNITION_HANDLER(ToNumber, InterpreterAssembler) {
1188   ToNumberOrNumeric(Object::Conversion::kToNumber);
1189 }
1190 
1191 // ToNumeric <slot>
1192 //
1193 // Convert the object referenced by the accumulator to a numeric.
IGNITION_HANDLER(ToNumeric,InterpreterAssembler)1194 IGNITION_HANDLER(ToNumeric, InterpreterAssembler) {
1195   ToNumberOrNumeric(Object::Conversion::kToNumeric);
1196 }
1197 
1198 // ToObject <dst>
1199 //
1200 // Convert the object referenced by the accumulator to a JSReceiver.
IGNITION_HANDLER(ToObject,InterpreterAssembler)1201 IGNITION_HANDLER(ToObject, InterpreterAssembler) {
1202   TNode<Object> accumulator = GetAccumulator();
1203   TNode<Context> context = GetContext();
1204   TNode<Object> result = CallBuiltin(Builtin::kToObject, context, accumulator);
1205   StoreRegisterAtOperandIndex(result, 0);
1206   Dispatch();
1207 }
1208 
1209 // ToString
1210 //
1211 // Convert the accumulator to a String.
IGNITION_HANDLER(ToString,InterpreterAssembler)1212 IGNITION_HANDLER(ToString, InterpreterAssembler) {
1213   SetAccumulator(ToString_Inline(GetContext(), GetAccumulator()));
1214   Dispatch();
1215 }
1216 
1217 // Inc
1218 //
1219 // Increments value in the accumulator by one.
IGNITION_HANDLER(Inc,InterpreterAssembler)1220 IGNITION_HANDLER(Inc, InterpreterAssembler) {
1221   TNode<Object> value = GetAccumulator();
1222   TNode<Context> context = GetContext();
1223   TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
1224   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1225 
1226   UnaryOpAssembler unary_op_asm(state());
1227   TNode<Object> result = unary_op_asm.Generate_IncrementWithFeedback(
1228       context, value, slot_index, maybe_feedback_vector,
1229       UpdateFeedbackMode::kOptionalFeedback);
1230 
1231   SetAccumulator(result);
1232   Dispatch();
1233 }
1234 
1235 // Dec
1236 //
1237 // Decrements value in the accumulator by one.
IGNITION_HANDLER(Dec,InterpreterAssembler)1238 IGNITION_HANDLER(Dec, InterpreterAssembler) {
1239   TNode<Object> value = GetAccumulator();
1240   TNode<Context> context = GetContext();
1241   TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
1242   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1243 
1244   UnaryOpAssembler unary_op_asm(state());
1245   TNode<Object> result = unary_op_asm.Generate_DecrementWithFeedback(
1246       context, value, slot_index, maybe_feedback_vector,
1247       UpdateFeedbackMode::kOptionalFeedback);
1248 
1249   SetAccumulator(result);
1250   Dispatch();
1251 }
1252 
1253 // ToBooleanLogicalNot
1254 //
1255 // Perform logical-not on the accumulator, first casting the
1256 // accumulator to a boolean value if required.
IGNITION_HANDLER(ToBooleanLogicalNot,InterpreterAssembler)1257 IGNITION_HANDLER(ToBooleanLogicalNot, InterpreterAssembler) {
1258   TNode<Object> value = GetAccumulator();
1259   TVARIABLE(Oddball, result);
1260   Label if_true(this), if_false(this), end(this);
1261   BranchIfToBooleanIsTrue(value, &if_true, &if_false);
1262   BIND(&if_true);
1263   {
1264     result = FalseConstant();
1265     Goto(&end);
1266   }
1267   BIND(&if_false);
1268   {
1269     result = TrueConstant();
1270     Goto(&end);
1271   }
1272   BIND(&end);
1273   SetAccumulator(result.value());
1274   Dispatch();
1275 }
1276 
1277 // LogicalNot
1278 //
1279 // Perform logical-not on the accumulator, which must already be a boolean
1280 // value.
IGNITION_HANDLER(LogicalNot,InterpreterAssembler)1281 IGNITION_HANDLER(LogicalNot, InterpreterAssembler) {
1282   TNode<Object> value = GetAccumulator();
1283   TVARIABLE(Oddball, result);
1284   Label if_true(this), if_false(this), end(this);
1285   TNode<Oddball> true_value = TrueConstant();
1286   TNode<Oddball> false_value = FalseConstant();
1287   Branch(TaggedEqual(value, true_value), &if_true, &if_false);
1288   BIND(&if_true);
1289   {
1290     result = false_value;
1291     Goto(&end);
1292   }
1293   BIND(&if_false);
1294   {
1295     CSA_DCHECK(this, TaggedEqual(value, false_value));
1296     result = true_value;
1297     Goto(&end);
1298   }
1299   BIND(&end);
1300   SetAccumulator(result.value());
1301   Dispatch();
1302 }
1303 
1304 // TypeOf
1305 //
1306 // Load the accumulator with the string representating type of the
1307 // object in the accumulator.
IGNITION_HANDLER(TypeOf,InterpreterAssembler)1308 IGNITION_HANDLER(TypeOf, InterpreterAssembler) {
1309   TNode<Object> value = GetAccumulator();
1310   TNode<String> result = Typeof(value);
1311   SetAccumulator(result);
1312   Dispatch();
1313 }
1314 
1315 // DeletePropertyStrict
1316 //
1317 // Delete the property specified in the accumulator from the object
1318 // referenced by the register operand following strict mode semantics.
IGNITION_HANDLER(DeletePropertyStrict,InterpreterAssembler)1319 IGNITION_HANDLER(DeletePropertyStrict, InterpreterAssembler) {
1320   TNode<Object> object = LoadRegisterAtOperandIndex(0);
1321   TNode<Object> key = GetAccumulator();
1322   TNode<Context> context = GetContext();
1323   TNode<Object> result =
1324       CallBuiltin(Builtin::kDeleteProperty, context, object, key,
1325                   SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
1326   SetAccumulator(result);
1327   Dispatch();
1328 }
1329 
1330 // DeletePropertySloppy
1331 //
1332 // Delete the property specified in the accumulator from the object
1333 // referenced by the register operand following sloppy mode semantics.
IGNITION_HANDLER(DeletePropertySloppy,InterpreterAssembler)1334 IGNITION_HANDLER(DeletePropertySloppy, InterpreterAssembler) {
1335   TNode<Object> object = LoadRegisterAtOperandIndex(0);
1336   TNode<Object> key = GetAccumulator();
1337   TNode<Context> context = GetContext();
1338   TNode<Object> result =
1339       CallBuiltin(Builtin::kDeleteProperty, context, object, key,
1340                   SmiConstant(Smi::FromEnum(LanguageMode::kSloppy)));
1341   SetAccumulator(result);
1342   Dispatch();
1343 }
1344 
1345 // GetSuperConstructor
1346 //
1347 // Get the super constructor from the object referenced by the accumulator.
1348 // The result is stored in register |reg|.
IGNITION_HANDLER(GetSuperConstructor,InterpreterAssembler)1349 IGNITION_HANDLER(GetSuperConstructor, InterpreterAssembler) {
1350   TNode<JSFunction> active_function = CAST(GetAccumulator());
1351   TNode<Object> result = GetSuperConstructor(active_function);
1352   StoreRegisterAtOperandIndex(result, 0);
1353   Dispatch();
1354 }
1355 
1356 class InterpreterJSCallAssembler : public InterpreterAssembler {
1357  public:
InterpreterJSCallAssembler(CodeAssemblerState * state,Bytecode bytecode,OperandScale operand_scale)1358   InterpreterJSCallAssembler(CodeAssemblerState* state, Bytecode bytecode,
1359                              OperandScale operand_scale)
1360       : InterpreterAssembler(state, bytecode, operand_scale) {}
1361 
1362   // Generates code to perform a JS call that collects type feedback.
JSCall(ConvertReceiverMode receiver_mode)1363   void JSCall(ConvertReceiverMode receiver_mode) {
1364     TNode<Object> function = LoadRegisterAtOperandIndex(0);
1365     LazyNode<Object> receiver = [=] {
1366       return receiver_mode == ConvertReceiverMode::kNullOrUndefined
1367                  ? UndefinedConstant()
1368                  : LoadRegisterAtOperandIndex(1);
1369     };
1370     RegListNodePair args = GetRegisterListAtOperandIndex(1);
1371     TNode<UintPtrT> slot_id = BytecodeOperandIdx(3);
1372     TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1373     TNode<Context> context = GetContext();
1374 
1375     // Collect the {function} feedback.
1376     CollectCallFeedback(function, receiver, context, maybe_feedback_vector,
1377                         slot_id);
1378 
1379     // Call the function and dispatch to the next handler.
1380     CallJSAndDispatch(function, context, args, receiver_mode);
1381   }
1382 
1383   // Generates code to perform a JS call with a known number of arguments that
1384   // collects type feedback.
JSCallN(int arg_count,ConvertReceiverMode receiver_mode)1385   void JSCallN(int arg_count, ConvertReceiverMode receiver_mode) {
1386     // Indices and counts of operands on the bytecode.
1387     const int kFirstArgumentOperandIndex = 1;
1388     const int kReceiverOperandCount =
1389         (receiver_mode == ConvertReceiverMode::kNullOrUndefined) ? 0 : 1;
1390     const int kReceiverAndArgOperandCount = kReceiverOperandCount + arg_count;
1391     const int kSlotOperandIndex =
1392         kFirstArgumentOperandIndex + kReceiverAndArgOperandCount;
1393 
1394     TNode<Object> function = LoadRegisterAtOperandIndex(0);
1395     LazyNode<Object> receiver = [=] {
1396       return receiver_mode == ConvertReceiverMode::kNullOrUndefined
1397                  ? UndefinedConstant()
1398                  : LoadRegisterAtOperandIndex(1);
1399     };
1400     TNode<UintPtrT> slot_id = BytecodeOperandIdx(kSlotOperandIndex);
1401     TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1402     TNode<Context> context = GetContext();
1403 
1404     // Collect the {function} feedback.
1405     CollectCallFeedback(function, receiver, context, maybe_feedback_vector,
1406                         slot_id);
1407 
1408     switch (kReceiverAndArgOperandCount) {
1409       case 0:
1410         CallJSAndDispatch(function, context, Int32Constant(arg_count),
1411                           receiver_mode);
1412         break;
1413       case 1:
1414         CallJSAndDispatch(
1415             function, context, Int32Constant(arg_count), receiver_mode,
1416             LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex));
1417         break;
1418       case 2:
1419         CallJSAndDispatch(
1420             function, context, Int32Constant(arg_count), receiver_mode,
1421             LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 1),
1422             LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex));
1423         break;
1424       case 3:
1425         CallJSAndDispatch(
1426             function, context, Int32Constant(arg_count), receiver_mode,
1427             LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 2),
1428             LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 1),
1429             LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex));
1430         break;
1431       default:
1432         UNREACHABLE();
1433     }
1434   }
1435 };
1436 
1437 // Call <callable> <receiver> <arg_count> <feedback_slot_id>
1438 //
1439 // Call a JSfunction or Callable in |callable| with the |receiver| and
1440 // |arg_count| arguments in subsequent registers. Collect type feedback
1441 // into |feedback_slot_id|
IGNITION_HANDLER(CallAnyReceiver,InterpreterJSCallAssembler)1442 IGNITION_HANDLER(CallAnyReceiver, InterpreterJSCallAssembler) {
1443   JSCall(ConvertReceiverMode::kAny);
1444 }
1445 
IGNITION_HANDLER(CallProperty,InterpreterJSCallAssembler)1446 IGNITION_HANDLER(CallProperty, InterpreterJSCallAssembler) {
1447   JSCall(ConvertReceiverMode::kNotNullOrUndefined);
1448 }
1449 
IGNITION_HANDLER(CallProperty0,InterpreterJSCallAssembler)1450 IGNITION_HANDLER(CallProperty0, InterpreterJSCallAssembler) {
1451   JSCallN(0, ConvertReceiverMode::kNotNullOrUndefined);
1452 }
1453 
IGNITION_HANDLER(CallProperty1,InterpreterJSCallAssembler)1454 IGNITION_HANDLER(CallProperty1, InterpreterJSCallAssembler) {
1455   JSCallN(1, ConvertReceiverMode::kNotNullOrUndefined);
1456 }
1457 
IGNITION_HANDLER(CallProperty2,InterpreterJSCallAssembler)1458 IGNITION_HANDLER(CallProperty2, InterpreterJSCallAssembler) {
1459   JSCallN(2, ConvertReceiverMode::kNotNullOrUndefined);
1460 }
1461 
IGNITION_HANDLER(CallUndefinedReceiver,InterpreterJSCallAssembler)1462 IGNITION_HANDLER(CallUndefinedReceiver, InterpreterJSCallAssembler) {
1463   JSCall(ConvertReceiverMode::kNullOrUndefined);
1464 }
1465 
IGNITION_HANDLER(CallUndefinedReceiver0,InterpreterJSCallAssembler)1466 IGNITION_HANDLER(CallUndefinedReceiver0, InterpreterJSCallAssembler) {
1467   JSCallN(0, ConvertReceiverMode::kNullOrUndefined);
1468 }
1469 
IGNITION_HANDLER(CallUndefinedReceiver1,InterpreterJSCallAssembler)1470 IGNITION_HANDLER(CallUndefinedReceiver1, InterpreterJSCallAssembler) {
1471   JSCallN(1, ConvertReceiverMode::kNullOrUndefined);
1472 }
1473 
IGNITION_HANDLER(CallUndefinedReceiver2,InterpreterJSCallAssembler)1474 IGNITION_HANDLER(CallUndefinedReceiver2, InterpreterJSCallAssembler) {
1475   JSCallN(2, ConvertReceiverMode::kNullOrUndefined);
1476 }
1477 
1478 // CallRuntime <function_id> <first_arg> <arg_count>
1479 //
1480 // Call the runtime function |function_id| with the first argument in
1481 // register |first_arg| and |arg_count| arguments in subsequent
1482 // registers.
IGNITION_HANDLER(CallRuntime,InterpreterAssembler)1483 IGNITION_HANDLER(CallRuntime, InterpreterAssembler) {
1484   TNode<Uint32T> function_id = BytecodeOperandRuntimeId(0);
1485   RegListNodePair args = GetRegisterListAtOperandIndex(1);
1486   TNode<Context> context = GetContext();
1487   TNode<Object> result = CallRuntimeN(function_id, context, args, 1);
1488   SetAccumulator(result);
1489   Dispatch();
1490 }
1491 
1492 // InvokeIntrinsic <function_id> <first_arg> <arg_count>
1493 //
1494 // Implements the semantic equivalent of calling the runtime function
1495 // |function_id| with the first argument in |first_arg| and |arg_count|
1496 // arguments in subsequent registers.
IGNITION_HANDLER(InvokeIntrinsic,InterpreterAssembler)1497 IGNITION_HANDLER(InvokeIntrinsic, InterpreterAssembler) {
1498   TNode<Uint32T> function_id = BytecodeOperandIntrinsicId(0);
1499   RegListNodePair args = GetRegisterListAtOperandIndex(1);
1500   TNode<Context> context = GetContext();
1501   TNode<Object> result =
1502       GenerateInvokeIntrinsic(this, function_id, context, args);
1503   SetAccumulator(result);
1504   Dispatch();
1505 }
1506 
1507 // CallRuntimeForPair <function_id> <first_arg> <arg_count> <first_return>
1508 //
1509 // Call the runtime function |function_id| which returns a pair, with the
1510 // first argument in register |first_arg| and |arg_count| arguments in
1511 // subsequent registers. Returns the result in <first_return> and
1512 // <first_return + 1>
IGNITION_HANDLER(CallRuntimeForPair,InterpreterAssembler)1513 IGNITION_HANDLER(CallRuntimeForPair, InterpreterAssembler) {
1514   // Call the runtime function.
1515   TNode<Uint32T> function_id = BytecodeOperandRuntimeId(0);
1516   RegListNodePair args = GetRegisterListAtOperandIndex(1);
1517   TNode<Context> context = GetContext();
1518   auto result_pair =
1519       CallRuntimeN<PairT<Object, Object>>(function_id, context, args, 2);
1520   // Store the results in <first_return> and <first_return + 1>
1521   TNode<Object> result0 = Projection<0>(result_pair);
1522   TNode<Object> result1 = Projection<1>(result_pair);
1523   StoreRegisterPairAtOperandIndex(result0, result1, 3);
1524   Dispatch();
1525 }
1526 
1527 // CallJSRuntime <context_index> <receiver> <arg_count>
1528 //
1529 // Call the JS runtime function that has the |context_index| with the receiver
1530 // in register |receiver| and |arg_count| arguments in subsequent registers.
IGNITION_HANDLER(CallJSRuntime,InterpreterAssembler)1531 IGNITION_HANDLER(CallJSRuntime, InterpreterAssembler) {
1532   TNode<IntPtrT> context_index = Signed(BytecodeOperandNativeContextIndex(0));
1533   RegListNodePair args = GetRegisterListAtOperandIndex(1);
1534 
1535   // Get the function to call from the native context.
1536   TNode<Context> context = GetContext();
1537   TNode<NativeContext> native_context = LoadNativeContext(context);
1538   TNode<Object> function = LoadContextElement(native_context, context_index);
1539 
1540   // Call the function.
1541   CallJSAndDispatch(function, context, args,
1542                     ConvertReceiverMode::kNullOrUndefined);
1543 }
1544 
1545 // CallWithSpread <callable> <first_arg> <arg_count>
1546 //
1547 // Call a JSfunction or Callable in |callable| with the receiver in
1548 // |first_arg| and |arg_count - 1| arguments in subsequent registers. The
1549 // final argument is always a spread.
1550 //
IGNITION_HANDLER(CallWithSpread,InterpreterAssembler)1551 IGNITION_HANDLER(CallWithSpread, InterpreterAssembler) {
1552   TNode<Object> callable = LoadRegisterAtOperandIndex(0);
1553   RegListNodePair args = GetRegisterListAtOperandIndex(1);
1554   TNode<UintPtrT> slot_id = BytecodeOperandIdx(3);
1555   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1556   TNode<Context> context = GetContext();
1557 
1558   // Call into Runtime function CallWithSpread which does everything.
1559   CallJSWithSpreadAndDispatch(callable, context, args, slot_id,
1560                               maybe_feedback_vector);
1561 }
1562 
1563 // ConstructWithSpread <first_arg> <arg_count>
1564 //
1565 // Call the constructor in |constructor| with the first argument in register
1566 // |first_arg| and |arg_count| arguments in subsequent registers. The final
1567 // argument is always a spread. The new.target is in the accumulator.
1568 //
IGNITION_HANDLER(ConstructWithSpread,InterpreterAssembler)1569 IGNITION_HANDLER(ConstructWithSpread, InterpreterAssembler) {
1570   TNode<Object> new_target = GetAccumulator();
1571   TNode<Object> constructor = LoadRegisterAtOperandIndex(0);
1572   RegListNodePair args = GetRegisterListAtOperandIndex(1);
1573   TNode<UintPtrT> slot_id = BytecodeOperandIdx(3);
1574   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1575   TNode<Context> context = GetContext();
1576   TNode<Object> result = ConstructWithSpread(
1577       constructor, context, new_target, args, slot_id, maybe_feedback_vector);
1578   SetAccumulator(result);
1579   Dispatch();
1580 }
1581 
1582 // Construct <constructor> <first_arg> <arg_count>
1583 //
1584 // Call operator construct with |constructor| and the first argument in
1585 // register |first_arg| and |arg_count| arguments in subsequent
1586 // registers. The new.target is in the accumulator.
1587 //
IGNITION_HANDLER(Construct,InterpreterAssembler)1588 IGNITION_HANDLER(Construct, InterpreterAssembler) {
1589   TNode<Object> new_target = GetAccumulator();
1590   TNode<Object> constructor = LoadRegisterAtOperandIndex(0);
1591   RegListNodePair args = GetRegisterListAtOperandIndex(1);
1592   TNode<UintPtrT> slot_id = BytecodeOperandIdx(3);
1593   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1594   TNode<Context> context = GetContext();
1595   TNode<Object> result = Construct(constructor, context, new_target, args,
1596                                    slot_id, maybe_feedback_vector);
1597   SetAccumulator(result);
1598   Dispatch();
1599 }
1600 
1601 class InterpreterCompareOpAssembler : public InterpreterAssembler {
1602  public:
InterpreterCompareOpAssembler(CodeAssemblerState * state,Bytecode bytecode,OperandScale operand_scale)1603   InterpreterCompareOpAssembler(CodeAssemblerState* state, Bytecode bytecode,
1604                                 OperandScale operand_scale)
1605       : InterpreterAssembler(state, bytecode, operand_scale) {}
1606 
CompareOpWithFeedback(Operation compare_op)1607   void CompareOpWithFeedback(Operation compare_op) {
1608     TNode<Object> lhs = LoadRegisterAtOperandIndex(0);
1609     TNode<Object> rhs = GetAccumulator();
1610     TNode<Context> context = GetContext();
1611 
1612     TVARIABLE(Smi, var_type_feedback);
1613     TNode<Oddball> result;
1614     switch (compare_op) {
1615       case Operation::kEqual:
1616         result = Equal(lhs, rhs, context, &var_type_feedback);
1617         break;
1618       case Operation::kStrictEqual:
1619         result = StrictEqual(lhs, rhs, &var_type_feedback);
1620         break;
1621       case Operation::kLessThan:
1622       case Operation::kGreaterThan:
1623       case Operation::kLessThanOrEqual:
1624       case Operation::kGreaterThanOrEqual:
1625         result = RelationalComparison(compare_op, lhs, rhs, context,
1626                                       &var_type_feedback);
1627         break;
1628       default:
1629         UNREACHABLE();
1630     }
1631 
1632     TNode<UintPtrT> slot_index = BytecodeOperandIdx(1);
1633     TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1634     MaybeUpdateFeedback(var_type_feedback.value(), maybe_feedback_vector,
1635                         slot_index);
1636     SetAccumulator(result);
1637     Dispatch();
1638   }
1639 };
1640 
1641 // TestEqual <src>
1642 //
1643 // Test if the value in the <src> register equals the accumulator.
IGNITION_HANDLER(TestEqual,InterpreterCompareOpAssembler)1644 IGNITION_HANDLER(TestEqual, InterpreterCompareOpAssembler) {
1645   CompareOpWithFeedback(Operation::kEqual);
1646 }
1647 
1648 // TestEqualStrict <src>
1649 //
1650 // Test if the value in the <src> register is strictly equal to the accumulator.
IGNITION_HANDLER(TestEqualStrict,InterpreterCompareOpAssembler)1651 IGNITION_HANDLER(TestEqualStrict, InterpreterCompareOpAssembler) {
1652   CompareOpWithFeedback(Operation::kStrictEqual);
1653 }
1654 
1655 // TestLessThan <src>
1656 //
1657 // Test if the value in the <src> register is less than the accumulator.
IGNITION_HANDLER(TestLessThan,InterpreterCompareOpAssembler)1658 IGNITION_HANDLER(TestLessThan, InterpreterCompareOpAssembler) {
1659   CompareOpWithFeedback(Operation::kLessThan);
1660 }
1661 
1662 // TestGreaterThan <src>
1663 //
1664 // Test if the value in the <src> register is greater than the accumulator.
IGNITION_HANDLER(TestGreaterThan,InterpreterCompareOpAssembler)1665 IGNITION_HANDLER(TestGreaterThan, InterpreterCompareOpAssembler) {
1666   CompareOpWithFeedback(Operation::kGreaterThan);
1667 }
1668 
1669 // TestLessThanOrEqual <src>
1670 //
1671 // Test if the value in the <src> register is less than or equal to the
1672 // accumulator.
IGNITION_HANDLER(TestLessThanOrEqual,InterpreterCompareOpAssembler)1673 IGNITION_HANDLER(TestLessThanOrEqual, InterpreterCompareOpAssembler) {
1674   CompareOpWithFeedback(Operation::kLessThanOrEqual);
1675 }
1676 
1677 // TestGreaterThanOrEqual <src>
1678 //
1679 // Test if the value in the <src> register is greater than or equal to the
1680 // accumulator.
IGNITION_HANDLER(TestGreaterThanOrEqual,InterpreterCompareOpAssembler)1681 IGNITION_HANDLER(TestGreaterThanOrEqual, InterpreterCompareOpAssembler) {
1682   CompareOpWithFeedback(Operation::kGreaterThanOrEqual);
1683 }
1684 
1685 // TestReferenceEqual <src>
1686 //
1687 // Test if the value in the <src> register is equal to the accumulator
1688 // by means of simple comparison. For SMIs and simple reference comparisons.
IGNITION_HANDLER(TestReferenceEqual,InterpreterAssembler)1689 IGNITION_HANDLER(TestReferenceEqual, InterpreterAssembler) {
1690   TNode<Object> lhs = LoadRegisterAtOperandIndex(0);
1691   TNode<Object> rhs = GetAccumulator();
1692   TNode<Oddball> result = SelectBooleanConstant(TaggedEqual(lhs, rhs));
1693   SetAccumulator(result);
1694   Dispatch();
1695 }
1696 
1697 // TestIn <src> <feedback_slot>
1698 //
1699 // Test if the object referenced by the register operand is a property of the
1700 // object referenced by the accumulator.
IGNITION_HANDLER(TestIn,InterpreterAssembler)1701 IGNITION_HANDLER(TestIn, InterpreterAssembler) {
1702   TNode<Object> name = LoadRegisterAtOperandIndex(0);
1703   TNode<Object> object = GetAccumulator();
1704   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
1705   TNode<HeapObject> feedback_vector = LoadFeedbackVector();
1706   TNode<Context> context = GetContext();
1707 
1708   TVARIABLE(Object, var_result);
1709   var_result = CallBuiltin(Builtin::kKeyedHasIC, context, object, name, slot,
1710                            feedback_vector);
1711   SetAccumulator(var_result.value());
1712   Dispatch();
1713 }
1714 
1715 // TestInstanceOf <src> <feedback_slot>
1716 //
1717 // Test if the object referenced by the <src> register is an an instance of type
1718 // referenced by the accumulator.
IGNITION_HANDLER(TestInstanceOf,InterpreterAssembler)1719 IGNITION_HANDLER(TestInstanceOf, InterpreterAssembler) {
1720   TNode<Object> object = LoadRegisterAtOperandIndex(0);
1721   TNode<Object> callable = GetAccumulator();
1722   TNode<UintPtrT> slot_id = BytecodeOperandIdx(1);
1723   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1724   TNode<Context> context = GetContext();
1725 
1726   CollectInstanceOfFeedback(callable, context, maybe_feedback_vector, slot_id);
1727   SetAccumulator(InstanceOf(object, callable, context));
1728   Dispatch();
1729 }
1730 
1731 // TestUndetectable
1732 //
1733 // Test if the value in the accumulator is undetectable (null, undefined or
1734 // document.all).
IGNITION_HANDLER(TestUndetectable,InterpreterAssembler)1735 IGNITION_HANDLER(TestUndetectable, InterpreterAssembler) {
1736   Label return_false(this), end(this);
1737   TNode<Object> object = GetAccumulator();
1738 
1739   // If the object is an Smi then return false.
1740   SetAccumulator(FalseConstant());
1741   GotoIf(TaggedIsSmi(object), &end);
1742 
1743   // If it is a HeapObject, load the map and check for undetectable bit.
1744   TNode<Oddball> result =
1745       SelectBooleanConstant(IsUndetectableMap(LoadMap(CAST(object))));
1746   SetAccumulator(result);
1747   Goto(&end);
1748 
1749   BIND(&end);
1750   Dispatch();
1751 }
1752 
1753 // TestNull
1754 //
1755 // Test if the value in accumulator is strictly equal to null.
IGNITION_HANDLER(TestNull,InterpreterAssembler)1756 IGNITION_HANDLER(TestNull, InterpreterAssembler) {
1757   TNode<Object> object = GetAccumulator();
1758   TNode<Oddball> result =
1759       SelectBooleanConstant(TaggedEqual(object, NullConstant()));
1760   SetAccumulator(result);
1761   Dispatch();
1762 }
1763 
1764 // TestUndefined
1765 //
1766 // Test if the value in the accumulator is strictly equal to undefined.
IGNITION_HANDLER(TestUndefined,InterpreterAssembler)1767 IGNITION_HANDLER(TestUndefined, InterpreterAssembler) {
1768   TNode<Object> object = GetAccumulator();
1769   TNode<Oddball> result =
1770       SelectBooleanConstant(TaggedEqual(object, UndefinedConstant()));
1771   SetAccumulator(result);
1772   Dispatch();
1773 }
1774 
1775 // TestTypeOf <literal_flag>
1776 //
1777 // Tests if the object in the <accumulator> is typeof the literal represented
1778 // by |literal_flag|.
IGNITION_HANDLER(TestTypeOf,InterpreterAssembler)1779 IGNITION_HANDLER(TestTypeOf, InterpreterAssembler) {
1780   TNode<Object> object = GetAccumulator();
1781   TNode<Uint32T> literal_flag = BytecodeOperandFlag(0);
1782 
1783 #define MAKE_LABEL(name, lower_case) Label if_##lower_case(this);
1784   TYPEOF_LITERAL_LIST(MAKE_LABEL)
1785 #undef MAKE_LABEL
1786 
1787 #define LABEL_POINTER(name, lower_case) &if_##lower_case,
1788   Label* labels[] = {TYPEOF_LITERAL_LIST(LABEL_POINTER)};
1789 #undef LABEL_POINTER
1790 
1791 #define CASE(name, lower_case) \
1792   static_cast<int32_t>(TestTypeOfFlags::LiteralFlag::k##name),
1793   int32_t cases[] = {TYPEOF_LITERAL_LIST(CASE)};
1794 #undef CASE
1795 
1796   Label if_true(this), if_false(this), end(this);
1797 
1798   // We just use the final label as the default and properly CSA_DCHECK
1799   // that the {literal_flag} is valid here; this significantly improves
1800   // the generated code (compared to having a default label that aborts).
1801   unsigned const num_cases = arraysize(cases);
1802   CSA_DCHECK(this, Uint32LessThan(literal_flag, Int32Constant(num_cases)));
1803   Switch(literal_flag, labels[num_cases - 1], cases, labels, num_cases - 1);
1804 
1805   BIND(&if_number);
1806   {
1807     Comment("IfNumber");
1808     GotoIfNumber(object, &if_true);
1809     Goto(&if_false);
1810   }
1811   BIND(&if_string);
1812   {
1813     Comment("IfString");
1814     GotoIf(TaggedIsSmi(object), &if_false);
1815     Branch(IsString(CAST(object)), &if_true, &if_false);
1816   }
1817   BIND(&if_symbol);
1818   {
1819     Comment("IfSymbol");
1820     GotoIf(TaggedIsSmi(object), &if_false);
1821     Branch(IsSymbol(CAST(object)), &if_true, &if_false);
1822   }
1823   BIND(&if_boolean);
1824   {
1825     Comment("IfBoolean");
1826     GotoIf(TaggedEqual(object, TrueConstant()), &if_true);
1827     Branch(TaggedEqual(object, FalseConstant()), &if_true, &if_false);
1828   }
1829   BIND(&if_bigint);
1830   {
1831     Comment("IfBigInt");
1832     GotoIf(TaggedIsSmi(object), &if_false);
1833     Branch(IsBigInt(CAST(object)), &if_true, &if_false);
1834   }
1835   BIND(&if_undefined);
1836   {
1837     Comment("IfUndefined");
1838     GotoIf(TaggedIsSmi(object), &if_false);
1839     // Check it is not null and the map has the undetectable bit set.
1840     GotoIf(IsNull(object), &if_false);
1841     Branch(IsUndetectableMap(LoadMap(CAST(object))), &if_true, &if_false);
1842   }
1843   BIND(&if_function);
1844   {
1845     Comment("IfFunction");
1846     GotoIf(TaggedIsSmi(object), &if_false);
1847     // Check if callable bit is set and not undetectable.
1848     TNode<Int32T> map_bitfield = LoadMapBitField(LoadMap(CAST(object)));
1849     TNode<Int32T> callable_undetectable = Word32And(
1850         map_bitfield, Int32Constant(Map::Bits1::IsUndetectableBit::kMask |
1851                                     Map::Bits1::IsCallableBit::kMask));
1852     Branch(Word32Equal(callable_undetectable,
1853                        Int32Constant(Map::Bits1::IsCallableBit::kMask)),
1854            &if_true, &if_false);
1855   }
1856   BIND(&if_object);
1857   {
1858     Comment("IfObject");
1859     GotoIf(TaggedIsSmi(object), &if_false);
1860 
1861     // If the object is null then return true.
1862     GotoIf(IsNull(object), &if_true);
1863 
1864     // Check if the object is a receiver type and is not undefined or callable.
1865     TNode<Map> map = LoadMap(CAST(object));
1866     GotoIfNot(IsJSReceiverMap(map), &if_false);
1867     TNode<Int32T> map_bitfield = LoadMapBitField(map);
1868     TNode<Int32T> callable_undetectable = Word32And(
1869         map_bitfield, Int32Constant(Map::Bits1::IsUndetectableBit::kMask |
1870                                     Map::Bits1::IsCallableBit::kMask));
1871     Branch(Word32Equal(callable_undetectable, Int32Constant(0)), &if_true,
1872            &if_false);
1873   }
1874   BIND(&if_other);
1875   {
1876     // Typeof doesn't return any other string value.
1877     Goto(&if_false);
1878   }
1879 
1880   BIND(&if_false);
1881   {
1882     SetAccumulator(FalseConstant());
1883     Goto(&end);
1884   }
1885   BIND(&if_true);
1886   {
1887     SetAccumulator(TrueConstant());
1888     Goto(&end);
1889   }
1890   BIND(&end);
1891   Dispatch();
1892 }
1893 
1894 // Jump <imm>
1895 //
1896 // Jump by the number of bytes represented by the immediate operand |imm|.
IGNITION_HANDLER(Jump,InterpreterAssembler)1897 IGNITION_HANDLER(Jump, InterpreterAssembler) {
1898   TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
1899   Jump(relative_jump);
1900 }
1901 
1902 // JumpConstant <idx>
1903 //
1904 // Jump by the number of bytes in the Smi in the |idx| entry in the constant
1905 // pool.
IGNITION_HANDLER(JumpConstant,InterpreterAssembler)1906 IGNITION_HANDLER(JumpConstant, InterpreterAssembler) {
1907   TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
1908   Jump(relative_jump);
1909 }
1910 
1911 // JumpIfTrue <imm>
1912 //
1913 // Jump by the number of bytes represented by an immediate operand if the
1914 // accumulator contains true. This only works for boolean inputs, and
1915 // will misbehave if passed arbitrary input values.
IGNITION_HANDLER(JumpIfTrue,InterpreterAssembler)1916 IGNITION_HANDLER(JumpIfTrue, InterpreterAssembler) {
1917   TNode<Object> accumulator = GetAccumulator();
1918   CSA_DCHECK(this, IsBoolean(CAST(accumulator)));
1919   JumpIfTaggedEqual(accumulator, TrueConstant(), 0);
1920 }
1921 
1922 // JumpIfTrueConstant <idx>
1923 //
1924 // Jump by the number of bytes in the Smi in the |idx| entry in the constant
1925 // pool if the accumulator contains true. This only works for boolean inputs,
1926 // and will misbehave if passed arbitrary input values.
IGNITION_HANDLER(JumpIfTrueConstant,InterpreterAssembler)1927 IGNITION_HANDLER(JumpIfTrueConstant, InterpreterAssembler) {
1928   TNode<Object> accumulator = GetAccumulator();
1929   CSA_DCHECK(this, IsBoolean(CAST(accumulator)));
1930   JumpIfTaggedEqualConstant(accumulator, TrueConstant(), 0);
1931 }
1932 
1933 // JumpIfFalse <imm>
1934 //
1935 // Jump by the number of bytes represented by an immediate operand if the
1936 // accumulator contains false. This only works for boolean inputs, and
1937 // will misbehave if passed arbitrary input values.
IGNITION_HANDLER(JumpIfFalse,InterpreterAssembler)1938 IGNITION_HANDLER(JumpIfFalse, InterpreterAssembler) {
1939   TNode<Object> accumulator = GetAccumulator();
1940   CSA_DCHECK(this, IsBoolean(CAST(accumulator)));
1941   JumpIfTaggedEqual(accumulator, FalseConstant(), 0);
1942 }
1943 
1944 // JumpIfFalseConstant <idx>
1945 //
1946 // Jump by the number of bytes in the Smi in the |idx| entry in the constant
1947 // pool if the accumulator contains false. This only works for boolean inputs,
1948 // and will misbehave if passed arbitrary input values.
IGNITION_HANDLER(JumpIfFalseConstant,InterpreterAssembler)1949 IGNITION_HANDLER(JumpIfFalseConstant, InterpreterAssembler) {
1950   TNode<Object> accumulator = GetAccumulator();
1951   CSA_DCHECK(this, IsBoolean(CAST(accumulator)));
1952   JumpIfTaggedEqualConstant(accumulator, FalseConstant(), 0);
1953 }
1954 
1955 // JumpIfToBooleanTrue <imm>
1956 //
1957 // Jump by the number of bytes represented by an immediate operand if the object
1958 // referenced by the accumulator is true when the object is cast to boolean.
IGNITION_HANDLER(JumpIfToBooleanTrue,InterpreterAssembler)1959 IGNITION_HANDLER(JumpIfToBooleanTrue, InterpreterAssembler) {
1960   TNode<Object> value = GetAccumulator();
1961   Label if_true(this), if_false(this);
1962   BranchIfToBooleanIsTrue(value, &if_true, &if_false);
1963   BIND(&if_true);
1964   TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
1965   Jump(relative_jump);
1966   BIND(&if_false);
1967   Dispatch();
1968 }
1969 
1970 // JumpIfToBooleanTrueConstant <idx>
1971 //
1972 // Jump by the number of bytes in the Smi in the |idx| entry in the constant
1973 // pool if the object referenced by the accumulator is true when the object is
1974 // cast to boolean.
IGNITION_HANDLER(JumpIfToBooleanTrueConstant,InterpreterAssembler)1975 IGNITION_HANDLER(JumpIfToBooleanTrueConstant, InterpreterAssembler) {
1976   TNode<Object> value = GetAccumulator();
1977   Label if_true(this), if_false(this);
1978   BranchIfToBooleanIsTrue(value, &if_true, &if_false);
1979   BIND(&if_true);
1980   TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
1981   Jump(relative_jump);
1982   BIND(&if_false);
1983   Dispatch();
1984 }
1985 
1986 // JumpIfToBooleanFalse <imm>
1987 //
1988 // Jump by the number of bytes represented by an immediate operand if the object
1989 // referenced by the accumulator is false when the object is cast to boolean.
IGNITION_HANDLER(JumpIfToBooleanFalse,InterpreterAssembler)1990 IGNITION_HANDLER(JumpIfToBooleanFalse, InterpreterAssembler) {
1991   TNode<Object> value = GetAccumulator();
1992   Label if_true(this), if_false(this);
1993   BranchIfToBooleanIsTrue(value, &if_true, &if_false);
1994   BIND(&if_true);
1995   Dispatch();
1996   BIND(&if_false);
1997   TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
1998   Jump(relative_jump);
1999 }
2000 
2001 // JumpIfToBooleanFalseConstant <idx>
2002 //
2003 // Jump by the number of bytes in the Smi in the |idx| entry in the constant
2004 // pool if the object referenced by the accumulator is false when the object is
2005 // cast to boolean.
IGNITION_HANDLER(JumpIfToBooleanFalseConstant,InterpreterAssembler)2006 IGNITION_HANDLER(JumpIfToBooleanFalseConstant, InterpreterAssembler) {
2007   TNode<Object> value = GetAccumulator();
2008   Label if_true(this), if_false(this);
2009   BranchIfToBooleanIsTrue(value, &if_true, &if_false);
2010   BIND(&if_true);
2011   Dispatch();
2012   BIND(&if_false);
2013   TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
2014   Jump(relative_jump);
2015 }
2016 
2017 // JumpIfNull <imm>
2018 //
2019 // Jump by the number of bytes represented by an immediate operand if the object
2020 // referenced by the accumulator is the null constant.
IGNITION_HANDLER(JumpIfNull,InterpreterAssembler)2021 IGNITION_HANDLER(JumpIfNull, InterpreterAssembler) {
2022   TNode<Object> accumulator = GetAccumulator();
2023   JumpIfTaggedEqual(accumulator, NullConstant(), 0);
2024 }
2025 
2026 // JumpIfNullConstant <idx>
2027 //
2028 // Jump by the number of bytes in the Smi in the |idx| entry in the constant
2029 // pool if the object referenced by the accumulator is the null constant.
IGNITION_HANDLER(JumpIfNullConstant,InterpreterAssembler)2030 IGNITION_HANDLER(JumpIfNullConstant, InterpreterAssembler) {
2031   TNode<Object> accumulator = GetAccumulator();
2032   JumpIfTaggedEqualConstant(accumulator, NullConstant(), 0);
2033 }
2034 
2035 // JumpIfNotNull <imm>
2036 //
2037 // Jump by the number of bytes represented by an immediate operand if the object
2038 // referenced by the accumulator is not the null constant.
IGNITION_HANDLER(JumpIfNotNull,InterpreterAssembler)2039 IGNITION_HANDLER(JumpIfNotNull, InterpreterAssembler) {
2040   TNode<Object> accumulator = GetAccumulator();
2041   JumpIfTaggedNotEqual(accumulator, NullConstant(), 0);
2042 }
2043 
2044 // JumpIfNotNullConstant <idx>
2045 //
2046 // Jump by the number of bytes in the Smi in the |idx| entry in the constant
2047 // pool if the object referenced by the accumulator is not the null constant.
IGNITION_HANDLER(JumpIfNotNullConstant,InterpreterAssembler)2048 IGNITION_HANDLER(JumpIfNotNullConstant, InterpreterAssembler) {
2049   TNode<Object> accumulator = GetAccumulator();
2050   JumpIfTaggedNotEqualConstant(accumulator, NullConstant(), 0);
2051 }
2052 
2053 // JumpIfUndefined <imm>
2054 //
2055 // Jump by the number of bytes represented by an immediate operand if the object
2056 // referenced by the accumulator is the undefined constant.
IGNITION_HANDLER(JumpIfUndefined,InterpreterAssembler)2057 IGNITION_HANDLER(JumpIfUndefined, InterpreterAssembler) {
2058   TNode<Object> accumulator = GetAccumulator();
2059   JumpIfTaggedEqual(accumulator, UndefinedConstant(), 0);
2060 }
2061 
2062 // JumpIfUndefinedConstant <idx>
2063 //
2064 // Jump by the number of bytes in the Smi in the |idx| entry in the constant
2065 // pool if the object referenced by the accumulator is the undefined constant.
IGNITION_HANDLER(JumpIfUndefinedConstant,InterpreterAssembler)2066 IGNITION_HANDLER(JumpIfUndefinedConstant, InterpreterAssembler) {
2067   TNode<Object> accumulator = GetAccumulator();
2068   JumpIfTaggedEqualConstant(accumulator, UndefinedConstant(), 0);
2069 }
2070 
2071 // JumpIfNotUndefined <imm>
2072 //
2073 // Jump by the number of bytes represented by an immediate operand if the object
2074 // referenced by the accumulator is not the undefined constant.
IGNITION_HANDLER(JumpIfNotUndefined,InterpreterAssembler)2075 IGNITION_HANDLER(JumpIfNotUndefined, InterpreterAssembler) {
2076   TNode<Object> accumulator = GetAccumulator();
2077   JumpIfTaggedNotEqual(accumulator, UndefinedConstant(), 0);
2078 }
2079 
2080 // JumpIfNotUndefinedConstant <idx>
2081 //
2082 // Jump by the number of bytes in the Smi in the |idx| entry in the constant
2083 // pool if the object referenced by the accumulator is not the undefined
2084 // constant.
IGNITION_HANDLER(JumpIfNotUndefinedConstant,InterpreterAssembler)2085 IGNITION_HANDLER(JumpIfNotUndefinedConstant, InterpreterAssembler) {
2086   TNode<Object> accumulator = GetAccumulator();
2087   JumpIfTaggedNotEqualConstant(accumulator, UndefinedConstant(), 0);
2088 }
2089 
2090 // JumpIfUndefinedOrNull <imm>
2091 //
2092 // Jump by the number of bytes represented by an immediate operand if the object
2093 // referenced by the accumulator is the undefined constant or the null constant.
IGNITION_HANDLER(JumpIfUndefinedOrNull,InterpreterAssembler)2094 IGNITION_HANDLER(JumpIfUndefinedOrNull, InterpreterAssembler) {
2095   TNode<Object> accumulator = GetAccumulator();
2096 
2097   Label do_jump(this);
2098   GotoIf(IsUndefined(accumulator), &do_jump);
2099   GotoIf(IsNull(accumulator), &do_jump);
2100   Dispatch();
2101 
2102   BIND(&do_jump);
2103   TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
2104   Jump(relative_jump);
2105 }
2106 
2107 // JumpIfUndefinedOrNullConstant <idx>
2108 //
2109 // Jump by the number of bytes in the Smi in the |idx| entry in the constant
2110 // pool if the object referenced by the accumulator is the undefined constant or
2111 // the null constant.
IGNITION_HANDLER(JumpIfUndefinedOrNullConstant,InterpreterAssembler)2112 IGNITION_HANDLER(JumpIfUndefinedOrNullConstant, InterpreterAssembler) {
2113   TNode<Object> accumulator = GetAccumulator();
2114 
2115   Label do_jump(this);
2116   GotoIf(IsUndefined(accumulator), &do_jump);
2117   GotoIf(IsNull(accumulator), &do_jump);
2118   Dispatch();
2119 
2120   BIND(&do_jump);
2121   TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
2122   Jump(relative_jump);
2123 }
2124 
2125 // JumpIfJSReceiver <imm>
2126 //
2127 // Jump by the number of bytes represented by an immediate operand if the object
2128 // referenced by the accumulator is a JSReceiver.
IGNITION_HANDLER(JumpIfJSReceiver,InterpreterAssembler)2129 IGNITION_HANDLER(JumpIfJSReceiver, InterpreterAssembler) {
2130   TNode<Object> accumulator = GetAccumulator();
2131 
2132   Label if_object(this), if_notobject(this, Label::kDeferred), if_notsmi(this);
2133   Branch(TaggedIsSmi(accumulator), &if_notobject, &if_notsmi);
2134 
2135   BIND(&if_notsmi);
2136   Branch(IsJSReceiver(CAST(accumulator)), &if_object, &if_notobject);
2137   BIND(&if_object);
2138   TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
2139   Jump(relative_jump);
2140 
2141   BIND(&if_notobject);
2142   Dispatch();
2143 }
2144 
2145 // JumpIfJSReceiverConstant <idx>
2146 //
2147 // Jump by the number of bytes in the Smi in the |idx| entry in the constant
2148 // pool if the object referenced by the accumulator is a JSReceiver.
IGNITION_HANDLER(JumpIfJSReceiverConstant,InterpreterAssembler)2149 IGNITION_HANDLER(JumpIfJSReceiverConstant, InterpreterAssembler) {
2150   TNode<Object> accumulator = GetAccumulator();
2151 
2152   Label if_object(this), if_notobject(this), if_notsmi(this);
2153   Branch(TaggedIsSmi(accumulator), &if_notobject, &if_notsmi);
2154 
2155   BIND(&if_notsmi);
2156   Branch(IsJSReceiver(CAST(accumulator)), &if_object, &if_notobject);
2157 
2158   BIND(&if_object);
2159   TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
2160   Jump(relative_jump);
2161 
2162   BIND(&if_notobject);
2163   Dispatch();
2164 }
2165 
2166 // JumpLoop <imm> <loop_depth>
2167 //
2168 // Jump by the number of bytes represented by the immediate operand |imm|. Also
2169 // performs a loop nesting check, a stack check, and potentially triggers OSR.
IGNITION_HANDLER(JumpLoop,InterpreterAssembler)2170 IGNITION_HANDLER(JumpLoop, InterpreterAssembler) {
2171   TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
2172   TNode<Int32T> loop_depth = BytecodeOperandImm(1);
2173   TNode<Int16T> osr_urgency_and_install_target =
2174       LoadOsrUrgencyAndInstallTarget();
2175   TNode<Context> context = GetContext();
2176 
2177   // OSR requests can be triggered either through urgency (when > the current
2178   // loop depth), or an explicit install target (= the lower bits of the
2179   // targeted bytecode offset).
2180   Label ok(this), maybe_osr(this, Label::kDeferred);
2181   Branch(Int32GreaterThanOrEqual(loop_depth, osr_urgency_and_install_target),
2182          &ok, &maybe_osr);
2183 
2184   BIND(&ok);
2185   // The backward jump can trigger a budget interrupt, which can handle stack
2186   // interrupts, so we don't need to explicitly handle them here.
2187   JumpBackward(relative_jump);
2188 
2189   BIND(&maybe_osr);
2190   Label osr(this);
2191   // OSR based on urgency, i.e. is the OSR urgency greater than the current
2192   // loop depth?
2193   STATIC_ASSERT(BytecodeArray::OsrUrgencyBits::kShift == 0);
2194   TNode<Word32T> osr_urgency = Word32And(osr_urgency_and_install_target,
2195                                          BytecodeArray::OsrUrgencyBits::kMask);
2196   GotoIf(Int32GreaterThan(osr_urgency, loop_depth), &osr);
2197 
2198   // OSR based on the install target offset, i.e. does the current bytecode
2199   // offset match the install target offset?
2200   //
2201   //  if (((offset << kShift) & kMask) == (target & kMask)) { ... }
2202   static constexpr int kShift = BytecodeArray::OsrInstallTargetBits::kShift;
2203   static constexpr int kMask = BytecodeArray::OsrInstallTargetBits::kMask;
2204   // Note: We OR in 1 to avoid 0 offsets, see Code::OsrInstallTargetFor.
2205   TNode<Word32T> actual = Word32Or(
2206       Int32Sub(TruncateIntPtrToInt32(BytecodeOffset()), kFirstBytecodeOffset),
2207       Int32Constant(1));
2208   actual = Word32And(Word32Shl(UncheckedCast<Int32T>(actual), kShift), kMask);
2209   TNode<Word32T> expected = Word32And(osr_urgency_and_install_target, kMask);
2210   Branch(Word32Equal(actual, expected), &osr, &ok);
2211 
2212   BIND(&osr);
2213   OnStackReplacement(context, relative_jump);
2214 }
2215 
2216 // SwitchOnSmiNoFeedback <table_start> <table_length> <case_value_base>
2217 //
2218 // Jump by the number of bytes defined by a Smi in a table in the constant pool,
2219 // where the table starts at |table_start| and has |table_length| entries.
2220 // The table is indexed by the accumulator, minus |case_value_base|. If the
2221 // case_value falls outside of the table |table_length|, fall-through to the
2222 // next bytecode.
IGNITION_HANDLER(SwitchOnSmiNoFeedback,InterpreterAssembler)2223 IGNITION_HANDLER(SwitchOnSmiNoFeedback, InterpreterAssembler) {
2224   // The accumulator must be a Smi.
2225   TNode<Object> acc = GetAccumulator();
2226   TNode<UintPtrT> table_start = BytecodeOperandIdx(0);
2227   TNode<UintPtrT> table_length = BytecodeOperandUImmWord(1);
2228   TNode<IntPtrT> case_value_base = BytecodeOperandImmIntPtr(2);
2229 
2230   Label fall_through(this);
2231 
2232   // TODO(leszeks): Use this as an alternative to adding extra bytecodes ahead
2233   // of a jump-table optimized switch statement, using this code, in lieu of the
2234   // current case_value line.
2235   // TNode<IntPtrT> acc_intptr = TryTaggedToInt32AsIntPtr(acc, &fall_through);
2236   // TNode<IntPtrT> case_value = IntPtrSub(acc_intptr, case_value_base);
2237 
2238   CSA_DCHECK(this, TaggedIsSmi(acc));
2239 
2240   TNode<IntPtrT> case_value = IntPtrSub(SmiUntag(CAST(acc)), case_value_base);
2241 
2242   GotoIf(IntPtrLessThan(case_value, IntPtrConstant(0)), &fall_through);
2243   GotoIf(IntPtrGreaterThanOrEqual(case_value, table_length), &fall_through);
2244 
2245   TNode<WordT> entry = IntPtrAdd(table_start, case_value);
2246   TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntry(entry);
2247   Jump(relative_jump);
2248 
2249   BIND(&fall_through);
2250   Dispatch();
2251 }
2252 
2253 // CreateRegExpLiteral <pattern_idx> <literal_idx> <flags>
2254 //
2255 // Creates a regular expression literal for literal index <literal_idx> with
2256 // <flags> and the pattern in <pattern_idx>.
IGNITION_HANDLER(CreateRegExpLiteral,InterpreterAssembler)2257 IGNITION_HANDLER(CreateRegExpLiteral, InterpreterAssembler) {
2258   TNode<String> pattern = CAST(LoadConstantPoolEntryAtOperandIndex(0));
2259   TNode<HeapObject> feedback_vector = LoadFeedbackVector();
2260   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
2261   TNode<Smi> flags =
2262       SmiFromInt32(UncheckedCast<Int32T>(BytecodeOperandFlag(2)));
2263   TNode<Context> context = GetContext();
2264 
2265   TVARIABLE(JSRegExp, result);
2266 
2267   ConstructorBuiltinsAssembler constructor_assembler(state());
2268   result = constructor_assembler.CreateRegExpLiteral(feedback_vector, slot,
2269                                                      pattern, flags, context);
2270   SetAccumulator(result.value());
2271   Dispatch();
2272 }
2273 
2274 // CreateArrayLiteral <element_idx> <literal_idx> <flags>
2275 //
2276 // Creates an array literal for literal index <literal_idx> with
2277 // CreateArrayLiteral flags <flags> and constant elements in <element_idx>.
IGNITION_HANDLER(CreateArrayLiteral,InterpreterAssembler)2278 IGNITION_HANDLER(CreateArrayLiteral, InterpreterAssembler) {
2279   TNode<HeapObject> feedback_vector = LoadFeedbackVector();
2280   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
2281   TNode<Context> context = GetContext();
2282   TNode<Uint32T> bytecode_flags = BytecodeOperandFlag(2);
2283 
2284   Label fast_shallow_clone(this), call_runtime(this, Label::kDeferred);
2285   // No feedback, so handle it as a slow case.
2286   GotoIf(IsUndefined(feedback_vector), &call_runtime);
2287 
2288   Branch(IsSetWord32<CreateArrayLiteralFlags::FastCloneSupportedBit>(
2289              bytecode_flags),
2290          &fast_shallow_clone, &call_runtime);
2291 
2292   BIND(&fast_shallow_clone);
2293   {
2294     ConstructorBuiltinsAssembler constructor_assembler(state());
2295     TNode<JSArray> result = constructor_assembler.CreateShallowArrayLiteral(
2296         CAST(feedback_vector), slot, context, TRACK_ALLOCATION_SITE,
2297         &call_runtime);
2298     SetAccumulator(result);
2299     Dispatch();
2300   }
2301 
2302   BIND(&call_runtime);
2303   {
2304     TNode<UintPtrT> flags_raw =
2305         DecodeWordFromWord32<CreateArrayLiteralFlags::FlagsBits>(
2306             bytecode_flags);
2307     TNode<Smi> flags = SmiTag(Signed(flags_raw));
2308     TNode<Object> constant_elements = LoadConstantPoolEntryAtOperandIndex(0);
2309     TNode<Object> result =
2310         CallRuntime(Runtime::kCreateArrayLiteral, context, feedback_vector,
2311                     slot, constant_elements, flags);
2312     SetAccumulator(result);
2313     Dispatch();
2314   }
2315 }
2316 
2317 // CreateEmptyArrayLiteral <literal_idx>
2318 //
2319 // Creates an empty JSArray literal for literal index <literal_idx>.
IGNITION_HANDLER(CreateEmptyArrayLiteral,InterpreterAssembler)2320 IGNITION_HANDLER(CreateEmptyArrayLiteral, InterpreterAssembler) {
2321   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
2322   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(0);
2323   TNode<Context> context = GetContext();
2324 
2325   Label no_feedback(this, Label::kDeferred), end(this);
2326   TVARIABLE(JSArray, result);
2327   GotoIf(IsUndefined(maybe_feedback_vector), &no_feedback);
2328 
2329   ConstructorBuiltinsAssembler constructor_assembler(state());
2330   result = constructor_assembler.CreateEmptyArrayLiteral(
2331       CAST(maybe_feedback_vector), slot, context);
2332   Goto(&end);
2333 
2334   BIND(&no_feedback);
2335   {
2336     TNode<Map> array_map = LoadJSArrayElementsMap(GetInitialFastElementsKind(),
2337                                                   LoadNativeContext(context));
2338     TNode<Smi> length = SmiConstant(0);
2339     TNode<IntPtrT> capacity = IntPtrConstant(0);
2340     result = AllocateJSArray(GetInitialFastElementsKind(), array_map, capacity,
2341                              length);
2342     Goto(&end);
2343   }
2344 
2345   BIND(&end);
2346   SetAccumulator(result.value());
2347   Dispatch();
2348 }
2349 
2350 // CreateArrayFromIterable
2351 //
2352 // Spread the given iterable from the accumulator into a new JSArray.
2353 // TODO(neis): Turn this into an intrinsic when we're running out of bytecodes.
IGNITION_HANDLER(CreateArrayFromIterable,InterpreterAssembler)2354 IGNITION_HANDLER(CreateArrayFromIterable, InterpreterAssembler) {
2355   TNode<Object> iterable = GetAccumulator();
2356   TNode<Context> context = GetContext();
2357   TNode<Object> result =
2358       CallBuiltin(Builtin::kIterableToListWithSymbolLookup, context, iterable);
2359   SetAccumulator(result);
2360   Dispatch();
2361 }
2362 
2363 // CreateObjectLiteral <element_idx> <literal_idx> <flags>
2364 //
2365 // Creates an object literal for literal index <literal_idx> with
2366 // CreateObjectLiteralFlags <flags> and constant elements in <element_idx>.
IGNITION_HANDLER(CreateObjectLiteral,InterpreterAssembler)2367 IGNITION_HANDLER(CreateObjectLiteral, InterpreterAssembler) {
2368   TNode<HeapObject> feedback_vector = LoadFeedbackVector();
2369   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
2370   TNode<Uint32T> bytecode_flags = BytecodeOperandFlag(2);
2371 
2372   Label if_fast_clone(this), if_not_fast_clone(this, Label::kDeferred);
2373   // No feedback, so handle it as a slow case.
2374   GotoIf(IsUndefined(feedback_vector), &if_not_fast_clone);
2375 
2376   // Check if we can do a fast clone or have to call the runtime.
2377   Branch(IsSetWord32<CreateObjectLiteralFlags::FastCloneSupportedBit>(
2378              bytecode_flags),
2379          &if_fast_clone, &if_not_fast_clone);
2380 
2381   BIND(&if_fast_clone);
2382   {
2383     // If we can do a fast clone do the fast-path in CreateShallowObjectLiteral.
2384     ConstructorBuiltinsAssembler constructor_assembler(state());
2385     TNode<HeapObject> result = constructor_assembler.CreateShallowObjectLiteral(
2386         CAST(feedback_vector), slot, &if_not_fast_clone);
2387     SetAccumulator(result);
2388     Dispatch();
2389   }
2390 
2391   BIND(&if_not_fast_clone);
2392   {
2393     // If we can't do a fast clone, call into the runtime.
2394     TNode<ObjectBoilerplateDescription> object_boilerplate_description =
2395         CAST(LoadConstantPoolEntryAtOperandIndex(0));
2396     TNode<Context> context = GetContext();
2397 
2398     TNode<UintPtrT> flags_raw =
2399         DecodeWordFromWord32<CreateObjectLiteralFlags::FlagsBits>(
2400             bytecode_flags);
2401     TNode<Smi> flags = SmiTag(Signed(flags_raw));
2402 
2403     TNode<Object> result =
2404         CallRuntime(Runtime::kCreateObjectLiteral, context, feedback_vector,
2405                     slot, object_boilerplate_description, flags);
2406     SetAccumulator(result);
2407     // TODO(klaasb) build a single dispatch once the call is inlined
2408     Dispatch();
2409   }
2410 }
2411 
2412 // CreateEmptyObjectLiteral
2413 //
2414 // Creates an empty JSObject literal.
IGNITION_HANDLER(CreateEmptyObjectLiteral,InterpreterAssembler)2415 IGNITION_HANDLER(CreateEmptyObjectLiteral, InterpreterAssembler) {
2416   TNode<Context> context = GetContext();
2417   ConstructorBuiltinsAssembler constructor_assembler(state());
2418   TNode<JSObject> result =
2419       constructor_assembler.CreateEmptyObjectLiteral(context);
2420   SetAccumulator(result);
2421   Dispatch();
2422 }
2423 
2424 // CloneObject <source_idx> <flags> <feedback_slot>
2425 //
2426 // Allocates a new JSObject with each enumerable own property copied from
2427 // {source}, converting getters into data properties.
IGNITION_HANDLER(CloneObject,InterpreterAssembler)2428 IGNITION_HANDLER(CloneObject, InterpreterAssembler) {
2429   TNode<Object> source = LoadRegisterAtOperandIndex(0);
2430   TNode<Uint32T> bytecode_flags = BytecodeOperandFlag(1);
2431   TNode<UintPtrT> raw_flags =
2432       DecodeWordFromWord32<CreateObjectLiteralFlags::FlagsBits>(bytecode_flags);
2433   TNode<Smi> smi_flags = SmiTag(Signed(raw_flags));
2434   TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(2);
2435   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
2436   TNode<Context> context = GetContext();
2437 
2438   TNode<Object> result = CallBuiltin(Builtin::kCloneObjectIC, context, source,
2439                                      smi_flags, slot, maybe_feedback_vector);
2440   SetAccumulator(result);
2441   Dispatch();
2442 }
2443 
2444 // GetTemplateObject <descriptor_idx> <literal_idx>
2445 //
2446 // Creates the template to pass for tagged templates and returns it in the
2447 // accumulator, creating and caching the site object on-demand as per the
2448 // specification.
IGNITION_HANDLER(GetTemplateObject,InterpreterAssembler)2449 IGNITION_HANDLER(GetTemplateObject, InterpreterAssembler) {
2450   TNode<Context> context = GetContext();
2451   TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
2452   TNode<SharedFunctionInfo> shared_info = LoadObjectField<SharedFunctionInfo>(
2453       closure, JSFunction::kSharedFunctionInfoOffset);
2454   TNode<Object> description = LoadConstantPoolEntryAtOperandIndex(0);
2455   TNode<UintPtrT> slot = BytecodeOperandIdx(1);
2456   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
2457   TNode<Object> result =
2458       CallBuiltin(Builtin::kGetTemplateObject, context, shared_info,
2459                   description, slot, maybe_feedback_vector);
2460   SetAccumulator(result);
2461   Dispatch();
2462 }
2463 
2464 // CreateClosure <index> <slot> <flags>
2465 //
2466 // Creates a new closure for SharedFunctionInfo at position |index| in the
2467 // constant pool and with pretenuring controlled by |flags|.
IGNITION_HANDLER(CreateClosure,InterpreterAssembler)2468 IGNITION_HANDLER(CreateClosure, InterpreterAssembler) {
2469   TNode<Object> shared = LoadConstantPoolEntryAtOperandIndex(0);
2470   TNode<Uint32T> flags = BytecodeOperandFlag(2);
2471   TNode<Context> context = GetContext();
2472   TNode<UintPtrT> slot = BytecodeOperandIdx(1);
2473 
2474   Label if_undefined(this);
2475   TNode<ClosureFeedbackCellArray> feedback_cell_array =
2476       LoadClosureFeedbackArray(
2477           CAST(LoadRegister(Register::function_closure())));
2478   TNode<FeedbackCell> feedback_cell =
2479       CAST(LoadFixedArrayElement(feedback_cell_array, slot));
2480 
2481   Label if_fast(this), if_slow(this, Label::kDeferred);
2482   Branch(IsSetWord32<CreateClosureFlags::FastNewClosureBit>(flags), &if_fast,
2483          &if_slow);
2484 
2485   BIND(&if_fast);
2486   {
2487     TNode<Object> result =
2488         CallBuiltin(Builtin::kFastNewClosure, context, shared, feedback_cell);
2489     SetAccumulator(result);
2490     Dispatch();
2491   }
2492 
2493   BIND(&if_slow);
2494   {
2495     Label if_newspace(this), if_oldspace(this);
2496     Branch(IsSetWord32<CreateClosureFlags::PretenuredBit>(flags), &if_oldspace,
2497            &if_newspace);
2498 
2499     BIND(&if_newspace);
2500     {
2501       TNode<Object> result =
2502           CallRuntime(Runtime::kNewClosure, context, shared, feedback_cell);
2503       SetAccumulator(result);
2504       Dispatch();
2505     }
2506 
2507     BIND(&if_oldspace);
2508     {
2509       TNode<Object> result = CallRuntime(Runtime::kNewClosure_Tenured, context,
2510                                          shared, feedback_cell);
2511       SetAccumulator(result);
2512       Dispatch();
2513     }
2514   }
2515 }
2516 
2517 // CreateBlockContext <index>
2518 //
2519 // Creates a new block context with the scope info constant at |index|.
IGNITION_HANDLER(CreateBlockContext,InterpreterAssembler)2520 IGNITION_HANDLER(CreateBlockContext, InterpreterAssembler) {
2521   TNode<ScopeInfo> scope_info = CAST(LoadConstantPoolEntryAtOperandIndex(0));
2522   TNode<Context> context = GetContext();
2523   SetAccumulator(CallRuntime(Runtime::kPushBlockContext, context, scope_info));
2524   Dispatch();
2525 }
2526 
2527 // CreateCatchContext <exception> <scope_info_idx>
2528 //
2529 // Creates a new context for a catch block with the |exception| in a register
2530 // and the ScopeInfo at |scope_info_idx|.
IGNITION_HANDLER(CreateCatchContext,InterpreterAssembler)2531 IGNITION_HANDLER(CreateCatchContext, InterpreterAssembler) {
2532   TNode<Object> exception = LoadRegisterAtOperandIndex(0);
2533   TNode<ScopeInfo> scope_info = CAST(LoadConstantPoolEntryAtOperandIndex(1));
2534   TNode<Context> context = GetContext();
2535   SetAccumulator(
2536       CallRuntime(Runtime::kPushCatchContext, context, exception, scope_info));
2537   Dispatch();
2538 }
2539 
2540 // CreateFunctionContext <scope_info_idx> <slots>
2541 //
2542 // Creates a new context with number of |slots| for the function closure.
IGNITION_HANDLER(CreateFunctionContext,InterpreterAssembler)2543 IGNITION_HANDLER(CreateFunctionContext, InterpreterAssembler) {
2544   TNode<UintPtrT> scope_info_idx = BytecodeOperandIdx(0);
2545   TNode<ScopeInfo> scope_info = CAST(LoadConstantPoolEntry(scope_info_idx));
2546   TNode<Uint32T> slots = BytecodeOperandUImm(1);
2547   TNode<Context> context = GetContext();
2548   ConstructorBuiltinsAssembler constructor_assembler(state());
2549   SetAccumulator(constructor_assembler.FastNewFunctionContext(
2550       scope_info, slots, context, FUNCTION_SCOPE));
2551   Dispatch();
2552 }
2553 
2554 // CreateEvalContext <scope_info_idx> <slots>
2555 //
2556 // Creates a new context with number of |slots| for an eval closure.
IGNITION_HANDLER(CreateEvalContext,InterpreterAssembler)2557 IGNITION_HANDLER(CreateEvalContext, InterpreterAssembler) {
2558   TNode<UintPtrT> scope_info_idx = BytecodeOperandIdx(0);
2559   TNode<ScopeInfo> scope_info = CAST(LoadConstantPoolEntry(scope_info_idx));
2560   TNode<Uint32T> slots = BytecodeOperandUImm(1);
2561   TNode<Context> context = GetContext();
2562   ConstructorBuiltinsAssembler constructor_assembler(state());
2563   SetAccumulator(constructor_assembler.FastNewFunctionContext(
2564       scope_info, slots, context, EVAL_SCOPE));
2565   Dispatch();
2566 }
2567 
2568 // CreateWithContext <register> <scope_info_idx>
2569 //
2570 // Creates a new context with the ScopeInfo at |scope_info_idx| for a
2571 // with-statement with the object in |register|.
IGNITION_HANDLER(CreateWithContext,InterpreterAssembler)2572 IGNITION_HANDLER(CreateWithContext, InterpreterAssembler) {
2573   TNode<Object> object = LoadRegisterAtOperandIndex(0);
2574   TNode<ScopeInfo> scope_info = CAST(LoadConstantPoolEntryAtOperandIndex(1));
2575   TNode<Context> context = GetContext();
2576   SetAccumulator(
2577       CallRuntime(Runtime::kPushWithContext, context, object, scope_info));
2578   Dispatch();
2579 }
2580 
2581 // CreateMappedArguments
2582 //
2583 // Creates a new mapped arguments object.
IGNITION_HANDLER(CreateMappedArguments,InterpreterAssembler)2584 IGNITION_HANDLER(CreateMappedArguments, InterpreterAssembler) {
2585   TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
2586   TNode<Context> context = GetContext();
2587 
2588   Label if_duplicate_parameters(this, Label::kDeferred);
2589   Label if_not_duplicate_parameters(this);
2590 
2591   // Check if function has duplicate parameters.
2592   // TODO(rmcilroy): Remove this check when FastNewSloppyArgumentsStub supports
2593   // duplicate parameters.
2594   TNode<SharedFunctionInfo> shared_info = LoadObjectField<SharedFunctionInfo>(
2595       closure, JSFunction::kSharedFunctionInfoOffset);
2596   TNode<Uint32T> flags =
2597       LoadObjectField<Uint32T>(shared_info, SharedFunctionInfo::kFlagsOffset);
2598   TNode<BoolT> has_duplicate_parameters =
2599       IsSetWord32<SharedFunctionInfo::HasDuplicateParametersBit>(flags);
2600   Branch(has_duplicate_parameters, &if_duplicate_parameters,
2601          &if_not_duplicate_parameters);
2602 
2603   BIND(&if_not_duplicate_parameters);
2604   {
2605     TNode<JSObject> result = EmitFastNewSloppyArguments(context, closure);
2606     SetAccumulator(result);
2607     Dispatch();
2608   }
2609 
2610   BIND(&if_duplicate_parameters);
2611   {
2612     TNode<Object> result =
2613         CallRuntime(Runtime::kNewSloppyArguments, context, closure);
2614     SetAccumulator(result);
2615     Dispatch();
2616   }
2617 }
2618 
2619 // CreateUnmappedArguments
2620 //
2621 // Creates a new unmapped arguments object.
IGNITION_HANDLER(CreateUnmappedArguments,InterpreterAssembler)2622 IGNITION_HANDLER(CreateUnmappedArguments, InterpreterAssembler) {
2623   TNode<Context> context = GetContext();
2624   TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
2625   TorqueGeneratedExportedMacrosAssembler builtins_assembler(state());
2626   TNode<JSObject> result =
2627       builtins_assembler.EmitFastNewStrictArguments(context, closure);
2628   SetAccumulator(result);
2629   Dispatch();
2630 }
2631 
2632 // CreateRestParameter
2633 //
2634 // Creates a new rest parameter array.
IGNITION_HANDLER(CreateRestParameter,InterpreterAssembler)2635 IGNITION_HANDLER(CreateRestParameter, InterpreterAssembler) {
2636   TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
2637   TNode<Context> context = GetContext();
2638   TorqueGeneratedExportedMacrosAssembler builtins_assembler(state());
2639   TNode<JSObject> result =
2640       builtins_assembler.EmitFastNewRestArguments(context, closure);
2641   SetAccumulator(result);
2642   Dispatch();
2643 }
2644 
2645 // SetPendingMessage
2646 //
2647 // Sets the pending message to the value in the accumulator, and returns the
2648 // previous pending message in the accumulator.
IGNITION_HANDLER(SetPendingMessage,InterpreterAssembler)2649 IGNITION_HANDLER(SetPendingMessage, InterpreterAssembler) {
2650   TNode<HeapObject> previous_message = GetPendingMessage();
2651   SetPendingMessage(CAST(GetAccumulator()));
2652   SetAccumulator(previous_message);
2653   Dispatch();
2654 }
2655 
2656 // Throw
2657 //
2658 // Throws the exception in the accumulator.
IGNITION_HANDLER(Throw,InterpreterAssembler)2659 IGNITION_HANDLER(Throw, InterpreterAssembler) {
2660   TNode<Object> exception = GetAccumulator();
2661   TNode<Context> context = GetContext();
2662   CallRuntime(Runtime::kThrow, context, exception);
2663   // We shouldn't ever return from a throw.
2664   Abort(AbortReason::kUnexpectedReturnFromThrow);
2665   Unreachable();
2666 }
2667 
2668 // ReThrow
2669 //
2670 // Re-throws the exception in the accumulator.
IGNITION_HANDLER(ReThrow,InterpreterAssembler)2671 IGNITION_HANDLER(ReThrow, InterpreterAssembler) {
2672   TNode<Object> exception = GetAccumulator();
2673   TNode<Context> context = GetContext();
2674   CallRuntime(Runtime::kReThrow, context, exception);
2675   // We shouldn't ever return from a throw.
2676   Abort(AbortReason::kUnexpectedReturnFromThrow);
2677   Unreachable();
2678 }
2679 
2680 // Abort <abort_reason>
2681 //
2682 // Aborts execution (via a call to the runtime function).
IGNITION_HANDLER(Abort,InterpreterAssembler)2683 IGNITION_HANDLER(Abort, InterpreterAssembler) {
2684   TNode<UintPtrT> reason = BytecodeOperandIdx(0);
2685   CallRuntime(Runtime::kAbort, NoContextConstant(), SmiTag(Signed(reason)));
2686   Unreachable();
2687 }
2688 
2689 // Return
2690 //
2691 // Return the value in the accumulator.
IGNITION_HANDLER(Return,InterpreterAssembler)2692 IGNITION_HANDLER(Return, InterpreterAssembler) {
2693   UpdateInterruptBudgetOnReturn();
2694   TNode<Object> accumulator = GetAccumulator();
2695   Return(accumulator);
2696 }
2697 
2698 // ThrowReferenceErrorIfHole <variable_name>
2699 //
2700 // Throws an exception if the value in the accumulator is TheHole.
IGNITION_HANDLER(ThrowReferenceErrorIfHole,InterpreterAssembler)2701 IGNITION_HANDLER(ThrowReferenceErrorIfHole, InterpreterAssembler) {
2702   TNode<Object> value = GetAccumulator();
2703 
2704   Label throw_error(this, Label::kDeferred);
2705   GotoIf(TaggedEqual(value, TheHoleConstant()), &throw_error);
2706   Dispatch();
2707 
2708   BIND(&throw_error);
2709   {
2710     TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
2711     CallRuntime(Runtime::kThrowAccessedUninitializedVariable, GetContext(),
2712                 name);
2713     // We shouldn't ever return from a throw.
2714     Abort(AbortReason::kUnexpectedReturnFromThrow);
2715     Unreachable();
2716   }
2717 }
2718 
2719 // ThrowSuperNotCalledIfHole
2720 //
2721 // Throws an exception if the value in the accumulator is TheHole.
IGNITION_HANDLER(ThrowSuperNotCalledIfHole,InterpreterAssembler)2722 IGNITION_HANDLER(ThrowSuperNotCalledIfHole, InterpreterAssembler) {
2723   TNode<Object> value = GetAccumulator();
2724 
2725   Label throw_error(this, Label::kDeferred);
2726   GotoIf(TaggedEqual(value, TheHoleConstant()), &throw_error);
2727   Dispatch();
2728 
2729   BIND(&throw_error);
2730   {
2731     CallRuntime(Runtime::kThrowSuperNotCalled, GetContext());
2732     // We shouldn't ever return from a throw.
2733     Abort(AbortReason::kUnexpectedReturnFromThrow);
2734     Unreachable();
2735   }
2736 }
2737 
2738 // ThrowSuperAlreadyCalledIfNotHole
2739 //
2740 // Throws SuperAlreadyCalled exception if the value in the accumulator is not
2741 // TheHole.
IGNITION_HANDLER(ThrowSuperAlreadyCalledIfNotHole,InterpreterAssembler)2742 IGNITION_HANDLER(ThrowSuperAlreadyCalledIfNotHole, InterpreterAssembler) {
2743   TNode<Object> value = GetAccumulator();
2744 
2745   Label throw_error(this, Label::kDeferred);
2746   GotoIf(TaggedNotEqual(value, TheHoleConstant()), &throw_error);
2747   Dispatch();
2748 
2749   BIND(&throw_error);
2750   {
2751     CallRuntime(Runtime::kThrowSuperAlreadyCalledError, GetContext());
2752     // We shouldn't ever return from a throw.
2753     Abort(AbortReason::kUnexpectedReturnFromThrow);
2754     Unreachable();
2755   }
2756 }
2757 
2758 // ThrowIfNotSuperConstructor <constructor>
2759 //
2760 // Throws an exception if the value in |constructor| is not in fact a
2761 // constructor.
IGNITION_HANDLER(ThrowIfNotSuperConstructor,InterpreterAssembler)2762 IGNITION_HANDLER(ThrowIfNotSuperConstructor, InterpreterAssembler) {
2763   TNode<HeapObject> constructor = CAST(LoadRegisterAtOperandIndex(0));
2764   TNode<Context> context = GetContext();
2765 
2766   Label is_not_constructor(this, Label::kDeferred);
2767   TNode<Map> constructor_map = LoadMap(constructor);
2768   GotoIfNot(IsConstructorMap(constructor_map), &is_not_constructor);
2769   Dispatch();
2770 
2771   BIND(&is_not_constructor);
2772   {
2773     TNode<JSFunction> function =
2774         CAST(LoadRegister(Register::function_closure()));
2775     CallRuntime(Runtime::kThrowNotSuperConstructor, context, constructor,
2776                 function);
2777     // We shouldn't ever return from a throw.
2778     Abort(AbortReason::kUnexpectedReturnFromThrow);
2779     Unreachable();
2780   }
2781 }
2782 
2783 // Debugger
2784 //
2785 // Call runtime to handle debugger statement.
IGNITION_HANDLER(Debugger,InterpreterAssembler)2786 IGNITION_HANDLER(Debugger, InterpreterAssembler) {
2787   TNode<Context> context = GetContext();
2788   CallRuntime(Runtime::kHandleDebuggerStatement, context);
2789   Dispatch();
2790 }
2791 
2792 // DebugBreak
2793 //
2794 // Call runtime to handle a debug break.
2795 #define DEBUG_BREAK(Name, ...)                                               \
2796   IGNITION_HANDLER(Name, InterpreterAssembler) {                             \
2797     TNode<Context> context = GetContext();                                   \
2798     TNode<Object> accumulator = GetAccumulator();                            \
2799     TNode<PairT<Object, Smi>> result_pair = CallRuntime<PairT<Object, Smi>>( \
2800         Runtime::kDebugBreakOnBytecode, context, accumulator);               \
2801     TNode<Object> return_value = Projection<0>(result_pair);                 \
2802     TNode<IntPtrT> original_bytecode = SmiUntag(Projection<1>(result_pair)); \
2803     SetAccumulator(return_value);                                            \
2804     DispatchToBytecodeWithOptionalStarLookahead(original_bytecode);          \
2805   }
2806 DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK)
2807 #undef DEBUG_BREAK
2808 
2809 // IncBlockCounter <slot>
2810 //
2811 // Increment the execution count for the given slot. Used for block code
2812 // coverage.
IGNITION_HANDLER(IncBlockCounter,InterpreterAssembler)2813 IGNITION_HANDLER(IncBlockCounter, InterpreterAssembler) {
2814   TNode<Object> closure = LoadRegister(Register::function_closure());
2815   TNode<Smi> coverage_array_slot = BytecodeOperandIdxSmi(0);
2816   TNode<Context> context = GetContext();
2817 
2818   CallBuiltin(Builtin::kIncBlockCounter, context, closure, coverage_array_slot);
2819 
2820   Dispatch();
2821 }
2822 
2823 // ForInEnumerate <receiver>
2824 //
2825 // Enumerates the enumerable keys of the |receiver| and either returns the
2826 // map of the |receiver| if it has a usable enum cache or a fixed array
2827 // with the keys to enumerate in the accumulator.
IGNITION_HANDLER(ForInEnumerate,InterpreterAssembler)2828 IGNITION_HANDLER(ForInEnumerate, InterpreterAssembler) {
2829   TNode<JSReceiver> receiver = CAST(LoadRegisterAtOperandIndex(0));
2830   TNode<Context> context = GetContext();
2831 
2832   Label if_empty(this), if_runtime(this, Label::kDeferred);
2833   TNode<Map> receiver_map = CheckEnumCache(receiver, &if_empty, &if_runtime);
2834   SetAccumulator(receiver_map);
2835   Dispatch();
2836 
2837   BIND(&if_empty);
2838   {
2839     TNode<FixedArray> result = EmptyFixedArrayConstant();
2840     SetAccumulator(result);
2841     Dispatch();
2842   }
2843 
2844   BIND(&if_runtime);
2845   {
2846     TNode<Object> result =
2847         CallRuntime(Runtime::kForInEnumerate, context, receiver);
2848     SetAccumulator(result);
2849     Dispatch();
2850   }
2851 }
2852 
2853 // ForInPrepare <cache_info_triple>
2854 //
2855 // Returns state for for..in loop execution based on the enumerator in
2856 // the accumulator register, which is the result of calling ForInEnumerate
2857 // on a JSReceiver object.
2858 // The result is output in registers |cache_info_triple| to
2859 // |cache_info_triple + 2|, with the registers holding cache_type, cache_array,
2860 // and cache_length respectively.
IGNITION_HANDLER(ForInPrepare,InterpreterAssembler)2861 IGNITION_HANDLER(ForInPrepare, InterpreterAssembler) {
2862   // The {enumerator} is either a Map or a FixedArray.
2863   TNode<HeapObject> enumerator = CAST(GetAccumulator());
2864   TNode<UintPtrT> vector_index = BytecodeOperandIdx(1);
2865   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
2866 
2867   TNode<HeapObject> cache_type = enumerator;  // Just to clarify the rename.
2868   TNode<FixedArray> cache_array;
2869   TNode<Smi> cache_length;
2870   ForInPrepare(enumerator, vector_index, maybe_feedback_vector, &cache_array,
2871                &cache_length, UpdateFeedbackMode::kOptionalFeedback);
2872 
2873   // The accumulator is clobbered soon after ForInPrepare, so avoid keeping it
2874   // alive too long and instead set it to cache_array to match the first return
2875   // value of Builtin::kForInPrepare.
2876   SetAccumulator(cache_array);
2877 
2878   StoreRegisterTripleAtOperandIndex(cache_type, cache_array, cache_length, 0);
2879   Dispatch();
2880 }
2881 
2882 // ForInNext <receiver> <index> <cache_info_pair>
2883 //
2884 // Returns the next enumerable property in the the accumulator.
IGNITION_HANDLER(ForInNext,InterpreterAssembler)2885 IGNITION_HANDLER(ForInNext, InterpreterAssembler) {
2886   TNode<HeapObject> receiver = CAST(LoadRegisterAtOperandIndex(0));
2887   TNode<Smi> index = CAST(LoadRegisterAtOperandIndex(1));
2888   TNode<Object> cache_type;
2889   TNode<Object> cache_array;
2890   std::tie(cache_type, cache_array) = LoadRegisterPairAtOperandIndex(2);
2891   TNode<UintPtrT> vector_index = BytecodeOperandIdx(3);
2892   TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
2893 
2894   // Load the next key from the enumeration array.
2895   TNode<Object> key = LoadFixedArrayElement(CAST(cache_array), index, 0);
2896 
2897   // Check if we can use the for-in fast path potentially using the enum cache.
2898   Label if_fast(this), if_slow(this, Label::kDeferred);
2899   TNode<Map> receiver_map = LoadMap(receiver);
2900   Branch(TaggedEqual(receiver_map, cache_type), &if_fast, &if_slow);
2901   BIND(&if_fast);
2902   {
2903     // Enum cache in use for {receiver}, the {key} is definitely valid.
2904     SetAccumulator(key);
2905     Dispatch();
2906   }
2907   BIND(&if_slow);
2908   {
2909     TNode<Object> result = ForInNextSlow(GetContext(), vector_index, receiver,
2910                                          key, cache_type, maybe_feedback_vector,
2911                                          UpdateFeedbackMode::kOptionalFeedback);
2912     SetAccumulator(result);
2913     Dispatch();
2914   }
2915 }
2916 
2917 // ForInContinue <index> <cache_length>
2918 //
2919 // Returns false if the end of the enumerable properties has been reached.
IGNITION_HANDLER(ForInContinue,InterpreterAssembler)2920 IGNITION_HANDLER(ForInContinue, InterpreterAssembler) {
2921   TNode<Object> index = LoadRegisterAtOperandIndex(0);
2922   TNode<Object> cache_length = LoadRegisterAtOperandIndex(1);
2923 
2924   // Check if {index} is at {cache_length} already.
2925   Label if_true(this), if_false(this), end(this);
2926   Branch(TaggedEqual(index, cache_length), &if_true, &if_false);
2927   BIND(&if_true);
2928   {
2929     SetAccumulator(FalseConstant());
2930     Goto(&end);
2931   }
2932   BIND(&if_false);
2933   {
2934     SetAccumulator(TrueConstant());
2935     Goto(&end);
2936   }
2937   BIND(&end);
2938   Dispatch();
2939 }
2940 
2941 // ForInStep <index>
2942 //
2943 // Increments the loop counter in register |index| and stores the result
2944 // in the accumulator.
IGNITION_HANDLER(ForInStep,InterpreterAssembler)2945 IGNITION_HANDLER(ForInStep, InterpreterAssembler) {
2946   TNode<Smi> index = CAST(LoadRegisterAtOperandIndex(0));
2947   TNode<Smi> one = SmiConstant(1);
2948   TNode<Smi> result = SmiAdd(index, one);
2949   SetAccumulator(result);
2950   Dispatch();
2951 }
2952 
2953 // GetIterator <object>
2954 //
2955 // Retrieves the object[Symbol.iterator] method, calls it and stores
2956 // the result in the accumulator
2957 // TODO(swapnilgaikwad): Extend the functionality of the bytecode to
2958 // check if the result is a JSReceiver else throw SymbolIteratorInvalid
2959 // runtime exception
IGNITION_HANDLER(GetIterator,InterpreterAssembler)2960 IGNITION_HANDLER(GetIterator, InterpreterAssembler) {
2961   TNode<Object> receiver = LoadRegisterAtOperandIndex(0);
2962   TNode<Context> context = GetContext();
2963   TNode<HeapObject> feedback_vector = LoadFeedbackVector();
2964   TNode<TaggedIndex> load_slot = BytecodeOperandIdxTaggedIndex(1);
2965   TNode<TaggedIndex> call_slot = BytecodeOperandIdxTaggedIndex(2);
2966 
2967   TNode<Object> iterator =
2968       CallBuiltin(Builtin::kGetIteratorWithFeedback, context, receiver,
2969                   load_slot, call_slot, feedback_vector);
2970   SetAccumulator(iterator);
2971   Dispatch();
2972 }
2973 
2974 // Wide
2975 //
2976 // Prefix bytecode indicating next bytecode has wide (16-bit) operands.
IGNITION_HANDLER(Wide,InterpreterAssembler)2977 IGNITION_HANDLER(Wide, InterpreterAssembler) {
2978   DispatchWide(OperandScale::kDouble);
2979 }
2980 
2981 // ExtraWide
2982 //
2983 // Prefix bytecode indicating next bytecode has extra-wide (32-bit) operands.
IGNITION_HANDLER(ExtraWide,InterpreterAssembler)2984 IGNITION_HANDLER(ExtraWide, InterpreterAssembler) {
2985   DispatchWide(OperandScale::kQuadruple);
2986 }
2987 
2988 // Illegal
2989 //
2990 // An invalid bytecode aborting execution if dispatched.
IGNITION_HANDLER(Illegal,InterpreterAssembler)2991 IGNITION_HANDLER(Illegal, InterpreterAssembler) {
2992   Abort(AbortReason::kInvalidBytecode);
2993   Unreachable();
2994 }
2995 
2996 // SuspendGenerator <generator> <first input register> <register count>
2997 // <suspend_id>
2998 //
2999 // Stores the parameters and the register file in the generator. Also stores
3000 // the current context, |suspend_id|, and the current bytecode offset
3001 // (for debugging purposes) into the generator. Then, returns the value
3002 // in the accumulator.
IGNITION_HANDLER(SuspendGenerator,InterpreterAssembler)3003 IGNITION_HANDLER(SuspendGenerator, InterpreterAssembler) {
3004   TNode<JSGeneratorObject> generator = CAST(LoadRegisterAtOperandIndex(0));
3005   TNode<FixedArray> array = CAST(LoadObjectField(
3006       generator, JSGeneratorObject::kParametersAndRegistersOffset));
3007   TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
3008   TNode<Context> context = GetContext();
3009   RegListNodePair registers = GetRegisterListAtOperandIndex(1);
3010   TNode<Smi> suspend_id = BytecodeOperandUImmSmi(3);
3011 
3012   TNode<SharedFunctionInfo> shared =
3013       CAST(LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset));
3014   TNode<Int32T> formal_parameter_count =
3015       LoadSharedFunctionInfoFormalParameterCountWithoutReceiver(shared);
3016 
3017   ExportParametersAndRegisterFile(array, registers, formal_parameter_count);
3018   StoreObjectField(generator, JSGeneratorObject::kContextOffset, context);
3019   StoreObjectField(generator, JSGeneratorObject::kContinuationOffset,
3020                    suspend_id);
3021 
3022   // Store the bytecode offset in the [input_or_debug_pos] field, to be used by
3023   // the inspector.
3024   TNode<Smi> offset = SmiTag(BytecodeOffset());
3025   StoreObjectField(generator, JSGeneratorObject::kInputOrDebugPosOffset,
3026                    offset);
3027 
3028   UpdateInterruptBudgetOnReturn();
3029   Return(GetAccumulator());
3030 }
3031 
3032 // SwitchOnGeneratorState <generator> <table_start> <table_length>
3033 //
3034 // If |generator| is undefined, falls through. Otherwise, loads the
3035 // generator's state (overwriting it with kGeneratorExecuting), sets the context
3036 // to the generator's resume context, and performs state dispatch on the
3037 // generator's state by looking up the generator state in a jump table in the
3038 // constant pool, starting at |table_start|, and of length |table_length|.
IGNITION_HANDLER(SwitchOnGeneratorState,InterpreterAssembler)3039 IGNITION_HANDLER(SwitchOnGeneratorState, InterpreterAssembler) {
3040   TNode<Object> maybe_generator = LoadRegisterAtOperandIndex(0);
3041 
3042   Label fallthrough(this);
3043   GotoIf(TaggedEqual(maybe_generator, UndefinedConstant()), &fallthrough);
3044 
3045   TNode<JSGeneratorObject> generator = CAST(maybe_generator);
3046 
3047   TNode<Smi> state =
3048       CAST(LoadObjectField(generator, JSGeneratorObject::kContinuationOffset));
3049   TNode<Smi> new_state = SmiConstant(JSGeneratorObject::kGeneratorExecuting);
3050   StoreObjectField(generator, JSGeneratorObject::kContinuationOffset,
3051                    new_state);
3052 
3053   TNode<Context> context =
3054       CAST(LoadObjectField(generator, JSGeneratorObject::kContextOffset));
3055   SetContext(context);
3056 
3057   TNode<UintPtrT> table_start = BytecodeOperandIdx(1);
3058   // TODO(leszeks): table_length is only used for a CSA_DCHECK, we don't
3059   // actually need it otherwise.
3060   TNode<UintPtrT> table_length = BytecodeOperandUImmWord(2);
3061 
3062   // The state must be a Smi.
3063   CSA_DCHECK(this, TaggedIsSmi(state));
3064 
3065   TNode<IntPtrT> case_value = SmiUntag(state);
3066 
3067   CSA_DCHECK(this, IntPtrGreaterThanOrEqual(case_value, IntPtrConstant(0)));
3068   CSA_DCHECK(this, IntPtrLessThan(case_value, table_length));
3069   USE(table_length);
3070 
3071   TNode<WordT> entry = IntPtrAdd(table_start, case_value);
3072   TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntry(entry);
3073   Jump(relative_jump);
3074 
3075   BIND(&fallthrough);
3076   Dispatch();
3077 }
3078 
3079 // ResumeGenerator <generator> <first output register> <register count>
3080 //
3081 // Imports the register file stored in the generator and marks the generator
3082 // state as executing.
IGNITION_HANDLER(ResumeGenerator,InterpreterAssembler)3083 IGNITION_HANDLER(ResumeGenerator, InterpreterAssembler) {
3084   TNode<JSGeneratorObject> generator = CAST(LoadRegisterAtOperandIndex(0));
3085   TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
3086   RegListNodePair registers = GetRegisterListAtOperandIndex(1);
3087 
3088   TNode<SharedFunctionInfo> shared =
3089       CAST(LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset));
3090   TNode<Int32T> formal_parameter_count =
3091       LoadSharedFunctionInfoFormalParameterCountWithoutReceiver(shared);
3092 
3093   ImportRegisterFile(
3094       CAST(LoadObjectField(generator,
3095                            JSGeneratorObject::kParametersAndRegistersOffset)),
3096       registers, formal_parameter_count);
3097 
3098   // Return the generator's input_or_debug_pos in the accumulator.
3099   SetAccumulator(
3100       LoadObjectField(generator, JSGeneratorObject::kInputOrDebugPosOffset));
3101 
3102   Dispatch();
3103 }
3104 
3105 #undef IGNITION_HANDLER
3106 
3107 }  // namespace
3108 
GenerateBytecodeHandler(Isolate * isolate,const char * debug_name,Bytecode bytecode,OperandScale operand_scale,Builtin builtin,const AssemblerOptions & options)3109 Handle<Code> GenerateBytecodeHandler(Isolate* isolate, const char* debug_name,
3110                                      Bytecode bytecode,
3111                                      OperandScale operand_scale,
3112                                      Builtin builtin,
3113                                      const AssemblerOptions& options) {
3114   Zone zone(isolate->allocator(), ZONE_NAME, kCompressGraphZone);
3115   compiler::CodeAssemblerState state(
3116       isolate, &zone, InterpreterDispatchDescriptor{},
3117       CodeKind::BYTECODE_HANDLER, debug_name, builtin);
3118 
3119   switch (bytecode) {
3120 #define CALL_GENERATOR(Name, ...)                     \
3121   case Bytecode::k##Name:                             \
3122     Name##Assembler::Generate(&state, operand_scale); \
3123     break;
3124     BYTECODE_LIST_WITH_UNIQUE_HANDLERS(CALL_GENERATOR);
3125 #undef CALL_GENERATOR
3126     case Bytecode::kIllegal:
3127       IllegalAssembler::Generate(&state, operand_scale);
3128       break;
3129     case Bytecode::kStar0:
3130       Star0Assembler::Generate(&state, operand_scale);
3131       break;
3132     default:
3133       // Others (the rest of the short stars, and the rest of the illegal range)
3134       // must not get their own handler generated. Rather, multiple entries in
3135       // the jump table point to those handlers.
3136       UNREACHABLE();
3137   }
3138 
3139   Handle<Code> code = compiler::CodeAssembler::GenerateCode(
3140       &state, options, ProfileDataFromFile::TryRead(debug_name));
3141 
3142 #ifdef ENABLE_DISASSEMBLER
3143   if (FLAG_trace_ignition_codegen) {
3144     StdoutStream os;
3145     code->Disassemble(Bytecodes::ToString(bytecode), os, isolate);
3146     os << std::flush;
3147   }
3148 #endif  // ENABLE_DISASSEMBLER
3149 
3150   return code;
3151 }
3152 
3153 }  // namespace interpreter
3154 }  // namespace internal
3155 }  // namespace v8
3156