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