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