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