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