Line data Source code
1 : // Copyright 2017 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/interpreter/interpreter-generator.h"
6 :
7 : #include <array>
8 : #include <tuple>
9 :
10 : #include "src/builtins/builtins-arguments-gen.h"
11 : #include "src/builtins/builtins-constructor-gen.h"
12 : #include "src/builtins/builtins-forin-gen.h"
13 : #include "src/code-events.h"
14 : #include "src/code-factory.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 86 : IGNITION_HANDLER(LdaZero, InterpreterAssembler) {
59 43 : Node* zero_value = NumberConstant(0.0);
60 43 : SetAccumulator(zero_value);
61 43 : Dispatch();
62 43 : }
63 :
64 : // LdaSmi <imm>
65 : //
66 : // Load an integer literal into the accumulator as a Smi.
67 258 : IGNITION_HANDLER(LdaSmi, InterpreterAssembler) {
68 129 : Node* smi_int = BytecodeOperandImmSmi(0);
69 129 : SetAccumulator(smi_int);
70 129 : Dispatch();
71 129 : }
72 :
73 : // LdaConstant <idx>
74 : //
75 : // Load constant literal at |idx| in the constant pool into the accumulator.
76 258 : IGNITION_HANDLER(LdaConstant, InterpreterAssembler) {
77 129 : Node* index = BytecodeOperandIdx(0);
78 129 : Node* constant = LoadConstantPoolEntry(index);
79 129 : SetAccumulator(constant);
80 129 : Dispatch();
81 129 : }
82 :
83 : // LdaUndefined
84 : //
85 : // Load Undefined into the accumulator.
86 86 : IGNITION_HANDLER(LdaUndefined, InterpreterAssembler) {
87 43 : SetAccumulator(UndefinedConstant());
88 43 : Dispatch();
89 43 : }
90 :
91 : // LdaNull
92 : //
93 : // Load Null into the accumulator.
94 86 : IGNITION_HANDLER(LdaNull, InterpreterAssembler) {
95 43 : SetAccumulator(NullConstant());
96 43 : Dispatch();
97 43 : }
98 :
99 : // LdaTheHole
100 : //
101 : // Load TheHole into the accumulator.
102 86 : IGNITION_HANDLER(LdaTheHole, InterpreterAssembler) {
103 43 : SetAccumulator(TheHoleConstant());
104 43 : Dispatch();
105 43 : }
106 :
107 : // LdaTrue
108 : //
109 : // Load True into the accumulator.
110 86 : IGNITION_HANDLER(LdaTrue, InterpreterAssembler) {
111 43 : SetAccumulator(TrueConstant());
112 43 : Dispatch();
113 43 : }
114 :
115 : // LdaFalse
116 : //
117 : // Load False into the accumulator.
118 86 : IGNITION_HANDLER(LdaFalse, InterpreterAssembler) {
119 43 : SetAccumulator(FalseConstant());
120 43 : Dispatch();
121 43 : }
122 :
123 : // Ldar <src>
124 : //
125 : // Load accumulator with value from register <src>.
126 258 : IGNITION_HANDLER(Ldar, InterpreterAssembler) {
127 129 : Node* reg_index = BytecodeOperandReg(0);
128 129 : Node* value = LoadRegister(reg_index);
129 129 : SetAccumulator(value);
130 129 : Dispatch();
131 129 : }
132 :
133 : // Star <dst>
134 : //
135 : // Store accumulator to register <dst>.
136 258 : IGNITION_HANDLER(Star, InterpreterAssembler) {
137 129 : Node* reg_index = BytecodeOperandReg(0);
138 129 : Node* accumulator = GetAccumulator();
139 129 : StoreRegister(accumulator, reg_index);
140 129 : Dispatch();
141 129 : }
142 :
143 : // Mov <src> <dst>
144 : //
145 : // Stores the value of register <src> to register <dst>.
146 258 : IGNITION_HANDLER(Mov, InterpreterAssembler) {
147 129 : Node* src_index = BytecodeOperandReg(0);
148 129 : Node* src_value = LoadRegister(src_index);
149 129 : Node* dst_index = BytecodeOperandReg(1);
150 129 : StoreRegister(src_value, dst_index);
151 129 : Dispatch();
152 129 : }
153 :
154 516 : class InterpreterLoadGlobalAssembler : public InterpreterAssembler {
155 : public:
156 : InterpreterLoadGlobalAssembler(CodeAssemblerState* state, Bytecode bytecode,
157 : OperandScale operand_scale)
158 516 : : InterpreterAssembler(state, bytecode, operand_scale) {}
159 :
160 516 : 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 516 : Node* feedback_vector = LoadFeedbackVector();
166 516 : Node* feedback_slot = BytecodeOperandIdx(slot_operand_index);
167 :
168 : AccessorAssembler accessor_asm(state());
169 :
170 1032 : 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 1032 : Variable var_result(this, MachineRepresentation::kTagged);
176 516 : ExitPoint exit_point(this, &done, &var_result);
177 :
178 : accessor_asm.LoadGlobalIC_TryPropertyCellCase(
179 : feedback_vector, feedback_slot, &exit_point, &try_handler, &miss,
180 516 : CodeStubAssembler::INTPTR_PARAMETERS);
181 :
182 516 : Bind(&done);
183 516 : SetAccumulator(var_result.value());
184 1032 : Dispatch();
185 : }
186 :
187 : // Slow path with frame construction.
188 : {
189 : Label done(this);
190 1032 : Variable var_result(this, MachineRepresentation::kTagged);
191 : ExitPoint exit_point(this, &done, &var_result);
192 :
193 516 : Bind(&try_handler);
194 : {
195 516 : Node* context = GetContext();
196 516 : Node* smi_slot = SmiTag(feedback_slot);
197 516 : Node* name_index = BytecodeOperandIdx(name_operand_index);
198 516 : 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 516 : &exit_point, &miss);
204 : }
205 :
206 516 : Bind(&miss);
207 : {
208 516 : Node* context = GetContext();
209 516 : Node* smi_slot = SmiTag(feedback_slot);
210 516 : Node* name_index = BytecodeOperandIdx(name_operand_index);
211 516 : Node* name = LoadConstantPoolEntry(name_index);
212 :
213 : AccessorAssembler::LoadICParameters params(context, nullptr, name,
214 : smi_slot, feedback_vector);
215 516 : accessor_asm.LoadGlobalIC_MissCase(¶ms, &exit_point);
216 : }
217 :
218 516 : Bind(&done);
219 : {
220 516 : SetAccumulator(var_result.value());
221 516 : Dispatch();
222 516 : }
223 : }
224 516 : }
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 387 : IGNITION_HANDLER(LdaGlobal, InterpreterLoadGlobalAssembler) {
232 : static const int kNameOperandIndex = 0;
233 : static const int kSlotOperandIndex = 1;
234 :
235 129 : 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 387 : IGNITION_HANDLER(LdaGlobalInsideTypeof, InterpreterLoadGlobalAssembler) {
243 : static const int kNameOperandIndex = 0;
244 : static const int kSlotOperandIndex = 1;
245 :
246 129 : LdaGlobal(kSlotOperandIndex, kNameOperandIndex, INSIDE_TYPEOF);
247 : }
248 :
249 258 : class InterpreterStoreGlobalAssembler : public InterpreterAssembler {
250 : public:
251 : InterpreterStoreGlobalAssembler(CodeAssemblerState* state, Bytecode bytecode,
252 : OperandScale operand_scale)
253 258 : : InterpreterAssembler(state, bytecode, operand_scale) {}
254 :
255 258 : void StaGlobal(Callable ic) {
256 : // Get the global object.
257 258 : Node* context = GetContext();
258 258 : Node* native_context = LoadNativeContext(context);
259 258 : Node* global = LoadContextElement(native_context, Context::EXTENSION_INDEX);
260 :
261 : // Store the global via the StoreIC.
262 258 : Node* code_target = HeapConstant(ic.code());
263 258 : Node* constant_index = BytecodeOperandIdx(0);
264 258 : Node* name = LoadConstantPoolEntry(constant_index);
265 258 : Node* value = GetAccumulator();
266 258 : Node* raw_slot = BytecodeOperandIdx(1);
267 258 : Node* smi_slot = SmiTag(raw_slot);
268 258 : Node* feedback_vector = LoadFeedbackVector();
269 : CallStub(ic.descriptor(), code_target, context, global, name, value,
270 258 : smi_slot, feedback_vector);
271 258 : Dispatch();
272 258 : }
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 516 : IGNITION_HANDLER(StaGlobalSloppy, InterpreterStoreGlobalAssembler) {
280 129 : Callable ic = CodeFactory::StoreGlobalICInOptimizedCode(isolate(), SLOPPY);
281 129 : StaGlobal(ic);
282 129 : }
283 :
284 : // StaGlobalStrict <name_index> <slot>
285 : //
286 : // Store the value in the accumulator into the global with name in constant pool
287 : // entry <name_index> using FeedBackVector slot <slot> in strict mode.
288 516 : IGNITION_HANDLER(StaGlobalStrict, InterpreterStoreGlobalAssembler) {
289 129 : Callable ic = CodeFactory::StoreGlobalICInOptimizedCode(isolate(), STRICT);
290 129 : StaGlobal(ic);
291 129 : }
292 :
293 : // LdaContextSlot <context> <slot_index> <depth>
294 : //
295 : // Load the object in |slot_index| of the context at |depth| in the context
296 : // chain starting at |context| into the accumulator.
297 258 : IGNITION_HANDLER(LdaContextSlot, InterpreterAssembler) {
298 129 : Node* reg_index = BytecodeOperandReg(0);
299 129 : Node* context = LoadRegister(reg_index);
300 129 : Node* slot_index = BytecodeOperandIdx(1);
301 129 : Node* depth = BytecodeOperandUImm(2);
302 129 : Node* slot_context = GetContextAtDepth(context, depth);
303 129 : Node* result = LoadContextElement(slot_context, slot_index);
304 129 : SetAccumulator(result);
305 129 : Dispatch();
306 129 : }
307 :
308 : // LdaImmutableContextSlot <context> <slot_index> <depth>
309 : //
310 : // Load the object in |slot_index| of the context at |depth| in the context
311 : // chain starting at |context| into the accumulator.
312 0 : IGNITION_HANDLER(LdaImmutableContextSlot, InterpreterAssembler) {
313 : // Same as LdaContextSlot, should never be called.
314 0 : UNREACHABLE();
315 : }
316 :
317 : // LdaCurrentContextSlot <slot_index>
318 : //
319 : // Load the object in |slot_index| of the current context into the accumulator.
320 258 : IGNITION_HANDLER(LdaCurrentContextSlot, InterpreterAssembler) {
321 129 : Node* slot_index = BytecodeOperandIdx(0);
322 129 : Node* slot_context = GetContext();
323 129 : Node* result = LoadContextElement(slot_context, slot_index);
324 129 : SetAccumulator(result);
325 129 : Dispatch();
326 129 : }
327 :
328 : // LdaImmutableCurrentContextSlot <slot_index>
329 : //
330 : // Load the object in |slot_index| of the current context into the accumulator.
331 0 : IGNITION_HANDLER(LdaImmutableCurrentContextSlot, InterpreterAssembler) {
332 : // Same as LdaCurrentContextSlot, should never be called.
333 0 : UNREACHABLE();
334 : }
335 :
336 : // StaContextSlot <context> <slot_index> <depth>
337 : //
338 : // Stores the object in the accumulator into |slot_index| of the context at
339 : // |depth| in the context chain starting at |context|.
340 258 : IGNITION_HANDLER(StaContextSlot, InterpreterAssembler) {
341 129 : Node* value = GetAccumulator();
342 129 : Node* reg_index = BytecodeOperandReg(0);
343 129 : Node* context = LoadRegister(reg_index);
344 129 : Node* slot_index = BytecodeOperandIdx(1);
345 129 : Node* depth = BytecodeOperandUImm(2);
346 129 : Node* slot_context = GetContextAtDepth(context, depth);
347 129 : StoreContextElement(slot_context, slot_index, value);
348 129 : Dispatch();
349 129 : }
350 :
351 : // StaCurrentContextSlot <slot_index>
352 : //
353 : // Stores the object in the accumulator into |slot_index| of the current
354 : // context.
355 258 : IGNITION_HANDLER(StaCurrentContextSlot, InterpreterAssembler) {
356 129 : Node* value = GetAccumulator();
357 129 : Node* slot_index = BytecodeOperandIdx(0);
358 129 : Node* slot_context = GetContext();
359 129 : StoreContextElement(slot_context, slot_index, value);
360 129 : Dispatch();
361 129 : }
362 :
363 : // LdaLookupSlot <name_index>
364 : //
365 : // Lookup the object with the name in constant pool entry |name_index|
366 : // dynamically.
367 258 : IGNITION_HANDLER(LdaLookupSlot, InterpreterAssembler) {
368 129 : Node* name_index = BytecodeOperandIdx(0);
369 129 : Node* name = LoadConstantPoolEntry(name_index);
370 129 : Node* context = GetContext();
371 129 : Node* result = CallRuntime(Runtime::kLoadLookupSlot, context, name);
372 129 : SetAccumulator(result);
373 129 : Dispatch();
374 129 : }
375 :
376 : // LdaLookupSlotInsideTypeof <name_index>
377 : //
378 : // Lookup the object with the name in constant pool entry |name_index|
379 : // dynamically without causing a NoReferenceError.
380 258 : IGNITION_HANDLER(LdaLookupSlotInsideTypeof, InterpreterAssembler) {
381 129 : Node* name_index = BytecodeOperandIdx(0);
382 129 : Node* name = LoadConstantPoolEntry(name_index);
383 129 : Node* context = GetContext();
384 : Node* result =
385 129 : CallRuntime(Runtime::kLoadLookupSlotInsideTypeof, context, name);
386 129 : SetAccumulator(result);
387 129 : Dispatch();
388 129 : }
389 :
390 258 : class InterpreterLookupContextSlotAssembler : public InterpreterAssembler {
391 : public:
392 : InterpreterLookupContextSlotAssembler(CodeAssemblerState* state,
393 : Bytecode bytecode,
394 : OperandScale operand_scale)
395 258 : : InterpreterAssembler(state, bytecode, operand_scale) {}
396 :
397 258 : void LookupContextSlot(Runtime::FunctionId function_id) {
398 258 : Node* context = GetContext();
399 258 : Node* name_index = BytecodeOperandIdx(0);
400 258 : Node* slot_index = BytecodeOperandIdx(1);
401 258 : Node* depth = BytecodeOperandUImm(2);
402 :
403 258 : Label slowpath(this, Label::kDeferred);
404 :
405 : // Check for context extensions to allow the fast path.
406 258 : GotoIfHasContextExtensionUpToDepth(context, depth, &slowpath);
407 :
408 : // Fast path does a normal load context.
409 : {
410 258 : Node* slot_context = GetContextAtDepth(context, depth);
411 258 : Node* result = LoadContextElement(slot_context, slot_index);
412 258 : SetAccumulator(result);
413 258 : Dispatch();
414 : }
415 :
416 : // Slow path when we have to call out to the runtime.
417 258 : Bind(&slowpath);
418 : {
419 258 : Node* name = LoadConstantPoolEntry(name_index);
420 258 : Node* result = CallRuntime(function_id, context, name);
421 258 : SetAccumulator(result);
422 258 : Dispatch();
423 258 : }
424 258 : }
425 : };
426 :
427 : // LdaLookupSlot <name_index>
428 : //
429 : // Lookup the object with the name in constant pool entry |name_index|
430 : // dynamically.
431 387 : IGNITION_HANDLER(LdaLookupContextSlot, InterpreterLookupContextSlotAssembler) {
432 129 : LookupContextSlot(Runtime::kLoadLookupSlot);
433 : }
434 :
435 : // LdaLookupSlotInsideTypeof <name_index>
436 : //
437 : // Lookup the object with the name in constant pool entry |name_index|
438 : // dynamically without causing a NoReferenceError.
439 387 : IGNITION_HANDLER(LdaLookupContextSlotInsideTypeof,
440 : InterpreterLookupContextSlotAssembler) {
441 129 : LookupContextSlot(Runtime::kLoadLookupSlotInsideTypeof);
442 : }
443 :
444 : class InterpreterLookupGlobalAssembler : public InterpreterLoadGlobalAssembler {
445 : public:
446 : InterpreterLookupGlobalAssembler(CodeAssemblerState* state, Bytecode bytecode,
447 : OperandScale operand_scale)
448 : : InterpreterLoadGlobalAssembler(state, bytecode, operand_scale) {}
449 :
450 258 : void LookupGlobalSlot(Runtime::FunctionId function_id) {
451 258 : Node* context = GetContext();
452 258 : Node* depth = BytecodeOperandUImm(2);
453 :
454 258 : Label slowpath(this, Label::kDeferred);
455 :
456 : // Check for context extensions to allow the fast path
457 258 : GotoIfHasContextExtensionUpToDepth(context, depth, &slowpath);
458 :
459 : // Fast path does a normal load global
460 : {
461 : static const int kNameOperandIndex = 0;
462 : static const int kSlotOperandIndex = 1;
463 :
464 : TypeofMode typeof_mode =
465 : function_id == Runtime::kLoadLookupSlotInsideTypeof
466 : ? INSIDE_TYPEOF
467 258 : : NOT_INSIDE_TYPEOF;
468 :
469 258 : LdaGlobal(kSlotOperandIndex, kNameOperandIndex, typeof_mode);
470 : }
471 :
472 : // Slow path when we have to call out to the runtime
473 258 : Bind(&slowpath);
474 : {
475 258 : Node* name_index = BytecodeOperandIdx(0);
476 258 : Node* name = LoadConstantPoolEntry(name_index);
477 258 : Node* result = CallRuntime(function_id, context, name);
478 258 : SetAccumulator(result);
479 258 : Dispatch();
480 258 : }
481 258 : }
482 : };
483 :
484 : // LdaLookupGlobalSlot <name_index> <feedback_slot> <depth>
485 : //
486 : // Lookup the object with the name in constant pool entry |name_index|
487 : // dynamically.
488 387 : IGNITION_HANDLER(LdaLookupGlobalSlot, InterpreterLookupGlobalAssembler) {
489 129 : LookupGlobalSlot(Runtime::kLoadLookupSlot);
490 : }
491 :
492 : // LdaLookupGlobalSlotInsideTypeof <name_index> <feedback_slot> <depth>
493 : //
494 : // Lookup the object with the name in constant pool entry |name_index|
495 : // dynamically without causing a NoReferenceError.
496 387 : IGNITION_HANDLER(LdaLookupGlobalSlotInsideTypeof,
497 : InterpreterLookupGlobalAssembler) {
498 129 : LookupGlobalSlot(Runtime::kLoadLookupSlotInsideTypeof);
499 : }
500 :
501 : // StaLookupSlotSloppy <name_index>
502 : //
503 : // Store the object in accumulator to the object with the name in constant
504 : // pool entry |name_index| in sloppy mode.
505 258 : IGNITION_HANDLER(StaLookupSlotSloppy, InterpreterAssembler) {
506 129 : Node* value = GetAccumulator();
507 129 : Node* index = BytecodeOperandIdx(0);
508 129 : Node* name = LoadConstantPoolEntry(index);
509 129 : Node* context = GetContext();
510 : Node* result =
511 129 : CallRuntime(Runtime::kStoreLookupSlot_Sloppy, context, name, value);
512 129 : SetAccumulator(result);
513 129 : Dispatch();
514 129 : }
515 :
516 : // StaLookupSlotStrict <name_index>
517 : //
518 : // Store the object in accumulator to the object with the name in constant
519 : // pool entry |name_index| in strict mode.
520 258 : IGNITION_HANDLER(StaLookupSlotStrict, InterpreterAssembler) {
521 129 : Node* value = GetAccumulator();
522 129 : Node* index = BytecodeOperandIdx(0);
523 129 : Node* name = LoadConstantPoolEntry(index);
524 129 : Node* context = GetContext();
525 : Node* result =
526 129 : CallRuntime(Runtime::kStoreLookupSlot_Strict, context, name, value);
527 129 : SetAccumulator(result);
528 129 : Dispatch();
529 129 : }
530 :
531 : // LdaNamedProperty <object> <name_index> <slot>
532 : //
533 : // Calls the LoadIC at FeedBackVector slot <slot> for <object> and the name at
534 : // constant pool entry <name_index>.
535 258 : IGNITION_HANDLER(LdaNamedProperty, InterpreterAssembler) {
536 129 : Node* feedback_vector = LoadFeedbackVector();
537 129 : Node* feedback_slot = BytecodeOperandIdx(2);
538 129 : Node* smi_slot = SmiTag(feedback_slot);
539 :
540 : // Load receiver.
541 129 : Node* register_index = BytecodeOperandReg(0);
542 129 : Node* recv = LoadRegister(register_index);
543 :
544 : // Load the name.
545 : // TODO(jgruber): Not needed for monomorphic smi handler constant/field case.
546 129 : Node* constant_index = BytecodeOperandIdx(1);
547 129 : Node* name = LoadConstantPoolEntry(constant_index);
548 :
549 129 : Node* context = GetContext();
550 :
551 129 : Label done(this);
552 258 : Variable var_result(this, MachineRepresentation::kTagged);
553 : ExitPoint exit_point(this, &done, &var_result);
554 :
555 : AccessorAssembler::LoadICParameters params(context, recv, name, smi_slot,
556 : feedback_vector);
557 : AccessorAssembler accessor_asm(state());
558 129 : accessor_asm.LoadIC_BytecodeHandler(¶ms, &exit_point);
559 :
560 129 : Bind(&done);
561 : {
562 129 : SetAccumulator(var_result.value());
563 129 : Dispatch();
564 129 : }
565 129 : }
566 :
567 : // KeyedLoadIC <object> <slot>
568 : //
569 : // Calls the KeyedLoadIC at FeedBackVector slot <slot> for <object> and the key
570 : // in the accumulator.
571 258 : IGNITION_HANDLER(LdaKeyedProperty, InterpreterAssembler) {
572 129 : Callable ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
573 129 : Node* code_target = HeapConstant(ic.code());
574 129 : Node* reg_index = BytecodeOperandReg(0);
575 129 : Node* object = LoadRegister(reg_index);
576 129 : Node* name = GetAccumulator();
577 129 : Node* raw_slot = BytecodeOperandIdx(1);
578 129 : Node* smi_slot = SmiTag(raw_slot);
579 129 : Node* feedback_vector = LoadFeedbackVector();
580 129 : Node* context = GetContext();
581 : Node* result = CallStub(ic.descriptor(), code_target, context, object, name,
582 129 : smi_slot, feedback_vector);
583 129 : SetAccumulator(result);
584 129 : Dispatch();
585 129 : }
586 :
587 387 : class InterpreterStoreNamedPropertyAssembler : public InterpreterAssembler {
588 : public:
589 : InterpreterStoreNamedPropertyAssembler(CodeAssemblerState* state,
590 : Bytecode bytecode,
591 : OperandScale operand_scale)
592 387 : : InterpreterAssembler(state, bytecode, operand_scale) {}
593 :
594 387 : void StaNamedProperty(Callable ic) {
595 387 : Node* code_target = HeapConstant(ic.code());
596 387 : Node* object_reg_index = BytecodeOperandReg(0);
597 387 : Node* object = LoadRegister(object_reg_index);
598 387 : Node* constant_index = BytecodeOperandIdx(1);
599 387 : Node* name = LoadConstantPoolEntry(constant_index);
600 387 : Node* value = GetAccumulator();
601 387 : Node* raw_slot = BytecodeOperandIdx(2);
602 387 : Node* smi_slot = SmiTag(raw_slot);
603 387 : Node* feedback_vector = LoadFeedbackVector();
604 387 : Node* context = GetContext();
605 : CallStub(ic.descriptor(), code_target, context, object, name, value,
606 387 : smi_slot, feedback_vector);
607 387 : Dispatch();
608 387 : }
609 : };
610 :
611 : // StaNamedPropertySloppy <object> <name_index> <slot>
612 : //
613 : // Calls the sloppy mode StoreIC at FeedBackVector slot <slot> for <object> and
614 : // the name in constant pool entry <name_index> with the value in the
615 : // accumulator.
616 516 : IGNITION_HANDLER(StaNamedPropertySloppy,
617 : InterpreterStoreNamedPropertyAssembler) {
618 129 : Callable ic = CodeFactory::StoreICInOptimizedCode(isolate(), SLOPPY);
619 129 : StaNamedProperty(ic);
620 129 : }
621 :
622 : // StaNamedPropertyStrict <object> <name_index> <slot>
623 : //
624 : // Calls the strict mode StoreIC at FeedBackVector slot <slot> for <object> and
625 : // the name in constant pool entry <name_index> with the value in the
626 : // accumulator.
627 516 : IGNITION_HANDLER(StaNamedPropertyStrict,
628 : InterpreterStoreNamedPropertyAssembler) {
629 129 : Callable ic = CodeFactory::StoreICInOptimizedCode(isolate(), STRICT);
630 129 : StaNamedProperty(ic);
631 129 : }
632 :
633 : // StaNamedOwnProperty <object> <name_index> <slot>
634 : //
635 : // Calls the StoreOwnIC at FeedBackVector slot <slot> for <object> and
636 : // the name in constant pool entry <name_index> with the value in the
637 : // accumulator.
638 516 : IGNITION_HANDLER(StaNamedOwnProperty, InterpreterStoreNamedPropertyAssembler) {
639 129 : Callable ic = CodeFactory::StoreOwnICInOptimizedCode(isolate());
640 129 : StaNamedProperty(ic);
641 129 : }
642 :
643 258 : class InterpreterStoreKeyedPropertyAssembler : public InterpreterAssembler {
644 : public:
645 : InterpreterStoreKeyedPropertyAssembler(CodeAssemblerState* state,
646 : Bytecode bytecode,
647 : OperandScale operand_scale)
648 258 : : InterpreterAssembler(state, bytecode, operand_scale) {}
649 :
650 258 : void StaKeyedProperty(Callable ic) {
651 258 : Node* code_target = HeapConstant(ic.code());
652 258 : Node* object_reg_index = BytecodeOperandReg(0);
653 258 : Node* object = LoadRegister(object_reg_index);
654 258 : Node* name_reg_index = BytecodeOperandReg(1);
655 258 : Node* name = LoadRegister(name_reg_index);
656 258 : Node* value = GetAccumulator();
657 258 : Node* raw_slot = BytecodeOperandIdx(2);
658 258 : Node* smi_slot = SmiTag(raw_slot);
659 258 : Node* feedback_vector = LoadFeedbackVector();
660 258 : Node* context = GetContext();
661 : CallStub(ic.descriptor(), code_target, context, object, name, value,
662 258 : smi_slot, feedback_vector);
663 258 : Dispatch();
664 258 : }
665 : };
666 :
667 : // StaKeyedPropertySloppy <object> <key> <slot>
668 : //
669 : // Calls the sloppy mode KeyStoreIC at FeedBackVector slot <slot> for <object>
670 : // and the key <key> with the value in the accumulator.
671 516 : IGNITION_HANDLER(StaKeyedPropertySloppy,
672 : InterpreterStoreKeyedPropertyAssembler) {
673 129 : Callable ic = CodeFactory::KeyedStoreICInOptimizedCode(isolate(), SLOPPY);
674 129 : StaKeyedProperty(ic);
675 129 : }
676 :
677 : // StaKeyedPropertyStrict <object> <key> <slot>
678 : //
679 : // Calls the strict mode KeyStoreIC at FeedBackVector slot <slot> for <object>
680 : // and the key <key> with the value in the accumulator.
681 516 : IGNITION_HANDLER(StaKeyedPropertyStrict,
682 : InterpreterStoreKeyedPropertyAssembler) {
683 129 : Callable ic = CodeFactory::KeyedStoreICInOptimizedCode(isolate(), STRICT);
684 129 : StaKeyedProperty(ic);
685 129 : }
686 :
687 : // StaDataPropertyInLiteral <object> <name> <flags>
688 : //
689 : // Define a property <name> with value from the accumulator in <object>.
690 : // Property attributes and whether set_function_name are stored in
691 : // DataPropertyInLiteralFlags <flags>.
692 : //
693 : // This definition is not observable and is used only for definitions
694 : // in object or class literals.
695 258 : IGNITION_HANDLER(StaDataPropertyInLiteral, InterpreterAssembler) {
696 129 : Node* object = LoadRegister(BytecodeOperandReg(0));
697 129 : Node* name = LoadRegister(BytecodeOperandReg(1));
698 129 : Node* value = GetAccumulator();
699 129 : Node* flags = SmiFromWord32(BytecodeOperandFlag(2));
700 129 : Node* vector_index = SmiTag(BytecodeOperandIdx(3));
701 :
702 129 : Node* feedback_vector = LoadFeedbackVector();
703 129 : Node* context = GetContext();
704 :
705 : CallRuntime(Runtime::kDefineDataPropertyInLiteral, context, object, name,
706 129 : value, flags, feedback_vector, vector_index);
707 129 : Dispatch();
708 129 : }
709 :
710 258 : IGNITION_HANDLER(CollectTypeProfile, InterpreterAssembler) {
711 129 : Node* position = BytecodeOperandImmSmi(0);
712 129 : Node* value = GetAccumulator();
713 :
714 129 : Node* feedback_vector = LoadFeedbackVector();
715 129 : Node* context = GetContext();
716 :
717 : CallRuntime(Runtime::kCollectTypeProfile, context, position, value,
718 129 : feedback_vector);
719 129 : Dispatch();
720 129 : }
721 :
722 : // LdaModuleVariable <cell_index> <depth>
723 : //
724 : // Load the contents of a module variable into the accumulator. The variable is
725 : // identified by <cell_index>. <depth> is the depth of the current context
726 : // relative to the module context.
727 258 : IGNITION_HANDLER(LdaModuleVariable, InterpreterAssembler) {
728 129 : Node* cell_index = BytecodeOperandImmIntPtr(0);
729 129 : Node* depth = BytecodeOperandUImm(1);
730 :
731 129 : Node* module_context = GetContextAtDepth(GetContext(), depth);
732 129 : Node* module = LoadContextElement(module_context, Context::EXTENSION_INDEX);
733 :
734 258 : Label if_export(this), if_import(this), end(this);
735 : Branch(IntPtrGreaterThan(cell_index, IntPtrConstant(0)), &if_export,
736 129 : &if_import);
737 :
738 129 : Bind(&if_export);
739 : {
740 : Node* regular_exports =
741 129 : LoadObjectField(module, Module::kRegularExportsOffset);
742 : // The actual array index is (cell_index - 1).
743 129 : Node* export_index = IntPtrSub(cell_index, IntPtrConstant(1));
744 129 : Node* cell = LoadFixedArrayElement(regular_exports, export_index);
745 129 : SetAccumulator(LoadObjectField(cell, Cell::kValueOffset));
746 129 : Goto(&end);
747 : }
748 :
749 129 : Bind(&if_import);
750 : {
751 : Node* regular_imports =
752 129 : LoadObjectField(module, Module::kRegularImportsOffset);
753 : // The actual array index is (-cell_index - 1).
754 129 : Node* import_index = IntPtrSub(IntPtrConstant(-1), cell_index);
755 129 : Node* cell = LoadFixedArrayElement(regular_imports, import_index);
756 129 : SetAccumulator(LoadObjectField(cell, Cell::kValueOffset));
757 129 : Goto(&end);
758 : }
759 :
760 129 : Bind(&end);
761 258 : Dispatch();
762 129 : }
763 :
764 : // StaModuleVariable <cell_index> <depth>
765 : //
766 : // Store accumulator to the module variable identified by <cell_index>.
767 : // <depth> is the depth of the current context relative to the module context.
768 258 : IGNITION_HANDLER(StaModuleVariable, InterpreterAssembler) {
769 129 : Node* value = GetAccumulator();
770 129 : Node* cell_index = BytecodeOperandImmIntPtr(0);
771 129 : Node* depth = BytecodeOperandUImm(1);
772 :
773 129 : Node* module_context = GetContextAtDepth(GetContext(), depth);
774 129 : Node* module = LoadContextElement(module_context, Context::EXTENSION_INDEX);
775 :
776 258 : Label if_export(this), if_import(this), end(this);
777 : Branch(IntPtrGreaterThan(cell_index, IntPtrConstant(0)), &if_export,
778 129 : &if_import);
779 :
780 129 : Bind(&if_export);
781 : {
782 : Node* regular_exports =
783 129 : LoadObjectField(module, Module::kRegularExportsOffset);
784 : // The actual array index is (cell_index - 1).
785 129 : Node* export_index = IntPtrSub(cell_index, IntPtrConstant(1));
786 129 : Node* cell = LoadFixedArrayElement(regular_exports, export_index);
787 129 : StoreObjectField(cell, Cell::kValueOffset, value);
788 129 : Goto(&end);
789 : }
790 :
791 129 : Bind(&if_import);
792 : {
793 : // Not supported (probably never).
794 129 : Abort(kUnsupportedModuleOperation);
795 129 : Goto(&end);
796 : }
797 :
798 129 : Bind(&end);
799 258 : Dispatch();
800 129 : }
801 :
802 : // PushContext <context>
803 : //
804 : // Saves the current context in <context>, and pushes the accumulator as the
805 : // new current context.
806 258 : IGNITION_HANDLER(PushContext, InterpreterAssembler) {
807 129 : Node* reg_index = BytecodeOperandReg(0);
808 129 : Node* new_context = GetAccumulator();
809 129 : Node* old_context = GetContext();
810 129 : StoreRegister(old_context, reg_index);
811 129 : SetContext(new_context);
812 129 : Dispatch();
813 129 : }
814 :
815 : // PopContext <context>
816 : //
817 : // Pops the current context and sets <context> as the new context.
818 258 : IGNITION_HANDLER(PopContext, InterpreterAssembler) {
819 129 : Node* reg_index = BytecodeOperandReg(0);
820 129 : Node* context = LoadRegister(reg_index);
821 129 : SetContext(context);
822 129 : Dispatch();
823 129 : }
824 :
825 645 : class InterpreterBinaryOpAssembler : public InterpreterAssembler {
826 : public:
827 : InterpreterBinaryOpAssembler(CodeAssemblerState* state, Bytecode bytecode,
828 : OperandScale operand_scale)
829 645 : : InterpreterAssembler(state, bytecode, operand_scale) {}
830 :
831 : typedef Node* (BinaryOpAssembler::*BinaryOpGenerator)(Node* context,
832 : Node* left, Node* right,
833 : Node* slot,
834 : Node* vector);
835 :
836 645 : void BinaryOpWithFeedback(BinaryOpGenerator generator) {
837 645 : Node* reg_index = BytecodeOperandReg(0);
838 645 : Node* lhs = LoadRegister(reg_index);
839 645 : Node* rhs = GetAccumulator();
840 645 : Node* context = GetContext();
841 645 : Node* slot_index = BytecodeOperandIdx(1);
842 645 : Node* feedback_vector = LoadFeedbackVector();
843 :
844 : BinaryOpAssembler binop_asm(state());
845 : Node* result =
846 645 : (binop_asm.*generator)(context, lhs, rhs, slot_index, feedback_vector);
847 645 : SetAccumulator(result);
848 645 : Dispatch();
849 645 : }
850 : };
851 :
852 : // Add <src>
853 : //
854 : // Add register <src> to accumulator.
855 387 : IGNITION_HANDLER(Add, InterpreterBinaryOpAssembler) {
856 129 : BinaryOpWithFeedback(&BinaryOpAssembler::Generate_AddWithFeedback);
857 : }
858 :
859 : // Sub <src>
860 : //
861 : // Subtract register <src> from accumulator.
862 387 : IGNITION_HANDLER(Sub, InterpreterBinaryOpAssembler) {
863 129 : BinaryOpWithFeedback(&BinaryOpAssembler::Generate_SubtractWithFeedback);
864 : }
865 :
866 : // Mul <src>
867 : //
868 : // Multiply accumulator by register <src>.
869 387 : IGNITION_HANDLER(Mul, InterpreterBinaryOpAssembler) {
870 129 : BinaryOpWithFeedback(&BinaryOpAssembler::Generate_MultiplyWithFeedback);
871 : }
872 :
873 : // Div <src>
874 : //
875 : // Divide register <src> by accumulator.
876 387 : IGNITION_HANDLER(Div, InterpreterBinaryOpAssembler) {
877 129 : BinaryOpWithFeedback(&BinaryOpAssembler::Generate_DivideWithFeedback);
878 : }
879 :
880 : // Mod <src>
881 : //
882 : // Modulo register <src> by accumulator.
883 387 : IGNITION_HANDLER(Mod, InterpreterBinaryOpAssembler) {
884 129 : BinaryOpWithFeedback(&BinaryOpAssembler::Generate_ModulusWithFeedback);
885 : }
886 :
887 : // AddSmi <imm>
888 : //
889 : // Adds an immediate value <imm> to the value in the accumulator.
890 258 : IGNITION_HANDLER(AddSmi, InterpreterAssembler) {
891 129 : Variable var_result(this, MachineRepresentation::kTagged);
892 129 : Label fastpath(this), slowpath(this, Label::kDeferred), end(this);
893 :
894 129 : Node* left = GetAccumulator();
895 129 : Node* right = BytecodeOperandImmSmi(0);
896 129 : Node* slot_index = BytecodeOperandIdx(1);
897 129 : Node* feedback_vector = LoadFeedbackVector();
898 :
899 : // {right} is known to be a Smi.
900 : // Check if the {left} is a Smi take the fast path.
901 129 : Branch(TaggedIsSmi(left), &fastpath, &slowpath);
902 129 : Bind(&fastpath);
903 : {
904 : // Try fast Smi addition first.
905 : Node* pair = IntPtrAddWithOverflow(BitcastTaggedToWord(left),
906 129 : BitcastTaggedToWord(right));
907 129 : Node* overflow = Projection(1, pair);
908 :
909 : // Check if the Smi additon overflowed.
910 : Label if_notoverflow(this);
911 129 : Branch(overflow, &slowpath, &if_notoverflow);
912 129 : Bind(&if_notoverflow);
913 : {
914 : UpdateFeedback(SmiConstant(BinaryOperationFeedback::kSignedSmall),
915 129 : feedback_vector, slot_index);
916 129 : var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair)));
917 129 : Goto(&end);
918 129 : }
919 : }
920 129 : Bind(&slowpath);
921 : {
922 129 : Node* context = GetContext();
923 : // TODO(ishell): pass slot as word-size value.
924 : var_result.Bind(CallBuiltin(Builtins::kAddWithFeedback, context, left,
925 : right, TruncateWordToWord32(slot_index),
926 129 : feedback_vector));
927 129 : Goto(&end);
928 : }
929 129 : Bind(&end);
930 : {
931 129 : SetAccumulator(var_result.value());
932 129 : Dispatch();
933 129 : }
934 129 : }
935 :
936 : // SubSmi <imm>
937 : //
938 : // Subtracts an immediate value <imm> from the value in the accumulator.
939 258 : IGNITION_HANDLER(SubSmi, InterpreterAssembler) {
940 129 : Variable var_result(this, MachineRepresentation::kTagged);
941 129 : Label fastpath(this), slowpath(this, Label::kDeferred), end(this);
942 :
943 129 : Node* left = GetAccumulator();
944 129 : Node* right = BytecodeOperandImmSmi(0);
945 129 : Node* slot_index = BytecodeOperandIdx(1);
946 129 : Node* feedback_vector = LoadFeedbackVector();
947 :
948 : // {right} is known to be a Smi.
949 : // Check if the {left} is a Smi take the fast path.
950 129 : Branch(TaggedIsSmi(left), &fastpath, &slowpath);
951 129 : Bind(&fastpath);
952 : {
953 : // Try fast Smi subtraction first.
954 : Node* pair = IntPtrSubWithOverflow(BitcastTaggedToWord(left),
955 129 : BitcastTaggedToWord(right));
956 129 : Node* overflow = Projection(1, pair);
957 :
958 : // Check if the Smi subtraction overflowed.
959 : Label if_notoverflow(this);
960 129 : Branch(overflow, &slowpath, &if_notoverflow);
961 129 : Bind(&if_notoverflow);
962 : {
963 : UpdateFeedback(SmiConstant(BinaryOperationFeedback::kSignedSmall),
964 129 : feedback_vector, slot_index);
965 129 : var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair)));
966 129 : Goto(&end);
967 129 : }
968 : }
969 129 : Bind(&slowpath);
970 : {
971 129 : Node* context = GetContext();
972 : // TODO(ishell): pass slot as word-size value.
973 : var_result.Bind(CallBuiltin(Builtins::kSubtractWithFeedback, context, left,
974 : right, TruncateWordToWord32(slot_index),
975 129 : feedback_vector));
976 129 : Goto(&end);
977 : }
978 129 : Bind(&end);
979 : {
980 129 : SetAccumulator(var_result.value());
981 129 : Dispatch();
982 129 : }
983 129 : }
984 :
985 : // MulSmi <imm>
986 : //
987 : // Multiplies an immediate value <imm> to the value in the accumulator.
988 258 : IGNITION_HANDLER(MulSmi, InterpreterAssembler) {
989 129 : Variable var_result(this, MachineRepresentation::kTagged);
990 129 : Label fastpath(this), slowpath(this, Label::kDeferred), end(this);
991 :
992 129 : Node* left = GetAccumulator();
993 129 : Node* right = BytecodeOperandImmSmi(0);
994 129 : Node* slot_index = BytecodeOperandIdx(1);
995 129 : Node* feedback_vector = LoadFeedbackVector();
996 :
997 : // {right} is known to be a Smi.
998 : // Check if the {left} is a Smi take the fast path.
999 129 : Branch(TaggedIsSmi(left), &fastpath, &slowpath);
1000 129 : Bind(&fastpath);
1001 : {
1002 : // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi,
1003 : // in case of overflow.
1004 129 : var_result.Bind(SmiMul(left, right));
1005 : Node* feedback = SelectSmiConstant(TaggedIsSmi(var_result.value()),
1006 : BinaryOperationFeedback::kSignedSmall,
1007 129 : BinaryOperationFeedback::kNumber);
1008 129 : UpdateFeedback(feedback, feedback_vector, slot_index);
1009 129 : Goto(&end);
1010 : }
1011 129 : Bind(&slowpath);
1012 : {
1013 129 : Node* context = GetContext();
1014 : // TODO(ishell): pass slot as word-size value.
1015 : var_result.Bind(CallBuiltin(Builtins::kMultiplyWithFeedback, context, left,
1016 : right, TruncateWordToWord32(slot_index),
1017 129 : feedback_vector));
1018 129 : Goto(&end);
1019 : }
1020 :
1021 129 : Bind(&end);
1022 : {
1023 129 : SetAccumulator(var_result.value());
1024 129 : Dispatch();
1025 129 : }
1026 129 : }
1027 :
1028 : // DivSmi <imm>
1029 : //
1030 : // Divides the value in the accumulator by immediate value <imm>.
1031 258 : IGNITION_HANDLER(DivSmi, InterpreterAssembler) {
1032 129 : Variable var_result(this, MachineRepresentation::kTagged);
1033 129 : Label fastpath(this), slowpath(this, Label::kDeferred), end(this);
1034 :
1035 129 : Node* left = GetAccumulator();
1036 129 : Node* right = BytecodeOperandImmSmi(0);
1037 129 : Node* slot_index = BytecodeOperandIdx(1);
1038 129 : Node* feedback_vector = LoadFeedbackVector();
1039 :
1040 : // {right} is known to be a Smi.
1041 : // Check if the {left} is a Smi take the fast path.
1042 129 : Branch(TaggedIsSmi(left), &fastpath, &slowpath);
1043 129 : Bind(&fastpath);
1044 : {
1045 129 : var_result.Bind(TrySmiDiv(left, right, &slowpath));
1046 : UpdateFeedback(SmiConstant(BinaryOperationFeedback::kSignedSmall),
1047 129 : feedback_vector, slot_index);
1048 129 : Goto(&end);
1049 : }
1050 129 : Bind(&slowpath);
1051 : {
1052 129 : Node* context = GetContext();
1053 : // TODO(ishell): pass slot as word-size value.
1054 : var_result.Bind(CallBuiltin(Builtins::kDivideWithFeedback, context, left,
1055 : right, TruncateWordToWord32(slot_index),
1056 129 : feedback_vector));
1057 129 : Goto(&end);
1058 : }
1059 :
1060 129 : Bind(&end);
1061 : {
1062 129 : SetAccumulator(var_result.value());
1063 129 : Dispatch();
1064 129 : }
1065 129 : }
1066 :
1067 : // ModSmi <imm>
1068 : //
1069 : // Modulo accumulator by immediate value <imm>.
1070 258 : IGNITION_HANDLER(ModSmi, InterpreterAssembler) {
1071 129 : Variable var_result(this, MachineRepresentation::kTagged);
1072 129 : Label fastpath(this), slowpath(this, Label::kDeferred), end(this);
1073 :
1074 129 : Node* left = GetAccumulator();
1075 129 : Node* right = BytecodeOperandImmSmi(0);
1076 129 : Node* slot_index = BytecodeOperandIdx(1);
1077 129 : Node* feedback_vector = LoadFeedbackVector();
1078 :
1079 : // {right} is known to be a Smi.
1080 : // Check if the {left} is a Smi take the fast path.
1081 129 : Branch(TaggedIsSmi(left), &fastpath, &slowpath);
1082 129 : Bind(&fastpath);
1083 : {
1084 : // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi.
1085 129 : var_result.Bind(SmiMod(left, right));
1086 : Node* feedback = SelectSmiConstant(TaggedIsSmi(var_result.value()),
1087 : BinaryOperationFeedback::kSignedSmall,
1088 129 : BinaryOperationFeedback::kNumber);
1089 129 : UpdateFeedback(feedback, feedback_vector, slot_index);
1090 129 : Goto(&end);
1091 : }
1092 129 : Bind(&slowpath);
1093 : {
1094 129 : Node* context = GetContext();
1095 : // TODO(ishell): pass slot as word-size value.
1096 : var_result.Bind(CallBuiltin(Builtins::kModulusWithFeedback, context, left,
1097 : right, TruncateWordToWord32(slot_index),
1098 129 : feedback_vector));
1099 129 : Goto(&end);
1100 : }
1101 :
1102 129 : Bind(&end);
1103 : {
1104 129 : SetAccumulator(var_result.value());
1105 129 : Dispatch();
1106 129 : }
1107 129 : }
1108 :
1109 774 : class InterpreterBitwiseBinaryOpAssembler : public InterpreterAssembler {
1110 : public:
1111 : InterpreterBitwiseBinaryOpAssembler(CodeAssemblerState* state,
1112 : Bytecode bytecode,
1113 : OperandScale operand_scale)
1114 774 : : InterpreterAssembler(state, bytecode, operand_scale) {}
1115 :
1116 774 : void BitwiseBinaryOpWithFeedback(Token::Value bitwise_op) {
1117 774 : Node* reg_index = BytecodeOperandReg(0);
1118 774 : Node* lhs = LoadRegister(reg_index);
1119 774 : Node* rhs = GetAccumulator();
1120 774 : Node* context = GetContext();
1121 774 : Node* slot_index = BytecodeOperandIdx(1);
1122 774 : Node* feedback_vector = LoadFeedbackVector();
1123 :
1124 774 : Variable var_lhs_type_feedback(this, MachineRepresentation::kTaggedSigned),
1125 1548 : var_rhs_type_feedback(this, MachineRepresentation::kTaggedSigned);
1126 : Node* lhs_value = TruncateTaggedToWord32WithFeedback(
1127 774 : context, lhs, &var_lhs_type_feedback);
1128 : Node* rhs_value = TruncateTaggedToWord32WithFeedback(
1129 774 : context, rhs, &var_rhs_type_feedback);
1130 : Node* result = nullptr;
1131 :
1132 774 : switch (bitwise_op) {
1133 : case Token::BIT_OR: {
1134 129 : Node* value = Word32Or(lhs_value, rhs_value);
1135 129 : result = ChangeInt32ToTagged(value);
1136 129 : } break;
1137 : case Token::BIT_AND: {
1138 129 : Node* value = Word32And(lhs_value, rhs_value);
1139 129 : result = ChangeInt32ToTagged(value);
1140 129 : } break;
1141 : case Token::BIT_XOR: {
1142 129 : Node* value = Word32Xor(lhs_value, rhs_value);
1143 129 : result = ChangeInt32ToTagged(value);
1144 129 : } break;
1145 : case Token::SHL: {
1146 : Node* value =
1147 129 : Word32Shl(lhs_value, Word32And(rhs_value, Int32Constant(0x1f)));
1148 129 : result = ChangeInt32ToTagged(value);
1149 129 : } break;
1150 : case Token::SHR: {
1151 : Node* value =
1152 129 : Word32Shr(lhs_value, Word32And(rhs_value, Int32Constant(0x1f)));
1153 129 : result = ChangeUint32ToTagged(value);
1154 129 : } break;
1155 : case Token::SAR: {
1156 : Node* value =
1157 129 : Word32Sar(lhs_value, Word32And(rhs_value, Int32Constant(0x1f)));
1158 129 : result = ChangeInt32ToTagged(value);
1159 129 : } break;
1160 : default:
1161 0 : UNREACHABLE();
1162 : }
1163 :
1164 : Node* result_type = SelectSmiConstant(TaggedIsSmi(result),
1165 : BinaryOperationFeedback::kSignedSmall,
1166 774 : BinaryOperationFeedback::kNumber);
1167 :
1168 774 : if (FLAG_debug_code) {
1169 : Label ok(this);
1170 0 : GotoIf(TaggedIsSmi(result), &ok);
1171 0 : Node* result_map = LoadMap(result);
1172 : AbortIfWordNotEqual(result_map, HeapNumberMapConstant(),
1173 0 : kExpectedHeapNumber);
1174 0 : Goto(&ok);
1175 0 : Bind(&ok);
1176 : }
1177 :
1178 : Node* input_feedback =
1179 774 : SmiOr(var_lhs_type_feedback.value(), var_rhs_type_feedback.value());
1180 : UpdateFeedback(SmiOr(result_type, input_feedback), feedback_vector,
1181 774 : slot_index);
1182 774 : SetAccumulator(result);
1183 1548 : Dispatch();
1184 774 : }
1185 : };
1186 :
1187 : // BitwiseOr <src>
1188 : //
1189 : // BitwiseOr register <src> to accumulator.
1190 387 : IGNITION_HANDLER(BitwiseOr, InterpreterBitwiseBinaryOpAssembler) {
1191 129 : BitwiseBinaryOpWithFeedback(Token::BIT_OR);
1192 : }
1193 :
1194 : // BitwiseXor <src>
1195 : //
1196 : // BitwiseXor register <src> to accumulator.
1197 387 : IGNITION_HANDLER(BitwiseXor, InterpreterBitwiseBinaryOpAssembler) {
1198 129 : BitwiseBinaryOpWithFeedback(Token::BIT_XOR);
1199 : }
1200 :
1201 : // BitwiseAnd <src>
1202 : //
1203 : // BitwiseAnd register <src> to accumulator.
1204 387 : IGNITION_HANDLER(BitwiseAnd, InterpreterBitwiseBinaryOpAssembler) {
1205 129 : BitwiseBinaryOpWithFeedback(Token::BIT_AND);
1206 : }
1207 :
1208 : // ShiftLeft <src>
1209 : //
1210 : // Left shifts register <src> by the count specified in the accumulator.
1211 : // Register <src> is converted to an int32 and the accumulator to uint32
1212 : // before the operation. 5 lsb bits from the accumulator are used as count
1213 : // i.e. <src> << (accumulator & 0x1F).
1214 387 : IGNITION_HANDLER(ShiftLeft, InterpreterBitwiseBinaryOpAssembler) {
1215 129 : BitwiseBinaryOpWithFeedback(Token::SHL);
1216 : }
1217 :
1218 : // ShiftRight <src>
1219 : //
1220 : // Right shifts register <src> by the count specified in the accumulator.
1221 : // Result is sign extended. Register <src> is converted to an int32 and the
1222 : // accumulator to uint32 before the operation. 5 lsb bits from the accumulator
1223 : // are used as count i.e. <src> >> (accumulator & 0x1F).
1224 387 : IGNITION_HANDLER(ShiftRight, InterpreterBitwiseBinaryOpAssembler) {
1225 129 : BitwiseBinaryOpWithFeedback(Token::SAR);
1226 : }
1227 :
1228 : // ShiftRightLogical <src>
1229 : //
1230 : // Right Shifts register <src> by the count specified in the accumulator.
1231 : // Result is zero-filled. The accumulator and register <src> are converted to
1232 : // uint32 before the operation 5 lsb bits from the accumulator are used as
1233 : // count i.e. <src> << (accumulator & 0x1F).
1234 387 : IGNITION_HANDLER(ShiftRightLogical, InterpreterBitwiseBinaryOpAssembler) {
1235 129 : BitwiseBinaryOpWithFeedback(Token::SHR);
1236 : }
1237 :
1238 : // BitwiseOr <imm>
1239 : //
1240 : // BitwiseOr accumulator with <imm>.
1241 258 : IGNITION_HANDLER(BitwiseOrSmi, InterpreterAssembler) {
1242 129 : Node* left = GetAccumulator();
1243 129 : Node* right = BytecodeOperandImmSmi(0);
1244 129 : Node* slot_index = BytecodeOperandIdx(1);
1245 129 : Node* feedback_vector = LoadFeedbackVector();
1246 129 : Node* context = GetContext();
1247 :
1248 129 : Variable var_lhs_type_feedback(this, MachineRepresentation::kTaggedSigned);
1249 : Node* lhs_value =
1250 129 : TruncateTaggedToWord32WithFeedback(context, left, &var_lhs_type_feedback);
1251 129 : Node* rhs_value = SmiToWord32(right);
1252 129 : Node* value = Word32Or(lhs_value, rhs_value);
1253 129 : Node* result = ChangeInt32ToTagged(value);
1254 : Node* result_type = SelectSmiConstant(TaggedIsSmi(result),
1255 : BinaryOperationFeedback::kSignedSmall,
1256 129 : BinaryOperationFeedback::kNumber);
1257 : UpdateFeedback(SmiOr(result_type, var_lhs_type_feedback.value()),
1258 129 : feedback_vector, slot_index);
1259 129 : SetAccumulator(result);
1260 129 : Dispatch();
1261 129 : }
1262 :
1263 : // BitwiseXor <imm>
1264 : //
1265 : // BitwiseXor accumulator with <imm>.
1266 258 : IGNITION_HANDLER(BitwiseXorSmi, InterpreterAssembler) {
1267 129 : Node* left = GetAccumulator();
1268 129 : Node* right = BytecodeOperandImmSmi(0);
1269 129 : Node* slot_index = BytecodeOperandIdx(1);
1270 129 : Node* feedback_vector = LoadFeedbackVector();
1271 129 : Node* context = GetContext();
1272 :
1273 129 : Variable var_lhs_type_feedback(this, MachineRepresentation::kTaggedSigned);
1274 : Node* lhs_value =
1275 129 : TruncateTaggedToWord32WithFeedback(context, left, &var_lhs_type_feedback);
1276 129 : Node* rhs_value = SmiToWord32(right);
1277 129 : Node* value = Word32Xor(lhs_value, rhs_value);
1278 129 : Node* result = ChangeInt32ToTagged(value);
1279 : Node* result_type = SelectSmiConstant(TaggedIsSmi(result),
1280 : BinaryOperationFeedback::kSignedSmall,
1281 129 : BinaryOperationFeedback::kNumber);
1282 : UpdateFeedback(SmiOr(result_type, var_lhs_type_feedback.value()),
1283 129 : feedback_vector, slot_index);
1284 129 : SetAccumulator(result);
1285 129 : Dispatch();
1286 129 : }
1287 :
1288 : // BitwiseAnd <imm>
1289 : //
1290 : // BitwiseAnd accumulator with <imm>.
1291 258 : IGNITION_HANDLER(BitwiseAndSmi, InterpreterAssembler) {
1292 129 : Node* left = GetAccumulator();
1293 129 : Node* right = BytecodeOperandImmSmi(0);
1294 129 : Node* slot_index = BytecodeOperandIdx(1);
1295 129 : Node* feedback_vector = LoadFeedbackVector();
1296 129 : Node* context = GetContext();
1297 :
1298 129 : Variable var_lhs_type_feedback(this, MachineRepresentation::kTaggedSigned);
1299 : Node* lhs_value =
1300 129 : TruncateTaggedToWord32WithFeedback(context, left, &var_lhs_type_feedback);
1301 129 : Node* rhs_value = SmiToWord32(right);
1302 129 : Node* value = Word32And(lhs_value, rhs_value);
1303 129 : Node* result = ChangeInt32ToTagged(value);
1304 : Node* result_type = SelectSmiConstant(TaggedIsSmi(result),
1305 : BinaryOperationFeedback::kSignedSmall,
1306 129 : BinaryOperationFeedback::kNumber);
1307 : UpdateFeedback(SmiOr(result_type, var_lhs_type_feedback.value()),
1308 129 : feedback_vector, slot_index);
1309 129 : SetAccumulator(result);
1310 129 : Dispatch();
1311 129 : }
1312 :
1313 : // ShiftLeftSmi <imm>
1314 : //
1315 : // Left shifts accumulator by the count specified in <imm>.
1316 : // The accumulator is converted to an int32 before the operation. The 5
1317 : // lsb bits from <imm> are used as count i.e. <src> << (<imm> & 0x1F).
1318 258 : IGNITION_HANDLER(ShiftLeftSmi, InterpreterAssembler) {
1319 129 : Node* left = GetAccumulator();
1320 129 : Node* right = BytecodeOperandImmSmi(0);
1321 129 : Node* slot_index = BytecodeOperandIdx(1);
1322 129 : Node* feedback_vector = LoadFeedbackVector();
1323 129 : Node* context = GetContext();
1324 :
1325 129 : Variable var_lhs_type_feedback(this, MachineRepresentation::kTaggedSigned);
1326 : Node* lhs_value =
1327 129 : TruncateTaggedToWord32WithFeedback(context, left, &var_lhs_type_feedback);
1328 129 : Node* rhs_value = SmiToWord32(right);
1329 129 : Node* shift_count = Word32And(rhs_value, Int32Constant(0x1f));
1330 129 : Node* value = Word32Shl(lhs_value, shift_count);
1331 129 : Node* result = ChangeInt32ToTagged(value);
1332 : Node* result_type = SelectSmiConstant(TaggedIsSmi(result),
1333 : BinaryOperationFeedback::kSignedSmall,
1334 129 : BinaryOperationFeedback::kNumber);
1335 : UpdateFeedback(SmiOr(result_type, var_lhs_type_feedback.value()),
1336 129 : feedback_vector, slot_index);
1337 129 : SetAccumulator(result);
1338 129 : Dispatch();
1339 129 : }
1340 :
1341 : // ShiftRightSmi <imm>
1342 : //
1343 : // Right shifts accumulator by the count specified in <imm>. Result is sign
1344 : // extended. The accumulator is converted to an int32 before the operation. The
1345 : // 5 lsb bits from <imm> are used as count i.e. <src> << (<imm> & 0x1F).
1346 258 : IGNITION_HANDLER(ShiftRightSmi, InterpreterAssembler) {
1347 129 : Node* left = GetAccumulator();
1348 129 : Node* right = BytecodeOperandImmSmi(0);
1349 129 : Node* slot_index = BytecodeOperandIdx(1);
1350 129 : Node* feedback_vector = LoadFeedbackVector();
1351 129 : Node* context = GetContext();
1352 :
1353 129 : Variable var_lhs_type_feedback(this, MachineRepresentation::kTaggedSigned);
1354 : Node* lhs_value =
1355 129 : TruncateTaggedToWord32WithFeedback(context, left, &var_lhs_type_feedback);
1356 129 : Node* rhs_value = SmiToWord32(right);
1357 129 : Node* shift_count = Word32And(rhs_value, Int32Constant(0x1f));
1358 129 : Node* value = Word32Sar(lhs_value, shift_count);
1359 129 : Node* result = ChangeInt32ToTagged(value);
1360 : Node* result_type = SelectSmiConstant(TaggedIsSmi(result),
1361 : BinaryOperationFeedback::kSignedSmall,
1362 129 : BinaryOperationFeedback::kNumber);
1363 : UpdateFeedback(SmiOr(result_type, var_lhs_type_feedback.value()),
1364 129 : feedback_vector, slot_index);
1365 129 : SetAccumulator(result);
1366 129 : Dispatch();
1367 129 : }
1368 :
1369 : // ShiftRightLogicalSmi <imm>
1370 : //
1371 : // Right shifts accumulator by the count specified in <imm>. Result is zero
1372 : // extended. The accumulator is converted to an int32 before the operation. The
1373 : // 5 lsb bits from <imm> are used as count i.e. <src> << (<imm> & 0x1F).
1374 258 : IGNITION_HANDLER(ShiftRightLogicalSmi, InterpreterAssembler) {
1375 129 : Node* left = GetAccumulator();
1376 129 : Node* right = BytecodeOperandImmSmi(0);
1377 129 : Node* slot_index = BytecodeOperandIdx(1);
1378 129 : Node* feedback_vector = LoadFeedbackVector();
1379 129 : Node* context = GetContext();
1380 :
1381 129 : Variable var_lhs_type_feedback(this, MachineRepresentation::kTaggedSigned);
1382 : Node* lhs_value =
1383 129 : TruncateTaggedToWord32WithFeedback(context, left, &var_lhs_type_feedback);
1384 129 : Node* rhs_value = SmiToWord32(right);
1385 129 : Node* shift_count = Word32And(rhs_value, Int32Constant(0x1f));
1386 129 : Node* value = Word32Shr(lhs_value, shift_count);
1387 129 : Node* result = ChangeUint32ToTagged(value);
1388 : Node* result_type = SelectSmiConstant(TaggedIsSmi(result),
1389 : BinaryOperationFeedback::kSignedSmall,
1390 129 : BinaryOperationFeedback::kNumber);
1391 : UpdateFeedback(SmiOr(result_type, var_lhs_type_feedback.value()),
1392 129 : feedback_vector, slot_index);
1393 129 : SetAccumulator(result);
1394 129 : Dispatch();
1395 129 : }
1396 :
1397 : // ToName
1398 : //
1399 : // Convert the object referenced by the accumulator to a name.
1400 258 : IGNITION_HANDLER(ToName, InterpreterAssembler) {
1401 129 : Node* object = GetAccumulator();
1402 129 : Node* context = GetContext();
1403 129 : Node* result = ToName(context, object);
1404 129 : StoreRegister(result, BytecodeOperandReg(0));
1405 129 : Dispatch();
1406 129 : }
1407 :
1408 : // ToNumber <dst> <slot>
1409 : //
1410 : // Convert the object referenced by the accumulator to a number.
1411 258 : IGNITION_HANDLER(ToNumber, InterpreterAssembler) {
1412 129 : Node* object = GetAccumulator();
1413 129 : Node* context = GetContext();
1414 :
1415 : // Convert the {object} to a Number and collect feedback for the {object}.
1416 129 : Variable var_type_feedback(this, MachineRepresentation::kTaggedSigned);
1417 258 : Variable var_result(this, MachineRepresentation::kTagged);
1418 129 : Label if_done(this), if_objectissmi(this), if_objectisnumber(this),
1419 129 : if_objectisother(this, Label::kDeferred);
1420 :
1421 129 : GotoIf(TaggedIsSmi(object), &if_objectissmi);
1422 129 : Node* object_map = LoadMap(object);
1423 129 : Branch(IsHeapNumberMap(object_map), &if_objectisnumber, &if_objectisother);
1424 :
1425 129 : Bind(&if_objectissmi);
1426 : {
1427 129 : var_result.Bind(object);
1428 129 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kSignedSmall));
1429 129 : Goto(&if_done);
1430 : }
1431 :
1432 129 : Bind(&if_objectisnumber);
1433 : {
1434 129 : var_result.Bind(object);
1435 129 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
1436 129 : Goto(&if_done);
1437 : }
1438 :
1439 129 : Bind(&if_objectisother);
1440 : {
1441 : // Convert the {object} to a Number.
1442 129 : Callable callable = CodeFactory::NonNumberToNumber(isolate());
1443 129 : var_result.Bind(CallStub(callable, context, object));
1444 129 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
1445 129 : Goto(&if_done);
1446 : }
1447 :
1448 129 : Bind(&if_done);
1449 129 : StoreRegister(var_result.value(), BytecodeOperandReg(0));
1450 :
1451 : // Record the type feedback collected for {object}.
1452 129 : Node* slot_index = BytecodeOperandIdx(1);
1453 129 : Node* feedback_vector = LoadFeedbackVector();
1454 129 : UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_index);
1455 :
1456 258 : Dispatch();
1457 129 : }
1458 :
1459 : // ToObject
1460 : //
1461 : // Convert the object referenced by the accumulator to a JSReceiver.
1462 258 : IGNITION_HANDLER(ToObject, InterpreterAssembler) {
1463 129 : Callable callable(CodeFactory::ToObject(isolate()));
1464 129 : Node* target = HeapConstant(callable.code());
1465 129 : Node* accumulator = GetAccumulator();
1466 129 : Node* context = GetContext();
1467 129 : Node* result = CallStub(callable.descriptor(), target, context, accumulator);
1468 129 : StoreRegister(result, BytecodeOperandReg(0));
1469 129 : Dispatch();
1470 129 : }
1471 :
1472 : // Inc
1473 : //
1474 : // Increments value in the accumulator by one.
1475 258 : IGNITION_HANDLER(Inc, InterpreterAssembler) {
1476 : typedef CodeStubAssembler::Label Label;
1477 : typedef compiler::Node Node;
1478 : typedef CodeStubAssembler::Variable Variable;
1479 :
1480 129 : Node* value = GetAccumulator();
1481 129 : Node* context = GetContext();
1482 129 : Node* slot_index = BytecodeOperandIdx(0);
1483 129 : Node* feedback_vector = LoadFeedbackVector();
1484 :
1485 : // Shared entry for floating point increment.
1486 258 : Label do_finc(this), end(this);
1487 258 : Variable var_finc_value(this, MachineRepresentation::kFloat64);
1488 :
1489 : // We might need to try again due to ToNumber conversion.
1490 258 : Variable value_var(this, MachineRepresentation::kTagged);
1491 258 : Variable result_var(this, MachineRepresentation::kTagged);
1492 258 : Variable var_type_feedback(this, MachineRepresentation::kTaggedSigned);
1493 129 : Variable* loop_vars[] = {&value_var, &var_type_feedback};
1494 258 : Label start(this, 2, loop_vars);
1495 129 : value_var.Bind(value);
1496 129 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNone));
1497 129 : Goto(&start);
1498 129 : Bind(&start);
1499 : {
1500 129 : value = value_var.value();
1501 :
1502 129 : Label if_issmi(this), if_isnotsmi(this);
1503 129 : Branch(TaggedIsSmi(value), &if_issmi, &if_isnotsmi);
1504 :
1505 129 : Bind(&if_issmi);
1506 : {
1507 : // Try fast Smi addition first.
1508 129 : Node* one = SmiConstant(Smi::FromInt(1));
1509 : Node* pair = IntPtrAddWithOverflow(BitcastTaggedToWord(value),
1510 129 : BitcastTaggedToWord(one));
1511 129 : Node* overflow = Projection(1, pair);
1512 :
1513 : // Check if the Smi addition overflowed.
1514 129 : Label if_overflow(this), if_notoverflow(this);
1515 129 : Branch(overflow, &if_overflow, &if_notoverflow);
1516 :
1517 129 : Bind(&if_notoverflow);
1518 : var_type_feedback.Bind(
1519 : SmiOr(var_type_feedback.value(),
1520 129 : SmiConstant(BinaryOperationFeedback::kSignedSmall)));
1521 129 : result_var.Bind(BitcastWordToTaggedSigned(Projection(0, pair)));
1522 129 : Goto(&end);
1523 :
1524 129 : Bind(&if_overflow);
1525 : {
1526 129 : var_finc_value.Bind(SmiToFloat64(value));
1527 129 : Goto(&do_finc);
1528 129 : }
1529 : }
1530 :
1531 129 : Bind(&if_isnotsmi);
1532 : {
1533 : // Check if the value is a HeapNumber.
1534 129 : Label if_valueisnumber(this), if_valuenotnumber(this, Label::kDeferred);
1535 129 : Node* value_map = LoadMap(value);
1536 129 : Branch(IsHeapNumberMap(value_map), &if_valueisnumber, &if_valuenotnumber);
1537 :
1538 129 : Bind(&if_valueisnumber);
1539 : {
1540 : // Load the HeapNumber value.
1541 129 : var_finc_value.Bind(LoadHeapNumberValue(value));
1542 129 : Goto(&do_finc);
1543 : }
1544 :
1545 129 : Bind(&if_valuenotnumber);
1546 : {
1547 : // We do not require an Or with earlier feedback here because once we
1548 : // convert the value to a number, we cannot reach this path. We can
1549 : // only reach this path on the first pass when the feedback is kNone.
1550 : CSA_ASSERT(this, SmiEqual(var_type_feedback.value(),
1551 : SmiConstant(BinaryOperationFeedback::kNone)));
1552 :
1553 129 : Label if_valueisoddball(this), if_valuenotoddball(this);
1554 129 : Node* instance_type = LoadMapInstanceType(value_map);
1555 : Node* is_oddball =
1556 129 : Word32Equal(instance_type, Int32Constant(ODDBALL_TYPE));
1557 129 : Branch(is_oddball, &if_valueisoddball, &if_valuenotoddball);
1558 :
1559 129 : Bind(&if_valueisoddball);
1560 : {
1561 : // Convert Oddball to Number and check again.
1562 129 : value_var.Bind(LoadObjectField(value, Oddball::kToNumberOffset));
1563 : var_type_feedback.Bind(
1564 129 : SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
1565 129 : Goto(&start);
1566 : }
1567 :
1568 129 : Bind(&if_valuenotoddball);
1569 : {
1570 : // Convert to a Number first and try again.
1571 129 : Callable callable = CodeFactory::NonNumberToNumber(isolate());
1572 129 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
1573 129 : value_var.Bind(CallStub(callable, context, value));
1574 129 : Goto(&start);
1575 129 : }
1576 129 : }
1577 129 : }
1578 : }
1579 :
1580 129 : Bind(&do_finc);
1581 : {
1582 129 : Node* finc_value = var_finc_value.value();
1583 129 : Node* one = Float64Constant(1.0);
1584 129 : Node* finc_result = Float64Add(finc_value, one);
1585 : var_type_feedback.Bind(
1586 : SmiOr(var_type_feedback.value(),
1587 129 : SmiConstant(BinaryOperationFeedback::kNumber)));
1588 129 : result_var.Bind(AllocateHeapNumberWithValue(finc_result));
1589 129 : Goto(&end);
1590 : }
1591 :
1592 129 : Bind(&end);
1593 129 : UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_index);
1594 :
1595 129 : SetAccumulator(result_var.value());
1596 258 : Dispatch();
1597 129 : }
1598 :
1599 : // Dec
1600 : //
1601 : // Decrements value in the accumulator by one.
1602 258 : IGNITION_HANDLER(Dec, InterpreterAssembler) {
1603 : typedef CodeStubAssembler::Label Label;
1604 : typedef compiler::Node Node;
1605 : typedef CodeStubAssembler::Variable Variable;
1606 :
1607 129 : Node* value = GetAccumulator();
1608 129 : Node* context = GetContext();
1609 129 : Node* slot_index = BytecodeOperandIdx(0);
1610 129 : Node* feedback_vector = LoadFeedbackVector();
1611 :
1612 : // Shared entry for floating point decrement.
1613 258 : Label do_fdec(this), end(this);
1614 258 : Variable var_fdec_value(this, MachineRepresentation::kFloat64);
1615 :
1616 : // We might need to try again due to ToNumber conversion.
1617 258 : Variable value_var(this, MachineRepresentation::kTagged);
1618 258 : Variable result_var(this, MachineRepresentation::kTagged);
1619 258 : Variable var_type_feedback(this, MachineRepresentation::kTaggedSigned);
1620 129 : Variable* loop_vars[] = {&value_var, &var_type_feedback};
1621 258 : Label start(this, 2, loop_vars);
1622 129 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNone));
1623 129 : value_var.Bind(value);
1624 129 : Goto(&start);
1625 129 : Bind(&start);
1626 : {
1627 129 : value = value_var.value();
1628 :
1629 129 : Label if_issmi(this), if_isnotsmi(this);
1630 129 : Branch(TaggedIsSmi(value), &if_issmi, &if_isnotsmi);
1631 :
1632 129 : Bind(&if_issmi);
1633 : {
1634 : // Try fast Smi subtraction first.
1635 129 : Node* one = SmiConstant(Smi::FromInt(1));
1636 : Node* pair = IntPtrSubWithOverflow(BitcastTaggedToWord(value),
1637 129 : BitcastTaggedToWord(one));
1638 129 : Node* overflow = Projection(1, pair);
1639 :
1640 : // Check if the Smi subtraction overflowed.
1641 129 : Label if_overflow(this), if_notoverflow(this);
1642 129 : Branch(overflow, &if_overflow, &if_notoverflow);
1643 :
1644 129 : Bind(&if_notoverflow);
1645 : var_type_feedback.Bind(
1646 : SmiOr(var_type_feedback.value(),
1647 129 : SmiConstant(BinaryOperationFeedback::kSignedSmall)));
1648 129 : result_var.Bind(BitcastWordToTaggedSigned(Projection(0, pair)));
1649 129 : Goto(&end);
1650 :
1651 129 : Bind(&if_overflow);
1652 : {
1653 129 : var_fdec_value.Bind(SmiToFloat64(value));
1654 129 : Goto(&do_fdec);
1655 129 : }
1656 : }
1657 :
1658 129 : Bind(&if_isnotsmi);
1659 : {
1660 : // Check if the value is a HeapNumber.
1661 129 : Label if_valueisnumber(this), if_valuenotnumber(this, Label::kDeferred);
1662 129 : Node* value_map = LoadMap(value);
1663 129 : Branch(IsHeapNumberMap(value_map), &if_valueisnumber, &if_valuenotnumber);
1664 :
1665 129 : Bind(&if_valueisnumber);
1666 : {
1667 : // Load the HeapNumber value.
1668 129 : var_fdec_value.Bind(LoadHeapNumberValue(value));
1669 129 : Goto(&do_fdec);
1670 : }
1671 :
1672 129 : Bind(&if_valuenotnumber);
1673 : {
1674 : // We do not require an Or with earlier feedback here because once we
1675 : // convert the value to a number, we cannot reach this path. We can
1676 : // only reach this path on the first pass when the feedback is kNone.
1677 : CSA_ASSERT(this, SmiEqual(var_type_feedback.value(),
1678 : SmiConstant(BinaryOperationFeedback::kNone)));
1679 :
1680 129 : Label if_valueisoddball(this), if_valuenotoddball(this);
1681 129 : Node* instance_type = LoadMapInstanceType(value_map);
1682 : Node* is_oddball =
1683 129 : Word32Equal(instance_type, Int32Constant(ODDBALL_TYPE));
1684 129 : Branch(is_oddball, &if_valueisoddball, &if_valuenotoddball);
1685 :
1686 129 : Bind(&if_valueisoddball);
1687 : {
1688 : // Convert Oddball to Number and check again.
1689 129 : value_var.Bind(LoadObjectField(value, Oddball::kToNumberOffset));
1690 : var_type_feedback.Bind(
1691 129 : SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
1692 129 : Goto(&start);
1693 : }
1694 :
1695 129 : Bind(&if_valuenotoddball);
1696 : {
1697 : // Convert to a Number first and try again.
1698 129 : Callable callable = CodeFactory::NonNumberToNumber(isolate());
1699 129 : var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
1700 129 : value_var.Bind(CallStub(callable, context, value));
1701 129 : Goto(&start);
1702 129 : }
1703 129 : }
1704 129 : }
1705 : }
1706 :
1707 129 : Bind(&do_fdec);
1708 : {
1709 129 : Node* fdec_value = var_fdec_value.value();
1710 129 : Node* one = Float64Constant(1.0);
1711 129 : Node* fdec_result = Float64Sub(fdec_value, one);
1712 : var_type_feedback.Bind(
1713 : SmiOr(var_type_feedback.value(),
1714 129 : SmiConstant(BinaryOperationFeedback::kNumber)));
1715 129 : result_var.Bind(AllocateHeapNumberWithValue(fdec_result));
1716 129 : Goto(&end);
1717 : }
1718 :
1719 129 : Bind(&end);
1720 129 : UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_index);
1721 :
1722 129 : SetAccumulator(result_var.value());
1723 258 : Dispatch();
1724 129 : }
1725 :
1726 : // LogicalNot
1727 : //
1728 : // Perform logical-not on the accumulator, first casting the
1729 : // accumulator to a boolean value if required.
1730 : // ToBooleanLogicalNot
1731 86 : IGNITION_HANDLER(ToBooleanLogicalNot, InterpreterAssembler) {
1732 43 : Node* value = GetAccumulator();
1733 43 : Variable result(this, MachineRepresentation::kTagged);
1734 43 : Label if_true(this), if_false(this), end(this);
1735 43 : Node* true_value = BooleanConstant(true);
1736 43 : Node* false_value = BooleanConstant(false);
1737 43 : BranchIfToBooleanIsTrue(value, &if_true, &if_false);
1738 43 : Bind(&if_true);
1739 : {
1740 43 : result.Bind(false_value);
1741 43 : Goto(&end);
1742 : }
1743 43 : Bind(&if_false);
1744 : {
1745 43 : result.Bind(true_value);
1746 43 : Goto(&end);
1747 : }
1748 43 : Bind(&end);
1749 43 : SetAccumulator(result.value());
1750 86 : Dispatch();
1751 43 : }
1752 :
1753 : // LogicalNot
1754 : //
1755 : // Perform logical-not on the accumulator, which must already be a boolean
1756 : // value.
1757 86 : IGNITION_HANDLER(LogicalNot, InterpreterAssembler) {
1758 43 : Node* value = GetAccumulator();
1759 43 : Variable result(this, MachineRepresentation::kTagged);
1760 43 : Label if_true(this), if_false(this), end(this);
1761 43 : Node* true_value = BooleanConstant(true);
1762 43 : Node* false_value = BooleanConstant(false);
1763 43 : Branch(WordEqual(value, true_value), &if_true, &if_false);
1764 43 : Bind(&if_true);
1765 : {
1766 43 : result.Bind(false_value);
1767 43 : Goto(&end);
1768 : }
1769 43 : Bind(&if_false);
1770 : {
1771 43 : if (FLAG_debug_code) {
1772 : AbortIfWordNotEqual(value, false_value,
1773 0 : BailoutReason::kExpectedBooleanValue);
1774 : }
1775 43 : result.Bind(true_value);
1776 43 : Goto(&end);
1777 : }
1778 43 : Bind(&end);
1779 43 : SetAccumulator(result.value());
1780 86 : Dispatch();
1781 43 : }
1782 :
1783 : // TypeOf
1784 : //
1785 : // Load the accumulator with the string representating type of the
1786 : // object in the accumulator.
1787 86 : IGNITION_HANDLER(TypeOf, InterpreterAssembler) {
1788 43 : Node* value = GetAccumulator();
1789 43 : Node* result = Typeof(value);
1790 43 : SetAccumulator(result);
1791 43 : Dispatch();
1792 43 : }
1793 :
1794 : // DeletePropertyStrict
1795 : //
1796 : // Delete the property specified in the accumulator from the object
1797 : // referenced by the register operand following strict mode semantics.
1798 258 : IGNITION_HANDLER(DeletePropertyStrict, InterpreterAssembler) {
1799 129 : Node* reg_index = BytecodeOperandReg(0);
1800 129 : Node* object = LoadRegister(reg_index);
1801 129 : Node* key = GetAccumulator();
1802 129 : Node* context = GetContext();
1803 : Node* result = CallBuiltin(Builtins::kDeleteProperty, context, object, key,
1804 129 : SmiConstant(STRICT));
1805 129 : SetAccumulator(result);
1806 129 : Dispatch();
1807 129 : }
1808 :
1809 : // DeletePropertySloppy
1810 : //
1811 : // Delete the property specified in the accumulator from the object
1812 : // referenced by the register operand following sloppy mode semantics.
1813 258 : IGNITION_HANDLER(DeletePropertySloppy, InterpreterAssembler) {
1814 129 : Node* reg_index = BytecodeOperandReg(0);
1815 129 : Node* object = LoadRegister(reg_index);
1816 129 : Node* key = GetAccumulator();
1817 129 : Node* context = GetContext();
1818 : Node* result = CallBuiltin(Builtins::kDeleteProperty, context, object, key,
1819 129 : SmiConstant(SLOPPY));
1820 129 : SetAccumulator(result);
1821 129 : Dispatch();
1822 129 : }
1823 :
1824 : // GetSuperConstructor
1825 : //
1826 : // Get the super constructor from the object referenced by the accumulator.
1827 : // The result is stored in register |reg|.
1828 258 : IGNITION_HANDLER(GetSuperConstructor, InterpreterAssembler) {
1829 129 : Node* active_function = GetAccumulator();
1830 129 : Node* context = GetContext();
1831 129 : Node* result = GetSuperConstructor(active_function, context);
1832 129 : Node* reg = BytecodeOperandReg(0);
1833 129 : StoreRegister(result, reg);
1834 129 : Dispatch();
1835 129 : }
1836 :
1837 1290 : class InterpreterJSCallAssembler : public InterpreterAssembler {
1838 : public:
1839 : InterpreterJSCallAssembler(CodeAssemblerState* state, Bytecode bytecode,
1840 : OperandScale operand_scale)
1841 1290 : : InterpreterAssembler(state, bytecode, operand_scale) {}
1842 :
1843 : // Generates code to perform a JS call that collects type feedback.
1844 516 : void JSCall(ConvertReceiverMode receiver_mode, TailCallMode tail_call_mode) {
1845 516 : Node* function_reg = BytecodeOperandReg(0);
1846 516 : Node* function = LoadRegister(function_reg);
1847 516 : Node* first_arg_reg = BytecodeOperandReg(1);
1848 516 : Node* first_arg = RegisterLocation(first_arg_reg);
1849 516 : Node* arg_list_count = BytecodeOperandCount(2);
1850 : Node* args_count;
1851 516 : if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
1852 : // The receiver is implied, so it is not in the argument list.
1853 : args_count = arg_list_count;
1854 : } else {
1855 : // Subtract the receiver from the argument count.
1856 387 : Node* receiver_count = Int32Constant(1);
1857 387 : args_count = Int32Sub(arg_list_count, receiver_count);
1858 : }
1859 516 : Node* slot_id = BytecodeOperandIdx(3);
1860 516 : Node* feedback_vector = LoadFeedbackVector();
1861 516 : Node* context = GetContext();
1862 : Node* result =
1863 : CallJSWithFeedback(function, context, first_arg, args_count, slot_id,
1864 516 : feedback_vector, receiver_mode, tail_call_mode);
1865 516 : SetAccumulator(result);
1866 516 : Dispatch();
1867 516 : }
1868 :
1869 : // Generates code to perform a JS call with a known number of arguments that
1870 : // collects type feedback.
1871 774 : void JSCallN(int arg_count, ConvertReceiverMode receiver_mode) {
1872 : // Indices and counts of operands on the bytecode.
1873 : const int kFirstArgumentOperandIndex = 1;
1874 : const int kReceiverOperandCount =
1875 774 : (receiver_mode == ConvertReceiverMode::kNullOrUndefined) ? 0 : 1;
1876 : const int kSlotOperandIndex =
1877 774 : kFirstArgumentOperandIndex + kReceiverOperandCount + arg_count;
1878 : // Indices and counts of parameters to the call stub.
1879 : const int kBoilerplateParameterCount = 7;
1880 : const int kReceiverParameterIndex = 5;
1881 : const int kReceiverParameterCount = 1;
1882 : // Only used in a DCHECK.
1883 : USE(kReceiverParameterCount);
1884 :
1885 774 : Node* function_reg = BytecodeOperandReg(0);
1886 774 : Node* function = LoadRegister(function_reg);
1887 : std::array<Node*, Bytecodes::kMaxOperands + kBoilerplateParameterCount>
1888 : temp;
1889 774 : Callable call_ic = CodeFactory::CallIC(isolate());
1890 774 : temp[0] = HeapConstant(call_ic.code());
1891 774 : temp[1] = function;
1892 774 : temp[2] = Int32Constant(arg_count);
1893 774 : temp[3] = BytecodeOperandIdxInt32(kSlotOperandIndex);
1894 774 : temp[4] = LoadFeedbackVector();
1895 :
1896 : int parameter_index = kReceiverParameterIndex;
1897 774 : if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
1898 : // The first argument parameter (the receiver) is implied to be undefined.
1899 : Node* undefined_value =
1900 774 : HeapConstant(isolate()->factory()->undefined_value());
1901 387 : temp[parameter_index++] = undefined_value;
1902 : }
1903 : // The bytecode argument operands are copied into the remaining argument
1904 : // parameters.
1905 1935 : for (int i = 0; i < (kReceiverOperandCount + arg_count); ++i) {
1906 1161 : Node* reg = BytecodeOperandReg(kFirstArgumentOperandIndex + i);
1907 1161 : temp[parameter_index++] = LoadRegister(reg);
1908 : }
1909 :
1910 : DCHECK_EQ(parameter_index,
1911 : kReceiverParameterIndex + kReceiverParameterCount + arg_count);
1912 774 : temp[parameter_index] = GetContext();
1913 :
1914 : Node* result = CallStubN(call_ic.descriptor(), 1,
1915 2322 : arg_count + kBoilerplateParameterCount, &temp[0]);
1916 774 : SetAccumulator(result);
1917 774 : Dispatch();
1918 774 : }
1919 : };
1920 :
1921 : // Call <callable> <receiver> <arg_count> <feedback_slot_id>
1922 : //
1923 : // Call a JSfunction or Callable in |callable| with the |receiver| and
1924 : // |arg_count| arguments in subsequent registers. Collect type feedback
1925 : // into |feedback_slot_id|
1926 387 : IGNITION_HANDLER(CallAnyReceiver, InterpreterJSCallAssembler) {
1927 129 : JSCall(ConvertReceiverMode::kAny, TailCallMode::kDisallow);
1928 : }
1929 :
1930 387 : IGNITION_HANDLER(CallProperty, InterpreterJSCallAssembler) {
1931 129 : JSCall(ConvertReceiverMode::kNotNullOrUndefined, TailCallMode::kDisallow);
1932 : }
1933 :
1934 387 : IGNITION_HANDLER(CallProperty0, InterpreterJSCallAssembler) {
1935 129 : JSCallN(0, ConvertReceiverMode::kNotNullOrUndefined);
1936 : }
1937 :
1938 387 : IGNITION_HANDLER(CallProperty1, InterpreterJSCallAssembler) {
1939 129 : JSCallN(1, ConvertReceiverMode::kNotNullOrUndefined);
1940 : }
1941 :
1942 387 : IGNITION_HANDLER(CallProperty2, InterpreterJSCallAssembler) {
1943 129 : JSCallN(2, ConvertReceiverMode::kNotNullOrUndefined);
1944 : }
1945 :
1946 387 : IGNITION_HANDLER(CallUndefinedReceiver, InterpreterJSCallAssembler) {
1947 129 : JSCall(ConvertReceiverMode::kNullOrUndefined, TailCallMode::kDisallow);
1948 : }
1949 :
1950 387 : IGNITION_HANDLER(CallUndefinedReceiver0, InterpreterJSCallAssembler) {
1951 129 : JSCallN(0, ConvertReceiverMode::kNullOrUndefined);
1952 : }
1953 :
1954 387 : IGNITION_HANDLER(CallUndefinedReceiver1, InterpreterJSCallAssembler) {
1955 129 : JSCallN(1, ConvertReceiverMode::kNullOrUndefined);
1956 : }
1957 :
1958 387 : IGNITION_HANDLER(CallUndefinedReceiver2, InterpreterJSCallAssembler) {
1959 129 : JSCallN(2, ConvertReceiverMode::kNullOrUndefined);
1960 : }
1961 :
1962 : // TailCall <callable> <receiver> <arg_count> <feedback_slot_id>
1963 : //
1964 : // Tail call a JSfunction or Callable in |callable| with the |receiver| and
1965 : // |arg_count| arguments in subsequent registers. Collect type feedback
1966 : // into |feedback_slot_id|
1967 387 : IGNITION_HANDLER(TailCall, InterpreterJSCallAssembler) {
1968 129 : JSCall(ConvertReceiverMode::kAny, TailCallMode::kAllow);
1969 : }
1970 :
1971 : // CallRuntime <function_id> <first_arg> <arg_count>
1972 : //
1973 : // Call the runtime function |function_id| with the first argument in
1974 : // register |first_arg| and |arg_count| arguments in subsequent
1975 : // registers.
1976 258 : IGNITION_HANDLER(CallRuntime, InterpreterAssembler) {
1977 129 : Node* function_id = BytecodeOperandRuntimeId(0);
1978 129 : Node* first_arg_reg = BytecodeOperandReg(1);
1979 129 : Node* first_arg = RegisterLocation(first_arg_reg);
1980 129 : Node* args_count = BytecodeOperandCount(2);
1981 129 : Node* context = GetContext();
1982 129 : Node* result = CallRuntimeN(function_id, context, first_arg, args_count);
1983 129 : SetAccumulator(result);
1984 129 : Dispatch();
1985 129 : }
1986 :
1987 : // InvokeIntrinsic <function_id> <first_arg> <arg_count>
1988 : //
1989 : // Implements the semantic equivalent of calling the runtime function
1990 : // |function_id| with the first argument in |first_arg| and |arg_count|
1991 : // arguments in subsequent registers.
1992 258 : IGNITION_HANDLER(InvokeIntrinsic, InterpreterAssembler) {
1993 129 : Node* function_id = BytecodeOperandIntrinsicId(0);
1994 129 : Node* first_arg_reg = BytecodeOperandReg(1);
1995 129 : Node* arg_count = BytecodeOperandCount(2);
1996 129 : Node* context = GetContext();
1997 : Node* result = GenerateInvokeIntrinsic(this, function_id, context,
1998 129 : first_arg_reg, arg_count);
1999 129 : SetAccumulator(result);
2000 129 : Dispatch();
2001 129 : }
2002 :
2003 : // CallRuntimeForPair <function_id> <first_arg> <arg_count> <first_return>
2004 : //
2005 : // Call the runtime function |function_id| which returns a pair, with the
2006 : // first argument in register |first_arg| and |arg_count| arguments in
2007 : // subsequent registers. Returns the result in <first_return> and
2008 : // <first_return + 1>
2009 258 : IGNITION_HANDLER(CallRuntimeForPair, InterpreterAssembler) {
2010 : // Call the runtime function.
2011 129 : Node* function_id = BytecodeOperandRuntimeId(0);
2012 129 : Node* first_arg_reg = BytecodeOperandReg(1);
2013 129 : Node* first_arg = RegisterLocation(first_arg_reg);
2014 129 : Node* args_count = BytecodeOperandCount(2);
2015 129 : Node* context = GetContext();
2016 : Node* result_pair =
2017 129 : CallRuntimeN(function_id, context, first_arg, args_count, 2);
2018 : // Store the results in <first_return> and <first_return + 1>
2019 129 : Node* first_return_reg = BytecodeOperandReg(3);
2020 129 : Node* second_return_reg = NextRegister(first_return_reg);
2021 129 : Node* result0 = Projection(0, result_pair);
2022 129 : Node* result1 = Projection(1, result_pair);
2023 129 : StoreRegister(result0, first_return_reg);
2024 129 : StoreRegister(result1, second_return_reg);
2025 129 : Dispatch();
2026 129 : }
2027 :
2028 : // CallJSRuntime <context_index> <receiver> <arg_count>
2029 : //
2030 : // Call the JS runtime function that has the |context_index| with the receiver
2031 : // in register |receiver| and |arg_count| arguments in subsequent registers.
2032 258 : IGNITION_HANDLER(CallJSRuntime, InterpreterAssembler) {
2033 129 : Node* context_index = BytecodeOperandIdx(0);
2034 129 : Node* receiver_reg = BytecodeOperandReg(1);
2035 129 : Node* first_arg = RegisterLocation(receiver_reg);
2036 129 : Node* receiver_args_count = BytecodeOperandCount(2);
2037 129 : Node* receiver_count = Int32Constant(1);
2038 129 : Node* args_count = Int32Sub(receiver_args_count, receiver_count);
2039 :
2040 : // Get the function to call from the native context.
2041 129 : Node* context = GetContext();
2042 129 : Node* native_context = LoadNativeContext(context);
2043 129 : Node* function = LoadContextElement(native_context, context_index);
2044 :
2045 : // Call the function.
2046 : Node* result = CallJS(function, context, first_arg, args_count,
2047 129 : ConvertReceiverMode::kAny, TailCallMode::kDisallow);
2048 129 : SetAccumulator(result);
2049 129 : Dispatch();
2050 129 : }
2051 :
2052 : // CallWithSpread <callable> <first_arg> <arg_count>
2053 : //
2054 : // Call a JSfunction or Callable in |callable| with the receiver in
2055 : // |first_arg| and |arg_count - 1| arguments in subsequent registers. The
2056 : // final argument is always a spread.
2057 : //
2058 258 : IGNITION_HANDLER(CallWithSpread, InterpreterAssembler) {
2059 129 : Node* callable_reg = BytecodeOperandReg(0);
2060 129 : Node* callable = LoadRegister(callable_reg);
2061 129 : Node* receiver_reg = BytecodeOperandReg(1);
2062 129 : Node* receiver_arg = RegisterLocation(receiver_reg);
2063 129 : Node* receiver_args_count = BytecodeOperandCount(2);
2064 129 : Node* receiver_count = Int32Constant(1);
2065 129 : Node* args_count = Int32Sub(receiver_args_count, receiver_count);
2066 129 : Node* context = GetContext();
2067 :
2068 : // Call into Runtime function CallWithSpread which does everything.
2069 129 : Node* result = CallJSWithSpread(callable, context, receiver_arg, args_count);
2070 129 : SetAccumulator(result);
2071 129 : Dispatch();
2072 129 : }
2073 :
2074 : // ConstructWithSpread <first_arg> <arg_count>
2075 : //
2076 : // Call the constructor in |constructor| with the first argument in register
2077 : // |first_arg| and |arg_count| arguments in subsequent registers. The final
2078 : // argument is always a spread. The new.target is in the accumulator.
2079 : //
2080 258 : IGNITION_HANDLER(ConstructWithSpread, InterpreterAssembler) {
2081 129 : Node* new_target = GetAccumulator();
2082 129 : Node* constructor_reg = BytecodeOperandReg(0);
2083 129 : Node* constructor = LoadRegister(constructor_reg);
2084 129 : Node* first_arg_reg = BytecodeOperandReg(1);
2085 129 : Node* first_arg = RegisterLocation(first_arg_reg);
2086 129 : Node* args_count = BytecodeOperandCount(2);
2087 129 : Node* context = GetContext();
2088 : Node* result = ConstructWithSpread(constructor, context, new_target,
2089 129 : first_arg, args_count);
2090 129 : SetAccumulator(result);
2091 129 : Dispatch();
2092 129 : }
2093 :
2094 : // Construct <constructor> <first_arg> <arg_count>
2095 : //
2096 : // Call operator construct with |constructor| and the first argument in
2097 : // register |first_arg| and |arg_count| arguments in subsequent
2098 : // registers. The new.target is in the accumulator.
2099 : //
2100 258 : IGNITION_HANDLER(Construct, InterpreterAssembler) {
2101 129 : Node* new_target = GetAccumulator();
2102 129 : Node* constructor_reg = BytecodeOperandReg(0);
2103 129 : Node* constructor = LoadRegister(constructor_reg);
2104 129 : Node* first_arg_reg = BytecodeOperandReg(1);
2105 129 : Node* first_arg = RegisterLocation(first_arg_reg);
2106 129 : Node* args_count = BytecodeOperandCount(2);
2107 129 : Node* slot_id = BytecodeOperandIdx(3);
2108 129 : Node* feedback_vector = LoadFeedbackVector();
2109 129 : Node* context = GetContext();
2110 : Node* result = Construct(constructor, context, new_target, first_arg,
2111 129 : args_count, slot_id, feedback_vector);
2112 129 : SetAccumulator(result);
2113 129 : Dispatch();
2114 129 : }
2115 :
2116 774 : class InterpreterCompareOpAssembler : public InterpreterAssembler {
2117 : public:
2118 : InterpreterCompareOpAssembler(CodeAssemblerState* state, Bytecode bytecode,
2119 : OperandScale operand_scale)
2120 774 : : InterpreterAssembler(state, bytecode, operand_scale) {}
2121 :
2122 774 : void CompareOpWithFeedback(Token::Value compare_op) {
2123 774 : Node* reg_index = BytecodeOperandReg(0);
2124 774 : Node* lhs = LoadRegister(reg_index);
2125 774 : Node* rhs = GetAccumulator();
2126 774 : Node* context = GetContext();
2127 774 : Node* slot_index = BytecodeOperandIdx(1);
2128 774 : Node* feedback_vector = LoadFeedbackVector();
2129 :
2130 774 : Variable var_result(this, MachineRepresentation::kTagged),
2131 1548 : var_fcmp_lhs(this, MachineRepresentation::kFloat64),
2132 1548 : var_fcmp_rhs(this, MachineRepresentation::kFloat64),
2133 1548 : non_number_value(this, MachineRepresentation::kTagged),
2134 1548 : maybe_smi_value(this, MachineRepresentation::kTagged);
2135 774 : Label lhs_is_not_smi(this), do_fcmp(this), slow_path(this),
2136 774 : fast_path_dispatch(this);
2137 :
2138 774 : GotoIf(TaggedIsNotSmi(lhs), &lhs_is_not_smi);
2139 : {
2140 : Label rhs_is_not_smi(this);
2141 774 : GotoIf(TaggedIsNotSmi(rhs), &rhs_is_not_smi);
2142 : {
2143 774 : Comment("Do integer comparison");
2144 : UpdateFeedback(SmiConstant(CompareOperationFeedback::kSignedSmall),
2145 774 : feedback_vector, slot_index);
2146 : Node* result;
2147 774 : switch (compare_op) {
2148 : case Token::LT:
2149 129 : result = SelectBooleanConstant(SmiLessThan(lhs, rhs));
2150 129 : break;
2151 : case Token::LTE:
2152 129 : result = SelectBooleanConstant(SmiLessThanOrEqual(lhs, rhs));
2153 129 : break;
2154 : case Token::GT:
2155 129 : result = SelectBooleanConstant(SmiLessThan(rhs, lhs));
2156 129 : break;
2157 : case Token::GTE:
2158 129 : result = SelectBooleanConstant(SmiLessThanOrEqual(rhs, lhs));
2159 129 : break;
2160 : case Token::EQ:
2161 : case Token::EQ_STRICT:
2162 258 : result = SelectBooleanConstant(WordEqual(lhs, rhs));
2163 258 : break;
2164 : default:
2165 0 : UNREACHABLE();
2166 : }
2167 774 : var_result.Bind(result);
2168 774 : Goto(&fast_path_dispatch);
2169 : }
2170 :
2171 774 : Bind(&rhs_is_not_smi);
2172 : {
2173 774 : Node* rhs_map = LoadMap(rhs);
2174 : Label rhs_is_not_number(this);
2175 774 : GotoIfNot(IsHeapNumberMap(rhs_map), &rhs_is_not_number);
2176 :
2177 774 : Comment("Convert lhs to float and load HeapNumber value from rhs");
2178 774 : var_fcmp_lhs.Bind(SmiToFloat64(lhs));
2179 774 : var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs));
2180 774 : Goto(&do_fcmp);
2181 :
2182 774 : Bind(&rhs_is_not_number);
2183 : {
2184 774 : non_number_value.Bind(rhs);
2185 774 : maybe_smi_value.Bind(lhs);
2186 774 : Goto(&slow_path);
2187 774 : }
2188 774 : }
2189 : }
2190 :
2191 774 : Bind(&lhs_is_not_smi);
2192 : {
2193 774 : Label rhs_is_not_smi(this), lhs_is_not_number(this),
2194 774 : rhs_is_not_number(this);
2195 :
2196 774 : Node* lhs_map = LoadMap(lhs);
2197 774 : GotoIfNot(IsHeapNumberMap(lhs_map), &lhs_is_not_number);
2198 :
2199 774 : GotoIfNot(TaggedIsSmi(rhs), &rhs_is_not_smi);
2200 :
2201 774 : Comment("Convert rhs to double and load HeapNumber value from lhs");
2202 774 : var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs));
2203 774 : var_fcmp_rhs.Bind(SmiToFloat64(rhs));
2204 774 : Goto(&do_fcmp);
2205 :
2206 774 : Bind(&rhs_is_not_smi);
2207 : {
2208 774 : Node* rhs_map = LoadMap(rhs);
2209 774 : GotoIfNot(IsHeapNumberMap(rhs_map), &rhs_is_not_number);
2210 :
2211 774 : Comment("Load HeapNumber values from lhs and rhs");
2212 774 : var_fcmp_lhs.Bind(LoadHeapNumberValue(lhs));
2213 774 : var_fcmp_rhs.Bind(LoadHeapNumberValue(rhs));
2214 774 : Goto(&do_fcmp);
2215 : }
2216 :
2217 774 : Bind(&lhs_is_not_number);
2218 : {
2219 774 : non_number_value.Bind(lhs);
2220 774 : maybe_smi_value.Bind(rhs);
2221 774 : Goto(&slow_path);
2222 : }
2223 :
2224 774 : Bind(&rhs_is_not_number);
2225 : {
2226 774 : non_number_value.Bind(rhs);
2227 774 : maybe_smi_value.Bind(lhs);
2228 774 : Goto(&slow_path);
2229 774 : }
2230 : }
2231 :
2232 774 : Bind(&do_fcmp);
2233 : {
2234 774 : Comment("Do floating point comparison");
2235 774 : Node* lhs_float = var_fcmp_lhs.value();
2236 774 : Node* rhs_float = var_fcmp_rhs.value();
2237 : UpdateFeedback(SmiConstant(CompareOperationFeedback::kNumber),
2238 774 : feedback_vector, slot_index);
2239 :
2240 : // Perform a fast floating point comparison.
2241 : Node* result;
2242 774 : switch (compare_op) {
2243 : case Token::LT:
2244 129 : result = SelectBooleanConstant(Float64LessThan(lhs_float, rhs_float));
2245 129 : break;
2246 : case Token::LTE:
2247 : result = SelectBooleanConstant(
2248 129 : Float64LessThanOrEqual(lhs_float, rhs_float));
2249 129 : break;
2250 : case Token::GT:
2251 : result =
2252 129 : SelectBooleanConstant(Float64GreaterThan(lhs_float, rhs_float));
2253 129 : break;
2254 : case Token::GTE:
2255 : result = SelectBooleanConstant(
2256 129 : Float64GreaterThanOrEqual(lhs_float, rhs_float));
2257 129 : break;
2258 : case Token::EQ:
2259 : case Token::EQ_STRICT: {
2260 : Label check_nan(this);
2261 258 : var_result.Bind(BooleanConstant(false));
2262 : Branch(Float64Equal(lhs_float, rhs_float), &check_nan,
2263 258 : &fast_path_dispatch);
2264 258 : Bind(&check_nan);
2265 258 : result = SelectBooleanConstant(Float64Equal(lhs_float, lhs_float));
2266 258 : } break;
2267 : default:
2268 0 : UNREACHABLE();
2269 : }
2270 774 : var_result.Bind(result);
2271 774 : Goto(&fast_path_dispatch);
2272 : }
2273 :
2274 774 : Bind(&fast_path_dispatch);
2275 : {
2276 774 : SetAccumulator(var_result.value());
2277 774 : Dispatch();
2278 : }
2279 :
2280 : // Marking a block with more than one predecessor causes register allocator
2281 : // to fail (v8:5998). Add a dummy block as a workaround.
2282 : Label slow_path_deferred(this, Label::kDeferred);
2283 774 : Bind(&slow_path);
2284 774 : Goto(&slow_path_deferred);
2285 :
2286 774 : Bind(&slow_path_deferred);
2287 : {
2288 : // When we reach here, one of the operands is not a Smi / HeapNumber and
2289 : // the other operand could be of any type. The cases where both of them
2290 : // are HeapNumbers / Smis are handled earlier.
2291 774 : Comment("Collect feedback for non HeapNumber cases.");
2292 : Label update_feedback_and_do_compare(this);
2293 1548 : Variable var_type_feedback(this, MachineRepresentation::kTaggedSigned);
2294 774 : var_type_feedback.Bind(SmiConstant(CompareOperationFeedback::kAny));
2295 :
2296 774 : if (Token::IsOrderedRelationalCompareOp(compare_op)) {
2297 : Label check_for_oddball(this);
2298 : // Check for NumberOrOddball feedback.
2299 : Node* non_number_instance_type =
2300 516 : LoadInstanceType(non_number_value.value());
2301 : GotoIf(
2302 : Word32Equal(non_number_instance_type, Int32Constant(ODDBALL_TYPE)),
2303 516 : &check_for_oddball);
2304 :
2305 : // Check for string feedback.
2306 : GotoIfNot(IsStringInstanceType(non_number_instance_type),
2307 516 : &update_feedback_and_do_compare);
2308 :
2309 : GotoIf(TaggedIsSmi(maybe_smi_value.value()),
2310 516 : &update_feedback_and_do_compare);
2311 :
2312 : Node* maybe_smi_instance_type =
2313 516 : LoadInstanceType(maybe_smi_value.value());
2314 : GotoIfNot(IsStringInstanceType(maybe_smi_instance_type),
2315 516 : &update_feedback_and_do_compare);
2316 :
2317 516 : var_type_feedback.Bind(SmiConstant(CompareOperationFeedback::kString));
2318 516 : Goto(&update_feedback_and_do_compare);
2319 :
2320 516 : Bind(&check_for_oddball);
2321 : {
2322 : Label compare_with_oddball_feedback(this);
2323 : GotoIf(TaggedIsSmi(maybe_smi_value.value()),
2324 516 : &compare_with_oddball_feedback);
2325 :
2326 : Node* maybe_smi_instance_type =
2327 516 : LoadInstanceType(maybe_smi_value.value());
2328 : GotoIf(Word32Equal(maybe_smi_instance_type,
2329 : Int32Constant(HEAP_NUMBER_TYPE)),
2330 516 : &compare_with_oddball_feedback);
2331 :
2332 : Branch(
2333 : Word32Equal(maybe_smi_instance_type, Int32Constant(ODDBALL_TYPE)),
2334 516 : &compare_with_oddball_feedback, &update_feedback_and_do_compare);
2335 :
2336 516 : Bind(&compare_with_oddball_feedback);
2337 : {
2338 : var_type_feedback.Bind(
2339 516 : SmiConstant(CompareOperationFeedback::kNumberOrOddball));
2340 516 : Goto(&update_feedback_and_do_compare);
2341 516 : }
2342 516 : }
2343 : } else {
2344 258 : Label not_string(this), both_are_strings(this);
2345 :
2346 : DCHECK(Token::IsEqualityOp(compare_op));
2347 :
2348 : // If one of them is a Smi and the other is not a number, record "Any"
2349 : // feedback. Equality comparisons do not need feedback about oddballs.
2350 : GotoIf(TaggedIsSmi(maybe_smi_value.value()),
2351 258 : &update_feedback_and_do_compare);
2352 :
2353 : Node* maybe_smi_instance_type =
2354 258 : LoadInstanceType(maybe_smi_value.value());
2355 : Node* non_number_instance_type =
2356 258 : LoadInstanceType(non_number_value.value());
2357 258 : GotoIfNot(IsStringInstanceType(maybe_smi_instance_type), ¬_string);
2358 :
2359 : // If one value is string and other isn't record "Any" feedback.
2360 : Branch(IsStringInstanceType(non_number_instance_type),
2361 258 : &both_are_strings, &update_feedback_and_do_compare);
2362 :
2363 258 : Bind(&both_are_strings);
2364 : {
2365 : Node* operand1_feedback = SelectSmiConstant(
2366 : Word32Equal(Word32And(maybe_smi_instance_type,
2367 : Int32Constant(kIsNotInternalizedMask)),
2368 : Int32Constant(kInternalizedTag)),
2369 : CompareOperationFeedback::kInternalizedString,
2370 258 : CompareOperationFeedback::kString);
2371 :
2372 : Node* operand2_feedback = SelectSmiConstant(
2373 : Word32Equal(Word32And(non_number_instance_type,
2374 : Int32Constant(kIsNotInternalizedMask)),
2375 : Int32Constant(kInternalizedTag)),
2376 : CompareOperationFeedback::kInternalizedString,
2377 258 : CompareOperationFeedback::kString);
2378 :
2379 258 : var_type_feedback.Bind(SmiOr(operand1_feedback, operand2_feedback));
2380 258 : Goto(&update_feedback_and_do_compare);
2381 : }
2382 :
2383 258 : Bind(¬_string);
2384 : {
2385 : // Check if both operands are of type JSReceiver.
2386 : GotoIfNot(IsJSReceiverInstanceType(maybe_smi_instance_type),
2387 258 : &update_feedback_and_do_compare);
2388 :
2389 : GotoIfNot(IsJSReceiverInstanceType(non_number_instance_type),
2390 258 : &update_feedback_and_do_compare);
2391 :
2392 : var_type_feedback.Bind(
2393 258 : SmiConstant(CompareOperationFeedback::kReceiver));
2394 258 : Goto(&update_feedback_and_do_compare);
2395 258 : }
2396 : }
2397 :
2398 774 : Bind(&update_feedback_and_do_compare);
2399 : {
2400 774 : Comment("Do the full compare operation");
2401 774 : UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_index);
2402 : Node* result;
2403 774 : switch (compare_op) {
2404 : case Token::EQ:
2405 129 : result = Equal(lhs, rhs, context);
2406 129 : break;
2407 : case Token::EQ_STRICT:
2408 129 : result = StrictEqual(lhs, rhs);
2409 129 : break;
2410 : case Token::LT:
2411 : result = RelationalComparison(CodeStubAssembler::kLessThan, lhs,
2412 129 : rhs, context);
2413 129 : break;
2414 : case Token::GT:
2415 : result = RelationalComparison(CodeStubAssembler::kGreaterThan, lhs,
2416 129 : rhs, context);
2417 129 : break;
2418 : case Token::LTE:
2419 : result = RelationalComparison(CodeStubAssembler::kLessThanOrEqual,
2420 129 : lhs, rhs, context);
2421 129 : break;
2422 : case Token::GTE:
2423 : result = RelationalComparison(
2424 129 : CodeStubAssembler::kGreaterThanOrEqual, lhs, rhs, context);
2425 129 : break;
2426 : default:
2427 0 : UNREACHABLE();
2428 : }
2429 774 : var_result.Bind(result);
2430 774 : SetAccumulator(var_result.value());
2431 774 : Dispatch();
2432 774 : }
2433 1548 : }
2434 774 : }
2435 : };
2436 :
2437 : // TestEqual <src>
2438 : //
2439 : // Test if the value in the <src> register equals the accumulator.
2440 387 : IGNITION_HANDLER(TestEqual, InterpreterCompareOpAssembler) {
2441 129 : CompareOpWithFeedback(Token::Value::EQ);
2442 : }
2443 :
2444 : // TestEqualStrict <src>
2445 : //
2446 : // Test if the value in the <src> register is strictly equal to the accumulator.
2447 387 : IGNITION_HANDLER(TestEqualStrict, InterpreterCompareOpAssembler) {
2448 129 : CompareOpWithFeedback(Token::Value::EQ_STRICT);
2449 : }
2450 :
2451 : // TestLessThan <src>
2452 : //
2453 : // Test if the value in the <src> register is less than the accumulator.
2454 387 : IGNITION_HANDLER(TestLessThan, InterpreterCompareOpAssembler) {
2455 129 : CompareOpWithFeedback(Token::Value::LT);
2456 : }
2457 :
2458 : // TestGreaterThan <src>
2459 : //
2460 : // Test if the value in the <src> register is greater than the accumulator.
2461 387 : IGNITION_HANDLER(TestGreaterThan, InterpreterCompareOpAssembler) {
2462 129 : CompareOpWithFeedback(Token::Value::GT);
2463 : }
2464 :
2465 : // TestLessThanOrEqual <src>
2466 : //
2467 : // Test if the value in the <src> register is less than or equal to the
2468 : // accumulator.
2469 387 : IGNITION_HANDLER(TestLessThanOrEqual, InterpreterCompareOpAssembler) {
2470 129 : CompareOpWithFeedback(Token::Value::LTE);
2471 : }
2472 :
2473 : // TestGreaterThanOrEqual <src>
2474 : //
2475 : // Test if the value in the <src> register is greater than or equal to the
2476 : // accumulator.
2477 387 : IGNITION_HANDLER(TestGreaterThanOrEqual, InterpreterCompareOpAssembler) {
2478 129 : CompareOpWithFeedback(Token::Value::GTE);
2479 : }
2480 :
2481 : // TestEqualStrictNoFeedback <src>
2482 : //
2483 : // Test if the value in the <src> register is strictly equal to the accumulator.
2484 : // Type feedback is not collected.
2485 258 : IGNITION_HANDLER(TestEqualStrictNoFeedback, InterpreterAssembler) {
2486 129 : Node* reg_index = BytecodeOperandReg(0);
2487 129 : Node* lhs = LoadRegister(reg_index);
2488 129 : Node* rhs = GetAccumulator();
2489 : // TODO(5310): This is called only when lhs and rhs are Smis (for ex:
2490 : // try-finally or generators) or strings (only when visiting
2491 : // ClassLiteralProperties). We should be able to optimize this and not perform
2492 : // the full strict equality.
2493 129 : Node* result = StrictEqual(lhs, rhs);
2494 129 : SetAccumulator(result);
2495 129 : Dispatch();
2496 129 : }
2497 :
2498 : // TestIn <src>
2499 : //
2500 : // Test if the object referenced by the register operand is a property of the
2501 : // object referenced by the accumulator.
2502 258 : IGNITION_HANDLER(TestIn, InterpreterAssembler) {
2503 129 : Node* reg_index = BytecodeOperandReg(0);
2504 129 : Node* property = LoadRegister(reg_index);
2505 129 : Node* object = GetAccumulator();
2506 129 : Node* context = GetContext();
2507 129 : SetAccumulator(HasProperty(object, property, context));
2508 129 : Dispatch();
2509 129 : }
2510 :
2511 : // TestInstanceOf <src>
2512 : //
2513 : // Test if the object referenced by the <src> register is an an instance of type
2514 : // referenced by the accumulator.
2515 258 : IGNITION_HANDLER(TestInstanceOf, InterpreterAssembler) {
2516 129 : Node* reg_index = BytecodeOperandReg(0);
2517 129 : Node* name = LoadRegister(reg_index);
2518 129 : Node* object = GetAccumulator();
2519 129 : Node* context = GetContext();
2520 129 : SetAccumulator(InstanceOf(name, object, context));
2521 129 : Dispatch();
2522 129 : }
2523 :
2524 : // TestUndetectable
2525 : //
2526 : // Test if the value in the accumulator is undetectable (null, undefined or
2527 : // document.all).
2528 86 : IGNITION_HANDLER(TestUndetectable, InterpreterAssembler) {
2529 86 : Label return_false(this), end(this);
2530 43 : Node* object = GetAccumulator();
2531 :
2532 : // If the object is an Smi then return false.
2533 43 : SetAccumulator(BooleanConstant(false));
2534 43 : GotoIf(TaggedIsSmi(object), &end);
2535 :
2536 : // If it is a HeapObject, load the map and check for undetectable bit.
2537 43 : Node* map = LoadMap(object);
2538 43 : Node* map_bitfield = LoadMapBitField(map);
2539 : Node* map_undetectable =
2540 43 : Word32And(map_bitfield, Int32Constant(1 << Map::kIsUndetectable));
2541 : Node* result =
2542 43 : SelectBooleanConstant(Word32NotEqual(map_undetectable, Int32Constant(0)));
2543 43 : SetAccumulator(result);
2544 43 : Goto(&end);
2545 :
2546 43 : Bind(&end);
2547 86 : Dispatch();
2548 43 : }
2549 :
2550 : // TestNull
2551 : //
2552 : // Test if the value in accumulator is strictly equal to null.
2553 86 : IGNITION_HANDLER(TestNull, InterpreterAssembler) {
2554 43 : Node* object = GetAccumulator();
2555 86 : Node* null_value = HeapConstant(isolate()->factory()->null_value());
2556 43 : Node* result = SelectBooleanConstant(WordEqual(object, null_value));
2557 43 : SetAccumulator(result);
2558 43 : Dispatch();
2559 43 : }
2560 :
2561 : // TestUndefined
2562 : //
2563 : // Test if the value in the accumulator is strictly equal to undefined.
2564 86 : IGNITION_HANDLER(TestUndefined, InterpreterAssembler) {
2565 43 : Node* object = GetAccumulator();
2566 86 : Node* undefined_value = HeapConstant(isolate()->factory()->undefined_value());
2567 43 : Node* result = SelectBooleanConstant(WordEqual(object, undefined_value));
2568 43 : SetAccumulator(result);
2569 43 : Dispatch();
2570 43 : }
2571 :
2572 : // TestTypeOf <literal_flag>
2573 : //
2574 : // Tests if the object in the <accumulator> is typeof the literal represented
2575 : // by |literal_flag|.
2576 86 : IGNITION_HANDLER(TestTypeOf, InterpreterAssembler) {
2577 43 : Node* object = GetAccumulator();
2578 43 : Node* literal_flag = BytecodeOperandFlag(0);
2579 :
2580 : #define MAKE_LABEL(name, lower_case) Label if_##lower_case(this);
2581 86 : TYPEOF_LITERAL_LIST(MAKE_LABEL)
2582 : #undef MAKE_LABEL
2583 :
2584 : #define LABEL_POINTER(name, lower_case) &if_##lower_case,
2585 43 : Label* labels[] = {TYPEOF_LITERAL_LIST(LABEL_POINTER)};
2586 : #undef LABEL_POINTER
2587 :
2588 : #define CASE(name, lower_case) \
2589 : static_cast<int32_t>(TestTypeOfFlags::LiteralFlag::k##name),
2590 43 : int32_t cases[] = {TYPEOF_LITERAL_LIST(CASE)};
2591 : #undef CASE
2592 :
2593 43 : Label if_true(this), if_false(this), end(this), abort(this, Label::kDeferred);
2594 :
2595 43 : Switch(literal_flag, &abort, cases, labels, arraysize(cases));
2596 :
2597 43 : Bind(&abort);
2598 : {
2599 43 : Comment("Abort");
2600 43 : Abort(BailoutReason::kUnexpectedTestTypeofLiteralFlag);
2601 43 : Goto(&if_false);
2602 : }
2603 43 : Bind(&if_number);
2604 : {
2605 43 : Comment("IfNumber");
2606 43 : GotoIfNumber(object, &if_true);
2607 43 : Goto(&if_false);
2608 : }
2609 43 : Bind(&if_string);
2610 : {
2611 43 : Comment("IfString");
2612 43 : GotoIf(TaggedIsSmi(object), &if_false);
2613 43 : Branch(IsString(object), &if_true, &if_false);
2614 : }
2615 43 : Bind(&if_symbol);
2616 : {
2617 43 : Comment("IfSymbol");
2618 43 : GotoIf(TaggedIsSmi(object), &if_false);
2619 43 : Branch(IsSymbol(object), &if_true, &if_false);
2620 : }
2621 43 : Bind(&if_boolean);
2622 : {
2623 43 : Comment("IfBoolean");
2624 43 : GotoIf(WordEqual(object, BooleanConstant(true)), &if_true);
2625 43 : Branch(WordEqual(object, BooleanConstant(false)), &if_true, &if_false);
2626 : }
2627 43 : Bind(&if_undefined);
2628 : {
2629 43 : Comment("IfUndefined");
2630 43 : GotoIf(TaggedIsSmi(object), &if_false);
2631 : // Check it is not null and the map has the undetectable bit set.
2632 43 : GotoIf(WordEqual(object, NullConstant()), &if_false);
2633 43 : Node* map_bitfield = LoadMapBitField(LoadMap(object));
2634 : Node* undetectable_bit =
2635 43 : Word32And(map_bitfield, Int32Constant(1 << Map::kIsUndetectable));
2636 : Branch(Word32Equal(undetectable_bit, Int32Constant(0)), &if_false,
2637 43 : &if_true);
2638 : }
2639 43 : Bind(&if_function);
2640 : {
2641 43 : Comment("IfFunction");
2642 43 : GotoIf(TaggedIsSmi(object), &if_false);
2643 : // Check if callable bit is set and not undetectable.
2644 43 : Node* map_bitfield = LoadMapBitField(LoadMap(object));
2645 : Node* callable_undetectable = Word32And(
2646 : map_bitfield,
2647 43 : Int32Constant(1 << Map::kIsUndetectable | 1 << Map::kIsCallable));
2648 : Branch(Word32Equal(callable_undetectable,
2649 : Int32Constant(1 << Map::kIsCallable)),
2650 43 : &if_true, &if_false);
2651 : }
2652 43 : Bind(&if_object);
2653 : {
2654 43 : Comment("IfObject");
2655 43 : GotoIf(TaggedIsSmi(object), &if_false);
2656 :
2657 : // If the object is null then return true.
2658 43 : GotoIf(WordEqual(object, NullConstant()), &if_true);
2659 :
2660 : // Check if the object is a receiver type and is not undefined or callable.
2661 43 : Node* map = LoadMap(object);
2662 43 : GotoIfNot(IsJSReceiverMap(map), &if_false);
2663 43 : Node* map_bitfield = LoadMapBitField(map);
2664 : Node* callable_undetectable = Word32And(
2665 : map_bitfield,
2666 43 : Int32Constant(1 << Map::kIsUndetectable | 1 << Map::kIsCallable));
2667 : Branch(Word32Equal(callable_undetectable, Int32Constant(0)), &if_true,
2668 43 : &if_false);
2669 : }
2670 43 : Bind(&if_other);
2671 : {
2672 : // Typeof doesn't return any other string value.
2673 43 : Goto(&if_false);
2674 : }
2675 :
2676 43 : Bind(&if_false);
2677 : {
2678 43 : SetAccumulator(BooleanConstant(false));
2679 43 : Goto(&end);
2680 : }
2681 43 : Bind(&if_true);
2682 : {
2683 43 : SetAccumulator(BooleanConstant(true));
2684 43 : Goto(&end);
2685 : }
2686 43 : Bind(&end);
2687 86 : Dispatch();
2688 43 : }
2689 :
2690 : // Jump <imm>
2691 : //
2692 : // Jump by number of bytes represented by the immediate operand |imm|.
2693 258 : IGNITION_HANDLER(Jump, InterpreterAssembler) {
2694 129 : Node* relative_jump = BytecodeOperandUImmWord(0);
2695 129 : Jump(relative_jump);
2696 129 : }
2697 :
2698 : // JumpConstant <idx>
2699 : //
2700 : // Jump by number of bytes in the Smi in the |idx| entry in the constant pool.
2701 258 : IGNITION_HANDLER(JumpConstant, InterpreterAssembler) {
2702 129 : Node* index = BytecodeOperandIdx(0);
2703 129 : Node* relative_jump = LoadAndUntagConstantPoolEntry(index);
2704 129 : Jump(relative_jump);
2705 129 : }
2706 :
2707 : // JumpIfTrue <imm>
2708 : //
2709 : // Jump by number of bytes represented by an immediate operand if the
2710 : // accumulator contains true. This only works for boolean inputs, and
2711 : // will misbehave if passed arbitrary input values.
2712 258 : IGNITION_HANDLER(JumpIfTrue, InterpreterAssembler) {
2713 129 : Node* accumulator = GetAccumulator();
2714 129 : Node* relative_jump = BytecodeOperandUImmWord(0);
2715 129 : Node* true_value = BooleanConstant(true);
2716 : CSA_ASSERT(this, TaggedIsNotSmi(accumulator));
2717 : CSA_ASSERT(this, IsBoolean(accumulator));
2718 129 : JumpIfWordEqual(accumulator, true_value, relative_jump);
2719 129 : }
2720 :
2721 : // JumpIfTrueConstant <idx>
2722 : //
2723 : // Jump by number of bytes in the Smi in the |idx| entry in the constant pool
2724 : // if the accumulator contains true. This only works for boolean inputs, and
2725 : // will misbehave if passed arbitrary input values.
2726 258 : IGNITION_HANDLER(JumpIfTrueConstant, InterpreterAssembler) {
2727 129 : Node* accumulator = GetAccumulator();
2728 129 : Node* index = BytecodeOperandIdx(0);
2729 129 : Node* relative_jump = LoadAndUntagConstantPoolEntry(index);
2730 129 : Node* true_value = BooleanConstant(true);
2731 : CSA_ASSERT(this, TaggedIsNotSmi(accumulator));
2732 : CSA_ASSERT(this, IsBoolean(accumulator));
2733 129 : JumpIfWordEqual(accumulator, true_value, relative_jump);
2734 129 : }
2735 :
2736 : // JumpIfFalse <imm>
2737 : //
2738 : // Jump by number of bytes represented by an immediate operand if the
2739 : // accumulator contains false. This only works for boolean inputs, and
2740 : // will misbehave if passed arbitrary input values.
2741 258 : IGNITION_HANDLER(JumpIfFalse, InterpreterAssembler) {
2742 129 : Node* accumulator = GetAccumulator();
2743 129 : Node* relative_jump = BytecodeOperandUImmWord(0);
2744 129 : Node* false_value = BooleanConstant(false);
2745 : CSA_ASSERT(this, TaggedIsNotSmi(accumulator));
2746 : CSA_ASSERT(this, IsBoolean(accumulator));
2747 129 : JumpIfWordEqual(accumulator, false_value, relative_jump);
2748 129 : }
2749 :
2750 : // JumpIfFalseConstant <idx>
2751 : //
2752 : // Jump by number of bytes in the Smi in the |idx| entry in the constant pool
2753 : // if the accumulator contains false. This only works for boolean inputs, and
2754 : // will misbehave if passed arbitrary input values.
2755 258 : IGNITION_HANDLER(JumpIfFalseConstant, InterpreterAssembler) {
2756 129 : Node* accumulator = GetAccumulator();
2757 129 : Node* index = BytecodeOperandIdx(0);
2758 129 : Node* relative_jump = LoadAndUntagConstantPoolEntry(index);
2759 129 : Node* false_value = BooleanConstant(false);
2760 : CSA_ASSERT(this, TaggedIsNotSmi(accumulator));
2761 : CSA_ASSERT(this, IsBoolean(accumulator));
2762 129 : JumpIfWordEqual(accumulator, false_value, relative_jump);
2763 129 : }
2764 :
2765 : // JumpIfToBooleanTrue <imm>
2766 : //
2767 : // Jump by number of bytes represented by an immediate operand if the object
2768 : // referenced by the accumulator is true when the object is cast to boolean.
2769 258 : IGNITION_HANDLER(JumpIfToBooleanTrue, InterpreterAssembler) {
2770 129 : Node* value = GetAccumulator();
2771 129 : Node* relative_jump = BytecodeOperandUImmWord(0);
2772 258 : Label if_true(this), if_false(this);
2773 129 : BranchIfToBooleanIsTrue(value, &if_true, &if_false);
2774 129 : Bind(&if_true);
2775 129 : Jump(relative_jump);
2776 129 : Bind(&if_false);
2777 258 : Dispatch();
2778 129 : }
2779 :
2780 : // JumpIfToBooleanTrueConstant <idx>
2781 : //
2782 : // Jump by number of bytes in the Smi in the |idx| entry in the constant pool
2783 : // if the object referenced by the accumulator is true when the object is cast
2784 : // to boolean.
2785 258 : IGNITION_HANDLER(JumpIfToBooleanTrueConstant, InterpreterAssembler) {
2786 129 : Node* value = GetAccumulator();
2787 129 : Node* index = BytecodeOperandIdx(0);
2788 129 : Node* relative_jump = LoadAndUntagConstantPoolEntry(index);
2789 258 : Label if_true(this), if_false(this);
2790 129 : BranchIfToBooleanIsTrue(value, &if_true, &if_false);
2791 129 : Bind(&if_true);
2792 129 : Jump(relative_jump);
2793 129 : Bind(&if_false);
2794 258 : Dispatch();
2795 129 : }
2796 :
2797 : // JumpIfToBooleanFalse <imm>
2798 : //
2799 : // Jump by number of bytes represented by an immediate operand if the object
2800 : // referenced by the accumulator is false when the object is cast to boolean.
2801 258 : IGNITION_HANDLER(JumpIfToBooleanFalse, InterpreterAssembler) {
2802 129 : Node* value = GetAccumulator();
2803 129 : Node* relative_jump = BytecodeOperandUImmWord(0);
2804 258 : Label if_true(this), if_false(this);
2805 129 : BranchIfToBooleanIsTrue(value, &if_true, &if_false);
2806 129 : Bind(&if_true);
2807 129 : Dispatch();
2808 129 : Bind(&if_false);
2809 258 : Jump(relative_jump);
2810 129 : }
2811 :
2812 : // JumpIfToBooleanFalseConstant <idx>
2813 : //
2814 : // Jump by number of bytes in the Smi in the |idx| entry in the constant pool
2815 : // if the object referenced by the accumulator is false when the object is cast
2816 : // to boolean.
2817 258 : IGNITION_HANDLER(JumpIfToBooleanFalseConstant, InterpreterAssembler) {
2818 129 : Node* value = GetAccumulator();
2819 129 : Node* index = BytecodeOperandIdx(0);
2820 129 : Node* relative_jump = LoadAndUntagConstantPoolEntry(index);
2821 258 : Label if_true(this), if_false(this);
2822 129 : BranchIfToBooleanIsTrue(value, &if_true, &if_false);
2823 129 : Bind(&if_true);
2824 129 : Dispatch();
2825 129 : Bind(&if_false);
2826 258 : Jump(relative_jump);
2827 129 : }
2828 :
2829 : // JumpIfNull <imm>
2830 : //
2831 : // Jump by number of bytes represented by an immediate operand if the object
2832 : // referenced by the accumulator is the null constant.
2833 258 : IGNITION_HANDLER(JumpIfNull, InterpreterAssembler) {
2834 129 : Node* accumulator = GetAccumulator();
2835 258 : Node* null_value = HeapConstant(isolate()->factory()->null_value());
2836 129 : Node* relative_jump = BytecodeOperandUImmWord(0);
2837 129 : JumpIfWordEqual(accumulator, null_value, relative_jump);
2838 129 : }
2839 :
2840 : // JumpIfNullConstant <idx>
2841 : //
2842 : // Jump by number of bytes in the Smi in the |idx| entry in the constant pool
2843 : // if the object referenced by the accumulator is the null constant.
2844 258 : IGNITION_HANDLER(JumpIfNullConstant, InterpreterAssembler) {
2845 129 : Node* accumulator = GetAccumulator();
2846 258 : Node* null_value = HeapConstant(isolate()->factory()->null_value());
2847 129 : Node* index = BytecodeOperandIdx(0);
2848 129 : Node* relative_jump = LoadAndUntagConstantPoolEntry(index);
2849 129 : JumpIfWordEqual(accumulator, null_value, relative_jump);
2850 129 : }
2851 :
2852 : // JumpIfNotNull <imm>
2853 : //
2854 : // Jump by number of bytes represented by an immediate operand if the object
2855 : // referenced by the accumulator is not the null constant.
2856 258 : IGNITION_HANDLER(JumpIfNotNull, InterpreterAssembler) {
2857 129 : Node* accumulator = GetAccumulator();
2858 258 : Node* null_value = HeapConstant(isolate()->factory()->null_value());
2859 129 : Node* relative_jump = BytecodeOperandUImmWord(0);
2860 129 : JumpIfWordNotEqual(accumulator, null_value, relative_jump);
2861 129 : }
2862 :
2863 : // JumpIfNotNullConstant <idx>
2864 : //
2865 : // Jump by number of bytes in the Smi in the |idx| entry in the constant pool
2866 : // if the object referenced by the accumulator is not the null constant.
2867 258 : IGNITION_HANDLER(JumpIfNotNullConstant, InterpreterAssembler) {
2868 129 : Node* accumulator = GetAccumulator();
2869 258 : Node* null_value = HeapConstant(isolate()->factory()->null_value());
2870 129 : Node* index = BytecodeOperandIdx(0);
2871 129 : Node* relative_jump = LoadAndUntagConstantPoolEntry(index);
2872 129 : JumpIfWordNotEqual(accumulator, null_value, relative_jump);
2873 129 : }
2874 :
2875 : // JumpIfUndefined <imm>
2876 : //
2877 : // Jump by number of bytes represented by an immediate operand if the object
2878 : // referenced by the accumulator is the undefined constant.
2879 258 : IGNITION_HANDLER(JumpIfUndefined, InterpreterAssembler) {
2880 129 : Node* accumulator = GetAccumulator();
2881 258 : Node* undefined_value = HeapConstant(isolate()->factory()->undefined_value());
2882 129 : Node* relative_jump = BytecodeOperandUImmWord(0);
2883 129 : JumpIfWordEqual(accumulator, undefined_value, relative_jump);
2884 129 : }
2885 :
2886 : // JumpIfUndefinedConstant <idx>
2887 : //
2888 : // Jump by number of bytes in the Smi in the |idx| entry in the constant pool
2889 : // if the object referenced by the accumulator is the undefined constant.
2890 258 : IGNITION_HANDLER(JumpIfUndefinedConstant, InterpreterAssembler) {
2891 129 : Node* accumulator = GetAccumulator();
2892 258 : Node* undefined_value = HeapConstant(isolate()->factory()->undefined_value());
2893 129 : Node* index = BytecodeOperandIdx(0);
2894 129 : Node* relative_jump = LoadAndUntagConstantPoolEntry(index);
2895 129 : JumpIfWordEqual(accumulator, undefined_value, relative_jump);
2896 129 : }
2897 :
2898 : // JumpIfNotUndefined <imm>
2899 : //
2900 : // Jump by number of bytes represented by an immediate operand if the object
2901 : // referenced by the accumulator is not the undefined constant.
2902 258 : IGNITION_HANDLER(JumpIfNotUndefined, InterpreterAssembler) {
2903 129 : Node* accumulator = GetAccumulator();
2904 258 : Node* undefined_value = HeapConstant(isolate()->factory()->undefined_value());
2905 129 : Node* relative_jump = BytecodeOperandUImmWord(0);
2906 129 : JumpIfWordNotEqual(accumulator, undefined_value, relative_jump);
2907 129 : }
2908 :
2909 : // JumpIfNotUndefinedConstant <idx>
2910 : //
2911 : // Jump by number of bytes in the Smi in the |idx| entry in the constant pool
2912 : // if the object referenced by the accumulator is not the undefined constant.
2913 258 : IGNITION_HANDLER(JumpIfNotUndefinedConstant, InterpreterAssembler) {
2914 129 : Node* accumulator = GetAccumulator();
2915 258 : Node* undefined_value = HeapConstant(isolate()->factory()->undefined_value());
2916 129 : Node* index = BytecodeOperandIdx(0);
2917 129 : Node* relative_jump = LoadAndUntagConstantPoolEntry(index);
2918 129 : JumpIfWordNotEqual(accumulator, undefined_value, relative_jump);
2919 129 : }
2920 :
2921 : // JumpIfJSReceiver <imm>
2922 : //
2923 : // Jump by number of bytes represented by an immediate operand if the object
2924 : // referenced by the accumulator is a JSReceiver.
2925 258 : IGNITION_HANDLER(JumpIfJSReceiver, InterpreterAssembler) {
2926 129 : Node* accumulator = GetAccumulator();
2927 129 : Node* relative_jump = BytecodeOperandUImmWord(0);
2928 :
2929 258 : Label if_object(this), if_notobject(this, Label::kDeferred), if_notsmi(this);
2930 129 : Branch(TaggedIsSmi(accumulator), &if_notobject, &if_notsmi);
2931 :
2932 129 : Bind(&if_notsmi);
2933 129 : Branch(IsJSReceiver(accumulator), &if_object, &if_notobject);
2934 129 : Bind(&if_object);
2935 129 : Jump(relative_jump);
2936 :
2937 129 : Bind(&if_notobject);
2938 258 : Dispatch();
2939 129 : }
2940 :
2941 : // JumpIfJSReceiverConstant <idx>
2942 : //
2943 : // Jump by number of bytes in the Smi in the |idx| entry in the constant pool if
2944 : // the object referenced by the accumulator is a JSReceiver.
2945 258 : IGNITION_HANDLER(JumpIfJSReceiverConstant, InterpreterAssembler) {
2946 129 : Node* accumulator = GetAccumulator();
2947 129 : Node* index = BytecodeOperandIdx(0);
2948 129 : Node* relative_jump = LoadAndUntagConstantPoolEntry(index);
2949 :
2950 258 : Label if_object(this), if_notobject(this), if_notsmi(this);
2951 129 : Branch(TaggedIsSmi(accumulator), &if_notobject, &if_notsmi);
2952 :
2953 129 : Bind(&if_notsmi);
2954 129 : Branch(IsJSReceiver(accumulator), &if_object, &if_notobject);
2955 :
2956 129 : Bind(&if_object);
2957 129 : Jump(relative_jump);
2958 :
2959 129 : Bind(&if_notobject);
2960 258 : Dispatch();
2961 129 : }
2962 :
2963 : // JumpIfNotHole <imm>
2964 : //
2965 : // Jump by number of bytes represented by an immediate operand if the object
2966 : // referenced by the accumulator is the hole.
2967 258 : IGNITION_HANDLER(JumpIfNotHole, InterpreterAssembler) {
2968 129 : Node* accumulator = GetAccumulator();
2969 258 : Node* the_hole_value = HeapConstant(isolate()->factory()->the_hole_value());
2970 129 : Node* relative_jump = BytecodeOperandUImmWord(0);
2971 129 : JumpIfWordNotEqual(accumulator, the_hole_value, relative_jump);
2972 129 : }
2973 :
2974 : // JumpIfNotHoleConstant <idx>
2975 : //
2976 : // Jump by number of bytes in the Smi in the |idx| entry in the constant pool
2977 : // if the object referenced by the accumulator is the hole constant.
2978 258 : IGNITION_HANDLER(JumpIfNotHoleConstant, InterpreterAssembler) {
2979 129 : Node* accumulator = GetAccumulator();
2980 258 : Node* the_hole_value = HeapConstant(isolate()->factory()->the_hole_value());
2981 129 : Node* index = BytecodeOperandIdx(0);
2982 129 : Node* relative_jump = LoadAndUntagConstantPoolEntry(index);
2983 129 : JumpIfWordNotEqual(accumulator, the_hole_value, relative_jump);
2984 129 : }
2985 :
2986 : // JumpLoop <imm> <loop_depth>
2987 : //
2988 : // Jump by number of bytes represented by the immediate operand |imm|. Also
2989 : // performs a loop nesting check and potentially triggers OSR in case the
2990 : // current OSR level matches (or exceeds) the specified |loop_depth|.
2991 258 : IGNITION_HANDLER(JumpLoop, InterpreterAssembler) {
2992 129 : Node* relative_jump = BytecodeOperandUImmWord(0);
2993 129 : Node* loop_depth = BytecodeOperandImm(1);
2994 129 : Node* osr_level = LoadOSRNestingLevel();
2995 :
2996 : // Check if OSR points at the given {loop_depth} are armed by comparing it to
2997 : // the current {osr_level} loaded from the header of the BytecodeArray.
2998 258 : Label ok(this), osr_armed(this, Label::kDeferred);
2999 129 : Node* condition = Int32GreaterThanOrEqual(loop_depth, osr_level);
3000 129 : Branch(condition, &ok, &osr_armed);
3001 :
3002 129 : Bind(&ok);
3003 129 : JumpBackward(relative_jump);
3004 :
3005 129 : Bind(&osr_armed);
3006 : {
3007 129 : Callable callable = CodeFactory::InterpreterOnStackReplacement(isolate());
3008 129 : Node* target = HeapConstant(callable.code());
3009 129 : Node* context = GetContext();
3010 129 : CallStub(callable.descriptor(), target, context);
3011 129 : JumpBackward(relative_jump);
3012 129 : }
3013 129 : }
3014 :
3015 : // CreateRegExpLiteral <pattern_idx> <literal_idx> <flags>
3016 : //
3017 : // Creates a regular expression literal for literal index <literal_idx> with
3018 : // <flags> and the pattern in <pattern_idx>.
3019 258 : IGNITION_HANDLER(CreateRegExpLiteral, InterpreterAssembler) {
3020 129 : Node* index = BytecodeOperandIdx(0);
3021 129 : Node* pattern = LoadConstantPoolEntry(index);
3022 129 : Node* literal_index = BytecodeOperandIdxSmi(1);
3023 129 : Node* flags = SmiFromWord32(BytecodeOperandFlag(2));
3024 129 : Node* closure = LoadRegister(Register::function_closure());
3025 129 : Node* context = GetContext();
3026 : ConstructorBuiltinsAssembler constructor_assembler(state());
3027 : Node* result = constructor_assembler.EmitFastCloneRegExp(
3028 129 : closure, literal_index, pattern, flags, context);
3029 129 : SetAccumulator(result);
3030 129 : Dispatch();
3031 129 : }
3032 :
3033 : // CreateArrayLiteral <element_idx> <literal_idx> <flags>
3034 : //
3035 : // Creates an array literal for literal index <literal_idx> with
3036 : // CreateArrayLiteral flags <flags> and constant elements in <element_idx>.
3037 258 : IGNITION_HANDLER(CreateArrayLiteral, InterpreterAssembler) {
3038 129 : Node* literal_index = BytecodeOperandIdxSmi(1);
3039 129 : Node* closure = LoadRegister(Register::function_closure());
3040 129 : Node* context = GetContext();
3041 129 : Node* bytecode_flags = BytecodeOperandFlag(2);
3042 :
3043 258 : Label fast_shallow_clone(this), call_runtime(this, Label::kDeferred);
3044 : Branch(
3045 : IsSetWord32<CreateArrayLiteralFlags::FastShallowCloneBit>(bytecode_flags),
3046 258 : &fast_shallow_clone, &call_runtime);
3047 :
3048 129 : Bind(&fast_shallow_clone);
3049 : {
3050 : ConstructorBuiltinsAssembler constructor_assembler(state());
3051 : Node* result = constructor_assembler.EmitFastCloneShallowArray(
3052 129 : closure, literal_index, context, &call_runtime, TRACK_ALLOCATION_SITE);
3053 129 : SetAccumulator(result);
3054 129 : Dispatch();
3055 : }
3056 :
3057 129 : Bind(&call_runtime);
3058 : {
3059 : Node* flags_raw = DecodeWordFromWord32<CreateArrayLiteralFlags::FlagsBits>(
3060 129 : bytecode_flags);
3061 129 : Node* flags = SmiTag(flags_raw);
3062 129 : Node* index = BytecodeOperandIdx(0);
3063 129 : Node* constant_elements = LoadConstantPoolEntry(index);
3064 : Node* result = CallRuntime(Runtime::kCreateArrayLiteral, context, closure,
3065 129 : literal_index, constant_elements, flags);
3066 129 : SetAccumulator(result);
3067 129 : Dispatch();
3068 129 : }
3069 129 : }
3070 :
3071 : // CreateObjectLiteral <element_idx> <literal_idx> <flags>
3072 : //
3073 : // Creates an object literal for literal index <literal_idx> with
3074 : // CreateObjectLiteralFlags <flags> and constant elements in <element_idx>.
3075 258 : IGNITION_HANDLER(CreateObjectLiteral, InterpreterAssembler) {
3076 129 : Node* literal_index = BytecodeOperandIdxSmi(1);
3077 129 : Node* bytecode_flags = BytecodeOperandFlag(2);
3078 129 : Node* closure = LoadRegister(Register::function_closure());
3079 :
3080 : // Check if we can do a fast clone or have to call the runtime.
3081 258 : Label if_fast_clone(this), if_not_fast_clone(this, Label::kDeferred);
3082 : Node* fast_clone_properties_count = DecodeWordFromWord32<
3083 129 : CreateObjectLiteralFlags::FastClonePropertiesCountBits>(bytecode_flags);
3084 : Branch(WordNotEqual(fast_clone_properties_count, IntPtrConstant(0)),
3085 129 : &if_fast_clone, &if_not_fast_clone);
3086 :
3087 129 : Bind(&if_fast_clone);
3088 : {
3089 : // If we can do a fast clone do the fast-path in FastCloneShallowObjectStub.
3090 : ConstructorBuiltinsAssembler constructor_assembler(state());
3091 : Node* result = constructor_assembler.EmitFastCloneShallowObject(
3092 : &if_not_fast_clone, closure, literal_index,
3093 129 : fast_clone_properties_count);
3094 129 : StoreRegister(result, BytecodeOperandReg(3));
3095 129 : Dispatch();
3096 : }
3097 :
3098 129 : Bind(&if_not_fast_clone);
3099 : {
3100 : // If we can't do a fast clone, call into the runtime.
3101 129 : Node* index = BytecodeOperandIdx(0);
3102 129 : Node* constant_elements = LoadConstantPoolEntry(index);
3103 129 : Node* context = GetContext();
3104 :
3105 : Node* flags_raw = DecodeWordFromWord32<CreateObjectLiteralFlags::FlagsBits>(
3106 129 : bytecode_flags);
3107 129 : Node* flags = SmiTag(flags_raw);
3108 :
3109 : Node* result = CallRuntime(Runtime::kCreateObjectLiteral, context, closure,
3110 129 : literal_index, constant_elements, flags);
3111 129 : StoreRegister(result, BytecodeOperandReg(3));
3112 : // TODO(klaasb) build a single dispatch once the call is inlined
3113 129 : Dispatch();
3114 129 : }
3115 129 : }
3116 :
3117 : // CreateClosure <index> <slot> <tenured>
3118 : //
3119 : // Creates a new closure for SharedFunctionInfo at position |index| in the
3120 : // constant pool and with the PretenureFlag <tenured>.
3121 258 : IGNITION_HANDLER(CreateClosure, InterpreterAssembler) {
3122 129 : Node* index = BytecodeOperandIdx(0);
3123 129 : Node* shared = LoadConstantPoolEntry(index);
3124 129 : Node* flags = BytecodeOperandFlag(2);
3125 129 : Node* context = GetContext();
3126 :
3127 129 : Label call_runtime(this, Label::kDeferred);
3128 : GotoIfNot(IsSetWord32<CreateClosureFlags::FastNewClosureBit>(flags),
3129 258 : &call_runtime);
3130 : ConstructorBuiltinsAssembler constructor_assembler(state());
3131 129 : Node* vector_index = BytecodeOperandIdx(1);
3132 129 : vector_index = SmiTag(vector_index);
3133 129 : Node* feedback_vector = LoadFeedbackVector();
3134 : SetAccumulator(constructor_assembler.EmitFastNewClosure(
3135 129 : shared, feedback_vector, vector_index, context));
3136 129 : Dispatch();
3137 :
3138 129 : Bind(&call_runtime);
3139 : {
3140 : Node* tenured_raw =
3141 129 : DecodeWordFromWord32<CreateClosureFlags::PretenuredBit>(flags);
3142 129 : Node* tenured = SmiTag(tenured_raw);
3143 129 : feedback_vector = LoadFeedbackVector();
3144 129 : vector_index = BytecodeOperandIdx(1);
3145 129 : vector_index = SmiTag(vector_index);
3146 : Node* result = CallRuntime(Runtime::kInterpreterNewClosure, context, shared,
3147 129 : feedback_vector, vector_index, tenured);
3148 129 : SetAccumulator(result);
3149 129 : Dispatch();
3150 129 : }
3151 129 : }
3152 :
3153 : // CreateBlockContext <index>
3154 : //
3155 : // Creates a new block context with the scope info constant at |index| and the
3156 : // closure in the accumulator.
3157 258 : IGNITION_HANDLER(CreateBlockContext, InterpreterAssembler) {
3158 129 : Node* index = BytecodeOperandIdx(0);
3159 129 : Node* scope_info = LoadConstantPoolEntry(index);
3160 129 : Node* closure = GetAccumulator();
3161 129 : Node* context = GetContext();
3162 : SetAccumulator(
3163 129 : CallRuntime(Runtime::kPushBlockContext, context, scope_info, closure));
3164 129 : Dispatch();
3165 129 : }
3166 :
3167 : // CreateCatchContext <exception> <name_idx> <scope_info_idx>
3168 : //
3169 : // Creates a new context for a catch block with the |exception| in a register,
3170 : // the variable name at |name_idx|, the ScopeInfo at |scope_info_idx|, and the
3171 : // closure in the accumulator.
3172 258 : IGNITION_HANDLER(CreateCatchContext, InterpreterAssembler) {
3173 129 : Node* exception_reg = BytecodeOperandReg(0);
3174 129 : Node* exception = LoadRegister(exception_reg);
3175 129 : Node* name_idx = BytecodeOperandIdx(1);
3176 129 : Node* name = LoadConstantPoolEntry(name_idx);
3177 129 : Node* scope_info_idx = BytecodeOperandIdx(2);
3178 129 : Node* scope_info = LoadConstantPoolEntry(scope_info_idx);
3179 129 : Node* closure = GetAccumulator();
3180 129 : Node* context = GetContext();
3181 : SetAccumulator(CallRuntime(Runtime::kPushCatchContext, context, name,
3182 129 : exception, scope_info, closure));
3183 129 : Dispatch();
3184 129 : }
3185 :
3186 : // CreateFunctionContext <slots>
3187 : //
3188 : // Creates a new context with number of |slots| for the function closure.
3189 258 : IGNITION_HANDLER(CreateFunctionContext, InterpreterAssembler) {
3190 129 : Node* closure = LoadRegister(Register::function_closure());
3191 129 : Node* slots = BytecodeOperandUImm(0);
3192 129 : Node* context = GetContext();
3193 : ConstructorBuiltinsAssembler constructor_assembler(state());
3194 : SetAccumulator(constructor_assembler.EmitFastNewFunctionContext(
3195 129 : closure, slots, context, FUNCTION_SCOPE));
3196 129 : Dispatch();
3197 129 : }
3198 :
3199 : // CreateEvalContext <slots>
3200 : //
3201 : // Creates a new context with number of |slots| for an eval closure.
3202 258 : IGNITION_HANDLER(CreateEvalContext, InterpreterAssembler) {
3203 129 : Node* closure = LoadRegister(Register::function_closure());
3204 129 : Node* slots = BytecodeOperandUImm(0);
3205 129 : Node* context = GetContext();
3206 : ConstructorBuiltinsAssembler constructor_assembler(state());
3207 : SetAccumulator(constructor_assembler.EmitFastNewFunctionContext(
3208 129 : closure, slots, context, EVAL_SCOPE));
3209 129 : Dispatch();
3210 129 : }
3211 :
3212 : // CreateWithContext <register> <scope_info_idx>
3213 : //
3214 : // Creates a new context with the ScopeInfo at |scope_info_idx| for a
3215 : // with-statement with the object in |register| and the closure in the
3216 : // accumulator.
3217 258 : IGNITION_HANDLER(CreateWithContext, InterpreterAssembler) {
3218 129 : Node* reg_index = BytecodeOperandReg(0);
3219 129 : Node* object = LoadRegister(reg_index);
3220 129 : Node* scope_info_idx = BytecodeOperandIdx(1);
3221 129 : Node* scope_info = LoadConstantPoolEntry(scope_info_idx);
3222 129 : Node* closure = GetAccumulator();
3223 129 : Node* context = GetContext();
3224 : SetAccumulator(CallRuntime(Runtime::kPushWithContext, context, object,
3225 129 : scope_info, closure));
3226 129 : Dispatch();
3227 129 : }
3228 :
3229 : // CreateMappedArguments
3230 : //
3231 : // Creates a new mapped arguments object.
3232 86 : IGNITION_HANDLER(CreateMappedArguments, InterpreterAssembler) {
3233 43 : Node* closure = LoadRegister(Register::function_closure());
3234 43 : Node* context = GetContext();
3235 :
3236 43 : Label if_duplicate_parameters(this, Label::kDeferred);
3237 43 : Label if_not_duplicate_parameters(this);
3238 :
3239 : // Check if function has duplicate parameters.
3240 : // TODO(rmcilroy): Remove this check when FastNewSloppyArgumentsStub supports
3241 : // duplicate parameters.
3242 : Node* shared_info =
3243 43 : LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset);
3244 : Node* compiler_hints = LoadObjectField(
3245 : shared_info, SharedFunctionInfo::kHasDuplicateParametersByteOffset,
3246 43 : MachineType::Uint8());
3247 : Node* duplicate_parameters_bit = Int32Constant(
3248 43 : 1 << SharedFunctionInfo::kHasDuplicateParametersBitWithinByte);
3249 43 : Node* compare = Word32And(compiler_hints, duplicate_parameters_bit);
3250 43 : Branch(compare, &if_duplicate_parameters, &if_not_duplicate_parameters);
3251 :
3252 43 : Bind(&if_not_duplicate_parameters);
3253 : {
3254 : ArgumentsBuiltinsAssembler constructor_assembler(state());
3255 : Node* result =
3256 43 : constructor_assembler.EmitFastNewSloppyArguments(context, closure);
3257 43 : SetAccumulator(result);
3258 43 : Dispatch();
3259 : }
3260 :
3261 43 : Bind(&if_duplicate_parameters);
3262 : {
3263 : Node* result =
3264 43 : CallRuntime(Runtime::kNewSloppyArguments_Generic, context, closure);
3265 43 : SetAccumulator(result);
3266 43 : Dispatch();
3267 43 : }
3268 43 : }
3269 :
3270 : // CreateUnmappedArguments
3271 : //
3272 : // Creates a new unmapped arguments object.
3273 86 : IGNITION_HANDLER(CreateUnmappedArguments, InterpreterAssembler) {
3274 43 : Node* context = GetContext();
3275 43 : Node* closure = LoadRegister(Register::function_closure());
3276 : ArgumentsBuiltinsAssembler builtins_assembler(state());
3277 : Node* result =
3278 43 : builtins_assembler.EmitFastNewStrictArguments(context, closure);
3279 43 : SetAccumulator(result);
3280 43 : Dispatch();
3281 43 : }
3282 :
3283 : // CreateRestParameter
3284 : //
3285 : // Creates a new rest parameter array.
3286 86 : IGNITION_HANDLER(CreateRestParameter, InterpreterAssembler) {
3287 43 : Node* closure = LoadRegister(Register::function_closure());
3288 43 : Node* context = GetContext();
3289 : ArgumentsBuiltinsAssembler builtins_assembler(state());
3290 43 : Node* result = builtins_assembler.EmitFastNewRestParameter(context, closure);
3291 43 : SetAccumulator(result);
3292 43 : Dispatch();
3293 43 : }
3294 :
3295 : // StackCheck
3296 : //
3297 : // Performs a stack guard check.
3298 86 : IGNITION_HANDLER(StackCheck, InterpreterAssembler) {
3299 86 : Label ok(this), stack_check_interrupt(this, Label::kDeferred);
3300 :
3301 43 : Node* interrupt = StackCheckTriggeredInterrupt();
3302 43 : Branch(interrupt, &stack_check_interrupt, &ok);
3303 :
3304 43 : Bind(&ok);
3305 43 : Dispatch();
3306 :
3307 43 : Bind(&stack_check_interrupt);
3308 : {
3309 43 : Node* context = GetContext();
3310 43 : CallRuntime(Runtime::kStackGuard, context);
3311 43 : Dispatch();
3312 43 : }
3313 43 : }
3314 :
3315 : // SetPendingMessage
3316 : //
3317 : // Sets the pending message to the value in the accumulator, and returns the
3318 : // previous pending message in the accumulator.
3319 86 : IGNITION_HANDLER(SetPendingMessage, InterpreterAssembler) {
3320 : Node* pending_message = ExternalConstant(
3321 43 : ExternalReference::address_of_pending_message_obj(isolate()));
3322 43 : Node* previous_message = Load(MachineType::TaggedPointer(), pending_message);
3323 43 : Node* new_message = GetAccumulator();
3324 : StoreNoWriteBarrier(MachineRepresentation::kTaggedPointer, pending_message,
3325 43 : new_message);
3326 43 : SetAccumulator(previous_message);
3327 43 : Dispatch();
3328 43 : }
3329 :
3330 : // Throw
3331 : //
3332 : // Throws the exception in the accumulator.
3333 86 : IGNITION_HANDLER(Throw, InterpreterAssembler) {
3334 43 : Node* exception = GetAccumulator();
3335 43 : Node* context = GetContext();
3336 43 : CallRuntime(Runtime::kThrow, context, exception);
3337 : // We shouldn't ever return from a throw.
3338 43 : Abort(kUnexpectedReturnFromThrow);
3339 43 : }
3340 :
3341 : // ReThrow
3342 : //
3343 : // Re-throws the exception in the accumulator.
3344 86 : IGNITION_HANDLER(ReThrow, InterpreterAssembler) {
3345 43 : Node* exception = GetAccumulator();
3346 43 : Node* context = GetContext();
3347 43 : CallRuntime(Runtime::kReThrow, context, exception);
3348 : // We shouldn't ever return from a throw.
3349 43 : Abort(kUnexpectedReturnFromThrow);
3350 43 : }
3351 :
3352 : // Return
3353 : //
3354 : // Return the value in the accumulator.
3355 86 : IGNITION_HANDLER(Return, InterpreterAssembler) {
3356 43 : UpdateInterruptBudgetOnReturn();
3357 43 : Node* accumulator = GetAccumulator();
3358 43 : Return(accumulator);
3359 43 : }
3360 :
3361 : // Debugger
3362 : //
3363 : // Call runtime to handle debugger statement.
3364 86 : IGNITION_HANDLER(Debugger, InterpreterAssembler) {
3365 43 : Node* context = GetContext();
3366 86 : CallStub(CodeFactory::HandleDebuggerStatement(isolate()), context);
3367 43 : Dispatch();
3368 43 : }
3369 :
3370 : // DebugBreak
3371 : //
3372 : // Call runtime to handle a debug break.
3373 : #define DEBUG_BREAK(Name, ...) \
3374 : IGNITION_HANDLER(Name, InterpreterAssembler) { \
3375 : Node* context = GetContext(); \
3376 : Node* accumulator = GetAccumulator(); \
3377 : Node* original_handler = \
3378 : CallRuntime(Runtime::kDebugBreakOnBytecode, context, accumulator); \
3379 : MaybeDropFrames(context); \
3380 : DispatchToBytecodeHandler(original_handler); \
3381 : }
3382 1806 : DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK);
3383 : #undef DEBUG_BREAK
3384 :
3385 129 : class InterpreterForInPrepareAssembler : public InterpreterAssembler {
3386 : public:
3387 : InterpreterForInPrepareAssembler(CodeAssemblerState* state, Bytecode bytecode,
3388 : OperandScale operand_scale)
3389 129 : : InterpreterAssembler(state, bytecode, operand_scale) {}
3390 :
3391 387 : void BuildForInPrepareResult(Node* output_register, Node* cache_type,
3392 : Node* cache_array, Node* cache_length) {
3393 387 : StoreRegister(cache_type, output_register);
3394 387 : output_register = NextRegister(output_register);
3395 387 : StoreRegister(cache_array, output_register);
3396 387 : output_register = NextRegister(output_register);
3397 387 : StoreRegister(cache_length, output_register);
3398 387 : }
3399 : };
3400 :
3401 : // ForInPrepare <receiver> <cache_info_triple>
3402 : //
3403 : // Returns state for for..in loop execution based on the object in the register
3404 : // |receiver|. The object must not be null or undefined and must have been
3405 : // converted to a receiver already.
3406 : // The result is output in registers |cache_info_triple| to
3407 : // |cache_info_triple + 2|, with the registers holding cache_type, cache_array,
3408 : // and cache_length respectively.
3409 516 : IGNITION_HANDLER(ForInPrepare, InterpreterForInPrepareAssembler) {
3410 129 : Node* object_register = BytecodeOperandReg(0);
3411 129 : Node* output_register = BytecodeOperandReg(1);
3412 129 : Node* receiver = LoadRegister(object_register);
3413 129 : Node* context = GetContext();
3414 :
3415 : Node* cache_type;
3416 : Node* cache_array;
3417 : Node* cache_length;
3418 129 : Label call_runtime(this, Label::kDeferred),
3419 129 : nothing_to_iterate(this, Label::kDeferred);
3420 :
3421 : ForInBuiltinsAssembler forin_assembler(state());
3422 258 : std::tie(cache_type, cache_array, cache_length) =
3423 : forin_assembler.EmitForInPrepare(receiver, context, &call_runtime,
3424 : ¬hing_to_iterate);
3425 :
3426 : BuildForInPrepareResult(output_register, cache_type, cache_array,
3427 129 : cache_length);
3428 129 : Dispatch();
3429 :
3430 129 : Bind(&call_runtime);
3431 : {
3432 : Node* result_triple =
3433 129 : CallRuntime(Runtime::kForInPrepare, context, receiver);
3434 129 : Node* cache_type = Projection(0, result_triple);
3435 129 : Node* cache_array = Projection(1, result_triple);
3436 129 : Node* cache_length = Projection(2, result_triple);
3437 : BuildForInPrepareResult(output_register, cache_type, cache_array,
3438 129 : cache_length);
3439 129 : Dispatch();
3440 : }
3441 129 : Bind(¬hing_to_iterate);
3442 : {
3443 : // Receiver is null or undefined or descriptors are zero length.
3444 129 : Node* zero = SmiConstant(0);
3445 129 : BuildForInPrepareResult(output_register, zero, zero, zero);
3446 129 : Dispatch();
3447 129 : }
3448 129 : }
3449 :
3450 : // ForInNext <receiver> <index> <cache_info_pair>
3451 : //
3452 : // Returns the next enumerable property in the the accumulator.
3453 258 : IGNITION_HANDLER(ForInNext, InterpreterAssembler) {
3454 129 : Node* receiver_reg = BytecodeOperandReg(0);
3455 129 : Node* receiver = LoadRegister(receiver_reg);
3456 129 : Node* index_reg = BytecodeOperandReg(1);
3457 129 : Node* index = LoadRegister(index_reg);
3458 129 : Node* cache_type_reg = BytecodeOperandReg(2);
3459 129 : Node* cache_type = LoadRegister(cache_type_reg);
3460 129 : Node* cache_array_reg = NextRegister(cache_type_reg);
3461 129 : Node* cache_array = LoadRegister(cache_array_reg);
3462 :
3463 : // Load the next key from the enumeration array.
3464 : Node* key = LoadFixedArrayElement(cache_array, index, 0,
3465 129 : CodeStubAssembler::SMI_PARAMETERS);
3466 :
3467 : // Check if we can use the for-in fast path potentially using the enum cache.
3468 258 : Label if_fast(this), if_slow(this, Label::kDeferred);
3469 129 : Node* receiver_map = LoadMap(receiver);
3470 129 : Branch(WordEqual(receiver_map, cache_type), &if_fast, &if_slow);
3471 129 : Bind(&if_fast);
3472 : {
3473 : // Enum cache in use for {receiver}, the {key} is definitely valid.
3474 129 : SetAccumulator(key);
3475 129 : Dispatch();
3476 : }
3477 129 : Bind(&if_slow);
3478 : {
3479 : // Record the fact that we hit the for-in slow path.
3480 129 : Node* vector_index = BytecodeOperandIdx(3);
3481 129 : Node* feedback_vector = LoadFeedbackVector();
3482 : Node* megamorphic_sentinel =
3483 258 : HeapConstant(FeedbackVector::MegamorphicSentinel(isolate()));
3484 : StoreFixedArrayElement(feedback_vector, vector_index, megamorphic_sentinel,
3485 129 : SKIP_WRITE_BARRIER);
3486 :
3487 : // Need to filter the {key} for the {receiver}.
3488 129 : Node* context = GetContext();
3489 129 : Callable callable = CodeFactory::ForInFilter(isolate());
3490 129 : Node* result = CallStub(callable, context, key, receiver);
3491 129 : SetAccumulator(result);
3492 129 : Dispatch();
3493 129 : }
3494 129 : }
3495 :
3496 : // ForInContinue <index> <cache_length>
3497 : //
3498 : // Returns false if the end of the enumerable properties has been reached.
3499 258 : IGNITION_HANDLER(ForInContinue, InterpreterAssembler) {
3500 129 : Node* index_reg = BytecodeOperandReg(0);
3501 129 : Node* index = LoadRegister(index_reg);
3502 129 : Node* cache_length_reg = BytecodeOperandReg(1);
3503 129 : Node* cache_length = LoadRegister(cache_length_reg);
3504 :
3505 : // Check if {index} is at {cache_length} already.
3506 258 : Label if_true(this), if_false(this), end(this);
3507 129 : Branch(WordEqual(index, cache_length), &if_true, &if_false);
3508 129 : Bind(&if_true);
3509 : {
3510 129 : SetAccumulator(BooleanConstant(false));
3511 129 : Goto(&end);
3512 : }
3513 129 : Bind(&if_false);
3514 : {
3515 129 : SetAccumulator(BooleanConstant(true));
3516 129 : Goto(&end);
3517 : }
3518 129 : Bind(&end);
3519 258 : Dispatch();
3520 129 : }
3521 :
3522 : // ForInStep <index>
3523 : //
3524 : // Increments the loop counter in register |index| and stores the result
3525 : // in the accumulator.
3526 258 : IGNITION_HANDLER(ForInStep, InterpreterAssembler) {
3527 129 : Node* index_reg = BytecodeOperandReg(0);
3528 129 : Node* index = LoadRegister(index_reg);
3529 129 : Node* one = SmiConstant(Smi::FromInt(1));
3530 129 : Node* result = SmiAdd(index, one);
3531 129 : SetAccumulator(result);
3532 129 : Dispatch();
3533 129 : }
3534 :
3535 : // Wide
3536 : //
3537 : // Prefix bytecode indicating next bytecode has wide (16-bit) operands.
3538 86 : IGNITION_HANDLER(Wide, InterpreterAssembler) {
3539 43 : DispatchWide(OperandScale::kDouble);
3540 : }
3541 :
3542 : // ExtraWide
3543 : //
3544 : // Prefix bytecode indicating next bytecode has extra-wide (32-bit) operands.
3545 86 : IGNITION_HANDLER(ExtraWide, InterpreterAssembler) {
3546 43 : DispatchWide(OperandScale::kQuadruple);
3547 : }
3548 :
3549 : // Illegal
3550 : //
3551 : // An invalid bytecode aborting execution if dispatched.
3552 43 : IGNITION_HANDLER(Illegal, InterpreterAssembler) { Abort(kInvalidBytecode); }
3553 :
3554 : // Nop
3555 : //
3556 : // No operation.
3557 43 : IGNITION_HANDLER(Nop, InterpreterAssembler) { Dispatch(); }
3558 :
3559 : // SuspendGenerator <generator>
3560 : //
3561 : // Exports the register file and stores it into the generator. Also stores the
3562 : // current context, the state given in the accumulator, and the current bytecode
3563 : // offset (for debugging purposes) into the generator.
3564 258 : IGNITION_HANDLER(SuspendGenerator, InterpreterAssembler) {
3565 129 : Node* generator_reg = BytecodeOperandReg(0);
3566 129 : Node* flags = BytecodeOperandFlag(1);
3567 129 : Node* generator = LoadRegister(generator_reg);
3568 :
3569 258 : Label if_stepping(this, Label::kDeferred), ok(this);
3570 : Node* step_action_address = ExternalConstant(
3571 129 : ExternalReference::debug_last_step_action_address(isolate()));
3572 129 : Node* step_action = Load(MachineType::Int8(), step_action_address);
3573 : STATIC_ASSERT(StepIn > StepNext);
3574 : STATIC_ASSERT(LastStepAction == StepIn);
3575 129 : Node* step_next = Int32Constant(StepNext);
3576 129 : Branch(Int32LessThanOrEqual(step_next, step_action), &if_stepping, &ok);
3577 129 : Bind(&ok);
3578 :
3579 : Node* array =
3580 129 : LoadObjectField(generator, JSGeneratorObject::kRegisterFileOffset);
3581 129 : Node* context = GetContext();
3582 129 : Node* state = GetAccumulator();
3583 :
3584 129 : ExportRegisterFile(array);
3585 129 : StoreObjectField(generator, JSGeneratorObject::kContextOffset, context);
3586 129 : StoreObjectField(generator, JSGeneratorObject::kContinuationOffset, state);
3587 :
3588 129 : Label if_asyncgeneratorawait(this), if_notasyncgeneratorawait(this),
3589 129 : merge(this);
3590 :
3591 : // Calculate bytecode offset to store in the [input_or_debug_pos] or
3592 : // [await_input_or_debug_pos] fields, to be used by the inspector.
3593 129 : Node* offset = SmiTag(BytecodeOffset());
3594 :
3595 : using AsyncGeneratorAwaitBits = SuspendGeneratorBytecodeFlags::FlagsBits;
3596 : Branch(Word32Equal(DecodeWord32<AsyncGeneratorAwaitBits>(flags),
3597 : Int32Constant(
3598 : static_cast<int>(SuspendFlags::kAsyncGeneratorAwait))),
3599 258 : &if_asyncgeneratorawait, &if_notasyncgeneratorawait);
3600 :
3601 129 : Bind(&if_notasyncgeneratorawait);
3602 : {
3603 : // For ordinary yields (and for AwaitExpressions in Async Functions, which
3604 : // are implemented as ordinary yields), it is safe to write over the
3605 : // [input_or_debug_pos] field.
3606 : StoreObjectField(generator, JSGeneratorObject::kInputOrDebugPosOffset,
3607 129 : offset);
3608 129 : Goto(&merge);
3609 : }
3610 :
3611 129 : Bind(&if_asyncgeneratorawait);
3612 : {
3613 : // An AwaitExpression in an Async Generator requires writing to the
3614 : // [await_input_or_debug_pos] field.
3615 : CSA_ASSERT(this,
3616 : HasInstanceType(generator, JS_ASYNC_GENERATOR_OBJECT_TYPE));
3617 : StoreObjectField(
3618 129 : generator, JSAsyncGeneratorObject::kAwaitInputOrDebugPosOffset, offset);
3619 129 : Goto(&merge);
3620 : }
3621 :
3622 129 : Bind(&merge);
3623 129 : Dispatch();
3624 :
3625 129 : Bind(&if_stepping);
3626 : {
3627 129 : Node* context = GetContext();
3628 129 : CallRuntime(Runtime::kDebugRecordGenerator, context, generator);
3629 129 : Goto(&ok);
3630 129 : }
3631 129 : }
3632 :
3633 : // ResumeGenerator <generator>
3634 : //
3635 : // Imports the register file stored in the generator. Also loads the
3636 : // generator's state and stores it in the accumulator, before overwriting it
3637 : // with kGeneratorExecuting.
3638 258 : IGNITION_HANDLER(ResumeGenerator, InterpreterAssembler) {
3639 129 : Node* generator_reg = BytecodeOperandReg(0);
3640 129 : Node* generator = LoadRegister(generator_reg);
3641 :
3642 : ImportRegisterFile(
3643 129 : LoadObjectField(generator, JSGeneratorObject::kRegisterFileOffset));
3644 :
3645 : Node* old_state =
3646 129 : LoadObjectField(generator, JSGeneratorObject::kContinuationOffset);
3647 129 : Node* new_state = Int32Constant(JSGeneratorObject::kGeneratorExecuting);
3648 : StoreObjectField(generator, JSGeneratorObject::kContinuationOffset,
3649 129 : SmiTag(new_state));
3650 129 : SetAccumulator(old_state);
3651 :
3652 129 : Dispatch();
3653 129 : }
3654 :
3655 : } // namespace
3656 :
3657 18533 : Handle<Code> GenerateBytecodeHandler(Isolate* isolate, Bytecode bytecode,
3658 : OperandScale operand_scale) {
3659 18533 : Zone zone(isolate->allocator(), ZONE_NAME);
3660 18533 : InterpreterDispatchDescriptor descriptor(isolate);
3661 : compiler::CodeAssemblerState state(
3662 : isolate, &zone, descriptor, Code::ComputeFlags(Code::BYTECODE_HANDLER),
3663 37066 : Bytecodes::ToString(bytecode), Bytecodes::ReturnCount(bytecode));
3664 :
3665 18533 : switch (bytecode) {
3666 : #define CALL_GENERATOR(Name, ...) \
3667 : case Bytecode::k##Name: \
3668 : Name##Assembler::Generate(&state, operand_scale); \
3669 : break;
3670 43 : BYTECODE_LIST(CALL_GENERATOR);
3671 : #undef CALL_GENERATOR
3672 : }
3673 :
3674 18533 : Handle<Code> code = compiler::CodeAssembler::GenerateCode(&state);
3675 55599 : PROFILE(isolate, CodeCreateEvent(
3676 : CodeEventListener::BYTECODE_HANDLER_TAG,
3677 : AbstractCode::cast(*code),
3678 : Bytecodes::ToString(bytecode, operand_scale).c_str()));
3679 : #ifdef ENABLE_DISASSEMBLER
3680 : if (FLAG_trace_ignition_codegen) {
3681 : OFStream os(stdout);
3682 : code->Disassemble(Bytecodes::ToString(bytecode), os);
3683 : os << std::flush;
3684 : }
3685 : #endif // ENABLE_DISASSEMBLER
3686 37066 : return code;
3687 : }
3688 :
3689 : } // namespace interpreter
3690 : } // namespace internal
3691 : } // namespace v8
|