interpreter-generator.cc 111 KB
Newer Older
1 2 3 4 5 6 7 8 9
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/interpreter/interpreter-generator.h"

#include <array>
#include <tuple>

10
#include "src/builtins/builtins-constructor-gen.h"
11
#include "src/builtins/builtins-iterator-gen.h"
12
#include "src/codegen/code-factory.h"
13
#include "src/debug/debug.h"
14
#include "src/ic/accessor-assembler.h"
15
#include "src/ic/binary-op-assembler.h"
16
#include "src/ic/ic.h"
17
#include "src/ic/unary-op-assembler.h"
18 19 20
#include "src/interpreter/bytecode-flags.h"
#include "src/interpreter/bytecodes.h"
#include "src/interpreter/interpreter-assembler.h"
21
#include "src/interpreter/interpreter-intrinsics-generator.h"
22
#include "src/objects/cell.h"
23
#include "src/objects/js-generator.h"
24
#include "src/objects/objects-inl.h"
25
#include "src/objects/oddball.h"
26
#include "src/objects/shared-function-info.h"
27
#include "src/objects/source-text-module.h"
28
#include "src/utils/ostreams.h"
29
#include "torque-generated/exported-macros-assembler-tq.h"
30 31 32 33 34

namespace v8 {
namespace internal {
namespace interpreter {

35 36
namespace {

37
using compiler::CodeAssemblerState;
38
using compiler::Node;
39
using Label = CodeStubAssembler::Label;
40

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#define IGNITION_HANDLER(Name, BaseAssembler)                         \
  class Name##Assembler : public BaseAssembler {                      \
   public:                                                            \
    explicit Name##Assembler(compiler::CodeAssemblerState* state,     \
                             Bytecode bytecode, OperandScale scale)   \
        : BaseAssembler(state, bytecode, scale) {}                    \
    static void Generate(compiler::CodeAssemblerState* state,         \
                         OperandScale scale);                         \
                                                                      \
   private:                                                           \
    void GenerateImpl();                                              \
    DISALLOW_COPY_AND_ASSIGN(Name##Assembler);                        \
  };                                                                  \
  void Name##Assembler::Generate(compiler::CodeAssemblerState* state, \
                                 OperandScale scale) {                \
    Name##Assembler assembler(state, Bytecode::k##Name, scale);       \
    state->SetInitialDebugInformation(#Name, __FILE__, __LINE__);     \
    assembler.GenerateImpl();                                         \
  }                                                                   \
  void Name##Assembler::GenerateImpl()
61 62 63 64

// LdaZero
//
// Load literal '0' into the accumulator.
65
IGNITION_HANDLER(LdaZero, InterpreterAssembler) {
66
  TNode<Number> zero_value = NumberConstant(0.0);
67 68
  SetAccumulator(zero_value);
  Dispatch();
69 70 71 72 73
}

// LdaSmi <imm>
//
// Load an integer literal into the accumulator as a Smi.
74
IGNITION_HANDLER(LdaSmi, InterpreterAssembler) {
75
  TNode<Smi> smi_int = BytecodeOperandImmSmi(0);
76 77
  SetAccumulator(smi_int);
  Dispatch();
78 79 80 81 82
}

// LdaConstant <idx>
//
// Load constant literal at |idx| in the constant pool into the accumulator.
83
IGNITION_HANDLER(LdaConstant, InterpreterAssembler) {
84
  TNode<Object> constant = LoadConstantPoolEntryAtOperandIndex(0);
85 86
  SetAccumulator(constant);
  Dispatch();
87 88 89 90 91
}

// LdaUndefined
//
// Load Undefined into the accumulator.
92 93 94
IGNITION_HANDLER(LdaUndefined, InterpreterAssembler) {
  SetAccumulator(UndefinedConstant());
  Dispatch();
95 96 97 98 99
}

// LdaNull
//
// Load Null into the accumulator.
100 101 102
IGNITION_HANDLER(LdaNull, InterpreterAssembler) {
  SetAccumulator(NullConstant());
  Dispatch();
103 104 105 106 107
}

// LdaTheHole
//
// Load TheHole into the accumulator.
108 109 110
IGNITION_HANDLER(LdaTheHole, InterpreterAssembler) {
  SetAccumulator(TheHoleConstant());
  Dispatch();
111 112 113 114 115
}

// LdaTrue
//
// Load True into the accumulator.
116 117 118
IGNITION_HANDLER(LdaTrue, InterpreterAssembler) {
  SetAccumulator(TrueConstant());
  Dispatch();
119 120 121 122 123
}

// LdaFalse
//
// Load False into the accumulator.
124 125 126
IGNITION_HANDLER(LdaFalse, InterpreterAssembler) {
  SetAccumulator(FalseConstant());
  Dispatch();
127 128 129 130 131
}

// Ldar <src>
//
// Load accumulator with value from register <src>.
132
IGNITION_HANDLER(Ldar, InterpreterAssembler) {
133
  TNode<Object> value = LoadRegisterAtOperandIndex(0);
134 135
  SetAccumulator(value);
  Dispatch();
136 137 138 139 140
}

// Star <dst>
//
// Store accumulator to register <dst>.
141
IGNITION_HANDLER(Star, InterpreterAssembler) {
142
  TNode<Object> accumulator = GetAccumulator();
143
  StoreRegisterAtOperandIndex(accumulator, 0);
144
  Dispatch();
145 146 147 148 149
}

// Mov <src> <dst>
//
// Stores the value of register <src> to register <dst>.
150
IGNITION_HANDLER(Mov, InterpreterAssembler) {
151
  TNode<Object> src_value = LoadRegisterAtOperandIndex(0);
152
  StoreRegisterAtOperandIndex(src_value, 1);
153
  Dispatch();
154 155
}

156 157 158 159 160
class InterpreterLoadGlobalAssembler : public InterpreterAssembler {
 public:
  InterpreterLoadGlobalAssembler(CodeAssemblerState* state, Bytecode bytecode,
                                 OperandScale operand_scale)
      : InterpreterAssembler(state, bytecode, operand_scale) {}
161

162 163
  void LdaGlobal(int slot_operand_index, int name_operand_index,
                 TypeofMode typeof_mode) {
164
    TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
165

166
    AccessorAssembler accessor_asm(state());
167
    ExitPoint exit_point(this, [=](TNode<Object> result) {
168 169 170
      SetAccumulator(result);
      Dispatch();
    });
171

172 173
    LazyNode<TaggedIndex> lazy_slot = [=] {
      return BytecodeOperandIdxTaggedIndex(slot_operand_index);
174 175 176
    };

    LazyNode<Context> lazy_context = [=] { return GetContext(); };
177

178 179 180 181 182 183
    LazyNode<Name> lazy_name = [=] {
      TNode<Name> name =
          CAST(LoadConstantPoolEntryAtOperandIndex(name_operand_index));
      return name;
    };

184 185
    accessor_asm.LoadGlobalIC(maybe_feedback_vector, lazy_slot, lazy_context,
                              lazy_name, typeof_mode, &exit_point);
186
  }
187
};
188 189 190 191 192

// LdaGlobal <name_index> <slot>
//
// Load the global with name in constant pool entry <name_index> into the
// accumulator using FeedBackVector slot <slot> outside of a typeof.
193
IGNITION_HANDLER(LdaGlobal, InterpreterLoadGlobalAssembler) {
194 195 196
  static const int kNameOperandIndex = 0;
  static const int kSlotOperandIndex = 1;

197
  LdaGlobal(kSlotOperandIndex, kNameOperandIndex, NOT_INSIDE_TYPEOF);
198 199 200 201 202 203
}

// LdaGlobalInsideTypeof <name_index> <slot>
//
// Load the global with name in constant pool entry <name_index> into the
// accumulator using FeedBackVector slot <slot> inside of a typeof.
204
IGNITION_HANDLER(LdaGlobalInsideTypeof, InterpreterLoadGlobalAssembler) {
205 206 207
  static const int kNameOperandIndex = 0;
  static const int kSlotOperandIndex = 1;

208
  LdaGlobal(kSlotOperandIndex, kNameOperandIndex, INSIDE_TYPEOF);
209 210
}

211
// StaGlobal <name_index> <slot>
212 213
//
// Store the value in the accumulator into the global with name in constant pool
214
// entry <name_index> using FeedBackVector slot <slot>.
215
IGNITION_HANDLER(StaGlobal, InterpreterAssembler) {
216
  TNode<Context> context = GetContext();
217 218

  // Store the global via the StoreGlobalIC.
219
  TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
220
  TNode<Object> value = GetAccumulator();
221
  TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
222
  TNode<HeapObject> maybe_vector = LoadFeedbackVector();
223 224 225 226

  Label no_feedback(this, Label::kDeferred), end(this);
  GotoIf(IsUndefined(maybe_vector), &no_feedback);

227
  CallBuiltin(Builtins::kStoreGlobalIC, context, name, value, slot,
228 229 230 231
              maybe_vector);
  Goto(&end);

  Bind(&no_feedback);
232
  CallRuntime(Runtime::kStoreGlobalICNoFeedback_Miss, context, value, name);
233 234 235
  Goto(&end);

  Bind(&end);
236
  Dispatch();
237 238 239 240 241 242
}

// LdaContextSlot <context> <slot_index> <depth>
//
// Load the object in |slot_index| of the context at |depth| in the context
// chain starting at |context| into the accumulator.
243
IGNITION_HANDLER(LdaContextSlot, InterpreterAssembler) {
244
  TNode<Context> context = CAST(LoadRegisterAtOperandIndex(0));
245
  TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(1));
246
  TNode<Uint32T> depth = BytecodeOperandUImm(2);
247
  TNode<Context> slot_context = GetContextAtDepth(context, depth);
248
  TNode<Object> result = LoadContextElement(slot_context, slot_index);
249 250
  SetAccumulator(result);
  Dispatch();
251 252 253 254 255 256
}

// LdaImmutableContextSlot <context> <slot_index> <depth>
//
// Load the object in |slot_index| of the context at |depth| in the context
// chain starting at |context| into the accumulator.
257
IGNITION_HANDLER(LdaImmutableContextSlot, InterpreterAssembler) {
258
  TNode<Context> context = CAST(LoadRegisterAtOperandIndex(0));
259
  TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(1));
260
  TNode<Uint32T> depth = BytecodeOperandUImm(2);
261
  TNode<Context> slot_context = GetContextAtDepth(context, depth);
262
  TNode<Object> result = LoadContextElement(slot_context, slot_index);
263 264
  SetAccumulator(result);
  Dispatch();
265 266 267 268 269
}

// LdaCurrentContextSlot <slot_index>
//
// Load the object in |slot_index| of the current context into the accumulator.
270
IGNITION_HANDLER(LdaCurrentContextSlot, InterpreterAssembler) {
271
  TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(0));
272 273
  TNode<Context> slot_context = GetContext();
  TNode<Object> result = LoadContextElement(slot_context, slot_index);
274 275
  SetAccumulator(result);
  Dispatch();
276 277 278 279 280
}

// LdaImmutableCurrentContextSlot <slot_index>
//
// Load the object in |slot_index| of the current context into the accumulator.
281
IGNITION_HANDLER(LdaImmutableCurrentContextSlot, InterpreterAssembler) {
282
  TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(0));
283 284
  TNode<Context> slot_context = GetContext();
  TNode<Object> result = LoadContextElement(slot_context, slot_index);
285 286
  SetAccumulator(result);
  Dispatch();
287 288 289 290 291 292
}

// StaContextSlot <context> <slot_index> <depth>
//
// Stores the object in the accumulator into |slot_index| of the context at
// |depth| in the context chain starting at |context|.
293
IGNITION_HANDLER(StaContextSlot, InterpreterAssembler) {
294
  TNode<Object> value = GetAccumulator();
295
  TNode<Context> context = CAST(LoadRegisterAtOperandIndex(0));
296
  TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(1));
297
  TNode<Uint32T> depth = BytecodeOperandUImm(2);
298
  TNode<Context> slot_context = GetContextAtDepth(context, depth);
299 300
  StoreContextElement(slot_context, slot_index, value);
  Dispatch();
301 302 303 304 305 306
}

// StaCurrentContextSlot <slot_index>
//
// Stores the object in the accumulator into |slot_index| of the current
// context.
307
IGNITION_HANDLER(StaCurrentContextSlot, InterpreterAssembler) {
308
  TNode<Object> value = GetAccumulator();
309
  TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(0));
310
  TNode<Context> slot_context = GetContext();
311 312
  StoreContextElement(slot_context, slot_index, value);
  Dispatch();
313 314 315 316 317 318
}

// LdaLookupSlot <name_index>
//
// Lookup the object with the name in constant pool entry |name_index|
// dynamically.
319
IGNITION_HANDLER(LdaLookupSlot, InterpreterAssembler) {
320
  TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
321
  TNode<Context> context = GetContext();
322
  TNode<Object> result = CallRuntime(Runtime::kLoadLookupSlot, context, name);
323 324
  SetAccumulator(result);
  Dispatch();
325 326 327 328 329 330
}

// LdaLookupSlotInsideTypeof <name_index>
//
// Lookup the object with the name in constant pool entry |name_index|
// dynamically without causing a NoReferenceError.
331
IGNITION_HANDLER(LdaLookupSlotInsideTypeof, InterpreterAssembler) {
332
  TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
333
  TNode<Context> context = GetContext();
334
  TNode<Object> result =
335 336 337
      CallRuntime(Runtime::kLoadLookupSlotInsideTypeof, context, name);
  SetAccumulator(result);
  Dispatch();
338 339
}

340 341 342 343 344 345
class InterpreterLookupContextSlotAssembler : public InterpreterAssembler {
 public:
  InterpreterLookupContextSlotAssembler(CodeAssemblerState* state,
                                        Bytecode bytecode,
                                        OperandScale operand_scale)
      : InterpreterAssembler(state, bytecode, operand_scale) {}
346

347
  void LookupContextSlot(Runtime::FunctionId function_id) {
348
    TNode<Context> context = GetContext();
349
    TNode<IntPtrT> slot_index = Signed(BytecodeOperandIdx(1));
350
    TNode<Uint32T> depth = BytecodeOperandUImm(2);
351

352
    Label slowpath(this, Label::kDeferred);
353

354 355
    // Check for context extensions to allow the fast path.
    GotoIfHasContextExtensionUpToDepth(context, depth, &slowpath);
356

357 358
    // Fast path does a normal load context.
    {
359
      TNode<Context> slot_context = GetContextAtDepth(context, depth);
360
      TNode<Object> result = LoadContextElement(slot_context, slot_index);
361 362 363 364 365
      SetAccumulator(result);
      Dispatch();
    }

    // Slow path when we have to call out to the runtime.
366
    BIND(&slowpath);
367
    {
368
      TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
369
      TNode<Object> result = CallRuntime(function_id, context, name);
370 371 372
      SetAccumulator(result);
      Dispatch();
    }
373
  }
374
};
375

376
// LdaLookupContextSlot <name_index>
377 378 379
//
// Lookup the object with the name in constant pool entry |name_index|
// dynamically.
380 381
IGNITION_HANDLER(LdaLookupContextSlot, InterpreterLookupContextSlotAssembler) {
  LookupContextSlot(Runtime::kLoadLookupSlot);
382 383
}

384
// LdaLookupContextSlotInsideTypeof <name_index>
385 386 387
//
// Lookup the object with the name in constant pool entry |name_index|
// dynamically without causing a NoReferenceError.
388 389 390
IGNITION_HANDLER(LdaLookupContextSlotInsideTypeof,
                 InterpreterLookupContextSlotAssembler) {
  LookupContextSlot(Runtime::kLoadLookupSlotInsideTypeof);
391 392
}

393 394 395 396 397 398 399
class InterpreterLookupGlobalAssembler : public InterpreterLoadGlobalAssembler {
 public:
  InterpreterLookupGlobalAssembler(CodeAssemblerState* state, Bytecode bytecode,
                                   OperandScale operand_scale)
      : InterpreterLoadGlobalAssembler(state, bytecode, operand_scale) {}

  void LookupGlobalSlot(Runtime::FunctionId function_id) {
400 401
    TNode<Context> context = GetContext();
    TNode<Uint32T> depth = BytecodeOperandUImm(2);
402

403
    Label slowpath(this, Label::kDeferred);
404

405 406
    // Check for context extensions to allow the fast path
    GotoIfHasContextExtensionUpToDepth(context, depth, &slowpath);
407

408 409 410 411
    // Fast path does a normal load global
    {
      static const int kNameOperandIndex = 0;
      static const int kSlotOperandIndex = 1;
412

413 414 415 416
      TypeofMode typeof_mode =
          function_id == Runtime::kLoadLookupSlotInsideTypeof
              ? INSIDE_TYPEOF
              : NOT_INSIDE_TYPEOF;
417

418 419
      LdaGlobal(kSlotOperandIndex, kNameOperandIndex, typeof_mode);
    }
420

421
    // Slow path when we have to call out to the runtime
422
    BIND(&slowpath);
423
    {
424
      TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
425
      TNode<Object> result = CallRuntime(function_id, context, name);
426 427 428
      SetAccumulator(result);
      Dispatch();
    }
429
  }
430
};
431 432 433 434 435

// LdaLookupGlobalSlot <name_index> <feedback_slot> <depth>
//
// Lookup the object with the name in constant pool entry |name_index|
// dynamically.
436 437
IGNITION_HANDLER(LdaLookupGlobalSlot, InterpreterLookupGlobalAssembler) {
  LookupGlobalSlot(Runtime::kLoadLookupSlot);
438 439 440 441 442 443
}

// LdaLookupGlobalSlotInsideTypeof <name_index> <feedback_slot> <depth>
//
// Lookup the object with the name in constant pool entry |name_index|
// dynamically without causing a NoReferenceError.
444 445 446
IGNITION_HANDLER(LdaLookupGlobalSlotInsideTypeof,
                 InterpreterLookupGlobalAssembler) {
  LookupGlobalSlot(Runtime::kLoadLookupSlotInsideTypeof);
447 448
}

449
// StaLookupSlot <name_index> <flags>
450 451
//
// Store the object in accumulator to the object with the name in constant
452 453
// pool entry |name_index|.
IGNITION_HANDLER(StaLookupSlot, InterpreterAssembler) {
454
  TNode<Object> value = GetAccumulator();
455 456
  TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
  TNode<Uint32T> bytecode_flags = BytecodeOperandFlag(1);
457
  TNode<Context> context = GetContext();
458
  TVARIABLE(Object, var_result);
459 460

  Label sloppy(this), strict(this), end(this);
461 462
  DCHECK_EQ(0, LanguageMode::kSloppy);
  DCHECK_EQ(1, LanguageMode::kStrict);
463 464 465 466 467 468 469 470 471
  DCHECK_EQ(0, static_cast<int>(LookupHoistingMode::kNormal));
  DCHECK_EQ(1, static_cast<int>(LookupHoistingMode::kLegacySloppy));
  Branch(IsSetWord32<StoreLookupSlotFlags::LanguageModeBit>(bytecode_flags),
         &strict, &sloppy);

  BIND(&strict);
  {
    CSA_ASSERT(this, IsClearWord32<StoreLookupSlotFlags::LookupHoistingModeBit>(
                         bytecode_flags));
472 473
    var_result =
        CallRuntime(Runtime::kStoreLookupSlot_Strict, context, name, value);
474 475
    Goto(&end);
  }
476

477 478 479 480 481 482 483 484 485
  BIND(&sloppy);
  {
    Label hoisting(this), ordinary(this);
    Branch(IsSetWord32<StoreLookupSlotFlags::LookupHoistingModeBit>(
               bytecode_flags),
           &hoisting, &ordinary);

    BIND(&hoisting);
    {
486 487
      var_result = CallRuntime(Runtime::kStoreLookupSlot_SloppyHoisting,
                               context, name, value);
488 489 490 491 492
      Goto(&end);
    }

    BIND(&ordinary);
    {
493 494
      var_result =
          CallRuntime(Runtime::kStoreLookupSlot_Sloppy, context, name, value);
495 496 497 498 499 500 501 502 503
      Goto(&end);
    }
  }

  BIND(&end);
  {
    SetAccumulator(var_result.value());
    Dispatch();
  }
504 505
}

506 507 508 509 510
// LdaNamedProperty <object> <name_index> <slot>
//
// Calls the LoadIC at FeedBackVector slot <slot> for <object> and the name at
// constant pool entry <name_index>.
IGNITION_HANDLER(LdaNamedProperty, InterpreterAssembler) {
511
  TNode<HeapObject> feedback_vector = LoadFeedbackVector();
512 513

  // Load receiver.
514
  TNode<Object> recv = LoadRegisterAtOperandIndex(0);
515

516
  // Load the name and context lazily.
517 518 519
  LazyNode<TaggedIndex> lazy_slot = [=] {
    return BytecodeOperandIdxTaggedIndex(2);
  };
520 521 522 523
  LazyNode<Name> lazy_name = [=] {
    return CAST(LoadConstantPoolEntryAtOperandIndex(1));
  };
  LazyNode<Context> lazy_context = [=] { return GetContext(); };
524

525
  Label done(this);
526
  TVARIABLE(Object, var_result);
527
  ExitPoint exit_point(this, &done, &var_result);
528

529 530
  AccessorAssembler::LazyLoadICParameters params(lazy_context, recv, lazy_name,
                                                 lazy_slot, feedback_vector);
531
  AccessorAssembler accessor_asm(state());
532 533
  accessor_asm.LoadIC_BytecodeHandler(&params, &exit_point);

534
  BIND(&done);
535
  {
536 537
    SetAccumulator(var_result.value());
    Dispatch();
538 539 540
  }
}

541 542 543 544
// LdaPropertyNofeedback <object> <slot>
//
// Calls the GetProperty builtin for <object> and the key in the accumulator.
IGNITION_HANDLER(LdaNamedPropertyNoFeedback, InterpreterAssembler) {
545
  TNode<Object> object = LoadRegisterAtOperandIndex(0);
546
  TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(1));
547
  TNode<Context> context = GetContext();
548 549
  TNode<Object> result =
      CallBuiltin(Builtins::kGetProperty, context, object, name);
550 551 552 553
  SetAccumulator(result);
  Dispatch();
}

554 555 556 557
// KeyedLoadIC <object> <slot>
//
// Calls the KeyedLoadIC at FeedBackVector slot <slot> for <object> and the key
// in the accumulator.
558
IGNITION_HANDLER(LdaKeyedProperty, InterpreterAssembler) {
559 560
  TNode<Object> object = LoadRegisterAtOperandIndex(0);
  TNode<Object> name = GetAccumulator();
561
  TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
562
  TNode<HeapObject> feedback_vector = LoadFeedbackVector();
563
  TNode<Context> context = GetContext();
564

565
  TVARIABLE(Object, var_result);
566 567
  var_result = CallBuiltin(Builtins::kKeyedLoadIC, context, object, name, slot,
                           feedback_vector);
568
  SetAccumulator(var_result.value());
569 570 571 572 573 574 575 576 577 578
  Dispatch();
}

class InterpreterStoreNamedPropertyAssembler : public InterpreterAssembler {
 public:
  InterpreterStoreNamedPropertyAssembler(CodeAssemblerState* state,
                                         Bytecode bytecode,
                                         OperandScale operand_scale)
      : InterpreterAssembler(state, bytecode, operand_scale) {}

579
  void StaNamedProperty(Callable ic, NamedPropertyType property_type) {
580 581
    TNode<Code> code_target = HeapConstant(ic.code());
    TNode<Object> object = LoadRegisterAtOperandIndex(0);
582
    TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(1));
583
    TNode<Object> value = GetAccumulator();
584
    TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(2);
585
    TNode<HeapObject> maybe_vector = LoadFeedbackVector();
586
    TNode<Context> context = GetContext();
587

588 589
    TVARIABLE(Object, var_result);
    var_result = CallStub(ic.descriptor(), code_target, context, object, name,
590
                          value, slot, maybe_vector);
591 592 593
    // To avoid special logic in the deoptimizer to re-materialize the value in
    // the accumulator, we overwrite the accumulator after the IC call. It
    // doesn't really matter what we write to the accumulator here, since we
594 595
    // restore to the correct value on the outside. Storing the result means we
    // don't need to keep unnecessary state alive across the callstub.
596
    SetAccumulator(var_result.value());
597 598 599
    Dispatch();
  }
};
600

601
// StaNamedProperty <object> <name_index> <slot>
602
//
603
// Calls the StoreIC at FeedBackVector slot <slot> for <object> and
604 605
// the name in constant pool entry <name_index> with the value in the
// accumulator.
606 607
IGNITION_HANDLER(StaNamedProperty, InterpreterStoreNamedPropertyAssembler) {
  Callable ic = Builtins::CallableFor(isolate(), Builtins::kStoreIC);
608
  StaNamedProperty(ic, NamedPropertyType::kNotOwn);
609 610 611 612 613 614 615
}

// StaNamedOwnProperty <object> <name_index> <slot>
//
// Calls the StoreOwnIC at FeedBackVector slot <slot> for <object> and
// the name in constant pool entry <name_index> with the value in the
// accumulator.
616 617
IGNITION_HANDLER(StaNamedOwnProperty, InterpreterStoreNamedPropertyAssembler) {
  Callable ic = CodeFactory::StoreOwnICInOptimizedCode(isolate());
618
  StaNamedProperty(ic, NamedPropertyType::kOwn);
619 620
}

621 622 623 624 625 626
// StaNamedPropertyNoFeedback <object> <name_index>
//
// Calls the SetPropertyBuiltin for <object> and the name in constant pool entry
// <name_index> with the value in the accumulator.
IGNITION_HANDLER(StaNamedPropertyNoFeedback,
                 InterpreterStoreNamedPropertyAssembler) {
627
  TNode<Object> object = LoadRegisterAtOperandIndex(0);
628
  TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(1));
629
  TNode<Object> value = GetAccumulator();
630
  TNode<Context> context = GetContext();
631

632
  TNode<Object> result =
633
      CallRuntime(Runtime::kSetNamedProperty, context, object, name, value);
634 635 636 637
  SetAccumulator(result);
  Dispatch();
}

638
// StaKeyedProperty <object> <key> <slot>
639
//
640 641 642
// Calls the KeyedStoreIC at FeedbackVector slot <slot> for <object> and
// the key <key> with the value in the accumulator.
IGNITION_HANDLER(StaKeyedProperty, InterpreterAssembler) {
643 644 645
  TNode<Object> object = LoadRegisterAtOperandIndex(0);
  TNode<Object> name = LoadRegisterAtOperandIndex(1);
  TNode<Object> value = GetAccumulator();
646
  TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(2);
647
  TNode<HeapObject> maybe_vector = LoadFeedbackVector();
648
  TNode<Context> context = GetContext();
649

650 651
  TVARIABLE(Object, var_result);
  var_result = CallBuiltin(Builtins::kKeyedStoreIC, context, object, name,
652
                           value, slot, maybe_vector);
653 654 655 656 657
  // To avoid special logic in the deoptimizer to re-materialize the value in
  // the accumulator, we overwrite the accumulator after the IC call. It
  // doesn't really matter what we write to the accumulator here, since we
  // restore to the correct value on the outside. Storing the result means we
  // don't need to keep unnecessary state alive across the callstub.
658
  SetAccumulator(var_result.value());
659 660 661 662 663 664 665 666
  Dispatch();
}

// StaInArrayLiteral <array> <index> <slot>
//
// Calls the StoreInArrayLiteralIC at FeedbackVector slot <slot> for <array> and
// the key <index> with the value in the accumulator.
IGNITION_HANDLER(StaInArrayLiteral, InterpreterAssembler) {
667 668 669
  TNode<Object> array = LoadRegisterAtOperandIndex(0);
  TNode<Object> index = LoadRegisterAtOperandIndex(1);
  TNode<Object> value = GetAccumulator();
670
  TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(2);
671
  TNode<HeapObject> feedback_vector = LoadFeedbackVector();
672
  TNode<Context> context = GetContext();
673

674 675
  TVARIABLE(Object, var_result);
  var_result = CallBuiltin(Builtins::kStoreInArrayLiteralIC, context, array,
676
                           index, value, slot, feedback_vector);
677 678 679
  // To avoid special logic in the deoptimizer to re-materialize the value in
  // the accumulator, we overwrite the accumulator after the IC call. It
  // doesn't really matter what we write to the accumulator here, since we
680 681
  // restore to the correct value on the outside. Storing the result means we
  // don't need to keep unnecessary state alive across the callstub.
682
  SetAccumulator(var_result.value());
683
  Dispatch();
684 685 686 687 688 689 690 691 692 693
}

// StaDataPropertyInLiteral <object> <name> <flags>
//
// Define a property <name> with value from the accumulator in <object>.
// Property attributes and whether set_function_name are stored in
// DataPropertyInLiteralFlags <flags>.
//
// This definition is not observable and is used only for definitions
// in object or class literals.
694
IGNITION_HANDLER(StaDataPropertyInLiteral, InterpreterAssembler) {
695 696 697
  TNode<Object> object = LoadRegisterAtOperandIndex(0);
  TNode<Object> name = LoadRegisterAtOperandIndex(1);
  TNode<Object> value = GetAccumulator();
698 699
  TNode<Smi> flags =
      SmiFromInt32(UncheckedCast<Int32T>(BytecodeOperandFlag(2)));
700
  TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(3);
701

702
  TNode<HeapObject> feedback_vector = LoadFeedbackVector();
703
  TNode<Context> context = GetContext();
704

705
  CallRuntime(Runtime::kDefineDataPropertyInLiteral, context, object, name,
706
              value, flags, feedback_vector, slot);
707
  Dispatch();
708 709
}

710
IGNITION_HANDLER(CollectTypeProfile, InterpreterAssembler) {
711
  TNode<Smi> position = BytecodeOperandImmSmi(0);
712
  TNode<Object> value = GetAccumulator();
713

714
  TNode<HeapObject> feedback_vector = LoadFeedbackVector();
715
  TNode<Context> context = GetContext();
716

717 718 719
  CallRuntime(Runtime::kCollectTypeProfile, context, position, value,
              feedback_vector);
  Dispatch();
720 721 722 723 724 725 726
}

// LdaModuleVariable <cell_index> <depth>
//
// Load the contents of a module variable into the accumulator.  The variable is
// identified by <cell_index>.  <depth> is the depth of the current context
// relative to the module context.
727
IGNITION_HANDLER(LdaModuleVariable, InterpreterAssembler) {
728
  TNode<IntPtrT> cell_index = BytecodeOperandImmIntPtr(0);
729
  TNode<Uint32T> depth = BytecodeOperandUImm(1);
730

731
  TNode<Context> module_context = GetContextAtDepth(GetContext(), depth);
732 733
  TNode<SourceTextModule> module =
      CAST(LoadContextElement(module_context, Context::EXTENSION_INDEX));
734

735 736 737
  Label if_export(this), if_import(this), end(this);
  Branch(IntPtrGreaterThan(cell_index, IntPtrConstant(0)), &if_export,
         &if_import);
738

739
  BIND(&if_export);
740
  {
741 742
    TNode<FixedArray> regular_exports = LoadObjectField<FixedArray>(
        module, SourceTextModule::kRegularExportsOffset);
743
    // The actual array index is (cell_index - 1).
744
    TNode<IntPtrT> export_index = IntPtrSub(cell_index, IntPtrConstant(1));
745 746
    TNode<Cell> cell =
        CAST(LoadFixedArrayElement(regular_exports, export_index));
747 748
    SetAccumulator(LoadObjectField(cell, Cell::kValueOffset));
    Goto(&end);
749 750
  }

751
  BIND(&if_import);
752
  {
753 754
    TNode<FixedArray> regular_imports = LoadObjectField<FixedArray>(
        module, SourceTextModule::kRegularImportsOffset);
755
    // The actual array index is (-cell_index - 1).
756
    TNode<IntPtrT> import_index = IntPtrSub(IntPtrConstant(-1), cell_index);
757 758
    TNode<Cell> cell =
        CAST(LoadFixedArrayElement(regular_imports, import_index));
759 760
    SetAccumulator(LoadObjectField(cell, Cell::kValueOffset));
    Goto(&end);
761 762
  }

763
  BIND(&end);
764
  Dispatch();
765 766 767 768 769 770
}

// StaModuleVariable <cell_index> <depth>
//
// Store accumulator to the module variable identified by <cell_index>.
// <depth> is the depth of the current context relative to the module context.
771
IGNITION_HANDLER(StaModuleVariable, InterpreterAssembler) {
772
  TNode<Object> value = GetAccumulator();
773
  TNode<IntPtrT> cell_index = BytecodeOperandImmIntPtr(0);
774
  TNode<Uint32T> depth = BytecodeOperandUImm(1);
775

776
  TNode<Context> module_context = GetContextAtDepth(GetContext(), depth);
777 778
  TNode<SourceTextModule> module =
      CAST(LoadContextElement(module_context, Context::EXTENSION_INDEX));
779

780 781 782
  Label if_export(this), if_import(this), end(this);
  Branch(IntPtrGreaterThan(cell_index, IntPtrConstant(0)), &if_export,
         &if_import);
783

784
  BIND(&if_export);
785
  {
786 787
    TNode<FixedArray> regular_exports = LoadObjectField<FixedArray>(
        module, SourceTextModule::kRegularExportsOffset);
788
    // The actual array index is (cell_index - 1).
789
    TNode<IntPtrT> export_index = IntPtrSub(cell_index, IntPtrConstant(1));
790 791
    TNode<HeapObject> cell =
        CAST(LoadFixedArrayElement(regular_exports, export_index));
792 793
    StoreObjectField(cell, Cell::kValueOffset, value);
    Goto(&end);
794 795
  }

796
  BIND(&if_import);
797 798
  {
    // Not supported (probably never).
799
    Abort(AbortReason::kUnsupportedModuleOperation);
800
    Goto(&end);
801 802
  }

803
  BIND(&end);
804
  Dispatch();
805 806 807 808 809 810
}

// PushContext <context>
//
// Saves the current context in <context>, and pushes the accumulator as the
// new current context.
811
IGNITION_HANDLER(PushContext, InterpreterAssembler) {
812 813
  TNode<Context> new_context = CAST(GetAccumulator());
  TNode<Context> old_context = GetContext();
814
  StoreRegisterAtOperandIndex(old_context, 0);
815 816
  SetContext(new_context);
  Dispatch();
817 818 819 820 821
}

// PopContext <context>
//
// Pops the current context and sets <context> as the new context.
822
IGNITION_HANDLER(PopContext, InterpreterAssembler) {
823
  TNode<Context> context = CAST(LoadRegisterAtOperandIndex(0));
824 825 826
  SetContext(context);
  Dispatch();
}
827

828 829 830 831 832
class InterpreterBinaryOpAssembler : public InterpreterAssembler {
 public:
  InterpreterBinaryOpAssembler(CodeAssemblerState* state, Bytecode bytecode,
                               OperandScale operand_scale)
      : InterpreterAssembler(state, bytecode, operand_scale) {}
833

834 835 836
  using BinaryOpGenerator = TNode<Object> (BinaryOpAssembler::*)(
      TNode<Context> context, TNode<Object> left, TNode<Object> right,
      TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
837
      bool rhs_known_smi);
838

839
  void BinaryOpWithFeedback(BinaryOpGenerator generator) {
840 841
    TNode<Object> lhs = LoadRegisterAtOperandIndex(0);
    TNode<Object> rhs = GetAccumulator();
842
    TNode<Context> context = GetContext();
843
    TNode<UintPtrT> slot_index = BytecodeOperandIdx(1);
844
    TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
845

846
    BinaryOpAssembler binop_asm(state());
847 848
    TNode<Object> result = (binop_asm.*generator)(context, lhs, rhs, slot_index,
                                                  maybe_feedback_vector, false);
849 850 851 852 853
    SetAccumulator(result);
    Dispatch();
  }

  void BinaryOpSmiWithFeedback(BinaryOpGenerator generator) {
854
    TNode<Object> lhs = GetAccumulator();
855
    TNode<Smi> rhs = BytecodeOperandImmSmi(0);
856
    TNode<Context> context = GetContext();
857
    TNode<UintPtrT> slot_index = BytecodeOperandIdx(1);
858
    TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
859 860

    BinaryOpAssembler binop_asm(state());
861 862
    TNode<Object> result = (binop_asm.*generator)(context, lhs, rhs, slot_index,
                                                  maybe_feedback_vector, true);
863 864
    SetAccumulator(result);
    Dispatch();
865
  }
866
};
867 868 869 870

// Add <src>
//
// Add register <src> to accumulator.
871 872
IGNITION_HANDLER(Add, InterpreterBinaryOpAssembler) {
  BinaryOpWithFeedback(&BinaryOpAssembler::Generate_AddWithFeedback);
873 874 875 876 877
}

// Sub <src>
//
// Subtract register <src> from accumulator.
878 879
IGNITION_HANDLER(Sub, InterpreterBinaryOpAssembler) {
  BinaryOpWithFeedback(&BinaryOpAssembler::Generate_SubtractWithFeedback);
880 881 882 883 884
}

// Mul <src>
//
// Multiply accumulator by register <src>.
885 886
IGNITION_HANDLER(Mul, InterpreterBinaryOpAssembler) {
  BinaryOpWithFeedback(&BinaryOpAssembler::Generate_MultiplyWithFeedback);
887 888 889 890 891
}

// Div <src>
//
// Divide register <src> by accumulator.
892 893
IGNITION_HANDLER(Div, InterpreterBinaryOpAssembler) {
  BinaryOpWithFeedback(&BinaryOpAssembler::Generate_DivideWithFeedback);
894 895 896 897 898
}

// Mod <src>
//
// Modulo register <src> by accumulator.
899 900
IGNITION_HANDLER(Mod, InterpreterBinaryOpAssembler) {
  BinaryOpWithFeedback(&BinaryOpAssembler::Generate_ModulusWithFeedback);
901 902
}

903 904 905 906 907 908 909
// Exp <src>
//
// Exponentiate register <src> (base) with accumulator (exponent).
IGNITION_HANDLER(Exp, InterpreterBinaryOpAssembler) {
  BinaryOpWithFeedback(&BinaryOpAssembler::Generate_ExponentiateWithFeedback);
}

910
// AddSmi <imm>
911
//
912
// Adds an immediate value <imm> to the value in the accumulator.
913 914
IGNITION_HANDLER(AddSmi, InterpreterBinaryOpAssembler) {
  BinaryOpSmiWithFeedback(&BinaryOpAssembler::Generate_AddWithFeedback);
915 916
}

917
// SubSmi <imm>
918
//
919
// Subtracts an immediate value <imm> from the value in the accumulator.
920 921
IGNITION_HANDLER(SubSmi, InterpreterBinaryOpAssembler) {
  BinaryOpSmiWithFeedback(&BinaryOpAssembler::Generate_SubtractWithFeedback);
922 923
}

924 925 926
// MulSmi <imm>
//
// Multiplies an immediate value <imm> to the value in the accumulator.
927 928
IGNITION_HANDLER(MulSmi, InterpreterBinaryOpAssembler) {
  BinaryOpSmiWithFeedback(&BinaryOpAssembler::Generate_MultiplyWithFeedback);
929 930 931 932 933
}

// DivSmi <imm>
//
// Divides the value in the accumulator by immediate value <imm>.
934 935
IGNITION_HANDLER(DivSmi, InterpreterBinaryOpAssembler) {
  BinaryOpSmiWithFeedback(&BinaryOpAssembler::Generate_DivideWithFeedback);
936 937 938 939 940
}

// ModSmi <imm>
//
// Modulo accumulator by immediate value <imm>.
941 942
IGNITION_HANDLER(ModSmi, InterpreterBinaryOpAssembler) {
  BinaryOpSmiWithFeedback(&BinaryOpAssembler::Generate_ModulusWithFeedback);
943 944
}

945 946 947 948 949 950 951 952
// ExpSmi <imm>
//
// Exponentiate accumulator (base) with immediate value <imm> (exponent).
IGNITION_HANDLER(ExpSmi, InterpreterBinaryOpAssembler) {
  BinaryOpSmiWithFeedback(
      &BinaryOpAssembler::Generate_ExponentiateWithFeedback);
}

953 954 955 956 957 958 959
class InterpreterBitwiseBinaryOpAssembler : public InterpreterAssembler {
 public:
  InterpreterBitwiseBinaryOpAssembler(CodeAssemblerState* state,
                                      Bytecode bytecode,
                                      OperandScale operand_scale)
      : InterpreterAssembler(state, bytecode, operand_scale) {}

960
  void BitwiseBinaryOpWithFeedback(Operation bitwise_op) {
961 962
    TNode<Object> left = LoadRegisterAtOperandIndex(0);
    TNode<Object> right = GetAccumulator();
963
    TNode<Context> context = GetContext();
964
    TNode<UintPtrT> slot_index = BytecodeOperandIdx(1);
965
    TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
966

967
    TVARIABLE(Smi, feedback);
968

969 970 971
    BinaryOpAssembler binop_asm(state());
    TNode<Object> result = binop_asm.Generate_BitwiseBinaryOpWithFeedback(
        bitwise_op, left, right, context, &feedback);
972

973 974
    UpdateFeedback(feedback.value(), maybe_feedback_vector, slot_index);
    SetAccumulator(result);
975 976 977
    Dispatch();
  }

978
  void BitwiseBinaryOpWithSmi(Operation bitwise_op) {
979
    TNode<Object> left = GetAccumulator();
980
    TNode<Smi> right = BytecodeOperandImmSmi(0);
981
    TNode<UintPtrT> slot_index = BytecodeOperandIdx(1);
982
    TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
983
    TNode<Context> context = GetContext();
984

985
    TVARIABLE(Smi, var_left_feedback);
986
    TVARIABLE(Word32T, var_left_word32);
987
    TVARIABLE(BigInt, var_left_bigint);
988 989 990 991 992 993
    Label do_smi_op(this), if_bigint_mix(this);

    TaggedToWord32OrBigIntWithFeedback(context, left, &do_smi_op,
                                       &var_left_word32, &if_bigint_mix,
                                       &var_left_bigint, &var_left_feedback);
    BIND(&do_smi_op);
994
    TNode<Number> result =
995
        BitwiseOp(var_left_word32.value(), SmiToInt32(right), bitwise_op);
996 997 998
    TNode<Smi> result_type = SelectSmiConstant(
        TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall,
        BinaryOperationFeedback::kNumber);
999
    UpdateFeedback(SmiOr(result_type, var_left_feedback.value()),
1000
                   maybe_feedback_vector, slot_index);
1001 1002 1003 1004
    SetAccumulator(result);
    Dispatch();

    BIND(&if_bigint_mix);
1005 1006
    UpdateFeedback(var_left_feedback.value(), maybe_feedback_vector,
                   slot_index);
1007 1008
    ThrowTypeError(context, MessageTemplate::kBigIntMixedTypes);
  }
1009 1010 1011 1012 1013 1014
};

// BitwiseOr <src>
//
// BitwiseOr register <src> to accumulator.
IGNITION_HANDLER(BitwiseOr, InterpreterBitwiseBinaryOpAssembler) {
1015
  BitwiseBinaryOpWithFeedback(Operation::kBitwiseOr);
1016 1017 1018 1019 1020 1021
}

// BitwiseXor <src>
//
// BitwiseXor register <src> to accumulator.
IGNITION_HANDLER(BitwiseXor, InterpreterBitwiseBinaryOpAssembler) {
1022
  BitwiseBinaryOpWithFeedback(Operation::kBitwiseXor);
1023 1024 1025 1026 1027 1028
}

// BitwiseAnd <src>
//
// BitwiseAnd register <src> to accumulator.
IGNITION_HANDLER(BitwiseAnd, InterpreterBitwiseBinaryOpAssembler) {
1029
  BitwiseBinaryOpWithFeedback(Operation::kBitwiseAnd);
1030 1031 1032 1033 1034 1035 1036 1037 1038
}

// ShiftLeft <src>
//
// Left shifts register <src> by the count specified in the accumulator.
// Register <src> is converted to an int32 and the accumulator to uint32
// before the operation. 5 lsb bits from the accumulator are used as count
// i.e. <src> << (accumulator & 0x1F).
IGNITION_HANDLER(ShiftLeft, InterpreterBitwiseBinaryOpAssembler) {
1039
  BitwiseBinaryOpWithFeedback(Operation::kShiftLeft);
1040 1041 1042 1043 1044 1045 1046 1047 1048
}

// ShiftRight <src>
//
// Right shifts register <src> by the count specified in the accumulator.
// Result is sign extended. Register <src> is converted to an int32 and the
// accumulator to uint32 before the operation. 5 lsb bits from the accumulator
// are used as count i.e. <src> >> (accumulator & 0x1F).
IGNITION_HANDLER(ShiftRight, InterpreterBitwiseBinaryOpAssembler) {
1049
  BitwiseBinaryOpWithFeedback(Operation::kShiftRight);
1050 1051 1052 1053 1054 1055 1056 1057 1058
}

// ShiftRightLogical <src>
//
// Right Shifts register <src> by the count specified in the accumulator.
// Result is zero-filled. The accumulator and register <src> are converted to
// uint32 before the operation 5 lsb bits from the accumulator are used as
// count i.e. <src> << (accumulator & 0x1F).
IGNITION_HANDLER(ShiftRightLogical, InterpreterBitwiseBinaryOpAssembler) {
1059
  BitwiseBinaryOpWithFeedback(Operation::kShiftRightLogical);
1060 1061
}

1062
// BitwiseOrSmi <imm>
1063
//
1064
// BitwiseOrSmi accumulator with <imm>.
1065
IGNITION_HANDLER(BitwiseOrSmi, InterpreterBitwiseBinaryOpAssembler) {
1066
  BitwiseBinaryOpWithSmi(Operation::kBitwiseOr);
1067 1068
}

1069
// BitwiseXorSmi <imm>
1070
//
1071
// BitwiseXorSmi accumulator with <imm>.
1072
IGNITION_HANDLER(BitwiseXorSmi, InterpreterBitwiseBinaryOpAssembler) {
1073
  BitwiseBinaryOpWithSmi(Operation::kBitwiseXor);
1074
}
1075

1076
// BitwiseAndSmi <imm>
1077
//
1078
// BitwiseAndSmi accumulator with <imm>.
1079
IGNITION_HANDLER(BitwiseAndSmi, InterpreterBitwiseBinaryOpAssembler) {
1080
  BitwiseBinaryOpWithSmi(Operation::kBitwiseAnd);
1081 1082
}

1083 1084 1085 1086
// BitwiseNot <feedback_slot>
//
// Perform bitwise-not on the accumulator.
IGNITION_HANDLER(BitwiseNot, InterpreterAssembler) {
1087 1088
  TNode<Object> value = GetAccumulator();
  TNode<Context> context = GetContext();
1089
  TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
1090
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1091

1092 1093 1094
  UnaryOpAssembler unary_op_asm(state());
  TNode<Object> result = unary_op_asm.Generate_BitwiseNotWithFeedback(
      context, value, slot_index, maybe_feedback_vector);
1095

1096
  SetAccumulator(result);
1097
  Dispatch();
1098 1099
}

1100
// ShiftLeftSmi <imm>
1101
//
1102 1103
// Left shifts accumulator by the count specified in <imm>.
// The accumulator is converted to an int32 before the operation. The 5
1104
// lsb bits from <imm> are used as count i.e. <src> << (<imm> & 0x1F).
1105
IGNITION_HANDLER(ShiftLeftSmi, InterpreterBitwiseBinaryOpAssembler) {
1106
  BitwiseBinaryOpWithSmi(Operation::kShiftLeft);
1107 1108
}

1109
// ShiftRightSmi <imm>
1110
//
1111 1112
// Right shifts accumulator by the count specified in <imm>. Result is sign
// extended. The accumulator is converted to an int32 before the operation. The
1113 1114
// 5 lsb bits from <imm> are used as count i.e. <src> >> (<imm> & 0x1F).
IGNITION_HANDLER(ShiftRightSmi, InterpreterBitwiseBinaryOpAssembler) {
1115
  BitwiseBinaryOpWithSmi(Operation::kShiftRight);
1116 1117
}

1118 1119 1120 1121
// ShiftRightLogicalSmi <imm>
//
// Right shifts accumulator by the count specified in <imm>. Result is zero
// extended. The accumulator is converted to an int32 before the operation. The
1122 1123
// 5 lsb bits from <imm> are used as count i.e. <src> >>> (<imm> & 0x1F).
IGNITION_HANDLER(ShiftRightLogicalSmi, InterpreterBitwiseBinaryOpAssembler) {
1124
  BitwiseBinaryOpWithSmi(Operation::kShiftRightLogical);
1125 1126
}

1127 1128 1129
// Negate <feedback_slot>
//
// Perform arithmetic negation on the accumulator.
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
IGNITION_HANDLER(Negate, InterpreterAssembler) {
  TNode<Object> value = GetAccumulator();
  TNode<Context> context = GetContext();
  TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();

  UnaryOpAssembler unary_op_asm(state());
  TNode<Object> result = unary_op_asm.Generate_NegateWithFeedback(
      context, value, slot_index, maybe_feedback_vector);

  SetAccumulator(result);
  Dispatch();
}
1143

1144
// ToName <dst>
1145 1146
//
// Convert the object referenced by the accumulator to a name.
1147
IGNITION_HANDLER(ToName, InterpreterAssembler) {
1148
  TNode<Object> object = GetAccumulator();
1149
  TNode<Context> context = GetContext();
1150
  TNode<Object> result = CallBuiltin(Builtins::kToName, context, object);
1151
  StoreRegisterAtOperandIndex(result, 0);
1152
  Dispatch();
1153 1154
}

1155
// ToNumber <slot>
1156 1157
//
// Convert the object referenced by the accumulator to a number.
1158
IGNITION_HANDLER(ToNumber, InterpreterAssembler) {
1159 1160
  ToNumberOrNumeric(Object::Conversion::kToNumber);
}
1161

1162 1163 1164 1165 1166
// ToNumeric <slot>
//
// Convert the object referenced by the accumulator to a numeric.
IGNITION_HANDLER(ToNumeric, InterpreterAssembler) {
  ToNumberOrNumeric(Object::Conversion::kToNumeric);
1167 1168
}

1169
// ToObject <dst>
1170 1171
//
// Convert the object referenced by the accumulator to a JSReceiver.
1172
IGNITION_HANDLER(ToObject, InterpreterAssembler) {
1173 1174
  TNode<Object> accumulator = GetAccumulator();
  TNode<Context> context = GetContext();
1175
  TNode<Object> result = CallBuiltin(Builtins::kToObject, context, accumulator);
1176
  StoreRegisterAtOperandIndex(result, 0);
1177
  Dispatch();
1178 1179
}

1180 1181 1182 1183 1184 1185 1186 1187
// ToString
//
// Convert the accumulator to a String.
IGNITION_HANDLER(ToString, InterpreterAssembler) {
  SetAccumulator(ToString_Inline(GetContext(), GetAccumulator()));
  Dispatch();
}

1188 1189 1190
// Inc
//
// Increments value in the accumulator by one.
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203
IGNITION_HANDLER(Inc, InterpreterAssembler) {
  TNode<Object> value = GetAccumulator();
  TNode<Context> context = GetContext();
  TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();

  UnaryOpAssembler unary_op_asm(state());
  TNode<Object> result = unary_op_asm.Generate_IncrementWithFeedback(
      context, value, slot_index, maybe_feedback_vector);

  SetAccumulator(result);
  Dispatch();
}
1204 1205 1206 1207

// Dec
//
// Decrements value in the accumulator by one.
1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
IGNITION_HANDLER(Dec, InterpreterAssembler) {
  TNode<Object> value = GetAccumulator();
  TNode<Context> context = GetContext();
  TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();

  UnaryOpAssembler unary_op_asm(state());
  TNode<Object> result = unary_op_asm.Generate_DecrementWithFeedback(
      context, value, slot_index, maybe_feedback_vector);

  SetAccumulator(result);
  Dispatch();
}
1221

1222
// ToBooleanLogicalNot
1223 1224 1225
//
// Perform logical-not on the accumulator, first casting the
// accumulator to a boolean value if required.
1226
IGNITION_HANDLER(ToBooleanLogicalNot, InterpreterAssembler) {
1227
  TNode<Object> value = GetAccumulator();
1228
  TVARIABLE(Oddball, result);
1229 1230
  Label if_true(this), if_false(this), end(this);
  BranchIfToBooleanIsTrue(value, &if_true, &if_false);
1231
  BIND(&if_true);
1232
  {
1233
    result = FalseConstant();
1234
    Goto(&end);
1235
  }
1236
  BIND(&if_false);
1237
  {
1238
    result = TrueConstant();
1239
    Goto(&end);
1240
  }
1241
  BIND(&end);
1242 1243
  SetAccumulator(result.value());
  Dispatch();
1244 1245 1246 1247 1248 1249
}

// LogicalNot
//
// Perform logical-not on the accumulator, which must already be a boolean
// value.
1250
IGNITION_HANDLER(LogicalNot, InterpreterAssembler) {
1251
  TNode<Object> value = GetAccumulator();
1252
  TVARIABLE(Oddball, result);
1253
  Label if_true(this), if_false(this), end(this);
1254 1255 1256
  TNode<Oddball> true_value = TrueConstant();
  TNode<Oddball> false_value = FalseConstant();
  Branch(TaggedEqual(value, true_value), &if_true, &if_false);
1257
  BIND(&if_true);
1258
  {
1259
    result = false_value;
1260
    Goto(&end);
1261
  }
1262
  BIND(&if_false);
1263
  {
1264
    CSA_ASSERT(this, TaggedEqual(value, false_value));
1265
    result = true_value;
1266
    Goto(&end);
1267
  }
1268
  BIND(&end);
1269 1270
  SetAccumulator(result.value());
  Dispatch();
1271 1272 1273 1274 1275 1276
}

// TypeOf
//
// Load the accumulator with the string representating type of the
// object in the accumulator.
1277
IGNITION_HANDLER(TypeOf, InterpreterAssembler) {
1278
  TNode<Object> value = GetAccumulator();
1279
  TNode<String> result = Typeof(value);
1280 1281
  SetAccumulator(result);
  Dispatch();
1282 1283 1284 1285 1286 1287
}

// DeletePropertyStrict
//
// Delete the property specified in the accumulator from the object
// referenced by the register operand following strict mode semantics.
1288
IGNITION_HANDLER(DeletePropertyStrict, InterpreterAssembler) {
1289 1290
  TNode<Object> object = LoadRegisterAtOperandIndex(0);
  TNode<Object> key = GetAccumulator();
1291
  TNode<Context> context = GetContext();
1292 1293 1294
  TNode<Object> result =
      CallBuiltin(Builtins::kDeleteProperty, context, object, key,
                  SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
1295 1296
  SetAccumulator(result);
  Dispatch();
1297 1298 1299 1300 1301 1302
}

// DeletePropertySloppy
//
// Delete the property specified in the accumulator from the object
// referenced by the register operand following sloppy mode semantics.
1303
IGNITION_HANDLER(DeletePropertySloppy, InterpreterAssembler) {
1304 1305
  TNode<Object> object = LoadRegisterAtOperandIndex(0);
  TNode<Object> key = GetAccumulator();
1306
  TNode<Context> context = GetContext();
1307 1308 1309
  TNode<Object> result =
      CallBuiltin(Builtins::kDeleteProperty, context, object, key,
                  SmiConstant(Smi::FromEnum(LanguageMode::kSloppy)));
1310 1311
  SetAccumulator(result);
  Dispatch();
1312 1313 1314 1315 1316 1317
}

// GetSuperConstructor
//
// Get the super constructor from the object referenced by the accumulator.
// The result is stored in register |reg|.
1318
IGNITION_HANDLER(GetSuperConstructor, InterpreterAssembler) {
1319
  TNode<JSFunction> active_function = CAST(GetAccumulator());
1320
  TNode<Context> context = GetContext();
1321
  TNode<Object> result = GetSuperConstructor(context, active_function);
1322
  StoreRegisterAtOperandIndex(result, 0);
1323
  Dispatch();
1324 1325
}

1326 1327 1328 1329 1330 1331 1332
class InterpreterJSCallAssembler : public InterpreterAssembler {
 public:
  InterpreterJSCallAssembler(CodeAssemblerState* state, Bytecode bytecode,
                             OperandScale operand_scale)
      : InterpreterAssembler(state, bytecode, operand_scale) {}

  // Generates code to perform a JS call that collects type feedback.
1333
  void JSCall(ConvertReceiverMode receiver_mode) {
1334
    TNode<Object> function = LoadRegisterAtOperandIndex(0);
1335
    RegListNodePair args = GetRegisterListAtOperandIndex(1);
1336
    TNode<UintPtrT> slot_id = BytecodeOperandIdx(3);
1337 1338
    TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
    TNode<Context> context = GetContext();
1339 1340

    // Collect the {function} feedback.
1341
    CollectCallFeedback(function, context, maybe_feedback_vector, slot_id);
1342

1343
    // Call the function and dispatch to the next handler.
1344
    CallJSAndDispatch(function, context, args, receiver_mode);
1345 1346
  }

1347 1348
  // Generates code to perform a JS call without collecting feedback.
  void JSCallNoFeedback(ConvertReceiverMode receiver_mode) {
1349
    TNode<Object> function = LoadRegisterAtOperandIndex(0);
1350
    RegListNodePair args = GetRegisterListAtOperandIndex(1);
1351
    TNode<Context> context = GetContext();
1352 1353 1354 1355 1356

    // Call the function and dispatch to the next handler.
    CallJSAndDispatch(function, context, args, receiver_mode);
  }

1357 1358 1359 1360 1361 1362 1363
  // Generates code to perform a JS call with a known number of arguments that
  // collects type feedback.
  void JSCallN(int arg_count, ConvertReceiverMode receiver_mode) {
    // Indices and counts of operands on the bytecode.
    const int kFirstArgumentOperandIndex = 1;
    const int kReceiverOperandCount =
        (receiver_mode == ConvertReceiverMode::kNullOrUndefined) ? 0 : 1;
1364
    const int kReceiverAndArgOperandCount = kReceiverOperandCount + arg_count;
1365
    const int kSlotOperandIndex =
1366
        kFirstArgumentOperandIndex + kReceiverAndArgOperandCount;
1367

1368
    TNode<Object> function = LoadRegisterAtOperandIndex(0);
1369
    TNode<UintPtrT> slot_id = BytecodeOperandIdx(kSlotOperandIndex);
1370 1371
    TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
    TNode<Context> context = GetContext();
1372 1373

    // Collect the {function} feedback.
1374
    CollectCallFeedback(function, context, maybe_feedback_vector, slot_id);
1375

1376
    switch (kReceiverAndArgOperandCount) {
1377 1378 1379 1380 1381 1382 1383
      case 0:
        CallJSAndDispatch(function, context, Int32Constant(arg_count),
                          receiver_mode);
        break;
      case 1:
        CallJSAndDispatch(
            function, context, Int32Constant(arg_count), receiver_mode,
1384
            LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex));
1385 1386
        break;
      case 2:
1387 1388 1389 1390 1391 1392
#ifdef V8_REVERSE_JSARGS
        CallJSAndDispatch(
            function, context, Int32Constant(arg_count), receiver_mode,
            LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 1),
            LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex));
#else
1393 1394
        CallJSAndDispatch(
            function, context, Int32Constant(arg_count), receiver_mode,
1395 1396
            LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex),
            LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 1));
1397
#endif
1398 1399
        break;
      case 3:
1400 1401 1402 1403 1404 1405 1406
#ifdef V8_REVERSE_JSARGS
        CallJSAndDispatch(
            function, context, Int32Constant(arg_count), receiver_mode,
            LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 2),
            LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 1),
            LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex));
#else
1407 1408
        CallJSAndDispatch(
            function, context, Int32Constant(arg_count), receiver_mode,
1409 1410 1411
            LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex),
            LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 1),
            LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 2));
1412
#endif
1413 1414 1415
        break;
      default:
        UNREACHABLE();
1416 1417 1418 1419
    }
  }
};

1420 1421 1422 1423 1424
// Call <callable> <receiver> <arg_count> <feedback_slot_id>
//
// Call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers. Collect type feedback
// into |feedback_slot_id|
1425
IGNITION_HANDLER(CallAnyReceiver, InterpreterJSCallAssembler) {
1426
  JSCall(ConvertReceiverMode::kAny);
1427 1428
}

1429
IGNITION_HANDLER(CallProperty, InterpreterJSCallAssembler) {
1430
  JSCall(ConvertReceiverMode::kNotNullOrUndefined);
1431 1432
}

1433 1434
IGNITION_HANDLER(CallProperty0, InterpreterJSCallAssembler) {
  JSCallN(0, ConvertReceiverMode::kNotNullOrUndefined);
1435 1436
}

1437 1438
IGNITION_HANDLER(CallProperty1, InterpreterJSCallAssembler) {
  JSCallN(1, ConvertReceiverMode::kNotNullOrUndefined);
1439 1440
}

1441 1442
IGNITION_HANDLER(CallProperty2, InterpreterJSCallAssembler) {
  JSCallN(2, ConvertReceiverMode::kNotNullOrUndefined);
1443 1444
}

1445
IGNITION_HANDLER(CallUndefinedReceiver, InterpreterJSCallAssembler) {
1446
  JSCall(ConvertReceiverMode::kNullOrUndefined);
1447 1448
}

1449 1450
IGNITION_HANDLER(CallUndefinedReceiver0, InterpreterJSCallAssembler) {
  JSCallN(0, ConvertReceiverMode::kNullOrUndefined);
1451 1452
}

1453 1454
IGNITION_HANDLER(CallUndefinedReceiver1, InterpreterJSCallAssembler) {
  JSCallN(1, ConvertReceiverMode::kNullOrUndefined);
1455 1456
}

1457 1458
IGNITION_HANDLER(CallUndefinedReceiver2, InterpreterJSCallAssembler) {
  JSCallN(2, ConvertReceiverMode::kNullOrUndefined);
1459 1460
}

1461 1462 1463 1464
IGNITION_HANDLER(CallNoFeedback, InterpreterJSCallAssembler) {
  JSCallNoFeedback(ConvertReceiverMode::kAny);
}

1465 1466 1467 1468 1469
// CallRuntime <function_id> <first_arg> <arg_count>
//
// Call the runtime function |function_id| with the first argument in
// register |first_arg| and |arg_count| arguments in subsequent
// registers.
1470
IGNITION_HANDLER(CallRuntime, InterpreterAssembler) {
1471
  TNode<Uint32T> function_id = BytecodeOperandRuntimeId(0);
1472
  RegListNodePair args = GetRegisterListAtOperandIndex(1);
1473
  TNode<Context> context = GetContext();
1474
  TNode<Object> result = CAST(CallRuntimeN(function_id, context, args));
1475 1476
  SetAccumulator(result);
  Dispatch();
1477 1478 1479 1480 1481 1482 1483
}

// InvokeIntrinsic <function_id> <first_arg> <arg_count>
//
// Implements the semantic equivalent of calling the runtime function
// |function_id| with the first argument in |first_arg| and |arg_count|
// arguments in subsequent registers.
1484
IGNITION_HANDLER(InvokeIntrinsic, InterpreterAssembler) {
1485
  TNode<Uint32T> function_id = BytecodeOperandIntrinsicId(0);
1486
  RegListNodePair args = GetRegisterListAtOperandIndex(1);
1487
  TNode<Context> context = GetContext();
1488 1489
  TNode<Object> result =
      GenerateInvokeIntrinsic(this, function_id, context, args);
1490 1491
  SetAccumulator(result);
  Dispatch();
1492 1493 1494 1495 1496 1497 1498 1499
}

// CallRuntimeForPair <function_id> <first_arg> <arg_count> <first_return>
//
// Call the runtime function |function_id| which returns a pair, with the
// first argument in register |first_arg| and |arg_count| arguments in
// subsequent registers. Returns the result in <first_return> and
// <first_return + 1>
1500
IGNITION_HANDLER(CallRuntimeForPair, InterpreterAssembler) {
1501
  // Call the runtime function.
1502
  TNode<Uint32T> function_id = BytecodeOperandRuntimeId(0);
1503
  RegListNodePair args = GetRegisterListAtOperandIndex(1);
1504
  TNode<Context> context = GetContext();
1505
  Node* result_pair = CallRuntimeN(function_id, context, args, 2);
1506
  // Store the results in <first_return> and <first_return + 1>
1507 1508
  TNode<Object> result0 = CAST(Projection(0, result_pair));
  TNode<Object> result1 = CAST(Projection(1, result_pair));
1509
  StoreRegisterPairAtOperandIndex(result0, result1, 3);
1510
  Dispatch();
1511 1512 1513 1514 1515 1516
}

// CallJSRuntime <context_index> <receiver> <arg_count>
//
// Call the JS runtime function that has the |context_index| with the receiver
// in register |receiver| and |arg_count| arguments in subsequent registers.
1517
IGNITION_HANDLER(CallJSRuntime, InterpreterAssembler) {
1518
  TNode<IntPtrT> context_index = Signed(BytecodeOperandNativeContextIndex(0));
1519
  RegListNodePair args = GetRegisterListAtOperandIndex(1);
1520 1521

  // Get the function to call from the native context.
1522
  TNode<Context> context = GetContext();
1523
  TNode<NativeContext> native_context = LoadNativeContext(context);
1524
  TNode<Object> function = LoadContextElement(native_context, context_index);
1525 1526

  // Call the function.
1527
  CallJSAndDispatch(function, context, args,
1528
                    ConvertReceiverMode::kNullOrUndefined);
1529 1530 1531 1532 1533 1534 1535 1536
}

// CallWithSpread <callable> <first_arg> <arg_count>
//
// Call a JSfunction or Callable in |callable| with the receiver in
// |first_arg| and |arg_count - 1| arguments in subsequent registers. The
// final argument is always a spread.
//
1537
IGNITION_HANDLER(CallWithSpread, InterpreterAssembler) {
1538
  TNode<Object> callable = LoadRegisterAtOperandIndex(0);
1539
  RegListNodePair args = GetRegisterListAtOperandIndex(1);
1540
  TNode<UintPtrT> slot_id = BytecodeOperandIdx(3);
1541
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1542
  TNode<Context> context = GetContext();
1543 1544

  // Call into Runtime function CallWithSpread which does everything.
1545
  CallJSWithSpreadAndDispatch(callable, context, args, slot_id,
1546
                              maybe_feedback_vector);
1547 1548 1549 1550 1551 1552 1553 1554
}

// ConstructWithSpread <first_arg> <arg_count>
//
// Call the constructor in |constructor| with the first argument in register
// |first_arg| and |arg_count| arguments in subsequent registers. The final
// argument is always a spread. The new.target is in the accumulator.
//
1555
IGNITION_HANDLER(ConstructWithSpread, InterpreterAssembler) {
1556 1557
  TNode<Object> new_target = GetAccumulator();
  TNode<Object> constructor = LoadRegisterAtOperandIndex(0);
1558
  RegListNodePair args = GetRegisterListAtOperandIndex(1);
1559
  TNode<UintPtrT> slot_id = BytecodeOperandIdx(3);
1560
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1561
  TNode<Context> context = GetContext();
1562 1563
  TNode<Object> result = ConstructWithSpread(
      constructor, context, new_target, args, slot_id, maybe_feedback_vector);
1564 1565
  SetAccumulator(result);
  Dispatch();
1566 1567 1568 1569 1570 1571 1572 1573
}

// Construct <constructor> <first_arg> <arg_count>
//
// Call operator construct with |constructor| and the first argument in
// register |first_arg| and |arg_count| arguments in subsequent
// registers. The new.target is in the accumulator.
//
1574
IGNITION_HANDLER(Construct, InterpreterAssembler) {
1575 1576
  TNode<Object> new_target = GetAccumulator();
  TNode<Object> constructor = LoadRegisterAtOperandIndex(0);
1577
  RegListNodePair args = GetRegisterListAtOperandIndex(1);
1578
  TNode<UintPtrT> slot_id = BytecodeOperandIdx(3);
1579
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1580
  TNode<Context> context = GetContext();
1581 1582
  TNode<Object> result = Construct(constructor, context, new_target, args,
                                   slot_id, maybe_feedback_vector);
1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
  SetAccumulator(result);
  Dispatch();
}

class InterpreterCompareOpAssembler : public InterpreterAssembler {
 public:
  InterpreterCompareOpAssembler(CodeAssemblerState* state, Bytecode bytecode,
                                OperandScale operand_scale)
      : InterpreterAssembler(state, bytecode, operand_scale) {}

1593
  void CompareOpWithFeedback(Operation compare_op) {
1594 1595
    TNode<Object> lhs = LoadRegisterAtOperandIndex(0);
    TNode<Object> rhs = GetAccumulator();
1596
    TNode<Context> context = GetContext();
1597

1598
    TVARIABLE(Smi, var_type_feedback);
1599
    TNode<Oddball> result;
1600
    switch (compare_op) {
1601
      case Operation::kEqual:
1602 1603
        result = Equal(lhs, rhs, context, &var_type_feedback);
        break;
1604
      case Operation::kStrictEqual:
1605 1606
        result = StrictEqual(lhs, rhs, &var_type_feedback);
        break;
1607 1608 1609 1610 1611 1612
      case Operation::kLessThan:
      case Operation::kGreaterThan:
      case Operation::kLessThanOrEqual:
      case Operation::kGreaterThanOrEqual:
        result = RelationalComparison(compare_op, lhs, rhs, context,
                                      &var_type_feedback);
1613 1614 1615
        break;
      default:
        UNREACHABLE();
1616 1617
    }

1618
    TNode<UintPtrT> slot_index = BytecodeOperandIdx(1);
1619
    TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1620 1621
    UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector,
                   slot_index);
1622 1623
    SetAccumulator(result);
    Dispatch();
1624 1625
  }
};
1626 1627 1628 1629

// TestEqual <src>
//
// Test if the value in the <src> register equals the accumulator.
1630
IGNITION_HANDLER(TestEqual, InterpreterCompareOpAssembler) {
1631
  CompareOpWithFeedback(Operation::kEqual);
1632 1633 1634 1635 1636
}

// TestEqualStrict <src>
//
// Test if the value in the <src> register is strictly equal to the accumulator.
1637
IGNITION_HANDLER(TestEqualStrict, InterpreterCompareOpAssembler) {
1638
  CompareOpWithFeedback(Operation::kStrictEqual);
1639 1640 1641 1642 1643
}

// TestLessThan <src>
//
// Test if the value in the <src> register is less than the accumulator.
1644
IGNITION_HANDLER(TestLessThan, InterpreterCompareOpAssembler) {
1645
  CompareOpWithFeedback(Operation::kLessThan);
1646 1647 1648 1649 1650
}

// TestGreaterThan <src>
//
// Test if the value in the <src> register is greater than the accumulator.
1651
IGNITION_HANDLER(TestGreaterThan, InterpreterCompareOpAssembler) {
1652
  CompareOpWithFeedback(Operation::kGreaterThan);
1653 1654 1655 1656 1657 1658
}

// TestLessThanOrEqual <src>
//
// Test if the value in the <src> register is less than or equal to the
// accumulator.
1659
IGNITION_HANDLER(TestLessThanOrEqual, InterpreterCompareOpAssembler) {
1660
  CompareOpWithFeedback(Operation::kLessThanOrEqual);
1661 1662 1663 1664 1665 1666
}

// TestGreaterThanOrEqual <src>
//
// Test if the value in the <src> register is greater than or equal to the
// accumulator.
1667
IGNITION_HANDLER(TestGreaterThanOrEqual, InterpreterCompareOpAssembler) {
1668
  CompareOpWithFeedback(Operation::kGreaterThanOrEqual);
1669 1670
}

1671
// TestReferenceEqual <src>
1672
//
1673 1674 1675
// Test if the value in the <src> register is equal to the accumulator
// by means of simple comparison. For SMIs and simple reference comparisons.
IGNITION_HANDLER(TestReferenceEqual, InterpreterAssembler) {
1676 1677
  TNode<Object> lhs = LoadRegisterAtOperandIndex(0);
  TNode<Object> rhs = GetAccumulator();
1678
  TNode<Oddball> result = SelectBooleanConstant(TaggedEqual(lhs, rhs));
1679 1680
  SetAccumulator(result);
  Dispatch();
1681 1682
}

1683
// TestIn <src> <feedback_slot>
1684 1685 1686
//
// Test if the object referenced by the register operand is a property of the
// object referenced by the accumulator.
1687
IGNITION_HANDLER(TestIn, InterpreterAssembler) {
1688 1689
  TNode<Object> name = LoadRegisterAtOperandIndex(0);
  TNode<Object> object = GetAccumulator();
1690
  TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
1691
  TNode<HeapObject> feedback_vector = LoadFeedbackVector();
1692
  TNode<Context> context = GetContext();
1693

1694
  TVARIABLE(Object, var_result);
1695 1696
  var_result = CallBuiltin(Builtins::kKeyedHasIC, context, object, name, slot,
                           feedback_vector);
1697
  SetAccumulator(var_result.value());
1698
  Dispatch();
1699 1700
}

1701
// TestInstanceOf <src> <feedback_slot>
1702 1703 1704
//
// Test if the object referenced by the <src> register is an an instance of type
// referenced by the accumulator.
1705
IGNITION_HANDLER(TestInstanceOf, InterpreterAssembler) {
1706 1707
  TNode<Object> object = LoadRegisterAtOperandIndex(0);
  TNode<Object> callable = GetAccumulator();
1708 1709
  TNode<UintPtrT> slot_id = BytecodeOperandIdx(1);
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
1710
  TNode<Context> context = GetContext();
1711

1712
  CollectInstanceOfFeedback(callable, context, maybe_feedback_vector, slot_id);
1713
  SetAccumulator(InstanceOf(object, callable, context));
1714
  Dispatch();
1715 1716
}

1717
// TestUndetectable
1718
//
1719 1720
// Test if the value in the accumulator is undetectable (null, undefined or
// document.all).
1721 1722
IGNITION_HANDLER(TestUndetectable, InterpreterAssembler) {
  Label return_false(this), end(this);
1723
  TNode<Object> object = GetAccumulator();
1724 1725

  // If the object is an Smi then return false.
1726
  SetAccumulator(FalseConstant());
1727
  GotoIf(TaggedIsSmi(object), &end);
1728 1729

  // If it is a HeapObject, load the map and check for undetectable bit.
1730 1731
  TNode<Oddball> result =
      SelectBooleanConstant(IsUndetectableMap(LoadMap(CAST(object))));
1732 1733
  SetAccumulator(result);
  Goto(&end);
1734

1735
  BIND(&end);
1736
  Dispatch();
1737 1738
}

1739
// TestNull
1740
//
1741
// Test if the value in accumulator is strictly equal to null.
1742
IGNITION_HANDLER(TestNull, InterpreterAssembler) {
1743
  TNode<Object> object = GetAccumulator();
1744 1745
  TNode<Oddball> result =
      SelectBooleanConstant(TaggedEqual(object, NullConstant()));
1746 1747
  SetAccumulator(result);
  Dispatch();
1748 1749
}

1750
// TestUndefined
1751
//
1752
// Test if the value in the accumulator is strictly equal to undefined.
1753
IGNITION_HANDLER(TestUndefined, InterpreterAssembler) {
1754
  TNode<Object> object = GetAccumulator();
1755
  TNode<Oddball> result =
1756
      SelectBooleanConstant(TaggedEqual(object, UndefinedConstant()));
1757 1758
  SetAccumulator(result);
  Dispatch();
1759 1760 1761 1762 1763 1764
}

// TestTypeOf <literal_flag>
//
// Tests if the object in the <accumulator> is typeof the literal represented
// by |literal_flag|.
1765
IGNITION_HANDLER(TestTypeOf, InterpreterAssembler) {
1766
  TNode<Object> object = GetAccumulator();
1767
  TNode<Uint32T> literal_flag = BytecodeOperandFlag(0);
1768

1769
#define MAKE_LABEL(name, lower_case) Label if_##lower_case(this);
1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781
  TYPEOF_LITERAL_LIST(MAKE_LABEL)
#undef MAKE_LABEL

#define LABEL_POINTER(name, lower_case) &if_##lower_case,
  Label* labels[] = {TYPEOF_LITERAL_LIST(LABEL_POINTER)};
#undef LABEL_POINTER

#define CASE(name, lower_case) \
  static_cast<int32_t>(TestTypeOfFlags::LiteralFlag::k##name),
  int32_t cases[] = {TYPEOF_LITERAL_LIST(CASE)};
#undef CASE

1782
  Label if_true(this), if_false(this), end(this);
1783

1784 1785 1786 1787 1788 1789
  // We juse use the final label as the default and properly CSA_ASSERT
  // that the {literal_flag} is valid here; this significantly improves
  // the generated code (compared to having a default label that aborts).
  unsigned const num_cases = arraysize(cases);
  CSA_ASSERT(this, Uint32LessThan(literal_flag, Int32Constant(num_cases)));
  Switch(literal_flag, labels[num_cases - 1], cases, labels, num_cases - 1);
1790

1791
  BIND(&if_number);
1792
  {
1793 1794 1795
    Comment("IfNumber");
    GotoIfNumber(object, &if_true);
    Goto(&if_false);
1796
  }
1797
  BIND(&if_string);
1798
  {
1799 1800
    Comment("IfString");
    GotoIf(TaggedIsSmi(object), &if_false);
1801
    Branch(IsString(CAST(object)), &if_true, &if_false);
1802
  }
1803
  BIND(&if_symbol);
1804
  {
1805 1806
    Comment("IfSymbol");
    GotoIf(TaggedIsSmi(object), &if_false);
1807
    Branch(IsSymbol(CAST(object)), &if_true, &if_false);
1808
  }
1809
  BIND(&if_boolean);
1810
  {
1811
    Comment("IfBoolean");
1812 1813
    GotoIf(TaggedEqual(object, TrueConstant()), &if_true);
    Branch(TaggedEqual(object, FalseConstant()), &if_true, &if_false);
1814
  }
Georg Neis's avatar
Georg Neis committed
1815 1816 1817 1818
  BIND(&if_bigint);
  {
    Comment("IfBigInt");
    GotoIf(TaggedIsSmi(object), &if_false);
1819
    Branch(IsBigInt(CAST(object)), &if_true, &if_false);
Georg Neis's avatar
Georg Neis committed
1820
  }
1821
  BIND(&if_undefined);
1822
  {
1823 1824
    Comment("IfUndefined");
    GotoIf(TaggedIsSmi(object), &if_false);
1825
    // Check it is not null and the map has the undetectable bit set.
1826
    GotoIf(IsNull(object), &if_false);
1827
    Branch(IsUndetectableMap(LoadMap(CAST(object))), &if_true, &if_false);
1828
  }
1829
  BIND(&if_function);
1830
  {
1831 1832
    Comment("IfFunction");
    GotoIf(TaggedIsSmi(object), &if_false);
1833
    // Check if callable bit is set and not undetectable.
1834
    TNode<Int32T> map_bitfield = LoadMapBitField(LoadMap(CAST(object)));
1835 1836 1837
    TNode<Int32T> callable_undetectable = Word32And(
        map_bitfield, Int32Constant(Map::Bits1::IsUndetectableBit::kMask |
                                    Map::Bits1::IsCallableBit::kMask));
1838
    Branch(Word32Equal(callable_undetectable,
1839
                       Int32Constant(Map::Bits1::IsCallableBit::kMask)),
1840
           &if_true, &if_false);
1841
  }
1842
  BIND(&if_object);
1843
  {
1844 1845
    Comment("IfObject");
    GotoIf(TaggedIsSmi(object), &if_false);
1846 1847

    // If the object is null then return true.
1848
    GotoIf(IsNull(object), &if_true);
1849 1850

    // Check if the object is a receiver type and is not undefined or callable.
1851
    TNode<Map> map = LoadMap(CAST(object));
1852
    GotoIfNot(IsJSReceiverMap(map), &if_false);
1853
    TNode<Int32T> map_bitfield = LoadMapBitField(map);
1854 1855 1856
    TNode<Int32T> callable_undetectable = Word32And(
        map_bitfield, Int32Constant(Map::Bits1::IsUndetectableBit::kMask |
                                    Map::Bits1::IsCallableBit::kMask));
1857 1858
    Branch(Word32Equal(callable_undetectable, Int32Constant(0)), &if_true,
           &if_false);
1859
  }
1860
  BIND(&if_other);
1861 1862
  {
    // Typeof doesn't return any other string value.
1863
    Goto(&if_false);
1864 1865
  }

1866
  BIND(&if_false);
1867
  {
1868
    SetAccumulator(FalseConstant());
1869
    Goto(&end);
1870
  }
1871
  BIND(&if_true);
1872
  {
1873
    SetAccumulator(TrueConstant());
1874
    Goto(&end);
1875
  }
1876
  BIND(&end);
1877
  Dispatch();
1878 1879 1880 1881
}

// Jump <imm>
//
1882
// Jump by the number of bytes represented by the immediate operand |imm|.
1883
IGNITION_HANDLER(Jump, InterpreterAssembler) {
1884
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
1885
  Jump(relative_jump);
1886 1887 1888 1889
}

// JumpConstant <idx>
//
1890 1891
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool.
1892
IGNITION_HANDLER(JumpConstant, InterpreterAssembler) {
1893
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
1894
  Jump(relative_jump);
1895 1896 1897 1898
}

// JumpIfTrue <imm>
//
1899
// Jump by the number of bytes represented by an immediate operand if the
1900 1901
// accumulator contains true. This only works for boolean inputs, and
// will misbehave if passed arbitrary input values.
1902
IGNITION_HANDLER(JumpIfTrue, InterpreterAssembler) {
1903
  TNode<Object> accumulator = GetAccumulator();
1904
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
1905 1906
  CSA_ASSERT(this, IsBoolean(CAST(accumulator)));
  JumpIfTaggedEqual(accumulator, TrueConstant(), relative_jump);
1907 1908 1909 1910
}

// JumpIfTrueConstant <idx>
//
1911 1912 1913
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the accumulator contains true. This only works for boolean inputs,
// and will misbehave if passed arbitrary input values.
1914
IGNITION_HANDLER(JumpIfTrueConstant, InterpreterAssembler) {
1915
  TNode<Object> accumulator = GetAccumulator();
1916
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
1917 1918
  CSA_ASSERT(this, IsBoolean(CAST(accumulator)));
  JumpIfTaggedEqual(accumulator, TrueConstant(), relative_jump);
1919 1920 1921 1922
}

// JumpIfFalse <imm>
//
1923
// Jump by the number of bytes represented by an immediate operand if the
1924 1925
// accumulator contains false. This only works for boolean inputs, and
// will misbehave if passed arbitrary input values.
1926
IGNITION_HANDLER(JumpIfFalse, InterpreterAssembler) {
1927
  TNode<Object> accumulator = GetAccumulator();
1928
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
1929 1930
  CSA_ASSERT(this, IsBoolean(CAST(accumulator)));
  JumpIfTaggedEqual(accumulator, FalseConstant(), relative_jump);
1931 1932 1933 1934
}

// JumpIfFalseConstant <idx>
//
1935 1936 1937
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the accumulator contains false. This only works for boolean inputs,
// and will misbehave if passed arbitrary input values.
1938
IGNITION_HANDLER(JumpIfFalseConstant, InterpreterAssembler) {
1939
  TNode<Object> accumulator = GetAccumulator();
1940
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
1941 1942
  CSA_ASSERT(this, IsBoolean(CAST(accumulator)));
  JumpIfTaggedEqual(accumulator, FalseConstant(), relative_jump);
1943 1944 1945 1946
}

// JumpIfToBooleanTrue <imm>
//
1947
// Jump by the number of bytes represented by an immediate operand if the object
1948
// referenced by the accumulator is true when the object is cast to boolean.
1949
IGNITION_HANDLER(JumpIfToBooleanTrue, InterpreterAssembler) {
1950
  TNode<Object> value = GetAccumulator();
1951
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
1952 1953
  Label if_true(this), if_false(this);
  BranchIfToBooleanIsTrue(value, &if_true, &if_false);
1954
  BIND(&if_true);
1955
  Jump(relative_jump);
1956
  BIND(&if_false);
1957
  Dispatch();
1958 1959 1960 1961
}

// JumpIfToBooleanTrueConstant <idx>
//
1962 1963 1964
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the object referenced by the accumulator is true when the object is
// cast to boolean.
1965
IGNITION_HANDLER(JumpIfToBooleanTrueConstant, InterpreterAssembler) {
1966 1967
  TNode<Object> value = GetAccumulator();
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
1968 1969
  Label if_true(this), if_false(this);
  BranchIfToBooleanIsTrue(value, &if_true, &if_false);
1970
  BIND(&if_true);
1971
  Jump(relative_jump);
1972
  BIND(&if_false);
1973
  Dispatch();
1974 1975 1976 1977
}

// JumpIfToBooleanFalse <imm>
//
1978
// Jump by the number of bytes represented by an immediate operand if the object
1979
// referenced by the accumulator is false when the object is cast to boolean.
1980
IGNITION_HANDLER(JumpIfToBooleanFalse, InterpreterAssembler) {
1981
  TNode<Object> value = GetAccumulator();
1982
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
1983 1984
  Label if_true(this), if_false(this);
  BranchIfToBooleanIsTrue(value, &if_true, &if_false);
1985
  BIND(&if_true);
1986
  Dispatch();
1987
  BIND(&if_false);
1988
  Jump(relative_jump);
1989 1990 1991 1992
}

// JumpIfToBooleanFalseConstant <idx>
//
1993 1994 1995
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the object referenced by the accumulator is false when the object is
// cast to boolean.
1996
IGNITION_HANDLER(JumpIfToBooleanFalseConstant, InterpreterAssembler) {
1997 1998
  TNode<Object> value = GetAccumulator();
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
1999 2000
  Label if_true(this), if_false(this);
  BranchIfToBooleanIsTrue(value, &if_true, &if_false);
2001
  BIND(&if_true);
2002
  Dispatch();
2003
  BIND(&if_false);
2004
  Jump(relative_jump);
2005 2006 2007 2008
}

// JumpIfNull <imm>
//
2009
// Jump by the number of bytes represented by an immediate operand if the object
2010
// referenced by the accumulator is the null constant.
2011
IGNITION_HANDLER(JumpIfNull, InterpreterAssembler) {
2012
  TNode<Object> accumulator = GetAccumulator();
2013
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
2014
  JumpIfTaggedEqual(accumulator, NullConstant(), relative_jump);
2015 2016 2017 2018
}

// JumpIfNullConstant <idx>
//
2019 2020
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the object referenced by the accumulator is the null constant.
2021
IGNITION_HANDLER(JumpIfNullConstant, InterpreterAssembler) {
2022
  TNode<Object> accumulator = GetAccumulator();
2023
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
2024
  JumpIfTaggedEqual(accumulator, NullConstant(), relative_jump);
2025 2026
}

2027 2028
// JumpIfNotNull <imm>
//
2029
// Jump by the number of bytes represented by an immediate operand if the object
2030
// referenced by the accumulator is not the null constant.
2031
IGNITION_HANDLER(JumpIfNotNull, InterpreterAssembler) {
2032
  TNode<Object> accumulator = GetAccumulator();
2033
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
2034
  JumpIfTaggedNotEqual(accumulator, NullConstant(), relative_jump);
2035 2036 2037 2038
}

// JumpIfNotNullConstant <idx>
//
2039 2040
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the object referenced by the accumulator is not the null constant.
2041
IGNITION_HANDLER(JumpIfNotNullConstant, InterpreterAssembler) {
2042
  TNode<Object> accumulator = GetAccumulator();
2043
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
2044
  JumpIfTaggedNotEqual(accumulator, NullConstant(), relative_jump);
2045 2046
}

2047 2048
// JumpIfUndefined <imm>
//
2049
// Jump by the number of bytes represented by an immediate operand if the object
2050
// referenced by the accumulator is the undefined constant.
2051
IGNITION_HANDLER(JumpIfUndefined, InterpreterAssembler) {
2052
  TNode<Object> accumulator = GetAccumulator();
2053
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
2054
  JumpIfTaggedEqual(accumulator, UndefinedConstant(), relative_jump);
2055 2056 2057 2058
}

// JumpIfUndefinedConstant <idx>
//
2059 2060
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the object referenced by the accumulator is the undefined constant.
2061
IGNITION_HANDLER(JumpIfUndefinedConstant, InterpreterAssembler) {
2062
  TNode<Object> accumulator = GetAccumulator();
2063
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
2064
  JumpIfTaggedEqual(accumulator, UndefinedConstant(), relative_jump);
2065 2066
}

2067 2068
// JumpIfNotUndefined <imm>
//
2069
// Jump by the number of bytes represented by an immediate operand if the object
2070
// referenced by the accumulator is not the undefined constant.
2071
IGNITION_HANDLER(JumpIfNotUndefined, InterpreterAssembler) {
2072
  TNode<Object> accumulator = GetAccumulator();
2073
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
2074
  JumpIfTaggedNotEqual(accumulator, UndefinedConstant(), relative_jump);
2075 2076 2077 2078
}

// JumpIfNotUndefinedConstant <idx>
//
2079 2080 2081
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the object referenced by the accumulator is not the undefined
// constant.
2082
IGNITION_HANDLER(JumpIfNotUndefinedConstant, InterpreterAssembler) {
2083
  TNode<Object> accumulator = GetAccumulator();
2084
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
2085
  JumpIfTaggedNotEqual(accumulator, UndefinedConstant(), relative_jump);
2086 2087
}

2088 2089 2090 2091 2092
// JumpIfUndefinedOrNull <imm>
//
// Jump by the number of bytes represented by an immediate operand if the object
// referenced by the accumulator is the undefined constant or the null constant.
IGNITION_HANDLER(JumpIfUndefinedOrNull, InterpreterAssembler) {
2093
  TNode<Object> accumulator = GetAccumulator();
2094 2095 2096 2097 2098 2099 2100

  Label do_jump(this);
  GotoIf(IsUndefined(accumulator), &do_jump);
  GotoIf(IsNull(accumulator), &do_jump);
  Dispatch();

  BIND(&do_jump);
2101
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
2102 2103 2104 2105 2106 2107 2108 2109 2110
  Jump(relative_jump);
}

// JumpIfUndefinedOrNullConstant <idx>
//
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the object referenced by the accumulator is the undefined constant or
// the null constant.
IGNITION_HANDLER(JumpIfUndefinedOrNullConstant, InterpreterAssembler) {
2111
  TNode<Object> accumulator = GetAccumulator();
2112 2113 2114 2115 2116 2117 2118

  Label do_jump(this);
  GotoIf(IsUndefined(accumulator), &do_jump);
  GotoIf(IsNull(accumulator), &do_jump);
  Dispatch();

  BIND(&do_jump);
2119
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
2120 2121 2122
  Jump(relative_jump);
}

2123 2124
// JumpIfJSReceiver <imm>
//
2125
// Jump by the number of bytes represented by an immediate operand if the object
2126
// referenced by the accumulator is a JSReceiver.
2127
IGNITION_HANDLER(JumpIfJSReceiver, InterpreterAssembler) {
2128
  TNode<Object> accumulator = GetAccumulator();
2129
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
2130

2131 2132
  Label if_object(this), if_notobject(this, Label::kDeferred), if_notsmi(this);
  Branch(TaggedIsSmi(accumulator), &if_notobject, &if_notsmi);
2133

2134
  BIND(&if_notsmi);
2135
  Branch(IsJSReceiver(CAST(accumulator)), &if_object, &if_notobject);
2136
  BIND(&if_object);
2137
  Jump(relative_jump);
2138

2139
  BIND(&if_notobject);
2140
  Dispatch();
2141 2142 2143 2144
}

// JumpIfJSReceiverConstant <idx>
//
2145 2146
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the object referenced by the accumulator is a JSReceiver.
2147
IGNITION_HANDLER(JumpIfJSReceiverConstant, InterpreterAssembler) {
2148
  TNode<Object> accumulator = GetAccumulator();
2149
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
2150

2151 2152
  Label if_object(this), if_notobject(this), if_notsmi(this);
  Branch(TaggedIsSmi(accumulator), &if_notobject, &if_notsmi);
2153

2154
  BIND(&if_notsmi);
2155
  Branch(IsJSReceiver(CAST(accumulator)), &if_object, &if_notobject);
2156

2157
  BIND(&if_object);
2158
  Jump(relative_jump);
2159

2160
  BIND(&if_notobject);
2161
  Dispatch();
2162 2163 2164 2165
}

// JumpLoop <imm> <loop_depth>
//
2166
// Jump by the number of bytes represented by the immediate operand |imm|. Also
2167 2168
// performs a loop nesting check, a stack check, and potentially triggers OSR in
// case the current OSR level matches (or exceeds) the specified |loop_depth|.
2169
IGNITION_HANDLER(JumpLoop, InterpreterAssembler) {
2170 2171
  TNode<IntPtrT> relative_jump = Signed(BytecodeOperandUImmWord(0));
  TNode<Int32T> loop_depth = BytecodeOperandImm(1);
2172
  TNode<Int8T> osr_level = LoadOsrNestingLevel();
2173 2174 2175
  TNode<Context> context = GetContext();

  PerformStackCheck(context);
2176 2177 2178

  // Check if OSR points at the given {loop_depth} are armed by comparing it to
  // the current {osr_level} loaded from the header of the BytecodeArray.
2179
  Label ok(this), osr_armed(this, Label::kDeferred);
2180
  TNode<BoolT> condition = Int32GreaterThanOrEqual(loop_depth, osr_level);
2181
  Branch(condition, &ok, &osr_armed);
2182

2183
  BIND(&ok);
2184
  JumpBackward(relative_jump);
2185

2186
  BIND(&osr_armed);
2187
  {
2188
    Callable callable = CodeFactory::InterpreterOnStackReplacement(isolate());
2189
    TNode<Code> target = HeapConstant(callable.code());
2190 2191
    CallStub(callable.descriptor(), target, context);
    JumpBackward(relative_jump);
2192 2193 2194
  }
}

2195 2196 2197 2198 2199 2200 2201 2202
// SwitchOnSmiNoFeedback <table_start> <table_length> <case_value_base>
//
// Jump by the number of bytes defined by a Smi in a table in the constant pool,
// where the table starts at |table_start| and has |table_length| entries.
// The table is indexed by the accumulator, minus |case_value_base|. If the
// case_value falls outside of the table |table_length|, fall-through to the
// next bytecode.
IGNITION_HANDLER(SwitchOnSmiNoFeedback, InterpreterAssembler) {
2203
  TNode<Object> acc = GetAccumulator();
2204 2205 2206
  TNode<UintPtrT> table_start = BytecodeOperandIdx(0);
  TNode<UintPtrT> table_length = BytecodeOperandUImmWord(1);
  TNode<IntPtrT> case_value_base = BytecodeOperandImmIntPtr(2);
2207 2208 2209 2210 2211 2212 2213 2214

  Label fall_through(this);

  // The accumulator must be a Smi.
  // TODO(leszeks): Add a bytecode with type feedback that allows other
  // accumulator values.
  CSA_ASSERT(this, TaggedIsSmi(acc));

2215
  TNode<IntPtrT> case_value = IntPtrSub(SmiUntag(CAST(acc)), case_value_base);
2216 2217
  GotoIf(IntPtrLessThan(case_value, IntPtrConstant(0)), &fall_through);
  GotoIf(IntPtrGreaterThanOrEqual(case_value, table_length), &fall_through);
2218 2219
  TNode<WordT> entry = IntPtrAdd(table_start, case_value);
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntry(entry);
2220 2221
  Jump(relative_jump);

2222
  BIND(&fall_through);
2223 2224 2225
  Dispatch();
}

2226 2227 2228 2229
// CreateRegExpLiteral <pattern_idx> <literal_idx> <flags>
//
// Creates a regular expression literal for literal index <literal_idx> with
// <flags> and the pattern in <pattern_idx>.
2230
IGNITION_HANDLER(CreateRegExpLiteral, InterpreterAssembler) {
2231
  TNode<Object> pattern = LoadConstantPoolEntryAtOperandIndex(0);
2232
  TNode<HeapObject> feedback_vector = LoadFeedbackVector();
2233
  TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
2234 2235
  TNode<Smi> flags =
      SmiFromInt32(UncheckedCast<Int32T>(BytecodeOperandFlag(2)));
2236
  TNode<Context> context = GetContext();
2237

2238
  TVARIABLE(JSRegExp, result);
2239

2240
  ConstructorBuiltinsAssembler constructor_assembler(state());
2241
  result = constructor_assembler.EmitCreateRegExpLiteral(
2242
      feedback_vector, slot, pattern, flags, context);
2243
  SetAccumulator(result.value());
2244
  Dispatch();
2245 2246 2247 2248 2249 2250
}

// CreateArrayLiteral <element_idx> <literal_idx> <flags>
//
// Creates an array literal for literal index <literal_idx> with
// CreateArrayLiteral flags <flags> and constant elements in <element_idx>.
2251
IGNITION_HANDLER(CreateArrayLiteral, InterpreterAssembler) {
2252
  TNode<HeapObject> feedback_vector = LoadFeedbackVector();
2253
  TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
2254
  TNode<Context> context = GetContext();
2255
  TNode<Uint32T> bytecode_flags = BytecodeOperandFlag(2);
2256 2257

  Label fast_shallow_clone(this), call_runtime(this, Label::kDeferred);
2258 2259 2260
  // No feedback, so handle it as a slow case.
  GotoIf(IsUndefined(feedback_vector), &call_runtime);

2261 2262 2263
  Branch(IsSetWord32<CreateArrayLiteralFlags::FastCloneSupportedBit>(
             bytecode_flags),
         &fast_shallow_clone, &call_runtime);
2264

2265
  BIND(&fast_shallow_clone);
2266
  {
2267
    ConstructorBuiltinsAssembler constructor_assembler(state());
2268
    TNode<JSArray> result = constructor_assembler.EmitCreateShallowArrayLiteral(
2269
        CAST(feedback_vector), slot, context, &call_runtime,
2270
        TRACK_ALLOCATION_SITE);
2271 2272
    SetAccumulator(result);
    Dispatch();
2273 2274
  }

2275
  BIND(&call_runtime);
2276
  {
2277
    TNode<UintPtrT> flags_raw =
2278 2279 2280
        DecodeWordFromWord32<CreateArrayLiteralFlags::FlagsBits>(
            bytecode_flags);
    TNode<Smi> flags = SmiTag(Signed(flags_raw));
2281
    TNode<Object> constant_elements = LoadConstantPoolEntryAtOperandIndex(0);
2282
    TNode<Object> result =
2283
        CallRuntime(Runtime::kCreateArrayLiteral, context, feedback_vector,
2284
                    slot, constant_elements, flags);
2285 2286
    SetAccumulator(result);
    Dispatch();
2287 2288 2289
  }
}

2290 2291 2292 2293
// CreateEmptyArrayLiteral <literal_idx>
//
// Creates an empty JSArray literal for literal index <literal_idx>.
IGNITION_HANDLER(CreateEmptyArrayLiteral, InterpreterAssembler) {
2294
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
2295
  TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(0);
2296
  TNode<Context> context = GetContext();
2297 2298

  Label no_feedback(this, Label::kDeferred), end(this);
2299
  TVARIABLE(JSArray, result);
2300
  GotoIf(IsUndefined(maybe_feedback_vector), &no_feedback);
2301

2302
  ConstructorBuiltinsAssembler constructor_assembler(state());
2303
  result = constructor_assembler.EmitCreateEmptyArrayLiteral(
2304
      CAST(maybe_feedback_vector), slot, context);
2305 2306 2307 2308 2309 2310
  Goto(&end);

  BIND(&no_feedback);
  {
    TNode<Map> array_map = LoadJSArrayElementsMap(GetInitialFastElementsKind(),
                                                  LoadNativeContext(context));
2311 2312 2313 2314
    TNode<Smi> length = SmiConstant(0);
    TNode<IntPtrT> capacity = IntPtrConstant(0);
    result = AllocateJSArray(GetInitialFastElementsKind(), array_map, capacity,
                             length);
2315 2316 2317 2318 2319
    Goto(&end);
  }

  BIND(&end);
  SetAccumulator(result.value());
2320 2321 2322
  Dispatch();
}

2323 2324 2325
// CreateArrayFromIterable
//
// Spread the given iterable from the accumulator into a new JSArray.
2326
// TODO(neis): Turn this into an intrinsic when we're running out of bytecodes.
2327
IGNITION_HANDLER(CreateArrayFromIterable, InterpreterAssembler) {
2328
  TNode<Object> iterable = GetAccumulator();
2329
  TNode<Context> context = GetContext();
2330
  TNode<Object> result =
2331 2332 2333 2334 2335
      CallBuiltin(Builtins::kIterableToListWithSymbolLookup, context, iterable);
  SetAccumulator(result);
  Dispatch();
}

2336 2337 2338 2339
// CreateObjectLiteral <element_idx> <literal_idx> <flags>
//
// Creates an object literal for literal index <literal_idx> with
// CreateObjectLiteralFlags <flags> and constant elements in <element_idx>.
2340
IGNITION_HANDLER(CreateObjectLiteral, InterpreterAssembler) {
2341
  TNode<HeapObject> feedback_vector = LoadFeedbackVector();
2342
  TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(1);
2343
  TNode<Uint32T> bytecode_flags = BytecodeOperandFlag(2);
2344

2345
  Label if_fast_clone(this), if_not_fast_clone(this, Label::kDeferred);
2346 2347 2348 2349
  // No feedback, so handle it as a slow case.
  GotoIf(IsUndefined(feedback_vector), &if_not_fast_clone);

  // Check if we can do a fast clone or have to call the runtime.
2350 2351
  Branch(IsSetWord32<CreateObjectLiteralFlags::FastCloneSupportedBit>(
             bytecode_flags),
2352
         &if_fast_clone, &if_not_fast_clone);
2353

2354
  BIND(&if_fast_clone);
2355
  {
2356
    // If we can do a fast clone do the fast-path in CreateShallowObjectLiteral.
2357
    ConstructorBuiltinsAssembler constructor_assembler(state());
2358 2359
    TNode<HeapObject> result =
        constructor_assembler.EmitCreateShallowObjectLiteral(
2360
            CAST(feedback_vector), slot, &if_not_fast_clone);
2361
    SetAccumulator(result);
2362
    Dispatch();
2363 2364
  }

2365
  BIND(&if_not_fast_clone);
2366 2367
  {
    // If we can't do a fast clone, call into the runtime.
2368 2369
    TNode<ObjectBoilerplateDescription> object_boilerplate_description =
        CAST(LoadConstantPoolEntryAtOperandIndex(0));
2370
    TNode<Context> context = GetContext();
2371

2372
    TNode<UintPtrT> flags_raw =
2373 2374 2375
        DecodeWordFromWord32<CreateObjectLiteralFlags::FlagsBits>(
            bytecode_flags);
    TNode<Smi> flags = SmiTag(Signed(flags_raw));
2376

2377 2378 2379
    TNode<Object> result =
        CallRuntime(Runtime::kCreateObjectLiteral, context, feedback_vector,
                    slot, object_boilerplate_description, flags);
2380
    SetAccumulator(result);
2381
    // TODO(klaasb) build a single dispatch once the call is inlined
2382
    Dispatch();
2383 2384 2385
  }
}

2386
// CreateEmptyObjectLiteral
2387
//
2388
// Creates an empty JSObject literal.
2389
IGNITION_HANDLER(CreateEmptyObjectLiteral, InterpreterAssembler) {
2390
  TNode<Context> context = GetContext();
2391
  ConstructorBuiltinsAssembler constructor_assembler(state());
2392 2393
  TNode<JSObject> result =
      constructor_assembler.EmitCreateEmptyObjectLiteral(context);
2394 2395 2396 2397
  SetAccumulator(result);
  Dispatch();
}

2398 2399 2400 2401 2402
// CloneObject <source_idx> <flags> <feedback_slot>
//
// Allocates a new JSObject with each enumerable own property copied from
// {source}, converting getters into data properties.
IGNITION_HANDLER(CloneObject, InterpreterAssembler) {
2403
  TNode<Object> source = LoadRegisterAtOperandIndex(0);
2404
  TNode<Uint32T> bytecode_flags = BytecodeOperandFlag(1);
2405
  TNode<UintPtrT> raw_flags =
2406
      DecodeWordFromWord32<CreateObjectLiteralFlags::FlagsBits>(bytecode_flags);
2407
  TNode<Smi> smi_flags = SmiTag(Signed(raw_flags));
2408
  TNode<TaggedIndex> slot = BytecodeOperandIdxTaggedIndex(2);
2409
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
2410
  TNode<Context> context = GetContext();
2411

2412 2413 2414
  TNode<Object> result = CallBuiltin(Builtins::kCloneObjectIC, context, source,
                                     smi_flags, slot, maybe_feedback_vector);
  SetAccumulator(result);
2415 2416 2417
  Dispatch();
}

2418
// GetTemplateObject <descriptor_idx> <literal_idx>
2419 2420 2421 2422 2423
//
// Creates the template to pass for tagged templates and returns it in the
// accumulator, creating and caching the site object on-demand as per the
// specification.
IGNITION_HANDLER(GetTemplateObject, InterpreterAssembler) {
2424 2425 2426 2427 2428
  TNode<Context> context = GetContext();
  TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
  TNode<SharedFunctionInfo> shared_info = LoadObjectField<SharedFunctionInfo>(
      closure, JSFunction::kSharedFunctionInfoOffset);
  TNode<Object> description = LoadConstantPoolEntryAtOperandIndex(0);
2429
  TNode<UintPtrT> slot = BytecodeOperandIdx(1);
2430 2431 2432 2433 2434
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
  TNode<Object> result =
      CallBuiltin(Builtins::kGetTemplateObject, context, shared_info,
                  description, slot, maybe_feedback_vector);
  SetAccumulator(result);
2435 2436 2437
  Dispatch();
}

2438
// CreateClosure <index> <slot> <flags>
2439 2440
//
// Creates a new closure for SharedFunctionInfo at position |index| in the
2441
// constant pool and with pretenuring controlled by |flags|.
2442
IGNITION_HANDLER(CreateClosure, InterpreterAssembler) {
2443 2444
  TNode<Object> shared = LoadConstantPoolEntryAtOperandIndex(0);
  TNode<Uint32T> flags = BytecodeOperandFlag(2);
2445
  TNode<Context> context = GetContext();
2446
  TNode<UintPtrT> slot = BytecodeOperandIdx(1);
2447

2448
  Label if_undefined(this);
2449 2450 2451
  TNode<ClosureFeedbackCellArray> feedback_cell_array =
      LoadClosureFeedbackArray(
          CAST(LoadRegister(Register::function_closure())));
2452 2453
  TNode<FeedbackCell> feedback_cell =
      CAST(LoadFixedArrayElement(feedback_cell_array, slot));
2454

2455 2456 2457 2458 2459
  Label if_fast(this), if_slow(this, Label::kDeferred);
  Branch(IsSetWord32<CreateClosureFlags::FastNewClosureBit>(flags), &if_fast,
         &if_slow);

  BIND(&if_fast);
2460
  {
2461
    TNode<Object> result =
2462
        CallBuiltin(Builtins::kFastNewClosure, context, shared, feedback_cell);
2463 2464
    SetAccumulator(result);
    Dispatch();
2465
  }
2466 2467 2468 2469 2470 2471 2472 2473 2474

  BIND(&if_slow);
  {
    Label if_newspace(this), if_oldspace(this);
    Branch(IsSetWord32<CreateClosureFlags::PretenuredBit>(flags), &if_oldspace,
           &if_newspace);

    BIND(&if_newspace);
    {
2475
      TNode<Object> result =
2476
          CallRuntime(Runtime::kNewClosure, context, shared, feedback_cell);
2477 2478 2479 2480 2481 2482
      SetAccumulator(result);
      Dispatch();
    }

    BIND(&if_oldspace);
    {
2483 2484
      TNode<Object> result = CallRuntime(Runtime::kNewClosure_Tenured, context,
                                         shared, feedback_cell);
2485 2486 2487 2488
      SetAccumulator(result);
      Dispatch();
    }
  }
2489 2490 2491 2492
}

// CreateBlockContext <index>
//
2493
// Creates a new block context with the scope info constant at |index|.
2494
IGNITION_HANDLER(CreateBlockContext, InterpreterAssembler) {
2495
  TNode<ScopeInfo> scope_info = CAST(LoadConstantPoolEntryAtOperandIndex(0));
2496
  TNode<Context> context = GetContext();
2497
  SetAccumulator(CallRuntime(Runtime::kPushBlockContext, context, scope_info));
2498
  Dispatch();
2499 2500
}

2501
// CreateCatchContext <exception> <scope_info_idx>
2502
//
2503 2504
// Creates a new context for a catch block with the |exception| in a register
// and the ScopeInfo at |scope_info_idx|.
2505
IGNITION_HANDLER(CreateCatchContext, InterpreterAssembler) {
2506
  TNode<Object> exception = LoadRegisterAtOperandIndex(0);
2507
  TNode<ScopeInfo> scope_info = CAST(LoadConstantPoolEntryAtOperandIndex(1));
2508
  TNode<Context> context = GetContext();
2509 2510
  SetAccumulator(
      CallRuntime(Runtime::kPushCatchContext, context, exception, scope_info));
2511
  Dispatch();
2512 2513
}

2514
// CreateFunctionContext <scope_info_idx> <slots>
2515 2516
//
// Creates a new context with number of |slots| for the function closure.
2517
IGNITION_HANDLER(CreateFunctionContext, InterpreterAssembler) {
2518 2519
  TNode<UintPtrT> scope_info_idx = BytecodeOperandIdx(0);
  TNode<ScopeInfo> scope_info = CAST(LoadConstantPoolEntry(scope_info_idx));
2520
  TNode<Uint32T> slots = BytecodeOperandUImm(1);
2521
  TNode<Context> context = GetContext();
2522 2523
  ConstructorBuiltinsAssembler constructor_assembler(state());
  SetAccumulator(constructor_assembler.EmitFastNewFunctionContext(
2524
      scope_info, slots, context, FUNCTION_SCOPE));
2525
  Dispatch();
2526 2527
}

2528
// CreateEvalContext <scope_info_idx> <slots>
2529 2530
//
// Creates a new context with number of |slots| for an eval closure.
2531
IGNITION_HANDLER(CreateEvalContext, InterpreterAssembler) {
2532 2533
  TNode<UintPtrT> scope_info_idx = BytecodeOperandIdx(0);
  TNode<ScopeInfo> scope_info = CAST(LoadConstantPoolEntry(scope_info_idx));
2534
  TNode<Uint32T> slots = BytecodeOperandUImm(1);
2535
  TNode<Context> context = GetContext();
2536 2537
  ConstructorBuiltinsAssembler constructor_assembler(state());
  SetAccumulator(constructor_assembler.EmitFastNewFunctionContext(
2538
      scope_info, slots, context, EVAL_SCOPE));
2539
  Dispatch();
2540 2541 2542 2543 2544
}

// CreateWithContext <register> <scope_info_idx>
//
// Creates a new context with the ScopeInfo at |scope_info_idx| for a
2545
// with-statement with the object in |register|.
2546
IGNITION_HANDLER(CreateWithContext, InterpreterAssembler) {
2547
  TNode<Object> object = LoadRegisterAtOperandIndex(0);
2548
  TNode<ScopeInfo> scope_info = CAST(LoadConstantPoolEntryAtOperandIndex(1));
2549
  TNode<Context> context = GetContext();
2550 2551
  SetAccumulator(
      CallRuntime(Runtime::kPushWithContext, context, object, scope_info));
2552
  Dispatch();
2553 2554 2555 2556 2557
}

// CreateMappedArguments
//
// Creates a new mapped arguments object.
2558
IGNITION_HANDLER(CreateMappedArguments, InterpreterAssembler) {
2559
  TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
2560
  TNode<Context> context = GetContext();
2561

2562 2563
  Label if_duplicate_parameters(this, Label::kDeferred);
  Label if_not_duplicate_parameters(this);
2564 2565 2566 2567

  // Check if function has duplicate parameters.
  // TODO(rmcilroy): Remove this check when FastNewSloppyArgumentsStub supports
  // duplicate parameters.
2568 2569
  TNode<SharedFunctionInfo> shared_info = LoadObjectField<SharedFunctionInfo>(
      closure, JSFunction::kSharedFunctionInfoOffset);
2570 2571
  TNode<Uint32T> flags =
      LoadObjectField<Uint32T>(shared_info, SharedFunctionInfo::kFlagsOffset);
2572
  TNode<BoolT> has_duplicate_parameters =
2573
      IsSetWord32<SharedFunctionInfo::HasDuplicateParametersBit>(flags);
2574 2575
  Branch(has_duplicate_parameters, &if_duplicate_parameters,
         &if_not_duplicate_parameters);
2576

2577
  BIND(&if_not_duplicate_parameters);
2578
  {
2579
    TNode<JSObject> result = EmitFastNewSloppyArguments(context, closure);
2580 2581
    SetAccumulator(result);
    Dispatch();
2582 2583
  }

2584
  BIND(&if_duplicate_parameters);
2585
  {
2586
    TNode<Object> result =
2587
        CallRuntime(Runtime::kNewSloppyArguments, context, closure);
2588 2589
    SetAccumulator(result);
    Dispatch();
2590 2591 2592 2593 2594 2595
  }
}

// CreateUnmappedArguments
//
// Creates a new unmapped arguments object.
2596
IGNITION_HANDLER(CreateUnmappedArguments, InterpreterAssembler) {
2597
  TNode<Context> context = GetContext();
2598
  TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
2599
  TorqueGeneratedExportedMacrosAssembler builtins_assembler(state());
2600
  TNode<JSObject> result =
2601
      builtins_assembler.EmitFastNewStrictArguments(context, closure);
2602 2603
  SetAccumulator(result);
  Dispatch();
2604 2605 2606 2607 2608
}

// CreateRestParameter
//
// Creates a new rest parameter array.
2609
IGNITION_HANDLER(CreateRestParameter, InterpreterAssembler) {
2610
  TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
2611
  TNode<Context> context = GetContext();
2612
  TorqueGeneratedExportedMacrosAssembler builtins_assembler(state());
2613
  TNode<JSObject> result =
2614
      builtins_assembler.EmitFastNewRestArguments(context, closure);
2615 2616
  SetAccumulator(result);
  Dispatch();
2617 2618 2619 2620 2621 2622
}

// SetPendingMessage
//
// Sets the pending message to the value in the accumulator, and returns the
// previous pending message in the accumulator.
2623
IGNITION_HANDLER(SetPendingMessage, InterpreterAssembler) {
2624
  TNode<ExternalReference> pending_message = ExternalConstant(
2625
      ExternalReference::address_of_pending_message_obj(isolate()));
2626 2627
  TNode<HeapObject> previous_message =
      UncheckedCast<HeapObject>(LoadFullTagged(pending_message));
2628
  TNode<Object> new_message = GetAccumulator();
2629
  StoreFullTaggedNoWriteBarrier(pending_message, new_message);
2630 2631
  SetAccumulator(previous_message);
  Dispatch();
2632 2633 2634 2635 2636
}

// Throw
//
// Throws the exception in the accumulator.
2637
IGNITION_HANDLER(Throw, InterpreterAssembler) {
2638
  TNode<Object> exception = GetAccumulator();
2639
  TNode<Context> context = GetContext();
2640
  CallRuntime(Runtime::kThrow, context, exception);
2641
  // We shouldn't ever return from a throw.
2642
  Abort(AbortReason::kUnexpectedReturnFromThrow);
2643
  Unreachable();
2644 2645 2646 2647 2648
}

// ReThrow
//
// Re-throws the exception in the accumulator.
2649
IGNITION_HANDLER(ReThrow, InterpreterAssembler) {
2650
  TNode<Object> exception = GetAccumulator();
2651
  TNode<Context> context = GetContext();
2652
  CallRuntime(Runtime::kReThrow, context, exception);
2653
  // We shouldn't ever return from a throw.
2654
  Abort(AbortReason::kUnexpectedReturnFromThrow);
2655
  Unreachable();
2656 2657
}

2658
// Abort <abort_reason>
2659 2660 2661
//
// Aborts execution (via a call to the runtime function).
IGNITION_HANDLER(Abort, InterpreterAssembler) {
2662 2663
  TNode<UintPtrT> reason = BytecodeOperandIdx(0);
  CallRuntime(Runtime::kAbort, NoContextConstant(), SmiTag(Signed(reason)));
2664 2665 2666
  Unreachable();
}

2667 2668 2669
// Return
//
// Return the value in the accumulator.
2670 2671
IGNITION_HANDLER(Return, InterpreterAssembler) {
  UpdateInterruptBudgetOnReturn();
2672
  TNode<Object> accumulator = GetAccumulator();
2673
  Return(accumulator);
2674 2675
}

2676 2677 2678 2679
// ThrowReferenceErrorIfHole <variable_name>
//
// Throws an exception if the value in the accumulator is TheHole.
IGNITION_HANDLER(ThrowReferenceErrorIfHole, InterpreterAssembler) {
2680
  TNode<Object> value = GetAccumulator();
2681 2682

  Label throw_error(this, Label::kDeferred);
2683
  GotoIf(TaggedEqual(value, TheHoleConstant()), &throw_error);
2684 2685 2686 2687
  Dispatch();

  BIND(&throw_error);
  {
2688
    TNode<Name> name = CAST(LoadConstantPoolEntryAtOperandIndex(0));
2689 2690
    CallRuntime(Runtime::kThrowAccessedUninitializedVariable, GetContext(),
                name);
2691
    // We shouldn't ever return from a throw.
2692
    Abort(AbortReason::kUnexpectedReturnFromThrow);
2693
    Unreachable();
2694 2695 2696 2697 2698 2699 2700
  }
}

// ThrowSuperNotCalledIfHole
//
// Throws an exception if the value in the accumulator is TheHole.
IGNITION_HANDLER(ThrowSuperNotCalledIfHole, InterpreterAssembler) {
2701
  TNode<Object> value = GetAccumulator();
2702 2703

  Label throw_error(this, Label::kDeferred);
2704
  GotoIf(TaggedEqual(value, TheHoleConstant()), &throw_error);
2705 2706 2707 2708 2709 2710
  Dispatch();

  BIND(&throw_error);
  {
    CallRuntime(Runtime::kThrowSuperNotCalled, GetContext());
    // We shouldn't ever return from a throw.
2711
    Abort(AbortReason::kUnexpectedReturnFromThrow);
2712
    Unreachable();
2713 2714 2715 2716 2717 2718 2719 2720
  }
}

// ThrowSuperAlreadyCalledIfNotHole
//
// Throws SuperAleradyCalled exception if the value in the accumulator is not
// TheHole.
IGNITION_HANDLER(ThrowSuperAlreadyCalledIfNotHole, InterpreterAssembler) {
2721
  TNode<Object> value = GetAccumulator();
2722 2723

  Label throw_error(this, Label::kDeferred);
2724
  GotoIf(TaggedNotEqual(value, TheHoleConstant()), &throw_error);
2725 2726 2727 2728 2729 2730
  Dispatch();

  BIND(&throw_error);
  {
    CallRuntime(Runtime::kThrowSuperAlreadyCalledError, GetContext());
    // We shouldn't ever return from a throw.
2731
    Abort(AbortReason::kUnexpectedReturnFromThrow);
2732
    Unreachable();
2733 2734 2735
  }
}

2736 2737 2738
// Debugger
//
// Call runtime to handle debugger statement.
2739
IGNITION_HANDLER(Debugger, InterpreterAssembler) {
2740
  TNode<Context> context = GetContext();
2741 2742
  CallStub(CodeFactory::HandleDebuggerStatement(isolate()), context);
  Dispatch();
2743 2744 2745 2746 2747
}

// DebugBreak
//
// Call runtime to handle a debug break.
2748 2749 2750 2751 2752 2753
#define DEBUG_BREAK(Name, ...)                                               \
  IGNITION_HANDLER(Name, InterpreterAssembler) {                             \
    TNode<Context> context = GetContext();                                   \
    TNode<Object> accumulator = GetAccumulator();                            \
    TNode<Object> result_pair =                                              \
        CallRuntime(Runtime::kDebugBreakOnBytecode, context, accumulator);   \
2754
    TNode<Object> return_value = CAST(Projection(0, result_pair));           \
2755 2756 2757 2758
    TNode<IntPtrT> original_bytecode = SmiUntag(Projection(1, result_pair)); \
    MaybeDropFrames(context);                                                \
    SetAccumulator(return_value);                                            \
    DispatchToBytecode(original_bytecode, BytecodeOffset());                 \
2759
  }
2760
DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK)
2761 2762
#undef DEBUG_BREAK

2763 2764 2765 2766 2767
// IncBlockCounter <slot>
//
// Increment the execution count for the given slot. Used for block code
// coverage.
IGNITION_HANDLER(IncBlockCounter, InterpreterAssembler) {
2768
  TNode<Object> closure = LoadRegister(Register::function_closure());
2769
  TNode<Smi> coverage_array_slot = BytecodeOperandIdxSmi(0);
2770
  TNode<Context> context = GetContext();
2771

2772 2773
  CallBuiltin(Builtins::kIncBlockCounter, context, closure,
              coverage_array_slot);
2774 2775 2776 2777

  Dispatch();
}

2778
// ForInEnumerate <receiver>
2779
//
2780 2781 2782 2783
// Enumerates the enumerable keys of the |receiver| and either returns the
// map of the |receiver| if it has a usable enum cache or a fixed array
// with the keys to enumerate in the accumulator.
IGNITION_HANDLER(ForInEnumerate, InterpreterAssembler) {
2784
  TNode<JSReceiver> receiver = CAST(LoadRegisterAtOperandIndex(0));
2785
  TNode<Context> context = GetContext();
2786 2787

  Label if_empty(this), if_runtime(this, Label::kDeferred);
2788
  TNode<Map> receiver_map = CheckEnumCache(receiver, &if_empty, &if_runtime);
2789 2790 2791 2792 2793
  SetAccumulator(receiver_map);
  Dispatch();

  BIND(&if_empty);
  {
2794
    TNode<FixedArray> result = EmptyFixedArrayConstant();
2795 2796 2797 2798 2799 2800
    SetAccumulator(result);
    Dispatch();
  }

  BIND(&if_runtime);
  {
2801 2802
    TNode<Object> result =
        CallRuntime(Runtime::kForInEnumerate, context, receiver);
2803 2804 2805 2806 2807 2808 2809 2810 2811 2812
    SetAccumulator(result);
    Dispatch();
  }
}

// ForInPrepare <cache_info_triple>
//
// Returns state for for..in loop execution based on the enumerator in
// the accumulator register, which is the result of calling ForInEnumerate
// on a JSReceiver object.
2813 2814 2815
// The result is output in registers |cache_info_triple| to
// |cache_info_triple + 2|, with the registers holding cache_type, cache_array,
// and cache_length respectively.
2816
IGNITION_HANDLER(ForInPrepare, InterpreterAssembler) {
2817
  // The {enumerator} is either a Map or a FixedArray.
2818
  TNode<HeapObject> enumerator = CAST(GetAccumulator());
2819
  TNode<UintPtrT> vector_index = BytecodeOperandIdx(1);
2820
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
2821

2822 2823 2824
  // Check if we're using an enum cache.
  Label if_fast(this), if_slow(this);
  Branch(IsMap(enumerator), &if_fast, &if_slow);
2825

2826
  BIND(&if_fast);
2827
  {
2828
    // Load the enumeration length and cache from the {enumerator}.
2829 2830
    TNode<Map> map_enumerator = CAST(enumerator);
    TNode<WordT> enum_length = LoadMapEnumLength(map_enumerator);
2831 2832
    CSA_ASSERT(this, WordNotEqual(enum_length,
                                  IntPtrConstant(kInvalidEnumCacheSentinel)));
2833
    TNode<DescriptorArray> descriptors = LoadMapDescriptors(map_enumerator);
2834 2835 2836 2837
    TNode<EnumCache> enum_cache = LoadObjectField<EnumCache>(
        descriptors, DescriptorArray::kEnumCacheOffset);
    TNode<FixedArray> enum_keys =
        LoadObjectField<FixedArray>(enum_cache, EnumCache::kKeysOffset);
2838 2839

    // Check if we have enum indices available.
2840 2841
    TNode<FixedArray> enum_indices =
        LoadObjectField<FixedArray>(enum_cache, EnumCache::kIndicesOffset);
2842 2843 2844
    TNode<IntPtrT> enum_indices_length =
        LoadAndUntagFixedArrayBaseLength(enum_indices);
    TNode<Smi> feedback = SelectSmiConstant(
2845 2846
        IntPtrLessThanOrEqual(enum_length, enum_indices_length),
        ForInFeedback::kEnumCacheKeysAndIndices, ForInFeedback::kEnumCacheKeys);
2847
    UpdateFeedback(feedback, maybe_feedback_vector, vector_index);
2848 2849

    // Construct the cache info triple.
2850 2851
    TNode<Map> cache_type = map_enumerator;
    TNode<FixedArray> cache_array = enum_keys;
2852
    TNode<Smi> cache_length = SmiTag(Signed(enum_length));
2853
    StoreRegisterTripleAtOperandIndex(cache_type, cache_array, cache_length, 0);
2854
    Dispatch();
2855
  }
2856 2857

  BIND(&if_slow);
2858
  {
2859
    // The {enumerator} is a FixedArray with all the keys to iterate.
2860
    TNode<FixedArray> array_enumerator = CAST(enumerator);
2861 2862

    // Record the fact that we hit the for-in slow-path.
2863
    UpdateFeedback(SmiConstant(ForInFeedback::kAny), maybe_feedback_vector,
2864 2865 2866
                   vector_index);

    // Construct the cache info triple.
2867 2868
    TNode<FixedArray> cache_type = array_enumerator;
    TNode<FixedArray> cache_array = array_enumerator;
2869
    TNode<Smi> cache_length = LoadFixedArrayBaseLength(array_enumerator);
2870
    StoreRegisterTripleAtOperandIndex(cache_type, cache_array, cache_length, 0);
2871
    Dispatch();
2872 2873 2874 2875 2876 2877
  }
}

// ForInNext <receiver> <index> <cache_info_pair>
//
// Returns the next enumerable property in the the accumulator.
2878
IGNITION_HANDLER(ForInNext, InterpreterAssembler) {
2879 2880
  TNode<HeapObject> receiver = CAST(LoadRegisterAtOperandIndex(0));
  TNode<Object> index = LoadRegisterAtOperandIndex(1);
2881 2882
  TNode<Object> cache_type;
  TNode<Object> cache_array;
2883
  std::tie(cache_type, cache_array) = LoadRegisterPairAtOperandIndex(2);
2884
  TNode<UintPtrT> vector_index = BytecodeOperandIdx(3);
2885
  TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
2886 2887

  // Load the next key from the enumeration array.
2888 2889
  TNode<Object> key = LoadFixedArrayElement(CAST(cache_array), index, 0,
                                            CodeStubAssembler::SMI_PARAMETERS);
2890 2891

  // Check if we can use the for-in fast path potentially using the enum cache.
2892
  Label if_fast(this), if_slow(this, Label::kDeferred);
2893 2894
  TNode<Map> receiver_map = LoadMap(receiver);
  Branch(TaggedEqual(receiver_map, cache_type), &if_fast, &if_slow);
2895
  BIND(&if_fast);
2896 2897
  {
    // Enum cache in use for {receiver}, the {key} is definitely valid.
2898 2899
    SetAccumulator(key);
    Dispatch();
2900
  }
2901
  BIND(&if_slow);
2902
  {
2903
    // Record the fact that we hit the for-in slow-path.
2904
    UpdateFeedback(SmiConstant(ForInFeedback::kAny), maybe_feedback_vector,
2905
                   vector_index);
2906 2907

    // Need to filter the {key} for the {receiver}.
2908
    TNode<Context> context = GetContext();
2909 2910
    TNode<Object> result =
        CallBuiltin(Builtins::kForInFilter, context, key, receiver);
2911 2912
    SetAccumulator(result);
    Dispatch();
2913 2914 2915 2916 2917 2918
  }
}

// ForInContinue <index> <cache_length>
//
// Returns false if the end of the enumerable properties has been reached.
2919
IGNITION_HANDLER(ForInContinue, InterpreterAssembler) {
2920 2921
  TNode<Object> index = LoadRegisterAtOperandIndex(0);
  TNode<Object> cache_length = LoadRegisterAtOperandIndex(1);
2922 2923

  // Check if {index} is at {cache_length} already.
2924
  Label if_true(this), if_false(this), end(this);
2925
  Branch(TaggedEqual(index, cache_length), &if_true, &if_false);
2926
  BIND(&if_true);
2927
  {
2928
    SetAccumulator(FalseConstant());
2929
    Goto(&end);
2930
  }
2931
  BIND(&if_false);
2932
  {
2933
    SetAccumulator(TrueConstant());
2934
    Goto(&end);
2935
  }
2936
  BIND(&end);
2937
  Dispatch();
2938 2939 2940 2941 2942 2943
}

// ForInStep <index>
//
// Increments the loop counter in register |index| and stores the result
// in the accumulator.
2944
IGNITION_HANDLER(ForInStep, InterpreterAssembler) {
2945 2946 2947
  TNode<Smi> index = CAST(LoadRegisterAtOperandIndex(0));
  TNode<Smi> one = SmiConstant(1);
  TNode<Smi> result = SmiAdd(index, one);
2948 2949
  SetAccumulator(result);
  Dispatch();
2950 2951
}

2952 2953
// GetIterator <object>
//
2954
// Retrieves the object[Symbol.iterator] method, calls it and stores
2955 2956 2957 2958
// the result in the accumulator
// TODO(swapnilgaikwad): Extend the functionality of the bytecode to
// check if the result is a JSReceiver else throw SymbolIteratorInvalid
// runtime exception
2959
IGNITION_HANDLER(GetIterator, InterpreterAssembler) {
2960 2961 2962
  TNode<Object> receiver = LoadRegisterAtOperandIndex(0);
  TNode<Context> context = GetContext();
  TNode<HeapObject> feedback_vector = LoadFeedbackVector();
2963 2964
  TNode<TaggedIndex> load_slot = BytecodeOperandIdxTaggedIndex(1);
  TNode<TaggedIndex> call_slot = BytecodeOperandIdxTaggedIndex(2);
2965

2966
  TNode<Object> iterator =
2967
      CallBuiltin(Builtins::kGetIteratorWithFeedback, context, receiver,
2968
                  load_slot, call_slot, feedback_vector);
2969
  SetAccumulator(iterator);
2970 2971 2972
  Dispatch();
}

2973 2974 2975
// Wide
//
// Prefix bytecode indicating next bytecode has wide (16-bit) operands.
2976 2977
IGNITION_HANDLER(Wide, InterpreterAssembler) {
  DispatchWide(OperandScale::kDouble);
2978 2979 2980 2981 2982
}

// ExtraWide
//
// Prefix bytecode indicating next bytecode has extra-wide (32-bit) operands.
2983 2984
IGNITION_HANDLER(ExtraWide, InterpreterAssembler) {
  DispatchWide(OperandScale::kQuadruple);
2985 2986 2987 2988 2989
}

// Illegal
//
// An invalid bytecode aborting execution if dispatched.
2990 2991
IGNITION_HANDLER(Illegal, InterpreterAssembler) {
  Abort(AbortReason::kInvalidBytecode);
2992
  Unreachable();
2993
}
2994

2995
// SuspendGenerator <generator> <first input register> <register count>
2996
// <suspend_id>
2997
//
2998 2999 3000 3001
// Stores the parameters and the register file in the generator. Also stores
// the current context, |suspend_id|, and the current bytecode offset
// (for debugging purposes) into the generator. Then, returns the value
// in the accumulator.
3002
IGNITION_HANDLER(SuspendGenerator, InterpreterAssembler) {
3003
  TNode<JSGeneratorObject> generator = CAST(LoadRegisterAtOperandIndex(0));
3004 3005
  TNode<FixedArray> array = CAST(LoadObjectField(
      generator, JSGeneratorObject::kParametersAndRegistersOffset));
3006
  TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
3007
  TNode<Context> context = GetContext();
3008
  RegListNodePair registers = GetRegisterListAtOperandIndex(1);
3009
  TNode<Smi> suspend_id = BytecodeOperandUImmSmi(3);
3010

3011 3012
  TNode<SharedFunctionInfo> shared =
      CAST(LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset));
3013 3014
  TNode<Int32T> formal_parameter_count = LoadObjectField<Uint16T>(
      shared, SharedFunctionInfo::kFormalParameterCountOffset);
3015 3016

  ExportParametersAndRegisterFile(array, registers, formal_parameter_count);
3017
  StoreObjectField(generator, JSGeneratorObject::kContextOffset, context);
3018 3019
  StoreObjectField(generator, JSGeneratorObject::kContinuationOffset,
                   suspend_id);
3020

3021 3022
  // Store the bytecode offset in the [input_or_debug_pos] field, to be used by
  // the inspector.
3023
  TNode<Smi> offset = SmiTag(BytecodeOffset());
3024 3025
  StoreObjectField(generator, JSGeneratorObject::kInputOrDebugPosOffset,
                   offset);
3026 3027

  UpdateInterruptBudgetOnReturn();
3028
  Return(GetAccumulator());
3029 3030
}

3031
// SwitchOnGeneratorState <generator> <table_start> <table_length>
3032
//
3033 3034 3035 3036
// If |generator| is undefined, falls through. Otherwise, loads the
// generator's state (overwriting it with kGeneratorExecuting), sets the context
// to the generator's resume context, and performs state dispatch on the
// generator's state by looking up the generator state in a jump table in the
3037 3038
// constant pool, starting at |table_start|, and of length |table_length|.
IGNITION_HANDLER(SwitchOnGeneratorState, InterpreterAssembler) {
3039
  TNode<Object> maybe_generator = LoadRegisterAtOperandIndex(0);
3040

3041
  Label fallthrough(this);
3042 3043 3044
  GotoIf(TaggedEqual(maybe_generator, UndefinedConstant()), &fallthrough);

  TNode<JSGeneratorObject> generator = CAST(maybe_generator);
3045

3046 3047 3048
  TNode<Smi> state =
      CAST(LoadObjectField(generator, JSGeneratorObject::kContinuationOffset));
  TNode<Smi> new_state = SmiConstant(JSGeneratorObject::kGeneratorExecuting);
3049
  StoreObjectField(generator, JSGeneratorObject::kContinuationOffset,
3050
                   new_state);
3051

3052 3053
  TNode<Context> context =
      CAST(LoadObjectField(generator, JSGeneratorObject::kContextOffset));
3054 3055
  SetContext(context);

3056
  TNode<UintPtrT> table_start = BytecodeOperandIdx(1);
3057 3058
  // TODO(leszeks): table_length is only used for a CSA_ASSERT, we don't
  // actually need it otherwise.
3059
  TNode<UintPtrT> table_length = BytecodeOperandUImmWord(2);
3060 3061 3062 3063

  // The state must be a Smi.
  CSA_ASSERT(this, TaggedIsSmi(state));

3064
  TNode<IntPtrT> case_value = SmiUntag(state);
3065 3066 3067 3068 3069

  CSA_ASSERT(this, IntPtrGreaterThanOrEqual(case_value, IntPtrConstant(0)));
  CSA_ASSERT(this, IntPtrLessThan(case_value, table_length));
  USE(table_length);

3070 3071
  TNode<WordT> entry = IntPtrAdd(table_start, case_value);
  TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntry(entry);
3072
  Jump(relative_jump);
3073 3074 3075

  BIND(&fallthrough);
  Dispatch();
3076 3077
}

3078
// ResumeGenerator <generator> <first output register> <register count>
3079
//
3080 3081 3082
// Imports the register file stored in the generator and marks the generator
// state as executing.
IGNITION_HANDLER(ResumeGenerator, InterpreterAssembler) {
3083 3084
  TNode<JSGeneratorObject> generator = CAST(LoadRegisterAtOperandIndex(0));
  TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
3085
  RegListNodePair registers = GetRegisterListAtOperandIndex(1);
3086

3087 3088
  TNode<SharedFunctionInfo> shared =
      CAST(LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset));
3089 3090
  TNode<Int32T> formal_parameter_count = LoadObjectField<Uint16T>(
      shared, SharedFunctionInfo::kFormalParameterCountOffset);
3091

3092
  ImportRegisterFile(
3093 3094
      CAST(LoadObjectField(generator,
                           JSGeneratorObject::kParametersAndRegistersOffset)),
3095
      registers, formal_parameter_count);
3096

3097 3098 3099 3100
  // Return the generator's input_or_debug_pos in the accumulator.
  SetAccumulator(
      LoadObjectField(generator, JSGeneratorObject::kInputOrDebugPosOffset));

3101 3102 3103
  Dispatch();
}

3104 3105
#undef IGNITION_HANDLER

3106 3107
}  // namespace

3108 3109
Handle<Code> GenerateBytecodeHandler(Isolate* isolate, const char* debug_name,
                                     Bytecode bytecode,
3110
                                     OperandScale operand_scale,
3111 3112
                                     int builtin_index,
                                     const AssemblerOptions& options) {
3113 3114
  Zone zone(isolate->allocator(), ZONE_NAME);
  compiler::CodeAssemblerState state(
3115
      isolate, &zone, InterpreterDispatchDescriptor{}, Code::BYTECODE_HANDLER,
3116
      debug_name,
3117 3118
      FLAG_untrusted_code_mitigations
          ? PoisoningMitigationLevel::kPoisonCriticalOnly
3119
          : PoisoningMitigationLevel::kDontPoison,
3120
      builtin_index);
3121

3122 3123 3124 3125 3126 3127 3128 3129 3130
  switch (bytecode) {
#define CALL_GENERATOR(Name, ...)                     \
  case Bytecode::k##Name:                             \
    Name##Assembler::Generate(&state, operand_scale); \
    break;
    BYTECODE_LIST(CALL_GENERATOR);
#undef CALL_GENERATOR
  }

3131
  Handle<Code> code = compiler::CodeAssembler::GenerateCode(&state, options);
3132

3133 3134
#ifdef ENABLE_DISASSEMBLER
  if (FLAG_trace_ignition_codegen) {
3135
    StdoutStream os;
3136
    code->Disassemble(Bytecodes::ToString(bytecode), os, isolate);
3137 3138 3139
    os << std::flush;
  }
#endif  // ENABLE_DISASSEMBLER
3140

3141
  return code;
3142 3143 3144 3145 3146
}

}  // namespace interpreter
}  // namespace internal
}  // namespace v8