Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(650)

Unified Diff: src/interpreter/interpreter.cc

Issue 2765433003: [interpreter] Split bytecode generation out of interpreter.cc (Closed)
Patch Set: addressed nits Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/interpreter/interpreter.h ('k') | src/interpreter/interpreter-generator.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/interpreter/interpreter.cc
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index 6af06fddbb74311de367d9aaca53e09592a8e0c6..c63e1e41372657125dfd15243bc87e3d0cee384b 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -4,40 +4,23 @@
#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/codegen.h"
#include "src/compilation-info.h"
#include "src/compiler.h"
#include "src/counters.h"
-#include "src/debug/debug.h"
-#include "src/factory.h"
-#include "src/ic/accessor-assembler.h"
-#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"
+#include "src/objects.h"
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 +77,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 +95,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 +143,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 +295,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 +367,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(&params, 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(&params, &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(&params, &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), &not_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)), &not_equal);
-
- __ SetAccumulator(__ BooleanConstant(true));
- __ Goto(&end);
-
- __ Bind(&not_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,
- &nothing_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(&nothing_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
« no previous file with comments | « src/interpreter/interpreter.h ('k') | src/interpreter/interpreter-generator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698