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