Chromium Code Reviews| Index: src/interpreter/interpreter.cc |
| diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc |
| index 6af06fddbb74311de367d9aaca53e09592a8e0c6..d0a8c1017f41b382e67ceb565dfa5d886ddb9a4e 100644 |
| --- a/src/interpreter/interpreter.cc |
| +++ b/src/interpreter/interpreter.cc |
| @@ -4,26 +4,19 @@ |
| #include "src/interpreter/interpreter.h" |
| -#include <array> |
| #include <fstream> |
| #include <memory> |
| #include "src/ast/prettyprinter.h" |
| -#include "src/builtins/builtins-arguments.h" |
| -#include "src/builtins/builtins-constructor.h" |
| -#include "src/builtins/builtins-forin.h" |
| -#include "src/code-factory.h" |
| #include "src/compilation-info.h" |
| #include "src/compiler.h" |
| #include "src/counters.h" |
| #include "src/debug/debug.h" |
| #include "src/factory.h" |
|
rmcilroy
2017/03/20 15:51:41
are debug.h and factory.h unneeded now?
Jakob Kummerow
2017/03/20 16:31:01
Done.
|
| #include "src/ic/accessor-assembler.h" |
|
rmcilroy
2017/03/20 15:51:41
unneeded?
Jakob Kummerow
2017/03/20 16:31:01
Yes, forgot to delete it. Done.
|
| -#include "src/interpreter/bytecode-flags.h" |
| #include "src/interpreter/bytecode-generator.h" |
| #include "src/interpreter/bytecodes.h" |
| -#include "src/interpreter/interpreter-assembler.h" |
| -#include "src/interpreter/interpreter-intrinsics.h" |
| +#include "src/interpreter/interpreter-generator.h" |
| #include "src/log.h" |
| #include "src/objects-inl.h" |
| #include "src/zone/zone.h" |
|
rmcilroy
2017/03/20 15:51:41
I think you can also probably drop zone.h and poss
Jakob Kummerow
2017/03/20 16:31:01
Done.
|
| @@ -32,12 +25,6 @@ namespace v8 { |
| namespace internal { |
| namespace interpreter { |
| -using compiler::Node; |
| -typedef CodeStubAssembler::Label Label; |
| -typedef CodeStubAssembler::Variable Variable; |
| - |
| -#define __ assembler-> |
| - |
| class InterpreterCompilationJob final : public CompilationJob { |
| public: |
| explicit InterpreterCompilationJob(CompilationInfo* info); |
| @@ -94,7 +81,6 @@ Interpreter::Interpreter(Isolate* isolate) : isolate_(isolate) { |
| void Interpreter::Initialize() { |
| if (!ShouldInitializeDispatchTable()) return; |
| - Zone zone(isolate_->allocator(), ZONE_NAME); |
| HandleScope scope(isolate_); |
| if (FLAG_trace_ignition_dispatches) { |
| @@ -113,9 +99,8 @@ void Interpreter::Initialize() { |
| }; |
| for (OperandScale operand_scale : kOperandScales) { |
| -#define GENERATE_CODE(Name, ...) \ |
| - InstallBytecodeHandler(&zone, Bytecode::k##Name, operand_scale, \ |
| - &Interpreter::Do##Name); |
| +#define GENERATE_CODE(Name, ...) \ |
| + InstallBytecodeHandler(isolate_, Bytecode::k##Name, operand_scale); |
| BYTECODE_LIST(GENERATE_CODE) |
| #undef GENERATE_CODE |
| } |
| @@ -162,29 +147,14 @@ bool Interpreter::ReuseExistingHandler(Bytecode bytecode, |
| } |
| } |
| -void Interpreter::InstallBytecodeHandler(Zone* zone, Bytecode bytecode, |
| - OperandScale operand_scale, |
| - BytecodeGeneratorFunc generator) { |
| +void Interpreter::InstallBytecodeHandler(Isolate* isolate, Bytecode bytecode, |
| + OperandScale operand_scale) { |
| if (!Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) return; |
| if (ReuseExistingHandler(bytecode, operand_scale)) return; |
| size_t index = GetDispatchTableIndex(bytecode, operand_scale); |
| - InterpreterDispatchDescriptor descriptor(isolate_); |
| - compiler::CodeAssemblerState state( |
| - isolate_, zone, descriptor, Code::ComputeFlags(Code::BYTECODE_HANDLER), |
| - Bytecodes::ToString(bytecode), Bytecodes::ReturnCount(bytecode)); |
| - InterpreterAssembler assembler(&state, bytecode, operand_scale); |
| - if (Bytecodes::MakesCallAlongCriticalPath(bytecode)) { |
| - assembler.SaveBytecodeOffset(); |
| - } |
| - (this->*generator)(&assembler); |
| - Handle<Code> code = compiler::CodeAssembler::GenerateCode(&state); |
| + Handle<Code> code = GenerateBytecodeHandler(isolate, bytecode, operand_scale); |
| dispatch_table_[index] = code->entry(); |
| - TraceCodegen(code); |
| - PROFILE(isolate_, CodeCreateEvent( |
| - CodeEventListener::BYTECODE_HANDLER_TAG, |
| - AbstractCode::cast(*code), |
| - Bytecodes::ToString(bytecode, operand_scale).c_str())); |
| } |
| Code* Interpreter::GetBytecodeHandler(Bytecode bytecode, |
| @@ -329,16 +299,6 @@ bool Interpreter::ShouldInitializeDispatchTable() { |
| return !IsDispatchTableInitialized(); |
| } |
| -void Interpreter::TraceCodegen(Handle<Code> code) { |
| -#ifdef ENABLE_DISASSEMBLER |
| - if (FLAG_trace_ignition_codegen) { |
| - OFStream os(stdout); |
| - code->Disassemble(nullptr, os); |
| - os << std::flush; |
| - } |
| -#endif // ENABLE_DISASSEMBLER |
| -} |
| - |
| const char* Interpreter::LookupNameOfBytecodeHandler(Code* code) { |
| #ifdef ENABLE_DISASSEMBLER |
| #define RETURN_NAME(Name, ...) \ |
| @@ -411,3209 +371,6 @@ Local<v8::Object> Interpreter::GetDispatchCountersObject() { |
| return counters_map; |
| } |
| -// LdaZero |
| -// |
| -// Load literal '0' into the accumulator. |
| -void Interpreter::DoLdaZero(InterpreterAssembler* assembler) { |
| - Node* zero_value = __ NumberConstant(0.0); |
| - __ SetAccumulator(zero_value); |
| - __ Dispatch(); |
| -} |
| - |
| -// LdaSmi <imm> |
| -// |
| -// Load an integer literal into the accumulator as a Smi. |
| -void Interpreter::DoLdaSmi(InterpreterAssembler* assembler) { |
| - Node* smi_int = __ BytecodeOperandImmSmi(0); |
| - __ SetAccumulator(smi_int); |
| - __ Dispatch(); |
| -} |
| - |
| -// LdaConstant <idx> |
| -// |
| -// Load constant literal at |idx| in the constant pool into the accumulator. |
| -void Interpreter::DoLdaConstant(InterpreterAssembler* assembler) { |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* constant = __ LoadConstantPoolEntry(index); |
| - __ SetAccumulator(constant); |
| - __ Dispatch(); |
| -} |
| - |
| -// LdaUndefined |
| -// |
| -// Load Undefined into the accumulator. |
| -void Interpreter::DoLdaUndefined(InterpreterAssembler* assembler) { |
| - Node* undefined_value = |
| - __ HeapConstant(isolate_->factory()->undefined_value()); |
| - __ SetAccumulator(undefined_value); |
| - __ Dispatch(); |
| -} |
| - |
| -// LdaNull |
| -// |
| -// Load Null into the accumulator. |
| -void Interpreter::DoLdaNull(InterpreterAssembler* assembler) { |
| - Node* null_value = __ HeapConstant(isolate_->factory()->null_value()); |
| - __ SetAccumulator(null_value); |
| - __ Dispatch(); |
| -} |
| - |
| -// LdaTheHole |
| -// |
| -// Load TheHole into the accumulator. |
| -void Interpreter::DoLdaTheHole(InterpreterAssembler* assembler) { |
| - Node* the_hole_value = __ HeapConstant(isolate_->factory()->the_hole_value()); |
| - __ SetAccumulator(the_hole_value); |
| - __ Dispatch(); |
| -} |
| - |
| -// LdaTrue |
| -// |
| -// Load True into the accumulator. |
| -void Interpreter::DoLdaTrue(InterpreterAssembler* assembler) { |
| - Node* true_value = __ HeapConstant(isolate_->factory()->true_value()); |
| - __ SetAccumulator(true_value); |
| - __ Dispatch(); |
| -} |
| - |
| -// LdaFalse |
| -// |
| -// Load False into the accumulator. |
| -void Interpreter::DoLdaFalse(InterpreterAssembler* assembler) { |
| - Node* false_value = __ HeapConstant(isolate_->factory()->false_value()); |
| - __ SetAccumulator(false_value); |
| - __ Dispatch(); |
| -} |
| - |
| -// Ldar <src> |
| -// |
| -// Load accumulator with value from register <src>. |
| -void Interpreter::DoLdar(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* value = __ LoadRegister(reg_index); |
| - __ SetAccumulator(value); |
| - __ Dispatch(); |
| -} |
| - |
| -// Star <dst> |
| -// |
| -// Store accumulator to register <dst>. |
| -void Interpreter::DoStar(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* accumulator = __ GetAccumulator(); |
| - __ StoreRegister(accumulator, reg_index); |
| - __ Dispatch(); |
| -} |
| - |
| -// Mov <src> <dst> |
| -// |
| -// Stores the value of register <src> to register <dst>. |
| -void Interpreter::DoMov(InterpreterAssembler* assembler) { |
| - Node* src_index = __ BytecodeOperandReg(0); |
| - Node* src_value = __ LoadRegister(src_index); |
| - Node* dst_index = __ BytecodeOperandReg(1); |
| - __ StoreRegister(src_value, dst_index); |
| - __ Dispatch(); |
| -} |
| - |
| -void Interpreter::BuildLoadGlobalIC(int slot_operand_index, |
| - int name_operand_index, |
| - TypeofMode typeof_mode, |
| - InterpreterAssembler* assembler) { |
| - // Must be kept in sync with AccessorAssembler::LoadGlobalIC. |
| - |
| - // Load the global via the LoadGlobalIC. |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Node* feedback_slot = __ BytecodeOperandIdx(slot_operand_index); |
| - |
| - AccessorAssembler accessor_asm(assembler->state()); |
| - |
| - Label try_handler(assembler, Label::kDeferred), |
| - miss(assembler, Label::kDeferred); |
| - |
| - // Fast path without frame construction for the data case. |
| - { |
| - Label done(assembler); |
| - Variable var_result(assembler, MachineRepresentation::kTagged); |
| - ExitPoint exit_point(assembler, &done, &var_result); |
| - |
| - accessor_asm.LoadGlobalIC_TryPropertyCellCase( |
| - feedback_vector, feedback_slot, &exit_point, &try_handler, &miss, |
| - CodeStubAssembler::INTPTR_PARAMETERS); |
| - |
| - __ Bind(&done); |
| - __ SetAccumulator(var_result.value()); |
| - __ Dispatch(); |
| - } |
| - |
| - // Slow path with frame construction. |
| - { |
| - Label done(assembler); |
| - Variable var_result(assembler, MachineRepresentation::kTagged); |
| - ExitPoint exit_point(assembler, &done, &var_result); |
| - |
| - __ Bind(&try_handler); |
| - { |
| - Node* context = __ GetContext(); |
| - Node* smi_slot = __ SmiTag(feedback_slot); |
| - Node* name_index = __ BytecodeOperandIdx(name_operand_index); |
| - Node* name = __ LoadConstantPoolEntry(name_index); |
| - |
| - AccessorAssembler::LoadICParameters params(context, nullptr, name, |
| - smi_slot, feedback_vector); |
| - accessor_asm.LoadGlobalIC_TryHandlerCase(¶ms, typeof_mode, |
| - &exit_point, &miss); |
| - } |
| - |
| - __ Bind(&miss); |
| - { |
| - Node* context = __ GetContext(); |
| - Node* smi_slot = __ SmiTag(feedback_slot); |
| - Node* name_index = __ BytecodeOperandIdx(name_operand_index); |
| - Node* name = __ LoadConstantPoolEntry(name_index); |
| - |
| - AccessorAssembler::LoadICParameters params(context, nullptr, name, |
| - smi_slot, feedback_vector); |
| - accessor_asm.LoadGlobalIC_MissCase(¶ms, &exit_point); |
| - } |
| - |
| - __ Bind(&done); |
| - { |
| - __ SetAccumulator(var_result.value()); |
| - __ Dispatch(); |
| - } |
| - } |
| -} |
| - |
| -// LdaGlobal <name_index> <slot> |
| -// |
| -// Load the global with name in constant pool entry <name_index> into the |
| -// accumulator using FeedBackVector slot <slot> outside of a typeof. |
| -void Interpreter::DoLdaGlobal(InterpreterAssembler* assembler) { |
| - static const int kNameOperandIndex = 0; |
| - static const int kSlotOperandIndex = 1; |
| - |
| - BuildLoadGlobalIC(kSlotOperandIndex, kNameOperandIndex, NOT_INSIDE_TYPEOF, |
| - assembler); |
| -} |
| - |
| -// LdaGlobalInsideTypeof <name_index> <slot> |
| -// |
| -// Load the global with name in constant pool entry <name_index> into the |
| -// accumulator using FeedBackVector slot <slot> inside of a typeof. |
| -void Interpreter::DoLdaGlobalInsideTypeof(InterpreterAssembler* assembler) { |
| - static const int kNameOperandIndex = 0; |
| - static const int kSlotOperandIndex = 1; |
| - |
| - BuildLoadGlobalIC(kSlotOperandIndex, kNameOperandIndex, INSIDE_TYPEOF, |
| - assembler); |
| -} |
| - |
| -void Interpreter::DoStaGlobal(Callable ic, InterpreterAssembler* assembler) { |
| - // Get the global object. |
| - Node* context = __ GetContext(); |
| - Node* native_context = __ LoadNativeContext(context); |
| - Node* global = |
| - __ LoadContextElement(native_context, Context::EXTENSION_INDEX); |
| - |
| - // Store the global via the StoreIC. |
| - Node* code_target = __ HeapConstant(ic.code()); |
| - Node* constant_index = __ BytecodeOperandIdx(0); |
| - Node* name = __ LoadConstantPoolEntry(constant_index); |
| - Node* value = __ GetAccumulator(); |
| - Node* raw_slot = __ BytecodeOperandIdx(1); |
| - Node* smi_slot = __ SmiTag(raw_slot); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - __ CallStub(ic.descriptor(), code_target, context, global, name, value, |
| - smi_slot, feedback_vector); |
| - __ Dispatch(); |
| -} |
| - |
| -// StaGlobalSloppy <name_index> <slot> |
| -// |
| -// Store the value in the accumulator into the global with name in constant pool |
| -// entry <name_index> using FeedBackVector slot <slot> in sloppy mode. |
| -void Interpreter::DoStaGlobalSloppy(InterpreterAssembler* assembler) { |
| - Callable ic = CodeFactory::StoreICInOptimizedCode(isolate_, SLOPPY); |
| - DoStaGlobal(ic, assembler); |
| -} |
| - |
| -// StaGlobalStrict <name_index> <slot> |
| -// |
| -// Store the value in the accumulator into the global with name in constant pool |
| -// entry <name_index> using FeedBackVector slot <slot> in strict mode. |
| -void Interpreter::DoStaGlobalStrict(InterpreterAssembler* assembler) { |
| - Callable ic = CodeFactory::StoreICInOptimizedCode(isolate_, STRICT); |
| - DoStaGlobal(ic, assembler); |
| -} |
| - |
| -// LdaContextSlot <context> <slot_index> <depth> |
| -// |
| -// Load the object in |slot_index| of the context at |depth| in the context |
| -// chain starting at |context| into the accumulator. |
| -void Interpreter::DoLdaContextSlot(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* context = __ LoadRegister(reg_index); |
| - Node* slot_index = __ BytecodeOperandIdx(1); |
| - Node* depth = __ BytecodeOperandUImm(2); |
| - Node* slot_context = __ GetContextAtDepth(context, depth); |
| - Node* result = __ LoadContextElement(slot_context, slot_index); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// LdaImmutableContextSlot <context> <slot_index> <depth> |
| -// |
| -// Load the object in |slot_index| of the context at |depth| in the context |
| -// chain starting at |context| into the accumulator. |
| -void Interpreter::DoLdaImmutableContextSlot(InterpreterAssembler* assembler) { |
| - // TODO(danno) Share the actual code object rather creating a duplicate one. |
| - DoLdaContextSlot(assembler); |
| -} |
| - |
| -// LdaCurrentContextSlot <slot_index> |
| -// |
| -// Load the object in |slot_index| of the current context into the accumulator. |
| -void Interpreter::DoLdaCurrentContextSlot(InterpreterAssembler* assembler) { |
| - Node* slot_index = __ BytecodeOperandIdx(0); |
| - Node* slot_context = __ GetContext(); |
| - Node* result = __ LoadContextElement(slot_context, slot_index); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// LdaImmutableCurrentContextSlot <slot_index> |
| -// |
| -// Load the object in |slot_index| of the current context into the accumulator. |
| -void Interpreter::DoLdaImmutableCurrentContextSlot( |
| - InterpreterAssembler* assembler) { |
| - // TODO(danno) Share the actual code object rather creating a duplicate one. |
| - DoLdaCurrentContextSlot(assembler); |
| -} |
| - |
| -// StaContextSlot <context> <slot_index> <depth> |
| -// |
| -// Stores the object in the accumulator into |slot_index| of the context at |
| -// |depth| in the context chain starting at |context|. |
| -void Interpreter::DoStaContextSlot(InterpreterAssembler* assembler) { |
| - Node* value = __ GetAccumulator(); |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* context = __ LoadRegister(reg_index); |
| - Node* slot_index = __ BytecodeOperandIdx(1); |
| - Node* depth = __ BytecodeOperandUImm(2); |
| - Node* slot_context = __ GetContextAtDepth(context, depth); |
| - __ StoreContextElement(slot_context, slot_index, value); |
| - __ Dispatch(); |
| -} |
| - |
| -// StaCurrentContextSlot <slot_index> |
| -// |
| -// Stores the object in the accumulator into |slot_index| of the current |
| -// context. |
| -void Interpreter::DoStaCurrentContextSlot(InterpreterAssembler* assembler) { |
| - Node* value = __ GetAccumulator(); |
| - Node* slot_index = __ BytecodeOperandIdx(0); |
| - Node* slot_context = __ GetContext(); |
| - __ StoreContextElement(slot_context, slot_index, value); |
| - __ Dispatch(); |
| -} |
| - |
| -void Interpreter::DoLdaLookupSlot(Runtime::FunctionId function_id, |
| - InterpreterAssembler* assembler) { |
| - Node* name_index = __ BytecodeOperandIdx(0); |
| - Node* name = __ LoadConstantPoolEntry(name_index); |
| - Node* context = __ GetContext(); |
| - Node* result = __ CallRuntime(function_id, context, name); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// LdaLookupSlot <name_index> |
| -// |
| -// Lookup the object with the name in constant pool entry |name_index| |
| -// dynamically. |
| -void Interpreter::DoLdaLookupSlot(InterpreterAssembler* assembler) { |
| - DoLdaLookupSlot(Runtime::kLoadLookupSlot, assembler); |
| -} |
| - |
| -// LdaLookupSlotInsideTypeof <name_index> |
| -// |
| -// Lookup the object with the name in constant pool entry |name_index| |
| -// dynamically without causing a NoReferenceError. |
| -void Interpreter::DoLdaLookupSlotInsideTypeof(InterpreterAssembler* assembler) { |
| - DoLdaLookupSlot(Runtime::kLoadLookupSlotInsideTypeof, assembler); |
| -} |
| - |
| -void Interpreter::DoLdaLookupContextSlot(Runtime::FunctionId function_id, |
| - InterpreterAssembler* assembler) { |
| - Node* context = __ GetContext(); |
| - Node* name_index = __ BytecodeOperandIdx(0); |
| - Node* slot_index = __ BytecodeOperandIdx(1); |
| - Node* depth = __ BytecodeOperandUImm(2); |
| - |
| - Label slowpath(assembler, Label::kDeferred); |
| - |
| - // Check for context extensions to allow the fast path. |
| - __ GotoIfHasContextExtensionUpToDepth(context, depth, &slowpath); |
| - |
| - // Fast path does a normal load context. |
| - { |
| - Node* slot_context = __ GetContextAtDepth(context, depth); |
| - Node* result = __ LoadContextElement(slot_context, slot_index); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| - } |
| - |
| - // Slow path when we have to call out to the runtime. |
| - __ Bind(&slowpath); |
| - { |
| - Node* name = __ LoadConstantPoolEntry(name_index); |
| - Node* result = __ CallRuntime(function_id, context, name); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| - } |
| -} |
| - |
| -// LdaLookupSlot <name_index> |
| -// |
| -// Lookup the object with the name in constant pool entry |name_index| |
| -// dynamically. |
| -void Interpreter::DoLdaLookupContextSlot(InterpreterAssembler* assembler) { |
| - DoLdaLookupContextSlot(Runtime::kLoadLookupSlot, assembler); |
| -} |
| - |
| -// LdaLookupSlotInsideTypeof <name_index> |
| -// |
| -// Lookup the object with the name in constant pool entry |name_index| |
| -// dynamically without causing a NoReferenceError. |
| -void Interpreter::DoLdaLookupContextSlotInsideTypeof( |
| - InterpreterAssembler* assembler) { |
| - DoLdaLookupContextSlot(Runtime::kLoadLookupSlotInsideTypeof, assembler); |
| -} |
| - |
| -void Interpreter::DoLdaLookupGlobalSlot(Runtime::FunctionId function_id, |
| - InterpreterAssembler* assembler) { |
| - Node* context = __ GetContext(); |
| - Node* depth = __ BytecodeOperandUImm(2); |
| - |
| - Label slowpath(assembler, Label::kDeferred); |
| - |
| - // Check for context extensions to allow the fast path |
| - __ GotoIfHasContextExtensionUpToDepth(context, depth, &slowpath); |
| - |
| - // Fast path does a normal load global |
| - { |
| - static const int kNameOperandIndex = 0; |
| - static const int kSlotOperandIndex = 1; |
| - |
| - TypeofMode typeof_mode = function_id == Runtime::kLoadLookupSlotInsideTypeof |
| - ? INSIDE_TYPEOF |
| - : NOT_INSIDE_TYPEOF; |
| - |
| - BuildLoadGlobalIC(kSlotOperandIndex, kNameOperandIndex, typeof_mode, |
| - assembler); |
| - } |
| - |
| - // Slow path when we have to call out to the runtime |
| - __ Bind(&slowpath); |
| - { |
| - Node* name_index = __ BytecodeOperandIdx(0); |
| - Node* name = __ LoadConstantPoolEntry(name_index); |
| - Node* result = __ CallRuntime(function_id, context, name); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| - } |
| -} |
| - |
| -// LdaLookupGlobalSlot <name_index> <feedback_slot> <depth> |
| -// |
| -// Lookup the object with the name in constant pool entry |name_index| |
| -// dynamically. |
| -void Interpreter::DoLdaLookupGlobalSlot(InterpreterAssembler* assembler) { |
| - DoLdaLookupGlobalSlot(Runtime::kLoadLookupSlot, assembler); |
| -} |
| - |
| -// LdaLookupGlobalSlotInsideTypeof <name_index> <feedback_slot> <depth> |
| -// |
| -// Lookup the object with the name in constant pool entry |name_index| |
| -// dynamically without causing a NoReferenceError. |
| -void Interpreter::DoLdaLookupGlobalSlotInsideTypeof( |
| - InterpreterAssembler* assembler) { |
| - DoLdaLookupGlobalSlot(Runtime::kLoadLookupSlotInsideTypeof, assembler); |
| -} |
| - |
| -void Interpreter::DoStaLookupSlot(LanguageMode language_mode, |
| - InterpreterAssembler* assembler) { |
| - Node* value = __ GetAccumulator(); |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* name = __ LoadConstantPoolEntry(index); |
| - Node* context = __ GetContext(); |
| - Node* result = __ CallRuntime(is_strict(language_mode) |
| - ? Runtime::kStoreLookupSlot_Strict |
| - : Runtime::kStoreLookupSlot_Sloppy, |
| - context, name, value); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// StaLookupSlotSloppy <name_index> |
| -// |
| -// Store the object in accumulator to the object with the name in constant |
| -// pool entry |name_index| in sloppy mode. |
| -void Interpreter::DoStaLookupSlotSloppy(InterpreterAssembler* assembler) { |
| - DoStaLookupSlot(LanguageMode::SLOPPY, assembler); |
| -} |
| - |
| -// StaLookupSlotStrict <name_index> |
| -// |
| -// Store the object in accumulator to the object with the name in constant |
| -// pool entry |name_index| in strict mode. |
| -void Interpreter::DoStaLookupSlotStrict(InterpreterAssembler* assembler) { |
| - DoStaLookupSlot(LanguageMode::STRICT, assembler); |
| -} |
| - |
| -void Interpreter::BuildLoadIC(int recv_operand_index, int slot_operand_index, |
| - int name_operand_index, |
| - InterpreterAssembler* assembler) { |
| - __ Comment("BuildLoadIC"); |
| - |
| - // Load vector and slot. |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Node* feedback_slot = __ BytecodeOperandIdx(slot_operand_index); |
| - Node* smi_slot = __ SmiTag(feedback_slot); |
| - |
| - // Load receiver. |
| - Node* register_index = __ BytecodeOperandReg(recv_operand_index); |
| - Node* recv = __ LoadRegister(register_index); |
| - |
| - // Load the name. |
| - // TODO(jgruber): Not needed for monomorphic smi handler constant/field case. |
| - Node* constant_index = __ BytecodeOperandIdx(name_operand_index); |
| - Node* name = __ LoadConstantPoolEntry(constant_index); |
| - |
| - Node* context = __ GetContext(); |
| - |
| - Label done(assembler); |
| - Variable var_result(assembler, MachineRepresentation::kTagged); |
| - ExitPoint exit_point(assembler, &done, &var_result); |
| - |
| - AccessorAssembler::LoadICParameters params(context, recv, name, smi_slot, |
| - feedback_vector); |
| - AccessorAssembler accessor_asm(assembler->state()); |
| - accessor_asm.LoadIC_BytecodeHandler(¶ms, &exit_point); |
| - |
| - __ Bind(&done); |
| - { |
| - __ SetAccumulator(var_result.value()); |
| - __ Dispatch(); |
| - } |
| -} |
| - |
| -// LdaNamedProperty <object> <name_index> <slot> |
| -// |
| -// Calls the LoadIC at FeedBackVector slot <slot> for <object> and the name at |
| -// constant pool entry <name_index>. |
| -void Interpreter::DoLdaNamedProperty(InterpreterAssembler* assembler) { |
| - static const int kRecvOperandIndex = 0; |
| - static const int kNameOperandIndex = 1; |
| - static const int kSlotOperandIndex = 2; |
| - |
| - BuildLoadIC(kRecvOperandIndex, kSlotOperandIndex, kNameOperandIndex, |
| - assembler); |
| -} |
| - |
| -// KeyedLoadIC <object> <slot> |
| -// |
| -// Calls the KeyedLoadIC at FeedBackVector slot <slot> for <object> and the key |
| -// in the accumulator. |
| -void Interpreter::DoLdaKeyedProperty(InterpreterAssembler* assembler) { |
| - Callable ic = CodeFactory::KeyedLoadICInOptimizedCode(isolate_); |
| - Node* code_target = __ HeapConstant(ic.code()); |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* object = __ LoadRegister(reg_index); |
| - Node* name = __ GetAccumulator(); |
| - Node* raw_slot = __ BytecodeOperandIdx(1); |
| - Node* smi_slot = __ SmiTag(raw_slot); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Node* context = __ GetContext(); |
| - Node* result = __ CallStub(ic.descriptor(), code_target, context, object, |
| - name, smi_slot, feedback_vector); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -void Interpreter::DoStoreIC(Callable ic, InterpreterAssembler* assembler) { |
| - Node* code_target = __ HeapConstant(ic.code()); |
| - Node* object_reg_index = __ BytecodeOperandReg(0); |
| - Node* object = __ LoadRegister(object_reg_index); |
| - Node* constant_index = __ BytecodeOperandIdx(1); |
| - Node* name = __ LoadConstantPoolEntry(constant_index); |
| - Node* value = __ GetAccumulator(); |
| - Node* raw_slot = __ BytecodeOperandIdx(2); |
| - Node* smi_slot = __ SmiTag(raw_slot); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Node* context = __ GetContext(); |
| - __ CallStub(ic.descriptor(), code_target, context, object, name, value, |
| - smi_slot, feedback_vector); |
| - __ Dispatch(); |
| -} |
| - |
| -// StaNamedPropertySloppy <object> <name_index> <slot> |
| -// |
| -// Calls the sloppy mode StoreIC at FeedBackVector slot <slot> for <object> and |
| -// the name in constant pool entry <name_index> with the value in the |
| -// accumulator. |
| -void Interpreter::DoStaNamedPropertySloppy(InterpreterAssembler* assembler) { |
| - Callable ic = CodeFactory::StoreICInOptimizedCode(isolate_, SLOPPY); |
| - DoStoreIC(ic, assembler); |
| -} |
| - |
| -// StaNamedPropertyStrict <object> <name_index> <slot> |
| -// |
| -// Calls the strict mode StoreIC at FeedBackVector slot <slot> for <object> and |
| -// the name in constant pool entry <name_index> with the value in the |
| -// accumulator. |
| -void Interpreter::DoStaNamedPropertyStrict(InterpreterAssembler* assembler) { |
| - Callable ic = CodeFactory::StoreICInOptimizedCode(isolate_, STRICT); |
| - DoStoreIC(ic, assembler); |
| -} |
| - |
| -// StaNamedOwnProperty <object> <name_index> <slot> |
| -// |
| -// Calls the StoreOwnIC at FeedBackVector slot <slot> for <object> and |
| -// the name in constant pool entry <name_index> with the value in the |
| -// accumulator. |
| -void Interpreter::DoStaNamedOwnProperty(InterpreterAssembler* assembler) { |
| - Callable ic = CodeFactory::StoreOwnICInOptimizedCode(isolate_); |
| - DoStoreIC(ic, assembler); |
| -} |
| - |
| -void Interpreter::DoKeyedStoreIC(Callable ic, InterpreterAssembler* assembler) { |
| - Node* code_target = __ HeapConstant(ic.code()); |
| - Node* object_reg_index = __ BytecodeOperandReg(0); |
| - Node* object = __ LoadRegister(object_reg_index); |
| - Node* name_reg_index = __ BytecodeOperandReg(1); |
| - Node* name = __ LoadRegister(name_reg_index); |
| - Node* value = __ GetAccumulator(); |
| - Node* raw_slot = __ BytecodeOperandIdx(2); |
| - Node* smi_slot = __ SmiTag(raw_slot); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Node* context = __ GetContext(); |
| - __ CallStub(ic.descriptor(), code_target, context, object, name, value, |
| - smi_slot, feedback_vector); |
| - __ Dispatch(); |
| -} |
| - |
| -// StaKeyedPropertySloppy <object> <key> <slot> |
| -// |
| -// Calls the sloppy mode KeyStoreIC at FeedBackVector slot <slot> for <object> |
| -// and the key <key> with the value in the accumulator. |
| -void Interpreter::DoStaKeyedPropertySloppy(InterpreterAssembler* assembler) { |
| - Callable ic = CodeFactory::KeyedStoreICInOptimizedCode(isolate_, SLOPPY); |
| - DoKeyedStoreIC(ic, assembler); |
| -} |
| - |
| -// StaKeyedPropertyStrict <object> <key> <slot> |
| -// |
| -// Calls the strict mode KeyStoreIC at FeedBackVector slot <slot> for <object> |
| -// and the key <key> with the value in the accumulator. |
| -void Interpreter::DoStaKeyedPropertyStrict(InterpreterAssembler* assembler) { |
| - Callable ic = CodeFactory::KeyedStoreICInOptimizedCode(isolate_, STRICT); |
| - DoKeyedStoreIC(ic, assembler); |
| -} |
| - |
| -// StaDataPropertyInLiteral <object> <name> <flags> |
| -// |
| -// Define a property <name> with value from the accumulator in <object>. |
| -// Property attributes and whether set_function_name are stored in |
| -// DataPropertyInLiteralFlags <flags>. |
| -// |
| -// This definition is not observable and is used only for definitions |
| -// in object or class literals. |
| -void Interpreter::DoStaDataPropertyInLiteral(InterpreterAssembler* assembler) { |
| - Node* object = __ LoadRegister(__ BytecodeOperandReg(0)); |
| - Node* name = __ LoadRegister(__ BytecodeOperandReg(1)); |
| - Node* value = __ GetAccumulator(); |
| - Node* flags = __ SmiFromWord32(__ BytecodeOperandFlag(2)); |
| - Node* vector_index = __ SmiTag(__ BytecodeOperandIdx(3)); |
| - |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Node* context = __ GetContext(); |
| - |
| - __ CallRuntime(Runtime::kDefineDataPropertyInLiteral, context, object, name, |
| - value, flags, feedback_vector, vector_index); |
| - __ Dispatch(); |
| -} |
| - |
| -void Interpreter::DoCollectTypeProfile(InterpreterAssembler* assembler) { |
| - Node* name = __ LoadRegister(__ BytecodeOperandReg(0)); |
| - Node* value = __ GetAccumulator(); |
| - Node* vector_index = __ SmiTag(__ BytecodeOperandIdx(1)); |
| - |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Node* context = __ GetContext(); |
| - |
| - __ CallRuntime(Runtime::kCollectTypeProfile, context, name, value, |
| - feedback_vector, vector_index); |
| - __ Dispatch(); |
| -} |
| - |
| -// LdaModuleVariable <cell_index> <depth> |
| -// |
| -// Load the contents of a module variable into the accumulator. The variable is |
| -// identified by <cell_index>. <depth> is the depth of the current context |
| -// relative to the module context. |
| -void Interpreter::DoLdaModuleVariable(InterpreterAssembler* assembler) { |
| - Node* cell_index = __ BytecodeOperandImmIntPtr(0); |
| - Node* depth = __ BytecodeOperandUImm(1); |
| - |
| - Node* module_context = __ GetContextAtDepth(__ GetContext(), depth); |
| - Node* module = |
| - __ LoadContextElement(module_context, Context::EXTENSION_INDEX); |
| - |
| - Label if_export(assembler), if_import(assembler), end(assembler); |
| - __ Branch(__ IntPtrGreaterThan(cell_index, __ IntPtrConstant(0)), &if_export, |
| - &if_import); |
| - |
| - __ Bind(&if_export); |
| - { |
| - Node* regular_exports = |
| - __ LoadObjectField(module, Module::kRegularExportsOffset); |
| - // The actual array index is (cell_index - 1). |
| - Node* export_index = __ IntPtrSub(cell_index, __ IntPtrConstant(1)); |
| - Node* cell = __ LoadFixedArrayElement(regular_exports, export_index); |
| - __ SetAccumulator(__ LoadObjectField(cell, Cell::kValueOffset)); |
| - __ Goto(&end); |
| - } |
| - |
| - __ Bind(&if_import); |
| - { |
| - Node* regular_imports = |
| - __ LoadObjectField(module, Module::kRegularImportsOffset); |
| - // The actual array index is (-cell_index - 1). |
| - Node* import_index = __ IntPtrSub(__ IntPtrConstant(-1), cell_index); |
| - Node* cell = __ LoadFixedArrayElement(regular_imports, import_index); |
| - __ SetAccumulator(__ LoadObjectField(cell, Cell::kValueOffset)); |
| - __ Goto(&end); |
| - } |
| - |
| - __ Bind(&end); |
| - __ Dispatch(); |
| -} |
| - |
| -// StaModuleVariable <cell_index> <depth> |
| -// |
| -// Store accumulator to the module variable identified by <cell_index>. |
| -// <depth> is the depth of the current context relative to the module context. |
| -void Interpreter::DoStaModuleVariable(InterpreterAssembler* assembler) { |
| - Node* value = __ GetAccumulator(); |
| - Node* cell_index = __ BytecodeOperandImmIntPtr(0); |
| - Node* depth = __ BytecodeOperandUImm(1); |
| - |
| - Node* module_context = __ GetContextAtDepth(__ GetContext(), depth); |
| - Node* module = |
| - __ LoadContextElement(module_context, Context::EXTENSION_INDEX); |
| - |
| - Label if_export(assembler), if_import(assembler), end(assembler); |
| - __ Branch(__ IntPtrGreaterThan(cell_index, __ IntPtrConstant(0)), &if_export, |
| - &if_import); |
| - |
| - __ Bind(&if_export); |
| - { |
| - Node* regular_exports = |
| - __ LoadObjectField(module, Module::kRegularExportsOffset); |
| - // The actual array index is (cell_index - 1). |
| - Node* export_index = __ IntPtrSub(cell_index, __ IntPtrConstant(1)); |
| - Node* cell = __ LoadFixedArrayElement(regular_exports, export_index); |
| - __ StoreObjectField(cell, Cell::kValueOffset, value); |
| - __ Goto(&end); |
| - } |
| - |
| - __ Bind(&if_import); |
| - { |
| - // Not supported (probably never). |
| - __ Abort(kUnsupportedModuleOperation); |
| - __ Goto(&end); |
| - } |
| - |
| - __ Bind(&end); |
| - __ Dispatch(); |
| -} |
| - |
| -// PushContext <context> |
| -// |
| -// Saves the current context in <context>, and pushes the accumulator as the |
| -// new current context. |
| -void Interpreter::DoPushContext(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* new_context = __ GetAccumulator(); |
| - Node* old_context = __ GetContext(); |
| - __ StoreRegister(old_context, reg_index); |
| - __ SetContext(new_context); |
| - __ Dispatch(); |
| -} |
| - |
| -// PopContext <context> |
| -// |
| -// Pops the current context and sets <context> as the new context. |
| -void Interpreter::DoPopContext(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* context = __ LoadRegister(reg_index); |
| - __ SetContext(context); |
| - __ Dispatch(); |
| -} |
| - |
| -// TODO(mythria): Remove this function once all CompareOps record type feedback. |
| -void Interpreter::DoCompareOp(Token::Value compare_op, |
| - InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* lhs = __ LoadRegister(reg_index); |
| - Node* rhs = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - Node* result; |
| - switch (compare_op) { |
| - case Token::IN: |
| - result = assembler->HasProperty(rhs, lhs, context); |
| - break; |
| - case Token::INSTANCEOF: |
| - result = assembler->InstanceOf(lhs, rhs, context); |
| - break; |
| - default: |
| - UNREACHABLE(); |
| - } |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -template <class Generator> |
| -void Interpreter::DoBinaryOpWithFeedback(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* lhs = __ LoadRegister(reg_index); |
| - Node* rhs = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - Node* slot_index = __ BytecodeOperandIdx(1); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Node* result = Generator::Generate(assembler, lhs, rhs, slot_index, |
| - feedback_vector, context); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -void Interpreter::DoCompareOpWithFeedback(Token::Value compare_op, |
| - InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* lhs = __ LoadRegister(reg_index); |
| - Node* rhs = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - Node* slot_index = __ BytecodeOperandIdx(1); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - |
| - // TODO(interpreter): the only reason this check is here is because we |
| - // sometimes emit comparisons that shouldn't collect feedback (e.g. |
| - // try-finally blocks and generators), and we could get rid of this by |
| - // introducing Smi equality tests. |
| - Label gather_type_feedback(assembler), do_compare(assembler); |
| - __ Branch(__ WordEqual(slot_index, __ IntPtrConstant(0)), &do_compare, |
| - &gather_type_feedback); |
| - |
| - __ Bind(&gather_type_feedback); |
| - { |
| - Variable var_type_feedback(assembler, MachineRepresentation::kTaggedSigned); |
| - Label lhs_is_not_smi(assembler), lhs_is_not_number(assembler), |
| - lhs_is_not_string(assembler), gather_rhs_type(assembler), |
| - update_feedback(assembler); |
| - |
| - __ GotoIfNot(__ TaggedIsSmi(lhs), &lhs_is_not_smi); |
| - |
| - var_type_feedback.Bind( |
| - __ SmiConstant(CompareOperationFeedback::kSignedSmall)); |
| - __ Goto(&gather_rhs_type); |
| - |
| - __ Bind(&lhs_is_not_smi); |
| - { |
| - Node* lhs_map = __ LoadMap(lhs); |
| - __ GotoIfNot(__ IsHeapNumberMap(lhs_map), &lhs_is_not_number); |
| - |
| - var_type_feedback.Bind(__ SmiConstant(CompareOperationFeedback::kNumber)); |
| - __ Goto(&gather_rhs_type); |
| - |
| - __ Bind(&lhs_is_not_number); |
| - { |
| - Node* lhs_instance_type = __ LoadInstanceType(lhs); |
| - if (Token::IsOrderedRelationalCompareOp(compare_op)) { |
| - Label lhs_is_not_oddball(assembler); |
| - __ GotoIfNot( |
| - __ Word32Equal(lhs_instance_type, __ Int32Constant(ODDBALL_TYPE)), |
| - &lhs_is_not_oddball); |
| - |
| - var_type_feedback.Bind( |
| - __ SmiConstant(CompareOperationFeedback::kNumberOrOddball)); |
| - __ Goto(&gather_rhs_type); |
| - |
| - __ Bind(&lhs_is_not_oddball); |
| - } |
| - |
| - Label lhs_is_not_string(assembler); |
| - __ GotoIfNot(__ IsStringInstanceType(lhs_instance_type), |
| - &lhs_is_not_string); |
| - |
| - if (Token::IsOrderedRelationalCompareOp(compare_op)) { |
| - var_type_feedback.Bind( |
| - __ SmiConstant(CompareOperationFeedback::kString)); |
| - } else { |
| - var_type_feedback.Bind(__ SelectSmiConstant( |
| - __ Word32Equal( |
| - __ Word32And(lhs_instance_type, |
| - __ Int32Constant(kIsNotInternalizedMask)), |
| - __ Int32Constant(kInternalizedTag)), |
| - CompareOperationFeedback::kInternalizedString, |
| - CompareOperationFeedback::kString)); |
| - } |
| - __ Goto(&gather_rhs_type); |
| - |
| - __ Bind(&lhs_is_not_string); |
| - if (Token::IsEqualityOp(compare_op)) { |
| - var_type_feedback.Bind(__ SelectSmiConstant( |
| - __ IsJSReceiverInstanceType(lhs_instance_type), |
| - CompareOperationFeedback::kReceiver, |
| - CompareOperationFeedback::kAny)); |
| - } else { |
| - var_type_feedback.Bind( |
| - __ SmiConstant(CompareOperationFeedback::kAny)); |
| - } |
| - __ Goto(&gather_rhs_type); |
| - } |
| - } |
| - |
| - __ Bind(&gather_rhs_type); |
| - { |
| - Label rhs_is_not_smi(assembler), rhs_is_not_number(assembler); |
| - |
| - __ GotoIfNot(__ TaggedIsSmi(rhs), &rhs_is_not_smi); |
| - |
| - var_type_feedback.Bind( |
| - __ SmiOr(var_type_feedback.value(), |
| - __ SmiConstant(CompareOperationFeedback::kSignedSmall))); |
| - __ Goto(&update_feedback); |
| - |
| - __ Bind(&rhs_is_not_smi); |
| - { |
| - Node* rhs_map = __ LoadMap(rhs); |
| - __ GotoIfNot(__ IsHeapNumberMap(rhs_map), &rhs_is_not_number); |
| - |
| - var_type_feedback.Bind( |
| - __ SmiOr(var_type_feedback.value(), |
| - __ SmiConstant(CompareOperationFeedback::kNumber))); |
| - __ Goto(&update_feedback); |
| - |
| - __ Bind(&rhs_is_not_number); |
| - { |
| - Node* rhs_instance_type = __ LoadInstanceType(rhs); |
| - if (Token::IsOrderedRelationalCompareOp(compare_op)) { |
| - Label rhs_is_not_oddball(assembler); |
| - __ GotoIfNot(__ Word32Equal(rhs_instance_type, |
| - __ Int32Constant(ODDBALL_TYPE)), |
| - &rhs_is_not_oddball); |
| - |
| - var_type_feedback.Bind(__ SmiOr( |
| - var_type_feedback.value(), |
| - __ SmiConstant(CompareOperationFeedback::kNumberOrOddball))); |
| - __ Goto(&update_feedback); |
| - |
| - __ Bind(&rhs_is_not_oddball); |
| - } |
| - |
| - Label rhs_is_not_string(assembler); |
| - __ GotoIfNot(__ IsStringInstanceType(rhs_instance_type), |
| - &rhs_is_not_string); |
| - |
| - if (Token::IsOrderedRelationalCompareOp(compare_op)) { |
| - var_type_feedback.Bind( |
| - __ SmiOr(var_type_feedback.value(), |
| - __ SmiConstant(CompareOperationFeedback::kString))); |
| - } else { |
| - var_type_feedback.Bind(__ SmiOr( |
| - var_type_feedback.value(), |
| - __ SelectSmiConstant( |
| - __ Word32Equal( |
| - __ Word32And(rhs_instance_type, |
| - __ Int32Constant(kIsNotInternalizedMask)), |
| - __ Int32Constant(kInternalizedTag)), |
| - CompareOperationFeedback::kInternalizedString, |
| - CompareOperationFeedback::kString))); |
| - } |
| - __ Goto(&update_feedback); |
| - |
| - __ Bind(&rhs_is_not_string); |
| - if (Token::IsEqualityOp(compare_op)) { |
| - var_type_feedback.Bind( |
| - __ SmiOr(var_type_feedback.value(), |
| - __ SelectSmiConstant( |
| - __ IsJSReceiverInstanceType(rhs_instance_type), |
| - CompareOperationFeedback::kReceiver, |
| - CompareOperationFeedback::kAny))); |
| - } else { |
| - var_type_feedback.Bind( |
| - __ SmiConstant(CompareOperationFeedback::kAny)); |
| - } |
| - __ Goto(&update_feedback); |
| - } |
| - } |
| - } |
| - |
| - __ Bind(&update_feedback); |
| - { |
| - __ UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_index); |
| - __ Goto(&do_compare); |
| - } |
| - } |
| - |
| - __ Bind(&do_compare); |
| - Node* result; |
| - switch (compare_op) { |
| - case Token::EQ: |
| - result = assembler->Equal(lhs, rhs, context); |
| - break; |
| - case Token::EQ_STRICT: |
| - result = assembler->StrictEqual(lhs, rhs); |
| - break; |
| - case Token::LT: |
| - result = assembler->RelationalComparison(CodeStubAssembler::kLessThan, |
| - lhs, rhs, context); |
| - break; |
| - case Token::GT: |
| - result = assembler->RelationalComparison(CodeStubAssembler::kGreaterThan, |
| - lhs, rhs, context); |
| - break; |
| - case Token::LTE: |
| - result = assembler->RelationalComparison( |
| - CodeStubAssembler::kLessThanOrEqual, lhs, rhs, context); |
| - break; |
| - case Token::GTE: |
| - result = assembler->RelationalComparison( |
| - CodeStubAssembler::kGreaterThanOrEqual, lhs, rhs, context); |
| - break; |
| - default: |
| - UNREACHABLE(); |
| - } |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// Add <src> |
| -// |
| -// Add register <src> to accumulator. |
| -void Interpreter::DoAdd(InterpreterAssembler* assembler) { |
| - DoBinaryOpWithFeedback<AddWithFeedbackStub>(assembler); |
| -} |
| - |
| -// Sub <src> |
| -// |
| -// Subtract register <src> from accumulator. |
| -void Interpreter::DoSub(InterpreterAssembler* assembler) { |
| - DoBinaryOpWithFeedback<SubtractWithFeedbackStub>(assembler); |
| -} |
| - |
| -// Mul <src> |
| -// |
| -// Multiply accumulator by register <src>. |
| -void Interpreter::DoMul(InterpreterAssembler* assembler) { |
| - DoBinaryOpWithFeedback<MultiplyWithFeedbackStub>(assembler); |
| -} |
| - |
| -// Div <src> |
| -// |
| -// Divide register <src> by accumulator. |
| -void Interpreter::DoDiv(InterpreterAssembler* assembler) { |
| - DoBinaryOpWithFeedback<DivideWithFeedbackStub>(assembler); |
| -} |
| - |
| -// Mod <src> |
| -// |
| -// Modulo register <src> by accumulator. |
| -void Interpreter::DoMod(InterpreterAssembler* assembler) { |
| - DoBinaryOpWithFeedback<ModulusWithFeedbackStub>(assembler); |
| -} |
| - |
| -void Interpreter::DoBitwiseBinaryOp(Token::Value bitwise_op, |
| - InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* lhs = __ LoadRegister(reg_index); |
| - Node* rhs = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - Node* slot_index = __ BytecodeOperandIdx(1); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - |
| - Variable var_lhs_type_feedback(assembler, |
| - MachineRepresentation::kTaggedSigned), |
| - var_rhs_type_feedback(assembler, MachineRepresentation::kTaggedSigned); |
| - Node* lhs_value = __ TruncateTaggedToWord32WithFeedback( |
| - context, lhs, &var_lhs_type_feedback); |
| - Node* rhs_value = __ TruncateTaggedToWord32WithFeedback( |
| - context, rhs, &var_rhs_type_feedback); |
| - Node* result = nullptr; |
| - |
| - switch (bitwise_op) { |
| - case Token::BIT_OR: { |
| - Node* value = __ Word32Or(lhs_value, rhs_value); |
| - result = __ ChangeInt32ToTagged(value); |
| - } break; |
| - case Token::BIT_AND: { |
| - Node* value = __ Word32And(lhs_value, rhs_value); |
| - result = __ ChangeInt32ToTagged(value); |
| - } break; |
| - case Token::BIT_XOR: { |
| - Node* value = __ Word32Xor(lhs_value, rhs_value); |
| - result = __ ChangeInt32ToTagged(value); |
| - } break; |
| - case Token::SHL: { |
| - Node* value = __ Word32Shl( |
| - lhs_value, __ Word32And(rhs_value, __ Int32Constant(0x1f))); |
| - result = __ ChangeInt32ToTagged(value); |
| - } break; |
| - case Token::SHR: { |
| - Node* value = __ Word32Shr( |
| - lhs_value, __ Word32And(rhs_value, __ Int32Constant(0x1f))); |
| - result = __ ChangeUint32ToTagged(value); |
| - } break; |
| - case Token::SAR: { |
| - Node* value = __ Word32Sar( |
| - lhs_value, __ Word32And(rhs_value, __ Int32Constant(0x1f))); |
| - result = __ ChangeInt32ToTagged(value); |
| - } break; |
| - default: |
| - UNREACHABLE(); |
| - } |
| - |
| - Node* result_type = __ SelectSmiConstant( |
| - __ TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall, |
| - BinaryOperationFeedback::kNumber); |
| - |
| - if (FLAG_debug_code) { |
| - Label ok(assembler); |
| - __ GotoIf(__ TaggedIsSmi(result), &ok); |
| - Node* result_map = __ LoadMap(result); |
| - __ AbortIfWordNotEqual(result_map, __ HeapNumberMapConstant(), |
| - kExpectedHeapNumber); |
| - __ Goto(&ok); |
| - __ Bind(&ok); |
| - } |
| - |
| - Node* input_feedback = |
| - __ SmiOr(var_lhs_type_feedback.value(), var_rhs_type_feedback.value()); |
| - __ UpdateFeedback(__ SmiOr(result_type, input_feedback), feedback_vector, |
| - slot_index); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// BitwiseOr <src> |
| -// |
| -// BitwiseOr register <src> to accumulator. |
| -void Interpreter::DoBitwiseOr(InterpreterAssembler* assembler) { |
| - DoBitwiseBinaryOp(Token::BIT_OR, assembler); |
| -} |
| - |
| -// BitwiseXor <src> |
| -// |
| -// BitwiseXor register <src> to accumulator. |
| -void Interpreter::DoBitwiseXor(InterpreterAssembler* assembler) { |
| - DoBitwiseBinaryOp(Token::BIT_XOR, assembler); |
| -} |
| - |
| -// BitwiseAnd <src> |
| -// |
| -// BitwiseAnd register <src> to accumulator. |
| -void Interpreter::DoBitwiseAnd(InterpreterAssembler* assembler) { |
| - DoBitwiseBinaryOp(Token::BIT_AND, assembler); |
| -} |
| - |
| -// ShiftLeft <src> |
| -// |
| -// Left shifts register <src> by the count specified in the accumulator. |
| -// Register <src> is converted to an int32 and the accumulator to uint32 |
| -// before the operation. 5 lsb bits from the accumulator are used as count |
| -// i.e. <src> << (accumulator & 0x1F). |
| -void Interpreter::DoShiftLeft(InterpreterAssembler* assembler) { |
| - DoBitwiseBinaryOp(Token::SHL, assembler); |
| -} |
| - |
| -// ShiftRight <src> |
| -// |
| -// Right shifts register <src> by the count specified in the accumulator. |
| -// Result is sign extended. Register <src> is converted to an int32 and the |
| -// accumulator to uint32 before the operation. 5 lsb bits from the accumulator |
| -// are used as count i.e. <src> >> (accumulator & 0x1F). |
| -void Interpreter::DoShiftRight(InterpreterAssembler* assembler) { |
| - DoBitwiseBinaryOp(Token::SAR, assembler); |
| -} |
| - |
| -// ShiftRightLogical <src> |
| -// |
| -// Right Shifts register <src> by the count specified in the accumulator. |
| -// Result is zero-filled. The accumulator and register <src> are converted to |
| -// uint32 before the operation 5 lsb bits from the accumulator are used as |
| -// count i.e. <src> << (accumulator & 0x1F). |
| -void Interpreter::DoShiftRightLogical(InterpreterAssembler* assembler) { |
| - DoBitwiseBinaryOp(Token::SHR, assembler); |
| -} |
| - |
| -// AddSmi <imm> <reg> |
| -// |
| -// Adds an immediate value <imm> to register <reg>. For this |
| -// operation <reg> is the lhs operand and <imm> is the <rhs> operand. |
| -void Interpreter::DoAddSmi(InterpreterAssembler* assembler) { |
| - Variable var_result(assembler, MachineRepresentation::kTagged); |
| - Label fastpath(assembler), slowpath(assembler, Label::kDeferred), |
| - end(assembler); |
| - |
| - Node* reg_index = __ BytecodeOperandReg(1); |
| - Node* left = __ LoadRegister(reg_index); |
| - Node* right = __ BytecodeOperandImmSmi(0); |
| - Node* slot_index = __ BytecodeOperandIdx(2); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - |
| - // {right} is known to be a Smi. |
| - // Check if the {left} is a Smi take the fast path. |
| - __ Branch(__ TaggedIsSmi(left), &fastpath, &slowpath); |
| - __ Bind(&fastpath); |
| - { |
| - // Try fast Smi addition first. |
| - Node* pair = __ IntPtrAddWithOverflow(__ BitcastTaggedToWord(left), |
| - __ BitcastTaggedToWord(right)); |
| - Node* overflow = __ Projection(1, pair); |
| - |
| - // Check if the Smi additon overflowed. |
| - Label if_notoverflow(assembler); |
| - __ Branch(overflow, &slowpath, &if_notoverflow); |
| - __ Bind(&if_notoverflow); |
| - { |
| - __ UpdateFeedback(__ SmiConstant(BinaryOperationFeedback::kSignedSmall), |
| - feedback_vector, slot_index); |
| - var_result.Bind(__ BitcastWordToTaggedSigned(__ Projection(0, pair))); |
| - __ Goto(&end); |
| - } |
| - } |
| - __ Bind(&slowpath); |
| - { |
| - Node* context = __ GetContext(); |
| - AddWithFeedbackStub stub(__ isolate()); |
| - Callable callable = |
| - Callable(stub.GetCode(), AddWithFeedbackStub::Descriptor(__ isolate())); |
| - var_result.Bind(__ CallStub(callable, context, left, right, |
| - __ TruncateWordToWord32(slot_index), |
| - feedback_vector)); |
| - __ Goto(&end); |
| - } |
| - __ Bind(&end); |
| - { |
| - __ SetAccumulator(var_result.value()); |
| - __ Dispatch(); |
| - } |
| -} |
| - |
| -// SubSmi <imm> <reg> |
| -// |
| -// Subtracts an immediate value <imm> to register <reg>. For this |
| -// operation <reg> is the lhs operand and <imm> is the rhs operand. |
| -void Interpreter::DoSubSmi(InterpreterAssembler* assembler) { |
| - Variable var_result(assembler, MachineRepresentation::kTagged); |
| - Label fastpath(assembler), slowpath(assembler, Label::kDeferred), |
| - end(assembler); |
| - |
| - Node* reg_index = __ BytecodeOperandReg(1); |
| - Node* left = __ LoadRegister(reg_index); |
| - Node* right = __ BytecodeOperandImmSmi(0); |
| - Node* slot_index = __ BytecodeOperandIdx(2); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - |
| - // {right} is known to be a Smi. |
| - // Check if the {left} is a Smi take the fast path. |
| - __ Branch(__ TaggedIsSmi(left), &fastpath, &slowpath); |
| - __ Bind(&fastpath); |
| - { |
| - // Try fast Smi subtraction first. |
| - Node* pair = __ IntPtrSubWithOverflow(__ BitcastTaggedToWord(left), |
| - __ BitcastTaggedToWord(right)); |
| - Node* overflow = __ Projection(1, pair); |
| - |
| - // Check if the Smi subtraction overflowed. |
| - Label if_notoverflow(assembler); |
| - __ Branch(overflow, &slowpath, &if_notoverflow); |
| - __ Bind(&if_notoverflow); |
| - { |
| - __ UpdateFeedback(__ SmiConstant(BinaryOperationFeedback::kSignedSmall), |
| - feedback_vector, slot_index); |
| - var_result.Bind(__ BitcastWordToTaggedSigned(__ Projection(0, pair))); |
| - __ Goto(&end); |
| - } |
| - } |
| - __ Bind(&slowpath); |
| - { |
| - Node* context = __ GetContext(); |
| - SubtractWithFeedbackStub stub(__ isolate()); |
| - Callable callable = Callable( |
| - stub.GetCode(), SubtractWithFeedbackStub::Descriptor(__ isolate())); |
| - var_result.Bind(__ CallStub(callable, context, left, right, |
| - __ TruncateWordToWord32(slot_index), |
| - feedback_vector)); |
| - __ Goto(&end); |
| - } |
| - __ Bind(&end); |
| - { |
| - __ SetAccumulator(var_result.value()); |
| - __ Dispatch(); |
| - } |
| -} |
| - |
| -// BitwiseOr <imm> <reg> |
| -// |
| -// BitwiseOr <reg> with <imm>. For this operation <reg> is the lhs |
| -// operand and <imm> is the rhs operand. |
| -void Interpreter::DoBitwiseOrSmi(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(1); |
| - Node* left = __ LoadRegister(reg_index); |
| - Node* right = __ BytecodeOperandImmSmi(0); |
| - Node* context = __ GetContext(); |
| - Node* slot_index = __ BytecodeOperandIdx(2); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Variable var_lhs_type_feedback(assembler, |
| - MachineRepresentation::kTaggedSigned); |
| - Node* lhs_value = __ TruncateTaggedToWord32WithFeedback( |
| - context, left, &var_lhs_type_feedback); |
| - Node* rhs_value = __ SmiToWord32(right); |
| - Node* value = __ Word32Or(lhs_value, rhs_value); |
| - Node* result = __ ChangeInt32ToTagged(value); |
| - Node* result_type = __ SelectSmiConstant( |
| - __ TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall, |
| - BinaryOperationFeedback::kNumber); |
| - __ UpdateFeedback(__ SmiOr(result_type, var_lhs_type_feedback.value()), |
| - feedback_vector, slot_index); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// BitwiseAnd <imm> <reg> |
| -// |
| -// BitwiseAnd <reg> with <imm>. For this operation <reg> is the lhs |
| -// operand and <imm> is the rhs operand. |
| -void Interpreter::DoBitwiseAndSmi(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(1); |
| - Node* left = __ LoadRegister(reg_index); |
| - Node* right = __ BytecodeOperandImmSmi(0); |
| - Node* context = __ GetContext(); |
| - Node* slot_index = __ BytecodeOperandIdx(2); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Variable var_lhs_type_feedback(assembler, |
| - MachineRepresentation::kTaggedSigned); |
| - Node* lhs_value = __ TruncateTaggedToWord32WithFeedback( |
| - context, left, &var_lhs_type_feedback); |
| - Node* rhs_value = __ SmiToWord32(right); |
| - Node* value = __ Word32And(lhs_value, rhs_value); |
| - Node* result = __ ChangeInt32ToTagged(value); |
| - Node* result_type = __ SelectSmiConstant( |
| - __ TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall, |
| - BinaryOperationFeedback::kNumber); |
| - __ UpdateFeedback(__ SmiOr(result_type, var_lhs_type_feedback.value()), |
| - feedback_vector, slot_index); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// ShiftLeftSmi <imm> <reg> |
| -// |
| -// Left shifts register <src> by the count specified in <imm>. |
| -// Register <src> is converted to an int32 before the operation. The 5 |
| -// lsb bits from <imm> are used as count i.e. <src> << (<imm> & 0x1F). |
| -void Interpreter::DoShiftLeftSmi(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(1); |
| - Node* left = __ LoadRegister(reg_index); |
| - Node* right = __ BytecodeOperandImmSmi(0); |
| - Node* context = __ GetContext(); |
| - Node* slot_index = __ BytecodeOperandIdx(2); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Variable var_lhs_type_feedback(assembler, |
| - MachineRepresentation::kTaggedSigned); |
| - Node* lhs_value = __ TruncateTaggedToWord32WithFeedback( |
| - context, left, &var_lhs_type_feedback); |
| - Node* rhs_value = __ SmiToWord32(right); |
| - Node* shift_count = __ Word32And(rhs_value, __ Int32Constant(0x1f)); |
| - Node* value = __ Word32Shl(lhs_value, shift_count); |
| - Node* result = __ ChangeInt32ToTagged(value); |
| - Node* result_type = __ SelectSmiConstant( |
| - __ TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall, |
| - BinaryOperationFeedback::kNumber); |
| - __ UpdateFeedback(__ SmiOr(result_type, var_lhs_type_feedback.value()), |
| - feedback_vector, slot_index); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// ShiftRightSmi <imm> <reg> |
| -// |
| -// Right shifts register <src> by the count specified in <imm>. |
| -// Register <src> is converted to an int32 before the operation. The 5 |
| -// lsb bits from <imm> are used as count i.e. <src> << (<imm> & 0x1F). |
| -void Interpreter::DoShiftRightSmi(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(1); |
| - Node* left = __ LoadRegister(reg_index); |
| - Node* right = __ BytecodeOperandImmSmi(0); |
| - Node* context = __ GetContext(); |
| - Node* slot_index = __ BytecodeOperandIdx(2); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Variable var_lhs_type_feedback(assembler, |
| - MachineRepresentation::kTaggedSigned); |
| - Node* lhs_value = __ TruncateTaggedToWord32WithFeedback( |
| - context, left, &var_lhs_type_feedback); |
| - Node* rhs_value = __ SmiToWord32(right); |
| - Node* shift_count = __ Word32And(rhs_value, __ Int32Constant(0x1f)); |
| - Node* value = __ Word32Sar(lhs_value, shift_count); |
| - Node* result = __ ChangeInt32ToTagged(value); |
| - Node* result_type = __ SelectSmiConstant( |
| - __ TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall, |
| - BinaryOperationFeedback::kNumber); |
| - __ UpdateFeedback(__ SmiOr(result_type, var_lhs_type_feedback.value()), |
| - feedback_vector, slot_index); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -Node* Interpreter::BuildUnaryOp(Callable callable, |
| - InterpreterAssembler* assembler) { |
| - Node* target = __ HeapConstant(callable.code()); |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - return __ CallStub(callable.descriptor(), target, context, accumulator); |
| -} |
| - |
| -template <class Generator> |
| -void Interpreter::DoUnaryOpWithFeedback(InterpreterAssembler* assembler) { |
| - Node* value = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - Node* slot_index = __ BytecodeOperandIdx(0); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Node* result = Generator::Generate(assembler, value, context, feedback_vector, |
| - slot_index); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// ToName |
| -// |
| -// Convert the object referenced by the accumulator to a name. |
| -void Interpreter::DoToName(InterpreterAssembler* assembler) { |
| - Node* object = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - Node* result = __ ToName(context, object); |
| - __ StoreRegister(result, __ BytecodeOperandReg(0)); |
| - __ Dispatch(); |
| -} |
| - |
| -// ToNumber |
| -// |
| -// Convert the object referenced by the accumulator to a number. |
| -void Interpreter::DoToNumber(InterpreterAssembler* assembler) { |
| - Node* object = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - Node* result = __ ToNumber(context, object); |
| - __ StoreRegister(result, __ BytecodeOperandReg(0)); |
| - __ Dispatch(); |
| -} |
| - |
| -// ToObject |
| -// |
| -// Convert the object referenced by the accumulator to a JSReceiver. |
| -void Interpreter::DoToObject(InterpreterAssembler* assembler) { |
| - Node* result = BuildUnaryOp(CodeFactory::ToObject(isolate_), assembler); |
| - __ StoreRegister(result, __ BytecodeOperandReg(0)); |
| - __ Dispatch(); |
| -} |
| - |
| -// Inc |
| -// |
| -// Increments value in the accumulator by one. |
| -void Interpreter::DoInc(InterpreterAssembler* assembler) { |
| - typedef CodeStubAssembler::Label Label; |
| - typedef compiler::Node Node; |
| - typedef CodeStubAssembler::Variable Variable; |
| - |
| - Node* value = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - Node* slot_index = __ BytecodeOperandIdx(0); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - |
| - // Shared entry for floating point increment. |
| - Label do_finc(assembler), end(assembler); |
| - Variable var_finc_value(assembler, MachineRepresentation::kFloat64); |
| - |
| - // We might need to try again due to ToNumber conversion. |
| - Variable value_var(assembler, MachineRepresentation::kTagged); |
| - Variable result_var(assembler, MachineRepresentation::kTagged); |
| - Variable var_type_feedback(assembler, MachineRepresentation::kTaggedSigned); |
| - Variable* loop_vars[] = {&value_var, &var_type_feedback}; |
| - Label start(assembler, 2, loop_vars); |
| - value_var.Bind(value); |
| - var_type_feedback.Bind( |
| - assembler->SmiConstant(BinaryOperationFeedback::kNone)); |
| - assembler->Goto(&start); |
| - assembler->Bind(&start); |
| - { |
| - value = value_var.value(); |
| - |
| - Label if_issmi(assembler), if_isnotsmi(assembler); |
| - assembler->Branch(assembler->TaggedIsSmi(value), &if_issmi, &if_isnotsmi); |
| - |
| - assembler->Bind(&if_issmi); |
| - { |
| - // Try fast Smi addition first. |
| - Node* one = assembler->SmiConstant(Smi::FromInt(1)); |
| - Node* pair = assembler->IntPtrAddWithOverflow( |
| - assembler->BitcastTaggedToWord(value), |
| - assembler->BitcastTaggedToWord(one)); |
| - Node* overflow = assembler->Projection(1, pair); |
| - |
| - // Check if the Smi addition overflowed. |
| - Label if_overflow(assembler), if_notoverflow(assembler); |
| - assembler->Branch(overflow, &if_overflow, &if_notoverflow); |
| - |
| - assembler->Bind(&if_notoverflow); |
| - var_type_feedback.Bind(assembler->SmiOr( |
| - var_type_feedback.value(), |
| - assembler->SmiConstant(BinaryOperationFeedback::kSignedSmall))); |
| - result_var.Bind( |
| - assembler->BitcastWordToTaggedSigned(assembler->Projection(0, pair))); |
| - assembler->Goto(&end); |
| - |
| - assembler->Bind(&if_overflow); |
| - { |
| - var_finc_value.Bind(assembler->SmiToFloat64(value)); |
| - assembler->Goto(&do_finc); |
| - } |
| - } |
| - |
| - assembler->Bind(&if_isnotsmi); |
| - { |
| - // Check if the value is a HeapNumber. |
| - Label if_valueisnumber(assembler), |
| - if_valuenotnumber(assembler, Label::kDeferred); |
| - Node* value_map = assembler->LoadMap(value); |
| - assembler->Branch(assembler->IsHeapNumberMap(value_map), |
| - &if_valueisnumber, &if_valuenotnumber); |
| - |
| - assembler->Bind(&if_valueisnumber); |
| - { |
| - // Load the HeapNumber value. |
| - var_finc_value.Bind(assembler->LoadHeapNumberValue(value)); |
| - assembler->Goto(&do_finc); |
| - } |
| - |
| - assembler->Bind(&if_valuenotnumber); |
| - { |
| - // We do not require an Or with earlier feedback here because once we |
| - // convert the value to a number, we cannot reach this path. We can |
| - // only reach this path on the first pass when the feedback is kNone. |
| - CSA_ASSERT(assembler, |
| - assembler->SmiEqual( |
| - var_type_feedback.value(), |
| - assembler->SmiConstant(BinaryOperationFeedback::kNone))); |
| - |
| - Label if_valueisoddball(assembler), if_valuenotoddball(assembler); |
| - Node* instance_type = assembler->LoadMapInstanceType(value_map); |
| - Node* is_oddball = assembler->Word32Equal( |
| - instance_type, assembler->Int32Constant(ODDBALL_TYPE)); |
| - assembler->Branch(is_oddball, &if_valueisoddball, &if_valuenotoddball); |
| - |
| - assembler->Bind(&if_valueisoddball); |
| - { |
| - // Convert Oddball to Number and check again. |
| - value_var.Bind( |
| - assembler->LoadObjectField(value, Oddball::kToNumberOffset)); |
| - var_type_feedback.Bind(assembler->SmiConstant( |
| - BinaryOperationFeedback::kNumberOrOddball)); |
| - assembler->Goto(&start); |
| - } |
| - |
| - assembler->Bind(&if_valuenotoddball); |
| - { |
| - // Convert to a Number first and try again. |
| - Callable callable = |
| - CodeFactory::NonNumberToNumber(assembler->isolate()); |
| - var_type_feedback.Bind( |
| - assembler->SmiConstant(BinaryOperationFeedback::kAny)); |
| - value_var.Bind(assembler->CallStub(callable, context, value)); |
| - assembler->Goto(&start); |
| - } |
| - } |
| - } |
| - } |
| - |
| - assembler->Bind(&do_finc); |
| - { |
| - Node* finc_value = var_finc_value.value(); |
| - Node* one = assembler->Float64Constant(1.0); |
| - Node* finc_result = assembler->Float64Add(finc_value, one); |
| - var_type_feedback.Bind(assembler->SmiOr( |
| - var_type_feedback.value(), |
| - assembler->SmiConstant(BinaryOperationFeedback::kNumber))); |
| - result_var.Bind(assembler->AllocateHeapNumberWithValue(finc_result)); |
| - assembler->Goto(&end); |
| - } |
| - |
| - assembler->Bind(&end); |
| - assembler->UpdateFeedback(var_type_feedback.value(), feedback_vector, |
| - slot_index); |
| - |
| - __ SetAccumulator(result_var.value()); |
| - __ Dispatch(); |
| -} |
| - |
| -// Dec |
| -// |
| -// Decrements value in the accumulator by one. |
| -void Interpreter::DoDec(InterpreterAssembler* assembler) { |
| - typedef CodeStubAssembler::Label Label; |
| - typedef compiler::Node Node; |
| - typedef CodeStubAssembler::Variable Variable; |
| - |
| - Node* value = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - Node* slot_index = __ BytecodeOperandIdx(0); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - |
| - // Shared entry for floating point decrement. |
| - Label do_fdec(assembler), end(assembler); |
| - Variable var_fdec_value(assembler, MachineRepresentation::kFloat64); |
| - |
| - // We might need to try again due to ToNumber conversion. |
| - Variable value_var(assembler, MachineRepresentation::kTagged); |
| - Variable result_var(assembler, MachineRepresentation::kTagged); |
| - Variable var_type_feedback(assembler, MachineRepresentation::kTaggedSigned); |
| - Variable* loop_vars[] = {&value_var, &var_type_feedback}; |
| - Label start(assembler, 2, loop_vars); |
| - var_type_feedback.Bind( |
| - assembler->SmiConstant(BinaryOperationFeedback::kNone)); |
| - value_var.Bind(value); |
| - assembler->Goto(&start); |
| - assembler->Bind(&start); |
| - { |
| - value = value_var.value(); |
| - |
| - Label if_issmi(assembler), if_isnotsmi(assembler); |
| - assembler->Branch(assembler->TaggedIsSmi(value), &if_issmi, &if_isnotsmi); |
| - |
| - assembler->Bind(&if_issmi); |
| - { |
| - // Try fast Smi subtraction first. |
| - Node* one = assembler->SmiConstant(Smi::FromInt(1)); |
| - Node* pair = assembler->IntPtrSubWithOverflow( |
| - assembler->BitcastTaggedToWord(value), |
| - assembler->BitcastTaggedToWord(one)); |
| - Node* overflow = assembler->Projection(1, pair); |
| - |
| - // Check if the Smi subtraction overflowed. |
| - Label if_overflow(assembler), if_notoverflow(assembler); |
| - assembler->Branch(overflow, &if_overflow, &if_notoverflow); |
| - |
| - assembler->Bind(&if_notoverflow); |
| - var_type_feedback.Bind(assembler->SmiOr( |
| - var_type_feedback.value(), |
| - assembler->SmiConstant(BinaryOperationFeedback::kSignedSmall))); |
| - result_var.Bind( |
| - assembler->BitcastWordToTaggedSigned(assembler->Projection(0, pair))); |
| - assembler->Goto(&end); |
| - |
| - assembler->Bind(&if_overflow); |
| - { |
| - var_fdec_value.Bind(assembler->SmiToFloat64(value)); |
| - assembler->Goto(&do_fdec); |
| - } |
| - } |
| - |
| - assembler->Bind(&if_isnotsmi); |
| - { |
| - // Check if the value is a HeapNumber. |
| - Label if_valueisnumber(assembler), |
| - if_valuenotnumber(assembler, Label::kDeferred); |
| - Node* value_map = assembler->LoadMap(value); |
| - assembler->Branch(assembler->IsHeapNumberMap(value_map), |
| - &if_valueisnumber, &if_valuenotnumber); |
| - |
| - assembler->Bind(&if_valueisnumber); |
| - { |
| - // Load the HeapNumber value. |
| - var_fdec_value.Bind(assembler->LoadHeapNumberValue(value)); |
| - assembler->Goto(&do_fdec); |
| - } |
| - |
| - assembler->Bind(&if_valuenotnumber); |
| - { |
| - // We do not require an Or with earlier feedback here because once we |
| - // convert the value to a number, we cannot reach this path. We can |
| - // only reach this path on the first pass when the feedback is kNone. |
| - CSA_ASSERT(assembler, |
| - assembler->SmiEqual( |
| - var_type_feedback.value(), |
| - assembler->SmiConstant(BinaryOperationFeedback::kNone))); |
| - |
| - Label if_valueisoddball(assembler), if_valuenotoddball(assembler); |
| - Node* instance_type = assembler->LoadMapInstanceType(value_map); |
| - Node* is_oddball = assembler->Word32Equal( |
| - instance_type, assembler->Int32Constant(ODDBALL_TYPE)); |
| - assembler->Branch(is_oddball, &if_valueisoddball, &if_valuenotoddball); |
| - |
| - assembler->Bind(&if_valueisoddball); |
| - { |
| - // Convert Oddball to Number and check again. |
| - value_var.Bind( |
| - assembler->LoadObjectField(value, Oddball::kToNumberOffset)); |
| - var_type_feedback.Bind(assembler->SmiConstant( |
| - BinaryOperationFeedback::kNumberOrOddball)); |
| - assembler->Goto(&start); |
| - } |
| - |
| - assembler->Bind(&if_valuenotoddball); |
| - { |
| - // Convert to a Number first and try again. |
| - Callable callable = |
| - CodeFactory::NonNumberToNumber(assembler->isolate()); |
| - var_type_feedback.Bind( |
| - assembler->SmiConstant(BinaryOperationFeedback::kAny)); |
| - value_var.Bind(assembler->CallStub(callable, context, value)); |
| - assembler->Goto(&start); |
| - } |
| - } |
| - } |
| - } |
| - |
| - assembler->Bind(&do_fdec); |
| - { |
| - Node* fdec_value = var_fdec_value.value(); |
| - Node* one = assembler->Float64Constant(1.0); |
| - Node* fdec_result = assembler->Float64Sub(fdec_value, one); |
| - var_type_feedback.Bind(assembler->SmiOr( |
| - var_type_feedback.value(), |
| - assembler->SmiConstant(BinaryOperationFeedback::kNumber))); |
| - result_var.Bind(assembler->AllocateHeapNumberWithValue(fdec_result)); |
| - assembler->Goto(&end); |
| - } |
| - |
| - assembler->Bind(&end); |
| - assembler->UpdateFeedback(var_type_feedback.value(), feedback_vector, |
| - slot_index); |
| - |
| - __ SetAccumulator(result_var.value()); |
| - __ Dispatch(); |
| -} |
| - |
| -// LogicalNot |
| -// |
| -// Perform logical-not on the accumulator, first casting the |
| -// accumulator to a boolean value if required. |
| -// ToBooleanLogicalNot |
| -void Interpreter::DoToBooleanLogicalNot(InterpreterAssembler* assembler) { |
| - Node* value = __ GetAccumulator(); |
| - Variable result(assembler, MachineRepresentation::kTagged); |
| - Label if_true(assembler), if_false(assembler), end(assembler); |
| - Node* true_value = __ BooleanConstant(true); |
| - Node* false_value = __ BooleanConstant(false); |
| - __ BranchIfToBooleanIsTrue(value, &if_true, &if_false); |
| - __ Bind(&if_true); |
| - { |
| - result.Bind(false_value); |
| - __ Goto(&end); |
| - } |
| - __ Bind(&if_false); |
| - { |
| - result.Bind(true_value); |
| - __ Goto(&end); |
| - } |
| - __ Bind(&end); |
| - __ SetAccumulator(result.value()); |
| - __ Dispatch(); |
| -} |
| - |
| -// LogicalNot |
| -// |
| -// Perform logical-not on the accumulator, which must already be a boolean |
| -// value. |
| -void Interpreter::DoLogicalNot(InterpreterAssembler* assembler) { |
| - Node* value = __ GetAccumulator(); |
| - Variable result(assembler, MachineRepresentation::kTagged); |
| - Label if_true(assembler), if_false(assembler), end(assembler); |
| - Node* true_value = __ BooleanConstant(true); |
| - Node* false_value = __ BooleanConstant(false); |
| - __ Branch(__ WordEqual(value, true_value), &if_true, &if_false); |
| - __ Bind(&if_true); |
| - { |
| - result.Bind(false_value); |
| - __ Goto(&end); |
| - } |
| - __ Bind(&if_false); |
| - { |
| - if (FLAG_debug_code) { |
| - __ AbortIfWordNotEqual(value, false_value, |
| - BailoutReason::kExpectedBooleanValue); |
| - } |
| - result.Bind(true_value); |
| - __ Goto(&end); |
| - } |
| - __ Bind(&end); |
| - __ SetAccumulator(result.value()); |
| - __ Dispatch(); |
| -} |
| - |
| -// TypeOf |
| -// |
| -// Load the accumulator with the string representating type of the |
| -// object in the accumulator. |
| -void Interpreter::DoTypeOf(InterpreterAssembler* assembler) { |
| - Node* value = __ GetAccumulator(); |
| - Node* result = assembler->Typeof(value); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -void Interpreter::DoDelete(Runtime::FunctionId function_id, |
| - InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* object = __ LoadRegister(reg_index); |
| - Node* key = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - Node* result = __ CallRuntime(function_id, context, object, key); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// DeletePropertyStrict |
| -// |
| -// Delete the property specified in the accumulator from the object |
| -// referenced by the register operand following strict mode semantics. |
| -void Interpreter::DoDeletePropertyStrict(InterpreterAssembler* assembler) { |
| - DoDelete(Runtime::kDeleteProperty_Strict, assembler); |
| -} |
| - |
| -// DeletePropertySloppy |
| -// |
| -// Delete the property specified in the accumulator from the object |
| -// referenced by the register operand following sloppy mode semantics. |
| -void Interpreter::DoDeletePropertySloppy(InterpreterAssembler* assembler) { |
| - DoDelete(Runtime::kDeleteProperty_Sloppy, assembler); |
| -} |
| - |
| -// GetSuperConstructor |
| -// |
| -// Get the super constructor from the object referenced by the accumulator. |
| -// The result is stored in register |reg|. |
| -void Interpreter::DoGetSuperConstructor(InterpreterAssembler* assembler) { |
| - Node* active_function = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - Node* result = __ GetSuperConstructor(active_function, context); |
| - Node* reg = __ BytecodeOperandReg(0); |
| - __ StoreRegister(result, reg); |
| - __ Dispatch(); |
| -} |
| - |
| -void Interpreter::DoJSCall(InterpreterAssembler* assembler, |
| - TailCallMode tail_call_mode) { |
| - Node* function_reg = __ BytecodeOperandReg(0); |
| - Node* function = __ LoadRegister(function_reg); |
| - Node* receiver_reg = __ BytecodeOperandReg(1); |
| - Node* receiver_arg = __ RegisterLocation(receiver_reg); |
| - Node* receiver_args_count = __ BytecodeOperandCount(2); |
| - Node* receiver_count = __ Int32Constant(1); |
| - Node* args_count = __ Int32Sub(receiver_args_count, receiver_count); |
| - Node* slot_id = __ BytecodeOperandIdx(3); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Node* context = __ GetContext(); |
| - Node* result = |
| - __ CallJSWithFeedback(function, context, receiver_arg, args_count, |
| - slot_id, feedback_vector, tail_call_mode); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -void Interpreter::DoJSCallN(InterpreterAssembler* assembler, int arg_count) { |
| - const int kReceiverOperandIndex = 1; |
| - const int kReceiverOperandCount = 1; |
| - const int kSlotOperandIndex = |
| - kReceiverOperandIndex + kReceiverOperandCount + arg_count; |
| - const int kBoilerplatParameterCount = 7; |
| - const int kReceiverParameterIndex = 5; |
| - |
| - Node* function_reg = __ BytecodeOperandReg(0); |
| - Node* function = __ LoadRegister(function_reg); |
| - std::array<Node*, Bytecodes::kMaxOperands + kBoilerplatParameterCount> temp; |
| - Callable call_ic = CodeFactory::CallIC(isolate_); |
| - temp[0] = __ HeapConstant(call_ic.code()); |
| - temp[1] = function; |
| - temp[2] = __ Int32Constant(arg_count); |
| - temp[3] = __ BytecodeOperandIdxInt32(kSlotOperandIndex); |
| - temp[4] = __ LoadFeedbackVector(); |
| - for (int i = 0; i < (arg_count + kReceiverOperandCount); ++i) { |
| - Node* reg = __ BytecodeOperandReg(i + kReceiverOperandIndex); |
| - temp[kReceiverParameterIndex + i] = __ LoadRegister(reg); |
| - } |
| - temp[kReceiverParameterIndex + arg_count + kReceiverOperandCount] = |
| - __ GetContext(); |
| - Node* result = __ CallStubN(call_ic.descriptor(), 1, |
| - arg_count + kBoilerplatParameterCount, &temp[0]); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// Call <callable> <receiver> <arg_count> <feedback_slot_id> |
| -// |
| -// Call a JSfunction or Callable in |callable| with the |receiver| and |
| -// |arg_count| arguments in subsequent registers. Collect type feedback |
| -// into |feedback_slot_id| |
| -void Interpreter::DoCall(InterpreterAssembler* assembler) { |
| - DoJSCall(assembler, TailCallMode::kDisallow); |
| -} |
| - |
| -void Interpreter::DoCall0(InterpreterAssembler* assembler) { |
| - DoJSCallN(assembler, 0); |
| -} |
| - |
| -void Interpreter::DoCall1(InterpreterAssembler* assembler) { |
| - DoJSCallN(assembler, 1); |
| -} |
| - |
| -void Interpreter::DoCall2(InterpreterAssembler* assembler) { |
| - DoJSCallN(assembler, 2); |
| -} |
| - |
| -void Interpreter::DoCallProperty(InterpreterAssembler* assembler) { |
| - // Same as Call |
| - UNREACHABLE(); |
| -} |
| - |
| -void Interpreter::DoCallProperty0(InterpreterAssembler* assembler) { |
| - // Same as Call0 |
| - UNREACHABLE(); |
| -} |
| - |
| -void Interpreter::DoCallProperty1(InterpreterAssembler* assembler) { |
| - // Same as Call1 |
| - UNREACHABLE(); |
| -} |
| - |
| -void Interpreter::DoCallProperty2(InterpreterAssembler* assembler) { |
| - // Same as Call2 |
| - UNREACHABLE(); |
| -} |
| - |
| -// TailCall <callable> <receiver> <arg_count> <feedback_slot_id> |
| -// |
| -// Tail call a JSfunction or Callable in |callable| with the |receiver| and |
| -// |arg_count| arguments in subsequent registers. Collect type feedback |
| -// into |feedback_slot_id| |
| -void Interpreter::DoTailCall(InterpreterAssembler* assembler) { |
| - DoJSCall(assembler, TailCallMode::kAllow); |
| -} |
| - |
| -// CallRuntime <function_id> <first_arg> <arg_count> |
| -// |
| -// Call the runtime function |function_id| with the first argument in |
| -// register |first_arg| and |arg_count| arguments in subsequent |
| -// registers. |
| -void Interpreter::DoCallRuntime(InterpreterAssembler* assembler) { |
| - Node* function_id = __ BytecodeOperandRuntimeId(0); |
| - Node* first_arg_reg = __ BytecodeOperandReg(1); |
| - Node* first_arg = __ RegisterLocation(first_arg_reg); |
| - Node* args_count = __ BytecodeOperandCount(2); |
| - Node* context = __ GetContext(); |
| - Node* result = __ CallRuntimeN(function_id, context, first_arg, args_count); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// InvokeIntrinsic <function_id> <first_arg> <arg_count> |
| -// |
| -// Implements the semantic equivalent of calling the runtime function |
| -// |function_id| with the first argument in |first_arg| and |arg_count| |
| -// arguments in subsequent registers. |
| -void Interpreter::DoInvokeIntrinsic(InterpreterAssembler* assembler) { |
| - Node* function_id = __ BytecodeOperandIntrinsicId(0); |
| - Node* first_arg_reg = __ BytecodeOperandReg(1); |
| - Node* arg_count = __ BytecodeOperandCount(2); |
| - Node* context = __ GetContext(); |
| - IntrinsicsHelper helper(assembler); |
| - Node* result = |
| - helper.InvokeIntrinsic(function_id, context, first_arg_reg, arg_count); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// CallRuntimeForPair <function_id> <first_arg> <arg_count> <first_return> |
| -// |
| -// Call the runtime function |function_id| which returns a pair, with the |
| -// first argument in register |first_arg| and |arg_count| arguments in |
| -// subsequent registers. Returns the result in <first_return> and |
| -// <first_return + 1> |
| -void Interpreter::DoCallRuntimeForPair(InterpreterAssembler* assembler) { |
| - // Call the runtime function. |
| - Node* function_id = __ BytecodeOperandRuntimeId(0); |
| - Node* first_arg_reg = __ BytecodeOperandReg(1); |
| - Node* first_arg = __ RegisterLocation(first_arg_reg); |
| - Node* args_count = __ BytecodeOperandCount(2); |
| - Node* context = __ GetContext(); |
| - Node* result_pair = |
| - __ CallRuntimeN(function_id, context, first_arg, args_count, 2); |
| - // Store the results in <first_return> and <first_return + 1> |
| - Node* first_return_reg = __ BytecodeOperandReg(3); |
| - Node* second_return_reg = __ NextRegister(first_return_reg); |
| - Node* result0 = __ Projection(0, result_pair); |
| - Node* result1 = __ Projection(1, result_pair); |
| - __ StoreRegister(result0, first_return_reg); |
| - __ StoreRegister(result1, second_return_reg); |
| - __ Dispatch(); |
| -} |
| - |
| -// CallJSRuntime <context_index> <receiver> <arg_count> |
| -// |
| -// Call the JS runtime function that has the |context_index| with the receiver |
| -// in register |receiver| and |arg_count| arguments in subsequent registers. |
| -void Interpreter::DoCallJSRuntime(InterpreterAssembler* assembler) { |
| - Node* context_index = __ BytecodeOperandIdx(0); |
| - Node* receiver_reg = __ BytecodeOperandReg(1); |
| - Node* first_arg = __ RegisterLocation(receiver_reg); |
| - Node* receiver_args_count = __ BytecodeOperandCount(2); |
| - Node* receiver_count = __ Int32Constant(1); |
| - Node* args_count = __ Int32Sub(receiver_args_count, receiver_count); |
| - |
| - // Get the function to call from the native context. |
| - Node* context = __ GetContext(); |
| - Node* native_context = __ LoadNativeContext(context); |
| - Node* function = __ LoadContextElement(native_context, context_index); |
| - |
| - // Call the function. |
| - Node* result = __ CallJS(function, context, first_arg, args_count, |
| - TailCallMode::kDisallow); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// CallWithSpread <callable> <first_arg> <arg_count> |
| -// |
| -// Call a JSfunction or Callable in |callable| with the receiver in |
| -// |first_arg| and |arg_count - 1| arguments in subsequent registers. The |
| -// final argument is always a spread. |
| -// |
| -void Interpreter::DoCallWithSpread(InterpreterAssembler* assembler) { |
| - Node* callable_reg = __ BytecodeOperandReg(0); |
| - Node* callable = __ LoadRegister(callable_reg); |
| - Node* receiver_reg = __ BytecodeOperandReg(1); |
| - Node* receiver_arg = __ RegisterLocation(receiver_reg); |
| - Node* receiver_args_count = __ BytecodeOperandCount(2); |
| - Node* receiver_count = __ Int32Constant(1); |
| - Node* args_count = __ Int32Sub(receiver_args_count, receiver_count); |
| - Node* context = __ GetContext(); |
| - |
| - // Call into Runtime function CallWithSpread which does everything. |
| - Node* result = |
| - __ CallJSWithSpread(callable, context, receiver_arg, args_count); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// ConstructWithSpread <first_arg> <arg_count> |
| -// |
| -// Call the constructor in |constructor| with the first argument in register |
| -// |first_arg| and |arg_count| arguments in subsequent registers. The final |
| -// argument is always a spread. The new.target is in the accumulator. |
| -// |
| -void Interpreter::DoConstructWithSpread(InterpreterAssembler* assembler) { |
| - Node* new_target = __ GetAccumulator(); |
| - Node* constructor_reg = __ BytecodeOperandReg(0); |
| - Node* constructor = __ LoadRegister(constructor_reg); |
| - Node* first_arg_reg = __ BytecodeOperandReg(1); |
| - Node* first_arg = __ RegisterLocation(first_arg_reg); |
| - Node* args_count = __ BytecodeOperandCount(2); |
| - Node* context = __ GetContext(); |
| - Node* result = __ ConstructWithSpread(constructor, context, new_target, |
| - first_arg, args_count); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// Construct <constructor> <first_arg> <arg_count> |
| -// |
| -// Call operator construct with |constructor| and the first argument in |
| -// register |first_arg| and |arg_count| arguments in subsequent |
| -// registers. The new.target is in the accumulator. |
| -// |
| -void Interpreter::DoConstruct(InterpreterAssembler* assembler) { |
| - Node* new_target = __ GetAccumulator(); |
| - Node* constructor_reg = __ BytecodeOperandReg(0); |
| - Node* constructor = __ LoadRegister(constructor_reg); |
| - Node* first_arg_reg = __ BytecodeOperandReg(1); |
| - Node* first_arg = __ RegisterLocation(first_arg_reg); |
| - Node* args_count = __ BytecodeOperandCount(2); |
| - Node* slot_id = __ BytecodeOperandIdx(3); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Node* context = __ GetContext(); |
| - Node* result = __ Construct(constructor, context, new_target, first_arg, |
| - args_count, slot_id, feedback_vector); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// TestEqual <src> |
| -// |
| -// Test if the value in the <src> register equals the accumulator. |
| -void Interpreter::DoTestEqual(InterpreterAssembler* assembler) { |
| - DoCompareOpWithFeedback(Token::Value::EQ, assembler); |
| -} |
| - |
| -// TestEqualStrict <src> |
| -// |
| -// Test if the value in the <src> register is strictly equal to the accumulator. |
| -void Interpreter::DoTestEqualStrict(InterpreterAssembler* assembler) { |
| - DoCompareOpWithFeedback(Token::Value::EQ_STRICT, assembler); |
| -} |
| - |
| -// TestLessThan <src> |
| -// |
| -// Test if the value in the <src> register is less than the accumulator. |
| -void Interpreter::DoTestLessThan(InterpreterAssembler* assembler) { |
| - DoCompareOpWithFeedback(Token::Value::LT, assembler); |
| -} |
| - |
| -// TestGreaterThan <src> |
| -// |
| -// Test if the value in the <src> register is greater than the accumulator. |
| -void Interpreter::DoTestGreaterThan(InterpreterAssembler* assembler) { |
| - DoCompareOpWithFeedback(Token::Value::GT, assembler); |
| -} |
| - |
| -// TestLessThanOrEqual <src> |
| -// |
| -// Test if the value in the <src> register is less than or equal to the |
| -// accumulator. |
| -void Interpreter::DoTestLessThanOrEqual(InterpreterAssembler* assembler) { |
| - DoCompareOpWithFeedback(Token::Value::LTE, assembler); |
| -} |
| - |
| -// TestGreaterThanOrEqual <src> |
| -// |
| -// Test if the value in the <src> register is greater than or equal to the |
| -// accumulator. |
| -void Interpreter::DoTestGreaterThanOrEqual(InterpreterAssembler* assembler) { |
| - DoCompareOpWithFeedback(Token::Value::GTE, assembler); |
| -} |
| - |
| -// TestIn <src> |
| -// |
| -// Test if the object referenced by the register operand is a property of the |
| -// object referenced by the accumulator. |
| -void Interpreter::DoTestIn(InterpreterAssembler* assembler) { |
| - DoCompareOp(Token::IN, assembler); |
| -} |
| - |
| -// TestInstanceOf <src> |
| -// |
| -// Test if the object referenced by the <src> register is an an instance of type |
| -// referenced by the accumulator. |
| -void Interpreter::DoTestInstanceOf(InterpreterAssembler* assembler) { |
| - DoCompareOp(Token::INSTANCEOF, assembler); |
| -} |
| - |
| -// TestUndetectable <src> |
| -// |
| -// Test if the value in the <src> register equals to null/undefined. This is |
| -// done by checking undetectable bit on the map of the object. |
| -void Interpreter::DoTestUndetectable(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* object = __ LoadRegister(reg_index); |
| - |
| - Label not_equal(assembler), end(assembler); |
| - // If the object is an Smi then return false. |
| - __ GotoIf(__ TaggedIsSmi(object), ¬_equal); |
| - |
| - // If it is a HeapObject, load the map and check for undetectable bit. |
| - Node* map = __ LoadMap(object); |
| - Node* map_bitfield = __ LoadMapBitField(map); |
| - Node* map_undetectable = |
| - __ Word32And(map_bitfield, __ Int32Constant(1 << Map::kIsUndetectable)); |
| - __ GotoIf(__ Word32Equal(map_undetectable, __ Int32Constant(0)), ¬_equal); |
| - |
| - __ SetAccumulator(__ BooleanConstant(true)); |
| - __ Goto(&end); |
| - |
| - __ Bind(¬_equal); |
| - { |
| - __ SetAccumulator(__ BooleanConstant(false)); |
| - __ Goto(&end); |
| - } |
| - |
| - __ Bind(&end); |
| - __ Dispatch(); |
| -} |
| - |
| -// TestNull <src> |
| -// |
| -// Test if the value in the <src> register is strictly equal to null. |
| -void Interpreter::DoTestNull(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* object = __ LoadRegister(reg_index); |
| - Node* null_value = __ HeapConstant(isolate_->factory()->null_value()); |
| - |
| - Label equal(assembler), end(assembler); |
| - __ GotoIf(__ WordEqual(object, null_value), &equal); |
| - __ SetAccumulator(__ BooleanConstant(false)); |
| - __ Goto(&end); |
| - |
| - __ Bind(&equal); |
| - { |
| - __ SetAccumulator(__ BooleanConstant(true)); |
| - __ Goto(&end); |
| - } |
| - |
| - __ Bind(&end); |
| - __ Dispatch(); |
| -} |
| - |
| -// TestUndefined <src> |
| -// |
| -// Test if the value in the <src> register is strictly equal to undefined. |
| -void Interpreter::DoTestUndefined(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* object = __ LoadRegister(reg_index); |
| - Node* undefined_value = |
| - __ HeapConstant(isolate_->factory()->undefined_value()); |
| - |
| - Label equal(assembler), end(assembler); |
| - __ GotoIf(__ WordEqual(object, undefined_value), &equal); |
| - __ SetAccumulator(__ BooleanConstant(false)); |
| - __ Goto(&end); |
| - |
| - __ Bind(&equal); |
| - { |
| - __ SetAccumulator(__ BooleanConstant(true)); |
| - __ Goto(&end); |
| - } |
| - |
| - __ Bind(&end); |
| - __ Dispatch(); |
| -} |
| - |
| -// TestTypeOf <literal_flag> |
| -// |
| -// Tests if the object in the <accumulator> is typeof the literal represented |
| -// by |literal_flag|. |
| -void Interpreter::DoTestTypeOf(InterpreterAssembler* assembler) { |
| - Node* object = __ GetAccumulator(); |
| - Node* literal_flag = __ BytecodeOperandFlag(0); |
| - |
| -#define MAKE_LABEL(name, lower_case) Label if_##lower_case(assembler); |
| - TYPEOF_LITERAL_LIST(MAKE_LABEL) |
| -#undef MAKE_LABEL |
| - |
| -#define LABEL_POINTER(name, lower_case) &if_##lower_case, |
| - Label* labels[] = {TYPEOF_LITERAL_LIST(LABEL_POINTER)}; |
| -#undef LABEL_POINTER |
| - |
| -#define CASE(name, lower_case) \ |
| - static_cast<int32_t>(TestTypeOfFlags::LiteralFlag::k##name), |
| - int32_t cases[] = {TYPEOF_LITERAL_LIST(CASE)}; |
| -#undef CASE |
| - |
| - Label if_true(assembler), if_false(assembler), end(assembler), |
| - abort(assembler, Label::kDeferred); |
| - |
| - __ Switch(literal_flag, &abort, cases, labels, arraysize(cases)); |
| - |
| - __ Bind(&abort); |
| - { |
| - __ Comment("Abort"); |
| - __ Abort(BailoutReason::kUnexpectedTestTypeofLiteralFlag); |
| - __ Goto(&if_false); |
| - } |
| - __ Bind(&if_number); |
| - { |
| - __ Comment("IfNumber"); |
| - __ GotoIfNumber(object, &if_true); |
| - __ Goto(&if_false); |
| - } |
| - __ Bind(&if_string); |
| - { |
| - __ Comment("IfString"); |
| - __ GotoIf(__ TaggedIsSmi(object), &if_false); |
| - __ Branch(__ IsString(object), &if_true, &if_false); |
| - } |
| - __ Bind(&if_symbol); |
| - { |
| - __ Comment("IfSymbol"); |
| - __ GotoIf(__ TaggedIsSmi(object), &if_false); |
| - __ Branch(__ IsSymbol(object), &if_true, &if_false); |
| - } |
| - __ Bind(&if_boolean); |
| - { |
| - __ Comment("IfBoolean"); |
| - __ GotoIf(__ WordEqual(object, __ BooleanConstant(true)), &if_true); |
| - __ Branch(__ WordEqual(object, __ BooleanConstant(false)), &if_true, |
| - &if_false); |
| - } |
| - __ Bind(&if_undefined); |
| - { |
| - __ Comment("IfUndefined"); |
| - __ GotoIf(__ TaggedIsSmi(object), &if_false); |
| - // Check it is not null and the map has the undetectable bit set. |
| - __ GotoIf(__ WordEqual(object, __ NullConstant()), &if_false); |
| - Node* map_bitfield = __ LoadMapBitField(__ LoadMap(object)); |
| - Node* undetectable_bit = |
| - __ Word32And(map_bitfield, __ Int32Constant(1 << Map::kIsUndetectable)); |
| - __ Branch(__ Word32Equal(undetectable_bit, __ Int32Constant(0)), &if_false, |
| - &if_true); |
| - } |
| - __ Bind(&if_function); |
| - { |
| - __ Comment("IfFunction"); |
| - __ GotoIf(__ TaggedIsSmi(object), &if_false); |
| - // Check if callable bit is set and not undetectable. |
| - Node* map_bitfield = __ LoadMapBitField(__ LoadMap(object)); |
| - Node* callable_undetectable = __ Word32And( |
| - map_bitfield, |
| - __ Int32Constant(1 << Map::kIsUndetectable | 1 << Map::kIsCallable)); |
| - __ Branch(__ Word32Equal(callable_undetectable, |
| - __ Int32Constant(1 << Map::kIsCallable)), |
| - &if_true, &if_false); |
| - } |
| - __ Bind(&if_object); |
| - { |
| - __ Comment("IfObject"); |
| - __ GotoIf(__ TaggedIsSmi(object), &if_false); |
| - |
| - // If the object is null then return true. |
| - __ GotoIf(__ WordEqual(object, __ NullConstant()), &if_true); |
| - |
| - // Check if the object is a receiver type and is not undefined or callable. |
| - Node* map = __ LoadMap(object); |
| - __ GotoIfNot(__ IsJSReceiverMap(map), &if_false); |
| - Node* map_bitfield = __ LoadMapBitField(map); |
| - Node* callable_undetectable = __ Word32And( |
| - map_bitfield, |
| - __ Int32Constant(1 << Map::kIsUndetectable | 1 << Map::kIsCallable)); |
| - __ Branch(__ Word32Equal(callable_undetectable, __ Int32Constant(0)), |
| - &if_true, &if_false); |
| - } |
| - __ Bind(&if_other); |
| - { |
| - // Typeof doesn't return any other string value. |
| - __ Goto(&if_false); |
| - } |
| - |
| - __ Bind(&if_false); |
| - { |
| - __ SetAccumulator(__ BooleanConstant(false)); |
| - __ Goto(&end); |
| - } |
| - __ Bind(&if_true); |
| - { |
| - __ SetAccumulator(__ BooleanConstant(true)); |
| - __ Goto(&end); |
| - } |
| - __ Bind(&end); |
| - __ Dispatch(); |
| -} |
| - |
| -// Jump <imm> |
| -// |
| -// Jump by number of bytes represented by the immediate operand |imm|. |
| -void Interpreter::DoJump(InterpreterAssembler* assembler) { |
| - Node* relative_jump = __ BytecodeOperandUImmWord(0); |
| - __ Jump(relative_jump); |
| -} |
| - |
| -// JumpConstant <idx> |
| -// |
| -// Jump by number of bytes in the Smi in the |idx| entry in the constant pool. |
| -void Interpreter::DoJumpConstant(InterpreterAssembler* assembler) { |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* relative_jump = __ LoadAndUntagConstantPoolEntry(index); |
| - __ Jump(relative_jump); |
| -} |
| - |
| -// JumpIfTrue <imm> |
| -// |
| -// Jump by number of bytes represented by an immediate operand if the |
| -// accumulator contains true. This only works for boolean inputs, and |
| -// will misbehave if passed arbitrary input values. |
| -void Interpreter::DoJumpIfTrue(InterpreterAssembler* assembler) { |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* relative_jump = __ BytecodeOperandUImmWord(0); |
| - Node* true_value = __ BooleanConstant(true); |
| - CSA_ASSERT(assembler, assembler->TaggedIsNotSmi(accumulator)); |
| - CSA_ASSERT(assembler, assembler->IsBoolean(accumulator)); |
| - __ JumpIfWordEqual(accumulator, true_value, relative_jump); |
| -} |
| - |
| -// JumpIfTrueConstant <idx> |
| -// |
| -// Jump by number of bytes in the Smi in the |idx| entry in the constant pool |
| -// if the accumulator contains true. This only works for boolean inputs, and |
| -// will misbehave if passed arbitrary input values. |
| -void Interpreter::DoJumpIfTrueConstant(InterpreterAssembler* assembler) { |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* relative_jump = __ LoadAndUntagConstantPoolEntry(index); |
| - Node* true_value = __ BooleanConstant(true); |
| - CSA_ASSERT(assembler, assembler->TaggedIsNotSmi(accumulator)); |
| - CSA_ASSERT(assembler, assembler->IsBoolean(accumulator)); |
| - __ JumpIfWordEqual(accumulator, true_value, relative_jump); |
| -} |
| - |
| -// JumpIfFalse <imm> |
| -// |
| -// Jump by number of bytes represented by an immediate operand if the |
| -// accumulator contains false. This only works for boolean inputs, and |
| -// will misbehave if passed arbitrary input values. |
| -void Interpreter::DoJumpIfFalse(InterpreterAssembler* assembler) { |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* relative_jump = __ BytecodeOperandUImmWord(0); |
| - Node* false_value = __ BooleanConstant(false); |
| - CSA_ASSERT(assembler, assembler->TaggedIsNotSmi(accumulator)); |
| - CSA_ASSERT(assembler, assembler->IsBoolean(accumulator)); |
| - __ JumpIfWordEqual(accumulator, false_value, relative_jump); |
| -} |
| - |
| -// JumpIfFalseConstant <idx> |
| -// |
| -// Jump by number of bytes in the Smi in the |idx| entry in the constant pool |
| -// if the accumulator contains false. This only works for boolean inputs, and |
| -// will misbehave if passed arbitrary input values. |
| -void Interpreter::DoJumpIfFalseConstant(InterpreterAssembler* assembler) { |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* relative_jump = __ LoadAndUntagConstantPoolEntry(index); |
| - Node* false_value = __ BooleanConstant(false); |
| - CSA_ASSERT(assembler, assembler->TaggedIsNotSmi(accumulator)); |
| - CSA_ASSERT(assembler, assembler->IsBoolean(accumulator)); |
| - __ JumpIfWordEqual(accumulator, false_value, relative_jump); |
| -} |
| - |
| -// JumpIfToBooleanTrue <imm> |
| -// |
| -// Jump by number of bytes represented by an immediate operand if the object |
| -// referenced by the accumulator is true when the object is cast to boolean. |
| -void Interpreter::DoJumpIfToBooleanTrue(InterpreterAssembler* assembler) { |
| - Node* value = __ GetAccumulator(); |
| - Node* relative_jump = __ BytecodeOperandUImmWord(0); |
| - Label if_true(assembler), if_false(assembler); |
| - __ BranchIfToBooleanIsTrue(value, &if_true, &if_false); |
| - __ Bind(&if_true); |
| - __ Jump(relative_jump); |
| - __ Bind(&if_false); |
| - __ Dispatch(); |
| -} |
| - |
| -// JumpIfToBooleanTrueConstant <idx> |
| -// |
| -// Jump by number of bytes in the Smi in the |idx| entry in the constant pool |
| -// if the object referenced by the accumulator is true when the object is cast |
| -// to boolean. |
| -void Interpreter::DoJumpIfToBooleanTrueConstant( |
| - InterpreterAssembler* assembler) { |
| - Node* value = __ GetAccumulator(); |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* relative_jump = __ LoadAndUntagConstantPoolEntry(index); |
| - Label if_true(assembler), if_false(assembler); |
| - __ BranchIfToBooleanIsTrue(value, &if_true, &if_false); |
| - __ Bind(&if_true); |
| - __ Jump(relative_jump); |
| - __ Bind(&if_false); |
| - __ Dispatch(); |
| -} |
| - |
| -// JumpIfToBooleanFalse <imm> |
| -// |
| -// Jump by number of bytes represented by an immediate operand if the object |
| -// referenced by the accumulator is false when the object is cast to boolean. |
| -void Interpreter::DoJumpIfToBooleanFalse(InterpreterAssembler* assembler) { |
| - Node* value = __ GetAccumulator(); |
| - Node* relative_jump = __ BytecodeOperandUImmWord(0); |
| - Label if_true(assembler), if_false(assembler); |
| - __ BranchIfToBooleanIsTrue(value, &if_true, &if_false); |
| - __ Bind(&if_true); |
| - __ Dispatch(); |
| - __ Bind(&if_false); |
| - __ Jump(relative_jump); |
| -} |
| - |
| -// JumpIfToBooleanFalseConstant <idx> |
| -// |
| -// Jump by number of bytes in the Smi in the |idx| entry in the constant pool |
| -// if the object referenced by the accumulator is false when the object is cast |
| -// to boolean. |
| -void Interpreter::DoJumpIfToBooleanFalseConstant( |
| - InterpreterAssembler* assembler) { |
| - Node* value = __ GetAccumulator(); |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* relative_jump = __ LoadAndUntagConstantPoolEntry(index); |
| - Label if_true(assembler), if_false(assembler); |
| - __ BranchIfToBooleanIsTrue(value, &if_true, &if_false); |
| - __ Bind(&if_true); |
| - __ Dispatch(); |
| - __ Bind(&if_false); |
| - __ Jump(relative_jump); |
| -} |
| - |
| -// JumpIfNull <imm> |
| -// |
| -// Jump by number of bytes represented by an immediate operand if the object |
| -// referenced by the accumulator is the null constant. |
| -void Interpreter::DoJumpIfNull(InterpreterAssembler* assembler) { |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* null_value = __ HeapConstant(isolate_->factory()->null_value()); |
| - Node* relative_jump = __ BytecodeOperandUImmWord(0); |
| - __ JumpIfWordEqual(accumulator, null_value, relative_jump); |
| -} |
| - |
| -// JumpIfNullConstant <idx> |
| -// |
| -// Jump by number of bytes in the Smi in the |idx| entry in the constant pool |
| -// if the object referenced by the accumulator is the null constant. |
| -void Interpreter::DoJumpIfNullConstant(InterpreterAssembler* assembler) { |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* null_value = __ HeapConstant(isolate_->factory()->null_value()); |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* relative_jump = __ LoadAndUntagConstantPoolEntry(index); |
| - __ JumpIfWordEqual(accumulator, null_value, relative_jump); |
| -} |
| - |
| -// JumpIfUndefined <imm> |
| -// |
| -// Jump by number of bytes represented by an immediate operand if the object |
| -// referenced by the accumulator is the undefined constant. |
| -void Interpreter::DoJumpIfUndefined(InterpreterAssembler* assembler) { |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* undefined_value = |
| - __ HeapConstant(isolate_->factory()->undefined_value()); |
| - Node* relative_jump = __ BytecodeOperandUImmWord(0); |
| - __ JumpIfWordEqual(accumulator, undefined_value, relative_jump); |
| -} |
| - |
| -// JumpIfUndefinedConstant <idx> |
| -// |
| -// Jump by number of bytes in the Smi in the |idx| entry in the constant pool |
| -// if the object referenced by the accumulator is the undefined constant. |
| -void Interpreter::DoJumpIfUndefinedConstant(InterpreterAssembler* assembler) { |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* undefined_value = |
| - __ HeapConstant(isolate_->factory()->undefined_value()); |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* relative_jump = __ LoadAndUntagConstantPoolEntry(index); |
| - __ JumpIfWordEqual(accumulator, undefined_value, relative_jump); |
| -} |
| - |
| -// JumpIfJSReceiver <imm> |
| -// |
| -// Jump by number of bytes represented by an immediate operand if the object |
| -// referenced by the accumulator is a JSReceiver. |
| -void Interpreter::DoJumpIfJSReceiver(InterpreterAssembler* assembler) { |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* relative_jump = __ BytecodeOperandUImmWord(0); |
| - |
| - Label if_object(assembler), if_notobject(assembler, Label::kDeferred), |
| - if_notsmi(assembler); |
| - __ Branch(__ TaggedIsSmi(accumulator), &if_notobject, &if_notsmi); |
| - |
| - __ Bind(&if_notsmi); |
| - __ Branch(__ IsJSReceiver(accumulator), &if_object, &if_notobject); |
| - __ Bind(&if_object); |
| - __ Jump(relative_jump); |
| - |
| - __ Bind(&if_notobject); |
| - __ Dispatch(); |
| -} |
| - |
| -// JumpIfJSReceiverConstant <idx> |
| -// |
| -// Jump by number of bytes in the Smi in the |idx| entry in the constant pool if |
| -// the object referenced by the accumulator is a JSReceiver. |
| -void Interpreter::DoJumpIfJSReceiverConstant(InterpreterAssembler* assembler) { |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* relative_jump = __ LoadAndUntagConstantPoolEntry(index); |
| - |
| - Label if_object(assembler), if_notobject(assembler), if_notsmi(assembler); |
| - __ Branch(__ TaggedIsSmi(accumulator), &if_notobject, &if_notsmi); |
| - |
| - __ Bind(&if_notsmi); |
| - __ Branch(__ IsJSReceiver(accumulator), &if_object, &if_notobject); |
| - |
| - __ Bind(&if_object); |
| - __ Jump(relative_jump); |
| - |
| - __ Bind(&if_notobject); |
| - __ Dispatch(); |
| -} |
| - |
| -// JumpIfNotHole <imm> |
| -// |
| -// Jump by number of bytes represented by an immediate operand if the object |
| -// referenced by the accumulator is the hole. |
| -void Interpreter::DoJumpIfNotHole(InterpreterAssembler* assembler) { |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* the_hole_value = __ HeapConstant(isolate_->factory()->the_hole_value()); |
| - Node* relative_jump = __ BytecodeOperandUImmWord(0); |
| - __ JumpIfWordNotEqual(accumulator, the_hole_value, relative_jump); |
| -} |
| - |
| -// JumpIfNotHoleConstant <idx> |
| -// |
| -// Jump by number of bytes in the Smi in the |idx| entry in the constant pool |
| -// if the object referenced by the accumulator is the hole constant. |
| -void Interpreter::DoJumpIfNotHoleConstant(InterpreterAssembler* assembler) { |
| - Node* accumulator = __ GetAccumulator(); |
| - Node* the_hole_value = __ HeapConstant(isolate_->factory()->the_hole_value()); |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* relative_jump = __ LoadAndUntagConstantPoolEntry(index); |
| - __ JumpIfWordNotEqual(accumulator, the_hole_value, relative_jump); |
| -} |
| - |
| -// JumpLoop <imm> <loop_depth> |
| -// |
| -// Jump by number of bytes represented by the immediate operand |imm|. Also |
| -// performs a loop nesting check and potentially triggers OSR in case the |
| -// current OSR level matches (or exceeds) the specified |loop_depth|. |
| -void Interpreter::DoJumpLoop(InterpreterAssembler* assembler) { |
| - Node* relative_jump = __ BytecodeOperandUImmWord(0); |
| - Node* loop_depth = __ BytecodeOperandImm(1); |
| - Node* osr_level = __ LoadOSRNestingLevel(); |
| - |
| - // Check if OSR points at the given {loop_depth} are armed by comparing it to |
| - // the current {osr_level} loaded from the header of the BytecodeArray. |
| - Label ok(assembler), osr_armed(assembler, Label::kDeferred); |
| - Node* condition = __ Int32GreaterThanOrEqual(loop_depth, osr_level); |
| - __ Branch(condition, &ok, &osr_armed); |
| - |
| - __ Bind(&ok); |
| - __ JumpBackward(relative_jump); |
| - |
| - __ Bind(&osr_armed); |
| - { |
| - Callable callable = CodeFactory::InterpreterOnStackReplacement(isolate_); |
| - Node* target = __ HeapConstant(callable.code()); |
| - Node* context = __ GetContext(); |
| - __ CallStub(callable.descriptor(), target, context); |
| - __ JumpBackward(relative_jump); |
| - } |
| -} |
| - |
| -// CreateRegExpLiteral <pattern_idx> <literal_idx> <flags> |
| -// |
| -// Creates a regular expression literal for literal index <literal_idx> with |
| -// <flags> and the pattern in <pattern_idx>. |
| -void Interpreter::DoCreateRegExpLiteral(InterpreterAssembler* assembler) { |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* pattern = __ LoadConstantPoolEntry(index); |
| - Node* literal_index = __ BytecodeOperandIdxSmi(1); |
| - Node* flags = __ SmiFromWord32(__ BytecodeOperandFlag(2)); |
| - Node* closure = __ LoadRegister(Register::function_closure()); |
| - Node* context = __ GetContext(); |
| - ConstructorBuiltinsAssembler constructor_assembler(assembler->state()); |
| - Node* result = constructor_assembler.EmitFastCloneRegExp( |
| - closure, literal_index, pattern, flags, context); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// CreateArrayLiteral <element_idx> <literal_idx> <flags> |
| -// |
| -// Creates an array literal for literal index <literal_idx> with |
| -// CreateArrayLiteral flags <flags> and constant elements in <element_idx>. |
| -void Interpreter::DoCreateArrayLiteral(InterpreterAssembler* assembler) { |
| - Node* literal_index = __ BytecodeOperandIdxSmi(1); |
| - Node* closure = __ LoadRegister(Register::function_closure()); |
| - Node* context = __ GetContext(); |
| - Node* bytecode_flags = __ BytecodeOperandFlag(2); |
| - |
| - Label fast_shallow_clone(assembler), |
| - call_runtime(assembler, Label::kDeferred); |
| - __ Branch(__ IsSetWord32<CreateArrayLiteralFlags::FastShallowCloneBit>( |
| - bytecode_flags), |
| - &fast_shallow_clone, &call_runtime); |
| - |
| - __ Bind(&fast_shallow_clone); |
| - { |
| - ConstructorBuiltinsAssembler constructor_assembler(assembler->state()); |
| - Node* result = constructor_assembler.EmitFastCloneShallowArray( |
| - closure, literal_index, context, &call_runtime, TRACK_ALLOCATION_SITE); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| - } |
| - |
| - __ Bind(&call_runtime); |
| - { |
| - Node* flags_raw = |
| - __ DecodeWordFromWord32<CreateArrayLiteralFlags::FlagsBits>( |
| - bytecode_flags); |
| - Node* flags = __ SmiTag(flags_raw); |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* constant_elements = __ LoadConstantPoolEntry(index); |
| - Node* result = |
| - __ CallRuntime(Runtime::kCreateArrayLiteral, context, closure, |
| - literal_index, constant_elements, flags); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| - } |
| -} |
| - |
| -// CreateObjectLiteral <element_idx> <literal_idx> <flags> |
| -// |
| -// Creates an object literal for literal index <literal_idx> with |
| -// CreateObjectLiteralFlags <flags> and constant elements in <element_idx>. |
| -void Interpreter::DoCreateObjectLiteral(InterpreterAssembler* assembler) { |
| - Node* literal_index = __ BytecodeOperandIdxSmi(1); |
| - Node* bytecode_flags = __ BytecodeOperandFlag(2); |
| - Node* closure = __ LoadRegister(Register::function_closure()); |
| - |
| - // Check if we can do a fast clone or have to call the runtime. |
| - Label if_fast_clone(assembler), |
| - if_not_fast_clone(assembler, Label::kDeferred); |
| - Node* fast_clone_properties_count = __ DecodeWordFromWord32< |
| - CreateObjectLiteralFlags::FastClonePropertiesCountBits>(bytecode_flags); |
| - __ Branch(__ WordNotEqual(fast_clone_properties_count, __ IntPtrConstant(0)), |
| - &if_fast_clone, &if_not_fast_clone); |
| - |
| - __ Bind(&if_fast_clone); |
| - { |
| - // If we can do a fast clone do the fast-path in FastCloneShallowObjectStub. |
| - ConstructorBuiltinsAssembler constructor_assembler(assembler->state()); |
| - Node* result = constructor_assembler.EmitFastCloneShallowObject( |
| - &if_not_fast_clone, closure, literal_index, |
| - fast_clone_properties_count); |
| - __ StoreRegister(result, __ BytecodeOperandReg(3)); |
| - __ Dispatch(); |
| - } |
| - |
| - __ Bind(&if_not_fast_clone); |
| - { |
| - // If we can't do a fast clone, call into the runtime. |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* constant_elements = __ LoadConstantPoolEntry(index); |
| - Node* context = __ GetContext(); |
| - |
| - Node* flags_raw = |
| - __ DecodeWordFromWord32<CreateObjectLiteralFlags::FlagsBits>( |
| - bytecode_flags); |
| - Node* flags = __ SmiTag(flags_raw); |
| - |
| - Node* result = |
| - __ CallRuntime(Runtime::kCreateObjectLiteral, context, closure, |
| - literal_index, constant_elements, flags); |
| - __ StoreRegister(result, __ BytecodeOperandReg(3)); |
| - // TODO(klaasb) build a single dispatch once the call is inlined |
| - __ Dispatch(); |
| - } |
| -} |
| - |
| -// CreateClosure <index> <slot> <tenured> |
| -// |
| -// Creates a new closure for SharedFunctionInfo at position |index| in the |
| -// constant pool and with the PretenureFlag <tenured>. |
| -void Interpreter::DoCreateClosure(InterpreterAssembler* assembler) { |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* shared = __ LoadConstantPoolEntry(index); |
| - Node* flags = __ BytecodeOperandFlag(2); |
| - Node* context = __ GetContext(); |
| - |
| - Label call_runtime(assembler, Label::kDeferred); |
| - __ GotoIfNot(__ IsSetWord32<CreateClosureFlags::FastNewClosureBit>(flags), |
| - &call_runtime); |
| - ConstructorBuiltinsAssembler constructor_assembler(assembler->state()); |
| - Node* vector_index = __ BytecodeOperandIdx(1); |
| - vector_index = __ SmiTag(vector_index); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - __ SetAccumulator(constructor_assembler.EmitFastNewClosure( |
| - shared, feedback_vector, vector_index, context)); |
| - __ Dispatch(); |
| - |
| - __ Bind(&call_runtime); |
| - { |
| - Node* tenured_raw = |
| - __ DecodeWordFromWord32<CreateClosureFlags::PretenuredBit>(flags); |
| - Node* tenured = __ SmiTag(tenured_raw); |
| - feedback_vector = __ LoadFeedbackVector(); |
| - vector_index = __ BytecodeOperandIdx(1); |
| - vector_index = __ SmiTag(vector_index); |
| - Node* result = |
| - __ CallRuntime(Runtime::kInterpreterNewClosure, context, shared, |
| - feedback_vector, vector_index, tenured); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| - } |
| -} |
| - |
| -// CreateBlockContext <index> |
| -// |
| -// Creates a new block context with the scope info constant at |index| and the |
| -// closure in the accumulator. |
| -void Interpreter::DoCreateBlockContext(InterpreterAssembler* assembler) { |
| - Node* index = __ BytecodeOperandIdx(0); |
| - Node* scope_info = __ LoadConstantPoolEntry(index); |
| - Node* closure = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - __ SetAccumulator( |
| - __ CallRuntime(Runtime::kPushBlockContext, context, scope_info, closure)); |
| - __ Dispatch(); |
| -} |
| - |
| -// CreateCatchContext <exception> <name_idx> <scope_info_idx> |
| -// |
| -// Creates a new context for a catch block with the |exception| in a register, |
| -// the variable name at |name_idx|, the ScopeInfo at |scope_info_idx|, and the |
| -// closure in the accumulator. |
| -void Interpreter::DoCreateCatchContext(InterpreterAssembler* assembler) { |
| - Node* exception_reg = __ BytecodeOperandReg(0); |
| - Node* exception = __ LoadRegister(exception_reg); |
| - Node* name_idx = __ BytecodeOperandIdx(1); |
| - Node* name = __ LoadConstantPoolEntry(name_idx); |
| - Node* scope_info_idx = __ BytecodeOperandIdx(2); |
| - Node* scope_info = __ LoadConstantPoolEntry(scope_info_idx); |
| - Node* closure = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - __ SetAccumulator(__ CallRuntime(Runtime::kPushCatchContext, context, name, |
| - exception, scope_info, closure)); |
| - __ Dispatch(); |
| -} |
| - |
| -// CreateFunctionContext <slots> |
| -// |
| -// Creates a new context with number of |slots| for the function closure. |
| -void Interpreter::DoCreateFunctionContext(InterpreterAssembler* assembler) { |
| - Node* closure = __ LoadRegister(Register::function_closure()); |
| - Node* slots = __ BytecodeOperandUImm(0); |
| - Node* context = __ GetContext(); |
| - ConstructorBuiltinsAssembler constructor_assembler(assembler->state()); |
| - __ SetAccumulator(constructor_assembler.EmitFastNewFunctionContext( |
| - closure, slots, context, FUNCTION_SCOPE)); |
| - __ Dispatch(); |
| -} |
| - |
| -// CreateEvalContext <slots> |
| -// |
| -// Creates a new context with number of |slots| for an eval closure. |
| -void Interpreter::DoCreateEvalContext(InterpreterAssembler* assembler) { |
| - Node* closure = __ LoadRegister(Register::function_closure()); |
| - Node* slots = __ BytecodeOperandUImm(0); |
| - Node* context = __ GetContext(); |
| - ConstructorBuiltinsAssembler constructor_assembler(assembler->state()); |
| - __ SetAccumulator(constructor_assembler.EmitFastNewFunctionContext( |
| - closure, slots, context, EVAL_SCOPE)); |
| - __ Dispatch(); |
| -} |
| - |
| -// CreateWithContext <register> <scope_info_idx> |
| -// |
| -// Creates a new context with the ScopeInfo at |scope_info_idx| for a |
| -// with-statement with the object in |register| and the closure in the |
| -// accumulator. |
| -void Interpreter::DoCreateWithContext(InterpreterAssembler* assembler) { |
| - Node* reg_index = __ BytecodeOperandReg(0); |
| - Node* object = __ LoadRegister(reg_index); |
| - Node* scope_info_idx = __ BytecodeOperandIdx(1); |
| - Node* scope_info = __ LoadConstantPoolEntry(scope_info_idx); |
| - Node* closure = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - __ SetAccumulator(__ CallRuntime(Runtime::kPushWithContext, context, object, |
| - scope_info, closure)); |
| - __ Dispatch(); |
| -} |
| - |
| -// CreateMappedArguments |
| -// |
| -// Creates a new mapped arguments object. |
| -void Interpreter::DoCreateMappedArguments(InterpreterAssembler* assembler) { |
| - Node* closure = __ LoadRegister(Register::function_closure()); |
| - Node* context = __ GetContext(); |
| - |
| - Label if_duplicate_parameters(assembler, Label::kDeferred); |
| - Label if_not_duplicate_parameters(assembler); |
| - |
| - // Check if function has duplicate parameters. |
| - // TODO(rmcilroy): Remove this check when FastNewSloppyArgumentsStub supports |
| - // duplicate parameters. |
| - Node* shared_info = |
| - __ LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset); |
| - Node* compiler_hints = __ LoadObjectField( |
| - shared_info, SharedFunctionInfo::kHasDuplicateParametersByteOffset, |
| - MachineType::Uint8()); |
| - Node* duplicate_parameters_bit = __ Int32Constant( |
| - 1 << SharedFunctionInfo::kHasDuplicateParametersBitWithinByte); |
| - Node* compare = __ Word32And(compiler_hints, duplicate_parameters_bit); |
| - __ Branch(compare, &if_duplicate_parameters, &if_not_duplicate_parameters); |
| - |
| - __ Bind(&if_not_duplicate_parameters); |
| - { |
| - ArgumentsBuiltinsAssembler constructor_assembler(assembler->state()); |
| - Node* result = |
| - constructor_assembler.EmitFastNewSloppyArguments(context, closure); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| - } |
| - |
| - __ Bind(&if_duplicate_parameters); |
| - { |
| - Node* result = |
| - __ CallRuntime(Runtime::kNewSloppyArguments_Generic, context, closure); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| - } |
| -} |
| - |
| -// CreateUnmappedArguments |
| -// |
| -// Creates a new unmapped arguments object. |
| -void Interpreter::DoCreateUnmappedArguments(InterpreterAssembler* assembler) { |
| - Node* context = __ GetContext(); |
| - Node* closure = __ LoadRegister(Register::function_closure()); |
| - ArgumentsBuiltinsAssembler builtins_assembler(assembler->state()); |
| - Node* result = |
| - builtins_assembler.EmitFastNewStrictArguments(context, closure); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// CreateRestParameter |
| -// |
| -// Creates a new rest parameter array. |
| -void Interpreter::DoCreateRestParameter(InterpreterAssembler* assembler) { |
| - Node* closure = __ LoadRegister(Register::function_closure()); |
| - Node* context = __ GetContext(); |
| - ArgumentsBuiltinsAssembler builtins_assembler(assembler->state()); |
| - Node* result = builtins_assembler.EmitFastNewRestParameter(context, closure); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// StackCheck |
| -// |
| -// Performs a stack guard check. |
| -void Interpreter::DoStackCheck(InterpreterAssembler* assembler) { |
| - Label ok(assembler), stack_check_interrupt(assembler, Label::kDeferred); |
| - |
| - Node* interrupt = __ StackCheckTriggeredInterrupt(); |
| - __ Branch(interrupt, &stack_check_interrupt, &ok); |
| - |
| - __ Bind(&ok); |
| - __ Dispatch(); |
| - |
| - __ Bind(&stack_check_interrupt); |
| - { |
| - Node* context = __ GetContext(); |
| - __ CallRuntime(Runtime::kStackGuard, context); |
| - __ Dispatch(); |
| - } |
| -} |
| - |
| -// SetPendingMessage |
| -// |
| -// Sets the pending message to the value in the accumulator, and returns the |
| -// previous pending message in the accumulator. |
| -void Interpreter::DoSetPendingMessage(InterpreterAssembler* assembler) { |
| - Node* pending_message = __ ExternalConstant( |
| - ExternalReference::address_of_pending_message_obj(isolate_)); |
| - Node* previous_message = |
| - __ Load(MachineType::TaggedPointer(), pending_message); |
| - Node* new_message = __ GetAccumulator(); |
| - __ StoreNoWriteBarrier(MachineRepresentation::kTaggedPointer, pending_message, |
| - new_message); |
| - __ SetAccumulator(previous_message); |
| - __ Dispatch(); |
| -} |
| - |
| -// Throw |
| -// |
| -// Throws the exception in the accumulator. |
| -void Interpreter::DoThrow(InterpreterAssembler* assembler) { |
| - Node* exception = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - __ CallRuntime(Runtime::kThrow, context, exception); |
| - // We shouldn't ever return from a throw. |
| - __ Abort(kUnexpectedReturnFromThrow); |
| -} |
| - |
| -// ReThrow |
| -// |
| -// Re-throws the exception in the accumulator. |
| -void Interpreter::DoReThrow(InterpreterAssembler* assembler) { |
| - Node* exception = __ GetAccumulator(); |
| - Node* context = __ GetContext(); |
| - __ CallRuntime(Runtime::kReThrow, context, exception); |
| - // We shouldn't ever return from a throw. |
| - __ Abort(kUnexpectedReturnFromThrow); |
| -} |
| - |
| -// Return |
| -// |
| -// Return the value in the accumulator. |
| -void Interpreter::DoReturn(InterpreterAssembler* assembler) { |
| - __ UpdateInterruptBudgetOnReturn(); |
| - Node* accumulator = __ GetAccumulator(); |
| - __ Return(accumulator); |
| -} |
| - |
| -// Debugger |
| -// |
| -// Call runtime to handle debugger statement. |
| -void Interpreter::DoDebugger(InterpreterAssembler* assembler) { |
| - Node* context = __ GetContext(); |
| - __ CallStub(CodeFactory::HandleDebuggerStatement(isolate_), context); |
| - __ Dispatch(); |
| -} |
| - |
| -// DebugBreak |
| -// |
| -// Call runtime to handle a debug break. |
| -#define DEBUG_BREAK(Name, ...) \ |
| - void Interpreter::Do##Name(InterpreterAssembler* assembler) { \ |
| - Node* context = __ GetContext(); \ |
| - Node* accumulator = __ GetAccumulator(); \ |
| - Node* original_handler = \ |
| - __ CallRuntime(Runtime::kDebugBreakOnBytecode, context, accumulator); \ |
| - __ MaybeDropFrames(context); \ |
| - __ DispatchToBytecodeHandler(original_handler); \ |
| - } |
| -DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK); |
| -#undef DEBUG_BREAK |
| - |
| -void Interpreter::BuildForInPrepareResult(Node* output_register, |
| - Node* cache_type, Node* cache_array, |
| - Node* cache_length, |
| - InterpreterAssembler* assembler) { |
| - __ StoreRegister(cache_type, output_register); |
| - output_register = __ NextRegister(output_register); |
| - __ StoreRegister(cache_array, output_register); |
| - output_register = __ NextRegister(output_register); |
| - __ StoreRegister(cache_length, output_register); |
| -} |
| - |
| -// ForInPrepare <receiver> <cache_info_triple> |
| -// |
| -// Returns state for for..in loop execution based on the object in the register |
| -// |receiver|. The object must not be null or undefined and must have been |
| -// converted to a receiver already. |
| -// The result is output in registers |cache_info_triple| to |
| -// |cache_info_triple + 2|, with the registers holding cache_type, cache_array, |
| -// and cache_length respectively. |
| -void Interpreter::DoForInPrepare(InterpreterAssembler* assembler) { |
| - Node* object_register = __ BytecodeOperandReg(0); |
| - Node* output_register = __ BytecodeOperandReg(1); |
| - Node* receiver = __ LoadRegister(object_register); |
| - Node* context = __ GetContext(); |
| - |
| - Node* cache_type; |
| - Node* cache_array; |
| - Node* cache_length; |
| - Label call_runtime(assembler, Label::kDeferred), |
| - nothing_to_iterate(assembler, Label::kDeferred); |
| - |
| - ForInBuiltinsAssembler forin_assembler(assembler->state()); |
| - std::tie(cache_type, cache_array, cache_length) = |
| - forin_assembler.EmitForInPrepare(receiver, context, &call_runtime, |
| - ¬hing_to_iterate); |
| - |
| - BuildForInPrepareResult(output_register, cache_type, cache_array, |
| - cache_length, assembler); |
| - __ Dispatch(); |
| - |
| - __ Bind(&call_runtime); |
| - { |
| - Node* result_triple = |
| - __ CallRuntime(Runtime::kForInPrepare, context, receiver); |
| - Node* cache_type = __ Projection(0, result_triple); |
| - Node* cache_array = __ Projection(1, result_triple); |
| - Node* cache_length = __ Projection(2, result_triple); |
| - BuildForInPrepareResult(output_register, cache_type, cache_array, |
| - cache_length, assembler); |
| - __ Dispatch(); |
| - } |
| - __ Bind(¬hing_to_iterate); |
| - { |
| - // Receiver is null or undefined or descriptors are zero length. |
| - Node* zero = __ SmiConstant(0); |
| - BuildForInPrepareResult(output_register, zero, zero, zero, assembler); |
| - __ Dispatch(); |
| - } |
| -} |
| - |
| -// ForInNext <receiver> <index> <cache_info_pair> |
| -// |
| -// Returns the next enumerable property in the the accumulator. |
| -void Interpreter::DoForInNext(InterpreterAssembler* assembler) { |
| - Node* receiver_reg = __ BytecodeOperandReg(0); |
| - Node* receiver = __ LoadRegister(receiver_reg); |
| - Node* index_reg = __ BytecodeOperandReg(1); |
| - Node* index = __ LoadRegister(index_reg); |
| - Node* cache_type_reg = __ BytecodeOperandReg(2); |
| - Node* cache_type = __ LoadRegister(cache_type_reg); |
| - Node* cache_array_reg = __ NextRegister(cache_type_reg); |
| - Node* cache_array = __ LoadRegister(cache_array_reg); |
| - |
| - // Load the next key from the enumeration array. |
| - Node* key = __ LoadFixedArrayElement(cache_array, index, 0, |
| - CodeStubAssembler::SMI_PARAMETERS); |
| - |
| - // Check if we can use the for-in fast path potentially using the enum cache. |
| - Label if_fast(assembler), if_slow(assembler, Label::kDeferred); |
| - Node* receiver_map = __ LoadMap(receiver); |
| - __ Branch(__ WordEqual(receiver_map, cache_type), &if_fast, &if_slow); |
| - __ Bind(&if_fast); |
| - { |
| - // Enum cache in use for {receiver}, the {key} is definitely valid. |
| - __ SetAccumulator(key); |
| - __ Dispatch(); |
| - } |
| - __ Bind(&if_slow); |
| - { |
| - // Record the fact that we hit the for-in slow path. |
| - Node* vector_index = __ BytecodeOperandIdx(3); |
| - Node* feedback_vector = __ LoadFeedbackVector(); |
| - Node* megamorphic_sentinel = |
| - __ HeapConstant(FeedbackVector::MegamorphicSentinel(isolate_)); |
| - __ StoreFixedArrayElement(feedback_vector, vector_index, |
| - megamorphic_sentinel, SKIP_WRITE_BARRIER); |
| - |
| - // Need to filter the {key} for the {receiver}. |
| - Node* context = __ GetContext(); |
| - Callable callable = CodeFactory::ForInFilter(assembler->isolate()); |
| - Node* result = __ CallStub(callable, context, key, receiver); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| - } |
| -} |
| - |
| -// ForInContinue <index> <cache_length> |
| -// |
| -// Returns false if the end of the enumerable properties has been reached. |
| -void Interpreter::DoForInContinue(InterpreterAssembler* assembler) { |
| - Node* index_reg = __ BytecodeOperandReg(0); |
| - Node* index = __ LoadRegister(index_reg); |
| - Node* cache_length_reg = __ BytecodeOperandReg(1); |
| - Node* cache_length = __ LoadRegister(cache_length_reg); |
| - |
| - // Check if {index} is at {cache_length} already. |
| - Label if_true(assembler), if_false(assembler), end(assembler); |
| - __ Branch(__ WordEqual(index, cache_length), &if_true, &if_false); |
| - __ Bind(&if_true); |
| - { |
| - __ SetAccumulator(__ BooleanConstant(false)); |
| - __ Goto(&end); |
| - } |
| - __ Bind(&if_false); |
| - { |
| - __ SetAccumulator(__ BooleanConstant(true)); |
| - __ Goto(&end); |
| - } |
| - __ Bind(&end); |
| - __ Dispatch(); |
| -} |
| - |
| -// ForInStep <index> |
| -// |
| -// Increments the loop counter in register |index| and stores the result |
| -// in the accumulator. |
| -void Interpreter::DoForInStep(InterpreterAssembler* assembler) { |
| - Node* index_reg = __ BytecodeOperandReg(0); |
| - Node* index = __ LoadRegister(index_reg); |
| - Node* one = __ SmiConstant(Smi::FromInt(1)); |
| - Node* result = __ SmiAdd(index, one); |
| - __ SetAccumulator(result); |
| - __ Dispatch(); |
| -} |
| - |
| -// Wide |
| -// |
| -// Prefix bytecode indicating next bytecode has wide (16-bit) operands. |
| -void Interpreter::DoWide(InterpreterAssembler* assembler) { |
| - __ DispatchWide(OperandScale::kDouble); |
| -} |
| - |
| -// ExtraWide |
| -// |
| -// Prefix bytecode indicating next bytecode has extra-wide (32-bit) operands. |
| -void Interpreter::DoExtraWide(InterpreterAssembler* assembler) { |
| - __ DispatchWide(OperandScale::kQuadruple); |
| -} |
| - |
| -// Illegal |
| -// |
| -// An invalid bytecode aborting execution if dispatched. |
| -void Interpreter::DoIllegal(InterpreterAssembler* assembler) { |
| - __ Abort(kInvalidBytecode); |
| -} |
| - |
| -// Nop |
| -// |
| -// No operation. |
| -void Interpreter::DoNop(InterpreterAssembler* assembler) { __ Dispatch(); } |
| - |
| -// SuspendGenerator <generator> |
| -// |
| -// Exports the register file and stores it into the generator. Also stores the |
| -// current context, the state given in the accumulator, and the current bytecode |
| -// offset (for debugging purposes) into the generator. |
| -void Interpreter::DoSuspendGenerator(InterpreterAssembler* assembler) { |
| - Node* generator_reg = __ BytecodeOperandReg(0); |
| - Node* generator = __ LoadRegister(generator_reg); |
| - |
| - Label if_stepping(assembler, Label::kDeferred), ok(assembler); |
| - Node* step_action_address = __ ExternalConstant( |
| - ExternalReference::debug_last_step_action_address(isolate_)); |
| - Node* step_action = __ Load(MachineType::Int8(), step_action_address); |
| - STATIC_ASSERT(StepIn > StepNext); |
| - STATIC_ASSERT(LastStepAction == StepIn); |
| - Node* step_next = __ Int32Constant(StepNext); |
| - __ Branch(__ Int32LessThanOrEqual(step_next, step_action), &if_stepping, &ok); |
| - __ Bind(&ok); |
| - |
| - Node* array = |
| - __ LoadObjectField(generator, JSGeneratorObject::kRegisterFileOffset); |
| - Node* context = __ GetContext(); |
| - Node* state = __ GetAccumulator(); |
| - |
| - __ ExportRegisterFile(array); |
| - __ StoreObjectField(generator, JSGeneratorObject::kContextOffset, context); |
| - __ StoreObjectField(generator, JSGeneratorObject::kContinuationOffset, state); |
| - |
| - Node* offset = __ SmiTag(__ BytecodeOffset()); |
| - __ StoreObjectField(generator, JSGeneratorObject::kInputOrDebugPosOffset, |
| - offset); |
| - |
| - __ Dispatch(); |
| - |
| - __ Bind(&if_stepping); |
| - { |
| - Node* context = __ GetContext(); |
| - __ CallRuntime(Runtime::kDebugRecordGenerator, context, generator); |
| - __ Goto(&ok); |
| - } |
| -} |
| - |
| -// ResumeGenerator <generator> |
| -// |
| -// Imports the register file stored in the generator. Also loads the |
| -// generator's state and stores it in the accumulator, before overwriting it |
| -// with kGeneratorExecuting. |
| -void Interpreter::DoResumeGenerator(InterpreterAssembler* assembler) { |
| - Node* generator_reg = __ BytecodeOperandReg(0); |
| - Node* generator = __ LoadRegister(generator_reg); |
| - |
| - __ ImportRegisterFile( |
| - __ LoadObjectField(generator, JSGeneratorObject::kRegisterFileOffset)); |
| - |
| - Node* old_state = |
| - __ LoadObjectField(generator, JSGeneratorObject::kContinuationOffset); |
| - Node* new_state = __ Int32Constant(JSGeneratorObject::kGeneratorExecuting); |
| - __ StoreObjectField(generator, JSGeneratorObject::kContinuationOffset, |
| - __ SmiTag(new_state)); |
| - __ SetAccumulator(old_state); |
| - |
| - __ Dispatch(); |
| -} |
| - |
| } // namespace interpreter |
| } // namespace internal |
| } // namespace v8 |