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