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