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