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