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