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