[interpreter]: Changes to interpreter builtins for accumulator and register file registers.
Makes the following modifications to the interpreter builtins and InterpreterAssembler: - Adds an accumulator register and initializes it to undefined() - Adds a register file pointer register and use it instead of FramePointer to access registers - Modifies builtin to support functions with 0 regiters in the register file - Modifies builtin to Call rather than TailCall to first bytecode handler. BUG=v8:4280 LOG=N Review URL: https://codereview.chromium.org/1289863003 Cr-Commit-Position: refs/heads/master@{#30219}
This commit is contained in:
parent
8aef442917
commit
00df60d1c6
@ -8,7 +8,6 @@
|
|||||||
#include "src/debug/debug.h"
|
#include "src/debug/debug.h"
|
||||||
#include "src/deoptimizer.h"
|
#include "src/deoptimizer.h"
|
||||||
#include "src/full-codegen/full-codegen.h"
|
#include "src/full-codegen/full-codegen.h"
|
||||||
#include "src/interpreter/bytecodes.h"
|
|
||||||
#include "src/runtime/runtime.h"
|
#include "src/runtime/runtime.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
@ -925,16 +924,17 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
__ bind(&ok);
|
__ bind(&ok);
|
||||||
|
|
||||||
// If ok, push undefined as the initial value for all register file entries.
|
// If ok, push undefined as the initial value for all register file entries.
|
||||||
// Note: there should always be at least one stack slot for the return
|
|
||||||
// register in the register file.
|
|
||||||
Label loop_header;
|
Label loop_header;
|
||||||
|
Label loop_check;
|
||||||
__ LoadRoot(r9, Heap::kUndefinedValueRootIndex);
|
__ LoadRoot(r9, Heap::kUndefinedValueRootIndex);
|
||||||
|
__ b(&loop_check, al);
|
||||||
__ bind(&loop_header);
|
__ bind(&loop_header);
|
||||||
// TODO(rmcilroy): Consider doing more than one push per loop iteration.
|
// TODO(rmcilroy): Consider doing more than one push per loop iteration.
|
||||||
__ push(r9);
|
__ push(r9);
|
||||||
// Continue loop if not done.
|
// Continue loop if not done.
|
||||||
|
__ bind(&loop_check);
|
||||||
__ sub(r4, r4, Operand(kPointerSize), SetCC);
|
__ sub(r4, r4, Operand(kPointerSize), SetCC);
|
||||||
__ b(&loop_header, ne);
|
__ b(&loop_header, ge);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(rmcilroy): List of things not currently dealt with here but done in
|
// TODO(rmcilroy): List of things not currently dealt with here but done in
|
||||||
@ -968,7 +968,11 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
__ bind(&ok);
|
__ bind(&ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load bytecode offset and dispatch table into registers.
|
// Load accumulator, register file, bytecode offset, dispatch table into
|
||||||
|
// registers.
|
||||||
|
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
|
||||||
|
__ sub(kInterpreterRegisterFileRegister, fp,
|
||||||
|
Operand(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
|
||||||
__ mov(kInterpreterBytecodeOffsetRegister,
|
__ mov(kInterpreterBytecodeOffsetRegister,
|
||||||
Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
||||||
__ LoadRoot(kInterpreterDispatchTableRegister,
|
__ LoadRoot(kInterpreterDispatchTableRegister,
|
||||||
@ -977,14 +981,14 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
||||||
|
|
||||||
// Dispatch to the first bytecode handler for the function.
|
// Dispatch to the first bytecode handler for the function.
|
||||||
__ ldrb(r0, MemOperand(kInterpreterBytecodeArrayRegister,
|
__ ldrb(r1, MemOperand(kInterpreterBytecodeArrayRegister,
|
||||||
kInterpreterBytecodeOffsetRegister));
|
kInterpreterBytecodeOffsetRegister));
|
||||||
__ ldr(ip, MemOperand(kInterpreterDispatchTableRegister, r0, LSL,
|
__ ldr(ip, MemOperand(kInterpreterDispatchTableRegister, r1, LSL,
|
||||||
kPointerSizeLog2));
|
kPointerSizeLog2));
|
||||||
// TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
|
// TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
|
||||||
// and header removal.
|
// and header removal.
|
||||||
__ add(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
|
__ add(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||||
__ Jump(ip);
|
__ Call(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -995,9 +999,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
|
|||||||
// - Support profiler (specifically decrementing profiling_counter
|
// - Support profiler (specifically decrementing profiling_counter
|
||||||
// appropriately and calling out to HandleInterrupts if necessary).
|
// appropriately and calling out to HandleInterrupts if necessary).
|
||||||
|
|
||||||
// Load return value into r0.
|
// The return value is in accumulator, which is already in r0.
|
||||||
__ ldr(r0, MemOperand(fp, -kPointerSize -
|
|
||||||
StandardFrameConstants::kFixedFrameSizeFromFp));
|
|
||||||
// Leave the frame (also dropping the register file).
|
// Leave the frame (also dropping the register file).
|
||||||
__ LeaveFrame(StackFrame::JAVA_SCRIPT);
|
__ LeaveFrame(StackFrame::JAVA_SCRIPT);
|
||||||
// Drop receiver + arguments.
|
// Drop receiver + arguments.
|
||||||
|
@ -18,6 +18,8 @@ const Register kReturnRegister0 = {kRegister_r0_Code};
|
|||||||
const Register kReturnRegister1 = {kRegister_r1_Code};
|
const Register kReturnRegister1 = {kRegister_r1_Code};
|
||||||
const Register kJSFunctionRegister = {kRegister_r1_Code};
|
const Register kJSFunctionRegister = {kRegister_r1_Code};
|
||||||
const Register kContextRegister = {kRegister_r7_Code};
|
const Register kContextRegister = {kRegister_r7_Code};
|
||||||
|
const Register kInterpreterAccumulatorRegister = {kRegister_r0_Code};
|
||||||
|
const Register kInterpreterRegisterFileRegister = {kRegister_r4_Code};
|
||||||
const Register kInterpreterBytecodeOffsetRegister = {kRegister_r5_Code};
|
const Register kInterpreterBytecodeOffsetRegister = {kRegister_r5_Code};
|
||||||
const Register kInterpreterBytecodeArrayRegister = {kRegister_r6_Code};
|
const Register kInterpreterBytecodeArrayRegister = {kRegister_r6_Code};
|
||||||
const Register kInterpreterDispatchTableRegister = {kRegister_r8_Code};
|
const Register kInterpreterDispatchTableRegister = {kRegister_r8_Code};
|
||||||
|
@ -990,7 +990,11 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
__ Bind(&ok);
|
__ Bind(&ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load bytecode offset and dispatch table into registers.
|
// Load accumulator, register file, bytecode offset, dispatch table into
|
||||||
|
// registers.
|
||||||
|
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
|
||||||
|
__ Sub(kInterpreterRegisterFileRegister, fp,
|
||||||
|
Operand(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
|
||||||
__ Mov(kInterpreterBytecodeOffsetRegister,
|
__ Mov(kInterpreterBytecodeOffsetRegister,
|
||||||
Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
||||||
__ LoadRoot(kInterpreterDispatchTableRegister,
|
__ LoadRoot(kInterpreterDispatchTableRegister,
|
||||||
@ -999,14 +1003,14 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
||||||
|
|
||||||
// Dispatch to the first bytecode handler for the function.
|
// Dispatch to the first bytecode handler for the function.
|
||||||
__ Ldrb(x0, MemOperand(kInterpreterBytecodeArrayRegister,
|
__ Ldrb(x1, MemOperand(kInterpreterBytecodeArrayRegister,
|
||||||
kInterpreterBytecodeOffsetRegister));
|
kInterpreterBytecodeOffsetRegister));
|
||||||
__ Mov(x0, Operand(x0, LSL, kPointerSizeLog2));
|
__ Mov(x1, Operand(x1, LSL, kPointerSizeLog2));
|
||||||
__ Ldr(ip0, MemOperand(kInterpreterDispatchTableRegister, x0));
|
__ Ldr(ip0, MemOperand(kInterpreterDispatchTableRegister, x1));
|
||||||
// TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
|
// TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
|
||||||
// and header removal.
|
// and header removal.
|
||||||
__ Add(ip0, ip0, Operand(Code::kHeaderSize - kHeapObjectTag));
|
__ Add(ip0, ip0, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||||
__ Jump(ip0);
|
__ Call(ip0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1017,9 +1021,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
|
|||||||
// - Support profiler (specifically decrementing profiling_counter
|
// - Support profiler (specifically decrementing profiling_counter
|
||||||
// appropriately and calling out to HandleInterrupts if necessary).
|
// appropriately and calling out to HandleInterrupts if necessary).
|
||||||
|
|
||||||
// Load return value into x0.
|
// The return value is in accumulator, which is already in x0.
|
||||||
__ ldr(x0, MemOperand(fp, -kPointerSize -
|
|
||||||
StandardFrameConstants::kFixedFrameSizeFromFp));
|
|
||||||
// Leave the frame (also dropping the register file).
|
// Leave the frame (also dropping the register file).
|
||||||
__ LeaveFrame(StackFrame::JAVA_SCRIPT);
|
__ LeaveFrame(StackFrame::JAVA_SCRIPT);
|
||||||
// Drop receiver + arguments.
|
// Drop receiver + arguments.
|
||||||
|
@ -39,6 +39,8 @@ namespace internal {
|
|||||||
#define kReturnRegister1 x1
|
#define kReturnRegister1 x1
|
||||||
#define kJSFunctionRegister x1
|
#define kJSFunctionRegister x1
|
||||||
#define kContextRegister cp
|
#define kContextRegister cp
|
||||||
|
#define kInterpreterAccumulatorRegister x0
|
||||||
|
#define kInterpreterRegisterFileRegister x18
|
||||||
#define kInterpreterBytecodeOffsetRegister x19
|
#define kInterpreterBytecodeOffsetRegister x19
|
||||||
#define kInterpreterBytecodeArrayRegister x20
|
#define kInterpreterBytecodeArrayRegister x20
|
||||||
#define kInterpreterDispatchTableRegister x21
|
#define kInterpreterDispatchTableRegister x21
|
||||||
|
@ -31,6 +31,8 @@ InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone,
|
|||||||
Linkage::GetInterpreterDispatchDescriptor(zone), kMachPtr,
|
Linkage::GetInterpreterDispatchDescriptor(zone), kMachPtr,
|
||||||
InstructionSelector::SupportedMachineOperatorFlags())),
|
InstructionSelector::SupportedMachineOperatorFlags())),
|
||||||
end_node_(nullptr),
|
end_node_(nullptr),
|
||||||
|
accumulator_(
|
||||||
|
raw_assembler_->Parameter(Linkage::kInterpreterAccumulatorParameter)),
|
||||||
code_generated_(false) {}
|
code_generated_(false) {}
|
||||||
|
|
||||||
|
|
||||||
@ -60,7 +62,22 @@ Handle<Code> InterpreterAssembler::GenerateCode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Node* InterpreterAssembler::BytecodeArrayPointer() {
|
Node* InterpreterAssembler::GetAccumulator() {
|
||||||
|
return accumulator_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InterpreterAssembler::SetAccumulator(Node* value) {
|
||||||
|
accumulator_ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Node* InterpreterAssembler::RegisterFileRawPointer() {
|
||||||
|
return raw_assembler_->Parameter(Linkage::kInterpreterRegisterFileParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Node* InterpreterAssembler::BytecodeArrayTaggedPointer() {
|
||||||
return raw_assembler_->Parameter(Linkage::kInterpreterBytecodeArrayParameter);
|
return raw_assembler_->Parameter(Linkage::kInterpreterBytecodeArrayParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,59 +88,46 @@ Node* InterpreterAssembler::BytecodeOffset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Node* InterpreterAssembler::DispatchTablePointer() {
|
Node* InterpreterAssembler::DispatchTableRawPointer() {
|
||||||
return raw_assembler_->Parameter(Linkage::kInterpreterDispatchTableParameter);
|
return raw_assembler_->Parameter(Linkage::kInterpreterDispatchTableParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Node* InterpreterAssembler::FramePointer() {
|
|
||||||
return raw_assembler_->LoadFramePointer();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Node* InterpreterAssembler::RegisterFrameOffset(int index) {
|
|
||||||
DCHECK_LE(index, kMaxRegisterIndex);
|
|
||||||
return Int32Constant(kFirstRegisterOffsetFromFp -
|
|
||||||
(index << kPointerSizeLog2));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Node* InterpreterAssembler::RegisterFrameOffset(Node* index) {
|
Node* InterpreterAssembler::RegisterFrameOffset(Node* index) {
|
||||||
return raw_assembler_->IntPtrSub(
|
return raw_assembler_->WordShl(index, Int32Constant(kPointerSizeLog2));
|
||||||
Int32Constant(kFirstRegisterOffsetFromFp),
|
}
|
||||||
raw_assembler_->WordShl(index, Int32Constant(kPointerSizeLog2)));
|
|
||||||
|
|
||||||
|
Node* InterpreterAssembler::LoadRegister(Node* reg_index) {
|
||||||
|
return raw_assembler_->Load(kMachPtr, RegisterFileRawPointer(),
|
||||||
|
RegisterFrameOffset(reg_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) {
|
||||||
|
return raw_assembler_->Store(kMachPtr, RegisterFileRawPointer(),
|
||||||
|
RegisterFrameOffset(reg_index), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Node* InterpreterAssembler::BytecodeOperand(int delta) {
|
Node* InterpreterAssembler::BytecodeOperand(int delta) {
|
||||||
DCHECK_LT(delta, interpreter::Bytecodes::NumberOfOperands(bytecode_));
|
DCHECK_LT(delta, interpreter::Bytecodes::NumberOfOperands(bytecode_));
|
||||||
return raw_assembler_->Load(
|
return raw_assembler_->Load(
|
||||||
kMachUint8, BytecodeArrayPointer(),
|
kMachUint8, BytecodeArrayTaggedPointer(),
|
||||||
raw_assembler_->IntPtrAdd(BytecodeOffset(), Int32Constant(1 + delta)));
|
raw_assembler_->IntPtrAdd(BytecodeOffset(), Int32Constant(1 + delta)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Node* InterpreterAssembler::LoadRegister(int index) {
|
Node* InterpreterAssembler::BytecodeOperandSignExtended(int delta) {
|
||||||
return raw_assembler_->Load(kMachPtr, FramePointer(),
|
DCHECK_LT(delta, interpreter::Bytecodes::NumberOfOperands(bytecode_));
|
||||||
RegisterFrameOffset(index));
|
Node* load = raw_assembler_->Load(
|
||||||
}
|
kMachInt8, BytecodeArrayTaggedPointer(),
|
||||||
|
raw_assembler_->IntPtrAdd(BytecodeOffset(), Int32Constant(1 + delta)));
|
||||||
|
// Ensure that we sign extend to full pointer size
|
||||||
Node* InterpreterAssembler::LoadRegister(Node* index) {
|
if (kPointerSize == 8) {
|
||||||
return raw_assembler_->Load(kMachPtr, FramePointer(),
|
load = raw_assembler_->ChangeInt32ToInt64(load);
|
||||||
RegisterFrameOffset(index));
|
}
|
||||||
}
|
return load;
|
||||||
|
|
||||||
|
|
||||||
Node* InterpreterAssembler::StoreRegister(Node* value, int index) {
|
|
||||||
return raw_assembler_->Store(kMachPtr, FramePointer(),
|
|
||||||
RegisterFrameOffset(index), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Node* InterpreterAssembler::StoreRegister(Node* value, Node* index) {
|
|
||||||
return raw_assembler_->Store(kMachPtr, FramePointer(),
|
|
||||||
RegisterFrameOffset(index), value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -132,14 +136,15 @@ void InterpreterAssembler::Return() {
|
|||||||
HeapConstant(Unique<HeapObject>::CreateImmovable(
|
HeapConstant(Unique<HeapObject>::CreateImmovable(
|
||||||
isolate()->builtins()->InterpreterExitTrampoline()));
|
isolate()->builtins()->InterpreterExitTrampoline()));
|
||||||
// If the order of the parameters you need to change the call signature below.
|
// If the order of the parameters you need to change the call signature below.
|
||||||
STATIC_ASSERT(0 == Linkage::kInterpreterBytecodeOffsetParameter);
|
STATIC_ASSERT(0 == Linkage::kInterpreterAccumulatorParameter);
|
||||||
STATIC_ASSERT(1 == Linkage::kInterpreterBytecodeArrayParameter);
|
STATIC_ASSERT(1 == Linkage::kInterpreterRegisterFileParameter);
|
||||||
STATIC_ASSERT(2 == Linkage::kInterpreterDispatchTableParameter);
|
STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
|
||||||
Node* tail_call = graph()->NewNode(
|
STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
|
||||||
common()->TailCall(call_descriptor()), exit_trampoline_code_object,
|
STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
|
||||||
BytecodeOffset(), BytecodeArrayPointer(), DispatchTablePointer(),
|
Node* tail_call = raw_assembler_->TailCallInterpreterDispatch(
|
||||||
graph()->start(), graph()->start());
|
call_descriptor(), exit_trampoline_code_object, GetAccumulator(),
|
||||||
schedule()->AddTailCall(raw_assembler_->CurrentBlock(), tail_call);
|
RegisterFileRawPointer(), BytecodeOffset(), BytecodeArrayTaggedPointer(),
|
||||||
|
DispatchTableRawPointer());
|
||||||
// This should always be the end node.
|
// This should always be the end node.
|
||||||
SetEndInput(tail_call);
|
SetEndInput(tail_call);
|
||||||
}
|
}
|
||||||
@ -153,24 +158,25 @@ Node* InterpreterAssembler::Advance(int delta) {
|
|||||||
void InterpreterAssembler::Dispatch() {
|
void InterpreterAssembler::Dispatch() {
|
||||||
Node* new_bytecode_offset = Advance(interpreter::Bytecodes::Size(bytecode_));
|
Node* new_bytecode_offset = Advance(interpreter::Bytecodes::Size(bytecode_));
|
||||||
Node* target_bytecode = raw_assembler_->Load(
|
Node* target_bytecode = raw_assembler_->Load(
|
||||||
kMachUint8, BytecodeArrayPointer(), new_bytecode_offset);
|
kMachUint8, BytecodeArrayTaggedPointer(), new_bytecode_offset);
|
||||||
|
|
||||||
// TODO(rmcilroy): Create a code target dispatch table to avoid conversion
|
// TODO(rmcilroy): Create a code target dispatch table to avoid conversion
|
||||||
// from code object on every dispatch.
|
// from code object on every dispatch.
|
||||||
Node* target_code_object = raw_assembler_->Load(
|
Node* target_code_object = raw_assembler_->Load(
|
||||||
kMachPtr, DispatchTablePointer(),
|
kMachPtr, DispatchTableRawPointer(),
|
||||||
raw_assembler_->Word32Shl(target_bytecode,
|
raw_assembler_->Word32Shl(target_bytecode,
|
||||||
Int32Constant(kPointerSizeLog2)));
|
Int32Constant(kPointerSizeLog2)));
|
||||||
|
|
||||||
// If the order of the parameters you need to change the call signature below.
|
// If the order of the parameters you need to change the call signature below.
|
||||||
STATIC_ASSERT(0 == Linkage::kInterpreterBytecodeOffsetParameter);
|
STATIC_ASSERT(0 == Linkage::kInterpreterAccumulatorParameter);
|
||||||
STATIC_ASSERT(1 == Linkage::kInterpreterBytecodeArrayParameter);
|
STATIC_ASSERT(1 == Linkage::kInterpreterRegisterFileParameter);
|
||||||
STATIC_ASSERT(2 == Linkage::kInterpreterDispatchTableParameter);
|
STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
|
||||||
Node* tail_call = graph()->NewNode(
|
STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
|
||||||
common()->TailCall(call_descriptor()), target_code_object,
|
STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
|
||||||
new_bytecode_offset, BytecodeArrayPointer(), DispatchTablePointer(),
|
Node* tail_call = raw_assembler_->TailCallInterpreterDispatch(
|
||||||
graph()->start(), graph()->start());
|
call_descriptor(), target_code_object, GetAccumulator(),
|
||||||
schedule()->AddTailCall(raw_assembler_->CurrentBlock(), tail_call);
|
RegisterFileRawPointer(), new_bytecode_offset,
|
||||||
|
BytecodeArrayTaggedPointer(), DispatchTableRawPointer());
|
||||||
// This should always be the end node.
|
// This should always be the end node.
|
||||||
SetEndInput(tail_call);
|
SetEndInput(tail_call);
|
||||||
}
|
}
|
||||||
@ -185,7 +191,7 @@ void InterpreterAssembler::SetEndInput(Node* input) {
|
|||||||
void InterpreterAssembler::End() {
|
void InterpreterAssembler::End() {
|
||||||
DCHECK(end_node_);
|
DCHECK(end_node_);
|
||||||
// TODO(rmcilroy): Support more than 1 end input.
|
// TODO(rmcilroy): Support more than 1 end input.
|
||||||
Node* end = graph()->NewNode(common()->End(1), end_node_);
|
Node* end = graph()->NewNode(raw_assembler_->common()->End(1), end_node_);
|
||||||
graph()->SetEnd(end);
|
graph()->SetEnd(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,16 +213,6 @@ Schedule* InterpreterAssembler::schedule() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MachineOperatorBuilder* InterpreterAssembler::machine() {
|
|
||||||
return raw_assembler_->machine();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CommonOperatorBuilder* InterpreterAssembler::common() {
|
|
||||||
return raw_assembler_->common();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Node* InterpreterAssembler::Int32Constant(int value) {
|
Node* InterpreterAssembler::Int32Constant(int value) {
|
||||||
return raw_assembler_->Int32Constant(value);
|
return raw_assembler_->Int32Constant(value);
|
||||||
}
|
}
|
||||||
@ -231,7 +227,6 @@ Node* InterpreterAssembler::HeapConstant(Unique<HeapObject> object) {
|
|||||||
return raw_assembler_->HeapConstant(object);
|
return raw_assembler_->HeapConstant(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace interpreter
|
} // namespace interpreter
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -22,9 +22,7 @@ class Zone;
|
|||||||
namespace compiler {
|
namespace compiler {
|
||||||
|
|
||||||
class CallDescriptor;
|
class CallDescriptor;
|
||||||
class CommonOperatorBuilder;
|
|
||||||
class Graph;
|
class Graph;
|
||||||
class MachineOperatorBuilder;
|
|
||||||
class Node;
|
class Node;
|
||||||
class Operator;
|
class Operator;
|
||||||
class RawMachineAssembler;
|
class RawMachineAssembler;
|
||||||
@ -38,33 +36,29 @@ class InterpreterAssembler {
|
|||||||
|
|
||||||
Handle<Code> GenerateCode();
|
Handle<Code> GenerateCode();
|
||||||
|
|
||||||
|
// Accumulator.
|
||||||
|
Node* GetAccumulator();
|
||||||
|
void SetAccumulator(Node* value);
|
||||||
|
|
||||||
|
// Loads from and stores to the interpreter register file.
|
||||||
|
Node* LoadRegister(Node* reg_index);
|
||||||
|
Node* StoreRegister(Node* value, Node* reg_index);
|
||||||
|
|
||||||
// Constants.
|
// Constants.
|
||||||
Node* Int32Constant(int value);
|
Node* Int32Constant(int value);
|
||||||
Node* NumberConstant(double value);
|
Node* NumberConstant(double value);
|
||||||
Node* HeapConstant(Unique<HeapObject> object);
|
Node* HeapConstant(Unique<HeapObject> object);
|
||||||
|
|
||||||
// Returns the bytecode operand |index| for the current bytecode.
|
|
||||||
Node* BytecodeOperand(int index);
|
|
||||||
|
|
||||||
// Loads from and stores to the interpreter register file.
|
|
||||||
Node* LoadRegister(int index);
|
|
||||||
Node* LoadRegister(Node* index);
|
|
||||||
Node* StoreRegister(Node* value, int index);
|
|
||||||
Node* StoreRegister(Node* value, Node* index);
|
|
||||||
|
|
||||||
// Returns from the function.
|
// Returns from the function.
|
||||||
void Return();
|
void Return();
|
||||||
|
|
||||||
// Dispatch to the bytecode.
|
// Dispatch to the bytecode.
|
||||||
void Dispatch();
|
void Dispatch();
|
||||||
|
|
||||||
|
Node* BytecodeOperand(int index);
|
||||||
|
Node* BytecodeOperandSignExtended(int index);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const int kFirstRegisterOffsetFromFp =
|
|
||||||
-kPointerSize - StandardFrameConstants::kFixedFrameSizeFromFp;
|
|
||||||
|
|
||||||
// TODO(rmcilroy): Increase this when required.
|
|
||||||
static const int kMaxRegisterIndex = 255;
|
|
||||||
|
|
||||||
// Close the graph.
|
// Close the graph.
|
||||||
void End();
|
void End();
|
||||||
|
|
||||||
@ -73,17 +67,16 @@ class InterpreterAssembler {
|
|||||||
Graph* graph();
|
Graph* graph();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Returns a raw pointer to start of the register file on the stack.
|
||||||
|
Node* RegisterFileRawPointer();
|
||||||
// Returns a tagged pointer to the current function's BytecodeArray object.
|
// Returns a tagged pointer to the current function's BytecodeArray object.
|
||||||
Node* BytecodeArrayPointer();
|
Node* BytecodeArrayTaggedPointer();
|
||||||
// Returns the offset from the BytecodeArrayPointer of the current bytecode.
|
// Returns the offset from the BytecodeArrayPointer of the current bytecode.
|
||||||
Node* BytecodeOffset();
|
Node* BytecodeOffset();
|
||||||
// Returns a pointer to first entry in the interpreter dispatch table.
|
// Returns a pointer to first entry in the interpreter dispatch table.
|
||||||
Node* DispatchTablePointer();
|
Node* DispatchTableRawPointer();
|
||||||
// Returns the frame pointer for the current function.
|
|
||||||
Node* FramePointer();
|
|
||||||
|
|
||||||
// Returns the offset of register |index|.
|
// Returns the offset of register |index| relative to RegisterFilePointer().
|
||||||
Node* RegisterFrameOffset(int index);
|
|
||||||
Node* RegisterFrameOffset(Node* index);
|
Node* RegisterFrameOffset(Node* index);
|
||||||
|
|
||||||
// Returns BytecodeOffset() advanced by delta bytecodes. Note: this does not
|
// Returns BytecodeOffset() advanced by delta bytecodes. Note: this does not
|
||||||
@ -96,12 +89,11 @@ class InterpreterAssembler {
|
|||||||
// Private helpers which delegate to RawMachineAssembler.
|
// Private helpers which delegate to RawMachineAssembler.
|
||||||
Isolate* isolate();
|
Isolate* isolate();
|
||||||
Schedule* schedule();
|
Schedule* schedule();
|
||||||
MachineOperatorBuilder* machine();
|
|
||||||
CommonOperatorBuilder* common();
|
|
||||||
|
|
||||||
interpreter::Bytecode bytecode_;
|
interpreter::Bytecode bytecode_;
|
||||||
base::SmartPointer<RawMachineAssembler> raw_assembler_;
|
base::SmartPointer<RawMachineAssembler> raw_assembler_;
|
||||||
Node* end_node_;
|
Node* end_node_;
|
||||||
|
Node* accumulator_;
|
||||||
bool code_generated_;
|
bool code_generated_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(InterpreterAssembler);
|
DISALLOW_COPY_AND_ASSIGN(InterpreterAssembler);
|
||||||
|
@ -392,19 +392,27 @@ CallDescriptor* Linkage::GetJSCallDescriptor(Zone* zone, bool is_osr,
|
|||||||
|
|
||||||
|
|
||||||
CallDescriptor* Linkage::GetInterpreterDispatchDescriptor(Zone* zone) {
|
CallDescriptor* Linkage::GetInterpreterDispatchDescriptor(Zone* zone) {
|
||||||
MachineSignature::Builder types(zone, 0, 3);
|
MachineSignature::Builder types(zone, 0, 5);
|
||||||
LocationSignature::Builder locations(zone, 0, 3);
|
LocationSignature::Builder locations(zone, 0, 5);
|
||||||
|
|
||||||
// Add registers for fixed parameters passed via interpreter dispatch.
|
// Add registers for fixed parameters passed via interpreter dispatch.
|
||||||
STATIC_ASSERT(0 == Linkage::kInterpreterBytecodeOffsetParameter);
|
STATIC_ASSERT(0 == Linkage::kInterpreterAccumulatorParameter);
|
||||||
|
types.AddParam(kMachAnyTagged);
|
||||||
|
locations.AddParam(regloc(kInterpreterAccumulatorRegister));
|
||||||
|
|
||||||
|
STATIC_ASSERT(1 == Linkage::kInterpreterRegisterFileParameter);
|
||||||
|
types.AddParam(kMachPtr);
|
||||||
|
locations.AddParam(regloc(kInterpreterRegisterFileRegister));
|
||||||
|
|
||||||
|
STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
|
||||||
types.AddParam(kMachIntPtr);
|
types.AddParam(kMachIntPtr);
|
||||||
locations.AddParam(regloc(kInterpreterBytecodeOffsetRegister));
|
locations.AddParam(regloc(kInterpreterBytecodeOffsetRegister));
|
||||||
|
|
||||||
STATIC_ASSERT(1 == Linkage::kInterpreterBytecodeArrayParameter);
|
STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
|
||||||
types.AddParam(kMachAnyTagged);
|
types.AddParam(kMachAnyTagged);
|
||||||
locations.AddParam(regloc(kInterpreterBytecodeArrayRegister));
|
locations.AddParam(regloc(kInterpreterBytecodeArrayRegister));
|
||||||
|
|
||||||
STATIC_ASSERT(2 == Linkage::kInterpreterDispatchTableParameter);
|
STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
|
||||||
types.AddParam(kMachPtr);
|
types.AddParam(kMachPtr);
|
||||||
locations.AddParam(regloc(kInterpreterDispatchTableRegister));
|
locations.AddParam(regloc(kInterpreterDispatchTableRegister));
|
||||||
|
|
||||||
|
@ -330,9 +330,11 @@ class Linkage : public ZoneObject {
|
|||||||
|
|
||||||
// Special parameter indices used to pass fixed register data through
|
// Special parameter indices used to pass fixed register data through
|
||||||
// interpreter dispatches.
|
// interpreter dispatches.
|
||||||
static const int kInterpreterBytecodeOffsetParameter = 0;
|
static const int kInterpreterAccumulatorParameter = 0;
|
||||||
static const int kInterpreterBytecodeArrayParameter = 1;
|
static const int kInterpreterRegisterFileParameter = 1;
|
||||||
static const int kInterpreterDispatchTableParameter = 2;
|
static const int kInterpreterBytecodeOffsetParameter = 2;
|
||||||
|
static const int kInterpreterBytecodeArrayParameter = 3;
|
||||||
|
static const int kInterpreterDispatchTableParameter = 4;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CallDescriptor* const incoming_;
|
CallDescriptor* const incoming_;
|
||||||
|
@ -232,6 +232,17 @@ Node* RawMachineAssembler::CallCFunction8(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Node* RawMachineAssembler::TailCallInterpreterDispatch(
|
||||||
|
const CallDescriptor* call_descriptor, Node* target, Node* arg1, Node* arg2,
|
||||||
|
Node* arg3, Node* arg4, Node* arg5) {
|
||||||
|
Node* tail_call =
|
||||||
|
graph()->NewNode(common()->TailCall(call_descriptor), target, arg1, arg2,
|
||||||
|
arg3, arg4, arg5, graph()->start(), graph()->start());
|
||||||
|
schedule()->AddTailCall(CurrentBlock(), tail_call);
|
||||||
|
return tail_call;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void RawMachineAssembler::Bind(Label* label) {
|
void RawMachineAssembler::Bind(Label* label) {
|
||||||
DCHECK(current_block_ == nullptr);
|
DCHECK(current_block_ == nullptr);
|
||||||
DCHECK(!label->bound_);
|
DCHECK(!label->bound_);
|
||||||
|
@ -508,6 +508,9 @@ class RawMachineAssembler {
|
|||||||
MachineType arg7_type, Node* function, Node* arg0,
|
MachineType arg7_type, Node* function, Node* arg0,
|
||||||
Node* arg1, Node* arg2, Node* arg3, Node* arg4,
|
Node* arg1, Node* arg2, Node* arg3, Node* arg4,
|
||||||
Node* arg5, Node* arg6, Node* arg7);
|
Node* arg5, Node* arg6, Node* arg7);
|
||||||
|
Node* TailCallInterpreterDispatch(const CallDescriptor* call_descriptor,
|
||||||
|
Node* target, Node* arg1, Node* arg2,
|
||||||
|
Node* arg3, Node* arg4, Node* arg5);
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
// The following utility methods deal with control flow, hence might switch
|
// The following utility methods deal with control flow, hence might switch
|
||||||
|
@ -634,20 +634,23 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
|
|
||||||
// Get the bytecode array from the function object and load the pointer to the
|
// Get the bytecode array from the function object and load the pointer to the
|
||||||
// first entry into edi (InterpreterBytecodeRegister).
|
// first entry into edi (InterpreterBytecodeRegister).
|
||||||
__ mov(edi, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
|
__ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
|
||||||
__ mov(edi, FieldOperand(edi, SharedFunctionInfo::kFunctionDataOffset));
|
__ mov(kInterpreterBytecodeArrayRegister,
|
||||||
|
FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset));
|
||||||
|
|
||||||
if (FLAG_debug_code) {
|
if (FLAG_debug_code) {
|
||||||
// Check function data field is actually a BytecodeArray object.
|
// Check function data field is actually a BytecodeArray object.
|
||||||
__ AssertNotSmi(edi);
|
__ AssertNotSmi(kInterpreterBytecodeArrayRegister);
|
||||||
__ CmpObjectType(edi, BYTECODE_ARRAY_TYPE, eax);
|
__ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
|
||||||
|
eax);
|
||||||
__ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
|
__ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the local and temporary register file on the stack.
|
// Allocate the local and temporary register file on the stack.
|
||||||
{
|
{
|
||||||
// Load frame size from the BytecodeArray object.
|
// Load frame size from the BytecodeArray object.
|
||||||
__ mov(ebx, FieldOperand(edi, BytecodeArray::kFrameSizeOffset));
|
__ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
|
||||||
|
BytecodeArray::kFrameSizeOffset));
|
||||||
|
|
||||||
// Do a stack check to ensure we don't go over the limit.
|
// Do a stack check to ensure we don't go over the limit.
|
||||||
Label ok;
|
Label ok;
|
||||||
@ -656,21 +659,22 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
ExternalReference stack_limit =
|
ExternalReference stack_limit =
|
||||||
ExternalReference::address_of_real_stack_limit(masm->isolate());
|
ExternalReference::address_of_real_stack_limit(masm->isolate());
|
||||||
__ cmp(ecx, Operand::StaticVariable(stack_limit));
|
__ cmp(ecx, Operand::StaticVariable(stack_limit));
|
||||||
__ j(above_equal, &ok, Label::kNear);
|
__ j(above_equal, &ok);
|
||||||
__ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
|
__ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
|
||||||
__ bind(&ok);
|
__ bind(&ok);
|
||||||
|
|
||||||
// If ok, push undefined as the initial value for all register file entries.
|
// If ok, push undefined as the initial value for all register file entries.
|
||||||
// Note: there should always be at least one stack slot for the return
|
|
||||||
// register in the register file.
|
|
||||||
Label loop_header;
|
Label loop_header;
|
||||||
|
Label loop_check;
|
||||||
__ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
|
__ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
|
||||||
|
__ jmp(&loop_check);
|
||||||
__ bind(&loop_header);
|
__ bind(&loop_header);
|
||||||
// TODO(rmcilroy): Consider doing more than one push per loop iteration.
|
// TODO(rmcilroy): Consider doing more than one push per loop iteration.
|
||||||
__ push(eax);
|
__ push(eax);
|
||||||
// Continue loop if not done.
|
// Continue loop if not done.
|
||||||
|
__ bind(&loop_check);
|
||||||
__ sub(ebx, Immediate(kPointerSize));
|
__ sub(ebx, Immediate(kPointerSize));
|
||||||
__ j(not_equal, &loop_header, Label::kNear);
|
__ j(greater_equal, &loop_header);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(rmcilroy): List of things not currently dealt with here but done in
|
// TODO(rmcilroy): List of things not currently dealt with here but done in
|
||||||
@ -700,25 +704,39 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
ExternalReference stack_limit =
|
ExternalReference stack_limit =
|
||||||
ExternalReference::address_of_stack_limit(masm->isolate());
|
ExternalReference::address_of_stack_limit(masm->isolate());
|
||||||
__ cmp(esp, Operand::StaticVariable(stack_limit));
|
__ cmp(esp, Operand::StaticVariable(stack_limit));
|
||||||
__ j(above_equal, &ok, Label::kNear);
|
__ j(above_equal, &ok);
|
||||||
__ CallRuntime(Runtime::kStackGuard, 0);
|
__ CallRuntime(Runtime::kStackGuard, 0);
|
||||||
__ bind(&ok);
|
__ bind(&ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load bytecode offset and dispatch table into registers.
|
// Load accumulator, register file, bytecode offset, dispatch table into
|
||||||
__ mov(ecx, Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
// registers.
|
||||||
|
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
|
||||||
|
__ mov(kInterpreterRegisterFileRegister, ebp);
|
||||||
|
__ sub(
|
||||||
|
kInterpreterRegisterFileRegister,
|
||||||
|
Immediate(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
|
||||||
|
__ mov(kInterpreterBytecodeOffsetRegister,
|
||||||
|
Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
||||||
// Since the dispatch table root might be set after builtins are generated,
|
// Since the dispatch table root might be set after builtins are generated,
|
||||||
// load directly from the roots table.
|
// load directly from the roots table.
|
||||||
__ LoadRoot(ebx, Heap::kInterpreterTableRootIndex);
|
__ LoadRoot(kInterpreterDispatchTableRegister,
|
||||||
__ add(ebx, Immediate(FixedArray::kHeaderSize - kHeapObjectTag));
|
Heap::kInterpreterTableRootIndex);
|
||||||
|
__ add(kInterpreterDispatchTableRegister,
|
||||||
|
Immediate(FixedArray::kHeaderSize - kHeapObjectTag));
|
||||||
|
|
||||||
|
// TODO(rmcilroy) Push our context as a stack located parameter of the
|
||||||
|
// bytecode handler.
|
||||||
|
|
||||||
// Dispatch to the first bytecode handler for the function.
|
// Dispatch to the first bytecode handler for the function.
|
||||||
__ movzx_b(eax, Operand(edi, ecx, times_1, 0));
|
__ movzx_b(esi, Operand(kInterpreterBytecodeArrayRegister,
|
||||||
__ mov(eax, Operand(ebx, eax, times_pointer_size, 0));
|
kInterpreterBytecodeOffsetRegister, times_1, 0));
|
||||||
|
__ mov(esi, Operand(kInterpreterDispatchTableRegister, esi,
|
||||||
|
times_pointer_size, 0));
|
||||||
// TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
|
// TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
|
||||||
// and header removal.
|
// and header removal.
|
||||||
__ add(eax, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
__ add(esi, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
||||||
__ jmp(eax);
|
__ call(esi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -729,9 +747,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
|
|||||||
// - Support profiler (specifically decrementing profiling_counter
|
// - Support profiler (specifically decrementing profiling_counter
|
||||||
// appropriately and calling out to HandleInterrupts if necessary).
|
// appropriately and calling out to HandleInterrupts if necessary).
|
||||||
|
|
||||||
// Load return value into r0.
|
// The return value is in accumulator, which is already in rax.
|
||||||
__ mov(eax, Operand(ebp, -kPointerSize -
|
|
||||||
StandardFrameConstants::kFixedFrameSizeFromFp));
|
|
||||||
// Leave the frame (also dropping the register file).
|
// Leave the frame (also dropping the register file).
|
||||||
__ leave();
|
__ leave();
|
||||||
// Return droping receiver + arguments.
|
// Return droping receiver + arguments.
|
||||||
|
@ -18,6 +18,8 @@ const Register kReturnRegister0 = {kRegister_eax_Code};
|
|||||||
const Register kReturnRegister1 = {kRegister_edx_Code};
|
const Register kReturnRegister1 = {kRegister_edx_Code};
|
||||||
const Register kJSFunctionRegister = {kRegister_edi_Code};
|
const Register kJSFunctionRegister = {kRegister_edi_Code};
|
||||||
const Register kContextRegister = {kRegister_esi_Code};
|
const Register kContextRegister = {kRegister_esi_Code};
|
||||||
|
const Register kInterpreterAccumulatorRegister = {kRegister_eax_Code};
|
||||||
|
const Register kInterpreterRegisterFileRegister = {kRegister_edx_Code};
|
||||||
const Register kInterpreterBytecodeOffsetRegister = {kRegister_ecx_Code};
|
const Register kInterpreterBytecodeOffsetRegister = {kRegister_ecx_Code};
|
||||||
const Register kInterpreterBytecodeArrayRegister = {kRegister_edi_Code};
|
const Register kInterpreterBytecodeArrayRegister = {kRegister_edi_Code};
|
||||||
const Register kInterpreterDispatchTableRegister = {kRegister_ebx_Code};
|
const Register kInterpreterDispatchTableRegister = {kRegister_ebx_Code};
|
||||||
|
@ -916,14 +916,15 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
__ bind(&ok);
|
__ bind(&ok);
|
||||||
|
|
||||||
// If ok, push undefined as the initial value for all register file entries.
|
// If ok, push undefined as the initial value for all register file entries.
|
||||||
// Note: there should always be at least one stack slot for the return
|
|
||||||
// register in the register file.
|
|
||||||
Label loop_header;
|
Label loop_header;
|
||||||
|
Label loop_check;
|
||||||
__ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
|
__ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
|
||||||
|
__ Branch(&loop_check);
|
||||||
__ bind(&loop_header);
|
__ bind(&loop_header);
|
||||||
// TODO(rmcilroy): Consider doing more than one push per loop iteration.
|
// TODO(rmcilroy): Consider doing more than one push per loop iteration.
|
||||||
__ push(t1);
|
__ push(t1);
|
||||||
// Continue loop if not done.
|
// Continue loop if not done.
|
||||||
|
__ bind(&loop_check);
|
||||||
__ Subu(t0, t0, Operand(kPointerSize));
|
__ Subu(t0, t0, Operand(kPointerSize));
|
||||||
__ Branch(&loop_header, ge, t0, Operand(zero_reg));
|
__ Branch(&loop_header, ge, t0, Operand(zero_reg));
|
||||||
}
|
}
|
||||||
@ -959,6 +960,10 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load bytecode offset and dispatch table into registers.
|
// Load bytecode offset and dispatch table into registers.
|
||||||
|
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
|
||||||
|
__ Subu(
|
||||||
|
kInterpreterRegisterFileRegister, fp,
|
||||||
|
Operand(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
|
||||||
__ li(kInterpreterBytecodeOffsetRegister,
|
__ li(kInterpreterBytecodeOffsetRegister,
|
||||||
Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
||||||
__ LoadRoot(kInterpreterDispatchTableRegister,
|
__ LoadRoot(kInterpreterDispatchTableRegister,
|
||||||
@ -976,7 +981,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
// TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
|
// TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
|
||||||
// and header removal.
|
// and header removal.
|
||||||
__ Addu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
|
__ Addu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||||
__ Jump(at);
|
__ Call(at);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -987,9 +992,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
|
|||||||
// - Support profiler (specifically decrementing profiling_counter
|
// - Support profiler (specifically decrementing profiling_counter
|
||||||
// appropriately and calling out to HandleInterrupts if necessary).
|
// appropriately and calling out to HandleInterrupts if necessary).
|
||||||
|
|
||||||
// Load return value into v0.
|
// The return value is in accumulator, which is already in v0.
|
||||||
__ lw(v0, MemOperand(fp, -kPointerSize -
|
|
||||||
StandardFrameConstants::kFixedFrameSizeFromFp));
|
|
||||||
// Leave the frame (also dropping the register file).
|
// Leave the frame (also dropping the register file).
|
||||||
__ LeaveFrame(StackFrame::JAVA_SCRIPT);
|
__ LeaveFrame(StackFrame::JAVA_SCRIPT);
|
||||||
// Drop receiver + arguments.
|
// Drop receiver + arguments.
|
||||||
|
@ -17,6 +17,8 @@ const Register kReturnRegister0 = {kRegister_v0_Code};
|
|||||||
const Register kReturnRegister1 = {kRegister_v1_Code};
|
const Register kReturnRegister1 = {kRegister_v1_Code};
|
||||||
const Register kJSFunctionRegister = {kRegister_a1_Code};
|
const Register kJSFunctionRegister = {kRegister_a1_Code};
|
||||||
const Register kContextRegister = {Register::kCpRegister};
|
const Register kContextRegister = {Register::kCpRegister};
|
||||||
|
const Register kInterpreterAccumulatorRegister = {kRegister_v0_Code};
|
||||||
|
const Register kInterpreterRegisterFileRegister = {kRegister_t3_Code};
|
||||||
const Register kInterpreterBytecodeOffsetRegister = {kRegister_t4_Code};
|
const Register kInterpreterBytecodeOffsetRegister = {kRegister_t4_Code};
|
||||||
const Register kInterpreterBytecodeArrayRegister = {kRegister_t5_Code};
|
const Register kInterpreterBytecodeArrayRegister = {kRegister_t5_Code};
|
||||||
const Register kInterpreterDispatchTableRegister = {kRegister_t6_Code};
|
const Register kInterpreterDispatchTableRegister = {kRegister_t6_Code};
|
||||||
|
@ -75,7 +75,7 @@ namespace internal {
|
|||||||
// Core register.
|
// Core register.
|
||||||
struct Register {
|
struct Register {
|
||||||
static const int kNumRegisters = v8::internal::kNumRegisters;
|
static const int kNumRegisters = v8::internal::kNumRegisters;
|
||||||
static const int kMaxNumAllocatableRegisters = 14; // v0 through t6 and cp.
|
static const int kMaxNumAllocatableRegisters = 14; // v0 through t2 and cp.
|
||||||
static const int kSizeInBytes = 8;
|
static const int kSizeInBytes = 8;
|
||||||
static const int kCpRegister = 23; // cp (s7) is the 23rd register.
|
static const int kCpRegister = 23; // cp (s7) is the 23rd register.
|
||||||
|
|
||||||
|
@ -913,14 +913,15 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
__ bind(&ok);
|
__ bind(&ok);
|
||||||
|
|
||||||
// If ok, push undefined as the initial value for all register file entries.
|
// If ok, push undefined as the initial value for all register file entries.
|
||||||
// Note: there should always be at least one stack slot for the return
|
|
||||||
// register in the register file.
|
|
||||||
Label loop_header;
|
Label loop_header;
|
||||||
|
Label loop_check;
|
||||||
__ LoadRoot(a5, Heap::kUndefinedValueRootIndex);
|
__ LoadRoot(a5, Heap::kUndefinedValueRootIndex);
|
||||||
|
__ Branch(&loop_check);
|
||||||
__ bind(&loop_header);
|
__ bind(&loop_header);
|
||||||
// TODO(rmcilroy): Consider doing more than one push per loop iteration.
|
// TODO(rmcilroy): Consider doing more than one push per loop iteration.
|
||||||
__ push(a5);
|
__ push(a5);
|
||||||
// Continue loop if not done.
|
// Continue loop if not done.
|
||||||
|
__ bind(&loop_check);
|
||||||
__ Dsubu(a4, a4, Operand(kPointerSize));
|
__ Dsubu(a4, a4, Operand(kPointerSize));
|
||||||
__ Branch(&loop_header, ge, a4, Operand(zero_reg));
|
__ Branch(&loop_header, ge, a4, Operand(zero_reg));
|
||||||
}
|
}
|
||||||
@ -956,6 +957,10 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load bytecode offset and dispatch table into registers.
|
// Load bytecode offset and dispatch table into registers.
|
||||||
|
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
|
||||||
|
__ Dsubu(
|
||||||
|
kInterpreterRegisterFileRegister, fp,
|
||||||
|
Operand(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
|
||||||
__ li(kInterpreterBytecodeOffsetRegister,
|
__ li(kInterpreterBytecodeOffsetRegister,
|
||||||
Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
||||||
__ LoadRoot(kInterpreterDispatchTableRegister,
|
__ LoadRoot(kInterpreterDispatchTableRegister,
|
||||||
@ -973,7 +978,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
// TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
|
// TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
|
||||||
// and header removal.
|
// and header removal.
|
||||||
__ Daddu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
|
__ Daddu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||||
__ Jump(at);
|
__ Call(at);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -984,9 +989,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
|
|||||||
// - Support profiler (specifically decrementing profiling_counter
|
// - Support profiler (specifically decrementing profiling_counter
|
||||||
// appropriately and calling out to HandleInterrupts if necessary).
|
// appropriately and calling out to HandleInterrupts if necessary).
|
||||||
|
|
||||||
// Load return value into v0.
|
// The return value is in accumulator, which is already in v0.
|
||||||
__ ld(v0, MemOperand(fp, -kPointerSize -
|
|
||||||
StandardFrameConstants::kFixedFrameSizeFromFp));
|
|
||||||
// Leave the frame (also dropping the register file).
|
// Leave the frame (also dropping the register file).
|
||||||
__ LeaveFrame(StackFrame::JAVA_SCRIPT);
|
__ LeaveFrame(StackFrame::JAVA_SCRIPT);
|
||||||
// Drop receiver + arguments.
|
// Drop receiver + arguments.
|
||||||
|
@ -17,6 +17,8 @@ const Register kReturnRegister0 = {kRegister_v0_Code};
|
|||||||
const Register kReturnRegister1 = {kRegister_v1_Code};
|
const Register kReturnRegister1 = {kRegister_v1_Code};
|
||||||
const Register kJSFunctionRegister = {kRegister_a1_Code};
|
const Register kJSFunctionRegister = {kRegister_a1_Code};
|
||||||
const Register kContextRegister = {kRegister_s7_Code};
|
const Register kContextRegister = {kRegister_s7_Code};
|
||||||
|
const Register kInterpreterAccumulatorRegister = {kRegister_v0_Code};
|
||||||
|
const Register kInterpreterRegisterFileRegister = {kRegister_a7_Code};
|
||||||
const Register kInterpreterBytecodeOffsetRegister = {kRegister_t0_Code};
|
const Register kInterpreterBytecodeOffsetRegister = {kRegister_t0_Code};
|
||||||
const Register kInterpreterBytecodeArrayRegister = {kRegister_t1_Code};
|
const Register kInterpreterBytecodeArrayRegister = {kRegister_t1_Code};
|
||||||
const Register kInterpreterDispatchTableRegister = {kRegister_t2_Code};
|
const Register kInterpreterDispatchTableRegister = {kRegister_t2_Code};
|
||||||
|
@ -694,20 +694,23 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
|
|
||||||
// Get the bytecode array from the function object and load the pointer to the
|
// Get the bytecode array from the function object and load the pointer to the
|
||||||
// first entry into edi (InterpreterBytecodeRegister).
|
// first entry into edi (InterpreterBytecodeRegister).
|
||||||
__ movp(r14, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
|
__ movp(rax, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
|
||||||
__ movp(r14, FieldOperand(r14, SharedFunctionInfo::kFunctionDataOffset));
|
__ movp(kInterpreterBytecodeArrayRegister,
|
||||||
|
FieldOperand(rax, SharedFunctionInfo::kFunctionDataOffset));
|
||||||
|
|
||||||
if (FLAG_debug_code) {
|
if (FLAG_debug_code) {
|
||||||
// Check function data field is actually a BytecodeArray object.
|
// Check function data field is actually a BytecodeArray object.
|
||||||
__ AssertNotSmi(r14);
|
__ AssertNotSmi(kInterpreterBytecodeArrayRegister);
|
||||||
__ CmpObjectType(r14, BYTECODE_ARRAY_TYPE, rax);
|
__ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
|
||||||
|
rax);
|
||||||
__ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
|
__ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the local and temporary register file on the stack.
|
// Allocate the local and temporary register file on the stack.
|
||||||
{
|
{
|
||||||
// Load frame size from the BytecodeArray object.
|
// Load frame size from the BytecodeArray object.
|
||||||
__ movl(rcx, FieldOperand(r14, BytecodeArray::kFrameSizeOffset));
|
__ movl(rcx, FieldOperand(kInterpreterBytecodeArrayRegister,
|
||||||
|
BytecodeArray::kFrameSizeOffset));
|
||||||
|
|
||||||
// Do a stack check to ensure we don't go over the limit.
|
// Do a stack check to ensure we don't go over the limit.
|
||||||
Label ok;
|
Label ok;
|
||||||
@ -719,16 +722,17 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
__ bind(&ok);
|
__ bind(&ok);
|
||||||
|
|
||||||
// If ok, push undefined as the initial value for all register file entries.
|
// If ok, push undefined as the initial value for all register file entries.
|
||||||
// Note: there should always be at least one stack slot for the return
|
|
||||||
// register in the register file.
|
|
||||||
Label loop_header;
|
Label loop_header;
|
||||||
|
Label loop_check;
|
||||||
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
|
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
|
||||||
|
__ j(always, &loop_check);
|
||||||
__ bind(&loop_header);
|
__ bind(&loop_header);
|
||||||
// TODO(rmcilroy): Consider doing more than one push per loop iteration.
|
// TODO(rmcilroy): Consider doing more than one push per loop iteration.
|
||||||
__ Push(rdx);
|
__ Push(rdx);
|
||||||
// Continue loop if not done.
|
// Continue loop if not done.
|
||||||
|
__ bind(&loop_check);
|
||||||
__ subp(rcx, Immediate(kPointerSize));
|
__ subp(rcx, Immediate(kPointerSize));
|
||||||
__ j(not_equal, &loop_header, Label::kNear);
|
__ j(greater_equal, &loop_header, Label::kNear);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(rmcilroy): List of things not currently dealt with here but done in
|
// TODO(rmcilroy): List of things not currently dealt with here but done in
|
||||||
@ -761,18 +765,29 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
|
|||||||
__ bind(&ok);
|
__ bind(&ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load bytecode offset and dispatch table into registers.
|
// Load accumulator, register file, bytecode offset, dispatch table into
|
||||||
__ movp(r12, Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
// registers.
|
||||||
__ LoadRoot(r15, Heap::kInterpreterTableRootIndex);
|
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
|
||||||
__ addp(r15, Immediate(FixedArray::kHeaderSize - kHeapObjectTag));
|
__ movp(kInterpreterRegisterFileRegister, rbp);
|
||||||
|
__ subp(
|
||||||
|
kInterpreterRegisterFileRegister,
|
||||||
|
Immediate(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
|
||||||
|
__ movp(kInterpreterBytecodeOffsetRegister,
|
||||||
|
Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
|
||||||
|
__ LoadRoot(kInterpreterDispatchTableRegister,
|
||||||
|
Heap::kInterpreterTableRootIndex);
|
||||||
|
__ addp(kInterpreterDispatchTableRegister,
|
||||||
|
Immediate(FixedArray::kHeaderSize - kHeapObjectTag));
|
||||||
|
|
||||||
// Dispatch to the first bytecode handler for the function.
|
// Dispatch to the first bytecode handler for the function.
|
||||||
__ movzxbp(rax, Operand(r14, r12, times_1, 0));
|
__ movzxbp(rbx, Operand(kInterpreterBytecodeArrayRegister,
|
||||||
__ movp(rax, Operand(r15, rax, times_pointer_size, 0));
|
kInterpreterBytecodeOffsetRegister, times_1, 0));
|
||||||
|
__ movp(rbx, Operand(kInterpreterDispatchTableRegister, rbx,
|
||||||
|
times_pointer_size, 0));
|
||||||
// TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
|
// TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
|
||||||
// and header removal.
|
// and header removal.
|
||||||
__ addp(rax, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
__ addp(rbx, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
||||||
__ jmp(rax);
|
__ call(rbx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -783,9 +798,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
|
|||||||
// - Support profiler (specifically decrementing profiling_counter
|
// - Support profiler (specifically decrementing profiling_counter
|
||||||
// appropriately and calling out to HandleInterrupts if necessary).
|
// appropriately and calling out to HandleInterrupts if necessary).
|
||||||
|
|
||||||
// Load return value into r0.
|
// The return value is in accumulator, which is already in rax.
|
||||||
__ movp(rax, Operand(rbp, -kPointerSize -
|
|
||||||
StandardFrameConstants::kFixedFrameSizeFromFp));
|
|
||||||
// Leave the frame (also dropping the register file).
|
// Leave the frame (also dropping the register file).
|
||||||
__ leave();
|
__ leave();
|
||||||
// Return droping receiver + arguments.
|
// Return droping receiver + arguments.
|
||||||
|
@ -20,6 +20,8 @@ const Register kReturnRegister0 = {kRegister_rax_Code};
|
|||||||
const Register kReturnRegister1 = {kRegister_rdx_Code};
|
const Register kReturnRegister1 = {kRegister_rdx_Code};
|
||||||
const Register kJSFunctionRegister = {kRegister_rdi_Code};
|
const Register kJSFunctionRegister = {kRegister_rdi_Code};
|
||||||
const Register kContextRegister = {kRegister_rsi_Code};
|
const Register kContextRegister = {kRegister_rsi_Code};
|
||||||
|
const Register kInterpreterAccumulatorRegister = {kRegister_rax_Code};
|
||||||
|
const Register kInterpreterRegisterFileRegister = {kRegister_r11_Code};
|
||||||
const Register kInterpreterBytecodeOffsetRegister = {kRegister_r12_Code};
|
const Register kInterpreterBytecodeOffsetRegister = {kRegister_r12_Code};
|
||||||
const Register kInterpreterBytecodeArrayRegister = {kRegister_r14_Code};
|
const Register kInterpreterBytecodeArrayRegister = {kRegister_r14_Code};
|
||||||
const Register kInterpreterDispatchTableRegister = {kRegister_r15_Code};
|
const Register kInterpreterDispatchTableRegister = {kRegister_r15_Code};
|
||||||
|
@ -72,9 +72,7 @@ TEST(TestInterpreterReturn) {
|
|||||||
handles.main_isolate()->factory()->undefined_value();
|
handles.main_isolate()->factory()->undefined_value();
|
||||||
|
|
||||||
BytecodeArrayBuilder builder(handles.main_isolate());
|
BytecodeArrayBuilder builder(handles.main_isolate());
|
||||||
// TODO(rmcilroy) set to 0 once BytecodeArray update to allow zero size
|
builder.set_locals_count(0);
|
||||||
// register file.
|
|
||||||
builder.set_locals_count(1);
|
|
||||||
builder.Return();
|
builder.Return();
|
||||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#include "test/unittests/compiler/compiler-test-utils.h"
|
#include "test/unittests/compiler/compiler-test-utils.h"
|
||||||
#include "test/unittests/compiler/node-test-utils.h"
|
#include "test/unittests/compiler/node-test-utils.h"
|
||||||
|
|
||||||
|
using ::testing::_;
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
namespace compiler {
|
namespace compiler {
|
||||||
@ -93,6 +95,8 @@ TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) {
|
|||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
tail_call_node,
|
tail_call_node,
|
||||||
IsTailCall(m.call_descriptor(), code_target_matcher,
|
IsTailCall(m.call_descriptor(), code_target_matcher,
|
||||||
|
IsParameter(Linkage::kInterpreterAccumulatorParameter),
|
||||||
|
IsParameter(Linkage::kInterpreterRegisterFileParameter),
|
||||||
next_bytecode_offset_matcher,
|
next_bytecode_offset_matcher,
|
||||||
IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
|
IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
|
||||||
IsParameter(Linkage::kInterpreterDispatchTableParameter),
|
IsParameter(Linkage::kInterpreterDispatchTableParameter),
|
||||||
@ -119,6 +123,8 @@ TARGET_TEST_F(InterpreterAssemblerTest, Return) {
|
|||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
tail_call_node,
|
tail_call_node,
|
||||||
IsTailCall(m.call_descriptor(), IsHeapConstant(exit_trampoline),
|
IsTailCall(m.call_descriptor(), IsHeapConstant(exit_trampoline),
|
||||||
|
IsParameter(Linkage::kInterpreterAccumulatorParameter),
|
||||||
|
IsParameter(Linkage::kInterpreterRegisterFileParameter),
|
||||||
IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
|
IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
|
||||||
IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
|
IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
|
||||||
IsParameter(Linkage::kInterpreterDispatchTableParameter),
|
IsParameter(Linkage::kInterpreterDispatchTableParameter),
|
||||||
@ -146,20 +152,55 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TARGET_TEST_F(InterpreterAssemblerTest, LoadRegisterFixed) {
|
TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperandSignExtended) {
|
||||||
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
|
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
|
||||||
InterpreterAssemblerForTest m(this, bytecode);
|
InterpreterAssemblerForTest m(this, bytecode);
|
||||||
for (int i = 0; i < m.kMaxRegisterIndex; i++) {
|
int number_of_operands = interpreter::Bytecodes::NumberOfOperands(bytecode);
|
||||||
Node* load_reg_node = m.LoadRegister(i);
|
for (int i = 0; i < number_of_operands; i++) {
|
||||||
EXPECT_THAT(load_reg_node,
|
Node* load_arg_node = m.BytecodeOperandSignExtended(i);
|
||||||
m.IsLoad(kMachPtr, IsLoadFramePointer(),
|
Matcher<Node*> load_matcher = m.IsLoad(
|
||||||
IsInt32Constant(m.kFirstRegisterOffsetFromFp -
|
kMachInt8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
|
||||||
(i << kPointerSizeLog2))));
|
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
|
||||||
|
IsInt32Constant(1 + i)));
|
||||||
|
if (kPointerSize == 8) {
|
||||||
|
load_matcher = IsChangeInt32ToInt64(load_matcher);
|
||||||
|
}
|
||||||
|
EXPECT_THAT(load_arg_node, load_matcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) {
|
||||||
|
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
|
||||||
|
InterpreterAssemblerForTest m(this, bytecode);
|
||||||
|
// Should be incoming accumulator if not set.
|
||||||
|
EXPECT_THAT(m.GetAccumulator(),
|
||||||
|
IsParameter(Linkage::kInterpreterAccumulatorParameter));
|
||||||
|
|
||||||
|
// Should be set by SedtAccumulator.
|
||||||
|
Node* accumulator_value_1 = m.Int32Constant(0xdeadbeef);
|
||||||
|
m.SetAccumulator(accumulator_value_1);
|
||||||
|
EXPECT_THAT(m.GetAccumulator(), accumulator_value_1);
|
||||||
|
Node* accumulator_value_2 = m.Int32Constant(42);
|
||||||
|
m.SetAccumulator(accumulator_value_2);
|
||||||
|
EXPECT_THAT(m.GetAccumulator(), accumulator_value_2);
|
||||||
|
|
||||||
|
// Should be passed to next bytecode handler on dispatch.
|
||||||
|
m.Dispatch();
|
||||||
|
Graph* graph = m.GetCompletedGraph();
|
||||||
|
|
||||||
|
Node* end = graph->end();
|
||||||
|
EXPECT_EQ(1, end->InputCount());
|
||||||
|
Node* tail_call_node = end->InputAt(0);
|
||||||
|
|
||||||
|
EXPECT_THAT(tail_call_node,
|
||||||
|
IsTailCall(m.call_descriptor(), _, accumulator_value_2, _, _, _,
|
||||||
|
_, graph->start(), graph->start()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) {
|
TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) {
|
||||||
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
|
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
|
||||||
InterpreterAssemblerForTest m(this, bytecode);
|
InterpreterAssemblerForTest m(this, bytecode);
|
||||||
@ -167,27 +208,9 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) {
|
|||||||
Node* load_reg_node = m.LoadRegister(reg_index_node);
|
Node* load_reg_node = m.LoadRegister(reg_index_node);
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
load_reg_node,
|
load_reg_node,
|
||||||
m.IsLoad(kMachPtr, IsLoadFramePointer(),
|
m.IsLoad(kMachPtr,
|
||||||
IsIntPtrSub(IsInt32Constant(m.kFirstRegisterOffsetFromFp),
|
IsParameter(Linkage::kInterpreterRegisterFileParameter),
|
||||||
IsWordShl(reg_index_node,
|
IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2))));
|
||||||
IsInt32Constant(kPointerSizeLog2)))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TARGET_TEST_F(InterpreterAssemblerTest, StoreRegisterFixed) {
|
|
||||||
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
|
|
||||||
InterpreterAssemblerForTest m(this, bytecode);
|
|
||||||
Node* store_value = m.Int32Constant(0xdeadbeef);
|
|
||||||
for (int i = 0; i < m.kMaxRegisterIndex; i++) {
|
|
||||||
Node* store_reg_node = m.StoreRegister(store_value, i);
|
|
||||||
EXPECT_THAT(store_reg_node,
|
|
||||||
m.IsStore(StoreRepresentation(kMachPtr, kNoWriteBarrier),
|
|
||||||
IsLoadFramePointer(),
|
|
||||||
IsInt32Constant(m.kFirstRegisterOffsetFromFp -
|
|
||||||
(i << kPointerSizeLog2)),
|
|
||||||
store_value));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,10 +224,8 @@ TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) {
|
|||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
store_reg_node,
|
store_reg_node,
|
||||||
m.IsStore(StoreRepresentation(kMachPtr, kNoWriteBarrier),
|
m.IsStore(StoreRepresentation(kMachPtr, kNoWriteBarrier),
|
||||||
IsLoadFramePointer(),
|
IsParameter(Linkage::kInterpreterRegisterFileParameter),
|
||||||
IsIntPtrSub(IsInt32Constant(m.kFirstRegisterOffsetFromFp),
|
IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)),
|
||||||
IsWordShl(reg_index_node,
|
|
||||||
IsInt32Constant(kPointerSizeLog2))),
|
|
||||||
store_value));
|
store_value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,6 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone {
|
|||||||
|
|
||||||
using InterpreterAssembler::call_descriptor;
|
using InterpreterAssembler::call_descriptor;
|
||||||
using InterpreterAssembler::graph;
|
using InterpreterAssembler::graph;
|
||||||
using InterpreterAssembler::kMaxRegisterIndex;
|
|
||||||
using InterpreterAssembler::kFirstRegisterOffsetFromFp;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_COPY_AND_ASSIGN(InterpreterAssemblerForTest);
|
DISALLOW_COPY_AND_ASSIGN(InterpreterAssemblerForTest);
|
||||||
|
@ -1730,6 +1730,42 @@ Matcher<Node*> IsTailCall(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Matcher<Node*> IsTailCall(
|
||||||
|
const Matcher<CallDescriptor const*>& descriptor_matcher,
|
||||||
|
const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
|
||||||
|
const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
|
||||||
|
const Matcher<Node*>& value4_matcher, const Matcher<Node*>& effect_matcher,
|
||||||
|
const Matcher<Node*>& control_matcher) {
|
||||||
|
std::vector<Matcher<Node*>> value_matchers;
|
||||||
|
value_matchers.push_back(value0_matcher);
|
||||||
|
value_matchers.push_back(value1_matcher);
|
||||||
|
value_matchers.push_back(value2_matcher);
|
||||||
|
value_matchers.push_back(value3_matcher);
|
||||||
|
value_matchers.push_back(value4_matcher);
|
||||||
|
return MakeMatcher(new IsTailCallMatcher(descriptor_matcher, value_matchers,
|
||||||
|
effect_matcher, control_matcher));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Matcher<Node*> IsTailCall(
|
||||||
|
const Matcher<CallDescriptor const*>& descriptor_matcher,
|
||||||
|
const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
|
||||||
|
const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
|
||||||
|
const Matcher<Node*>& value4_matcher, const Matcher<Node*>& value5_matcher,
|
||||||
|
const Matcher<Node*>& effect_matcher,
|
||||||
|
const Matcher<Node*>& control_matcher) {
|
||||||
|
std::vector<Matcher<Node*>> value_matchers;
|
||||||
|
value_matchers.push_back(value0_matcher);
|
||||||
|
value_matchers.push_back(value1_matcher);
|
||||||
|
value_matchers.push_back(value2_matcher);
|
||||||
|
value_matchers.push_back(value3_matcher);
|
||||||
|
value_matchers.push_back(value4_matcher);
|
||||||
|
value_matchers.push_back(value5_matcher);
|
||||||
|
return MakeMatcher(new IsTailCallMatcher(descriptor_matcher, value_matchers,
|
||||||
|
effect_matcher, control_matcher));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
|
Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
|
||||||
const Matcher<Node*>& lhs_matcher,
|
const Matcher<Node*>& lhs_matcher,
|
||||||
const Matcher<Node*>& rhs_matcher) {
|
const Matcher<Node*>& rhs_matcher) {
|
||||||
|
@ -145,6 +145,20 @@ Matcher<Node*> IsTailCall(
|
|||||||
const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
|
const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
|
||||||
const Matcher<Node*>& effect_matcher,
|
const Matcher<Node*>& effect_matcher,
|
||||||
const Matcher<Node*>& control_matcher);
|
const Matcher<Node*>& control_matcher);
|
||||||
|
Matcher<Node*> IsTailCall(
|
||||||
|
const Matcher<CallDescriptor const*>& descriptor_matcher,
|
||||||
|
const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
|
||||||
|
const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
|
||||||
|
const Matcher<Node*>& value4_matcher, const Matcher<Node*>& effect_matcher,
|
||||||
|
const Matcher<Node*>& control_matcher);
|
||||||
|
Matcher<Node*> IsTailCall(
|
||||||
|
const Matcher<CallDescriptor const*>& descriptor_matcher,
|
||||||
|
const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
|
||||||
|
const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
|
||||||
|
const Matcher<Node*>& value4_matcher, const Matcher<Node*>& value5_matcher,
|
||||||
|
const Matcher<Node*>& effect_matcher,
|
||||||
|
const Matcher<Node*>& control_matcher);
|
||||||
|
|
||||||
|
|
||||||
Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher);
|
Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher);
|
||||||
Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
|
Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
|
||||||
|
Loading…
Reference in New Issue
Block a user