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