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