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