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