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