Commit 00df60d1 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[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}
parent 8aef4429
...@@ -8,7 +8,6 @@ ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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}; ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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 { ...@@ -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, ...@@ -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,70 +62,72 @@ Handle<Code> InterpreterAssembler::GenerateCode() { ...@@ -60,70 +62,72 @@ Handle<Code> InterpreterAssembler::GenerateCode() {
} }
Node* InterpreterAssembler::BytecodeArrayPointer() { Node* InterpreterAssembler::GetAccumulator() {
return raw_assembler_->Parameter(Linkage::kInterpreterBytecodeArrayParameter); return accumulator_;
} }
Node* InterpreterAssembler::BytecodeOffset() { void InterpreterAssembler::SetAccumulator(Node* value) {
return raw_assembler_->Parameter( accumulator_ = value;
Linkage::kInterpreterBytecodeOffsetParameter);
} }
Node* InterpreterAssembler::DispatchTablePointer() { Node* InterpreterAssembler::RegisterFileRawPointer() {
return raw_assembler_->Parameter(Linkage::kInterpreterDispatchTableParameter); return raw_assembler_->Parameter(Linkage::kInterpreterRegisterFileParameter);
} }
Node* InterpreterAssembler::FramePointer() { Node* InterpreterAssembler::BytecodeArrayTaggedPointer() {
return raw_assembler_->LoadFramePointer(); return raw_assembler_->Parameter(Linkage::kInterpreterBytecodeArrayParameter);
} }
Node* InterpreterAssembler::RegisterFrameOffset(int index) { Node* InterpreterAssembler::BytecodeOffset() {
DCHECK_LE(index, kMaxRegisterIndex); return raw_assembler_->Parameter(
return Int32Constant(kFirstRegisterOffsetFromFp - Linkage::kInterpreterBytecodeOffsetParameter);
(index << kPointerSizeLog2));
} }
Node* InterpreterAssembler::RegisterFrameOffset(Node* index) { Node* InterpreterAssembler::DispatchTableRawPointer() {
return raw_assembler_->IntPtrSub( return raw_assembler_->Parameter(Linkage::kInterpreterDispatchTableParameter);
Int32Constant(kFirstRegisterOffsetFromFp),
raw_assembler_->WordShl(index, Int32Constant(kPointerSizeLog2)));
} }
Node* InterpreterAssembler::BytecodeOperand(int delta) { Node* InterpreterAssembler::RegisterFrameOffset(Node* index) {
DCHECK_LT(delta, interpreter::Bytecodes::NumberOfOperands(bytecode_)); return raw_assembler_->WordShl(index, Int32Constant(kPointerSizeLog2));
return raw_assembler_->Load(
kMachUint8, BytecodeArrayPointer(),
raw_assembler_->IntPtrAdd(BytecodeOffset(), Int32Constant(1 + delta)));
} }
Node* InterpreterAssembler::LoadRegister(int index) { Node* InterpreterAssembler::LoadRegister(Node* reg_index) {
return raw_assembler_->Load(kMachPtr, FramePointer(), return raw_assembler_->Load(kMachPtr, RegisterFileRawPointer(),
RegisterFrameOffset(index)); RegisterFrameOffset(reg_index));
} }
Node* InterpreterAssembler::LoadRegister(Node* index) { Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) {
return raw_assembler_->Load(kMachPtr, FramePointer(), return raw_assembler_->Store(kMachPtr, RegisterFileRawPointer(),
RegisterFrameOffset(index)); RegisterFrameOffset(reg_index), value);
} }
Node* InterpreterAssembler::StoreRegister(Node* value, int index) { Node* InterpreterAssembler::BytecodeOperand(int delta) {
return raw_assembler_->Store(kMachPtr, FramePointer(), DCHECK_LT(delta, interpreter::Bytecodes::NumberOfOperands(bytecode_));
RegisterFrameOffset(index), value); return raw_assembler_->Load(
kMachUint8, BytecodeArrayTaggedPointer(),
raw_assembler_->IntPtrAdd(BytecodeOffset(), Int32Constant(1 + delta)));
} }
Node* InterpreterAssembler::StoreRegister(Node* value, Node* index) { Node* InterpreterAssembler::BytecodeOperandSignExtended(int delta) {
return raw_assembler_->Store(kMachPtr, FramePointer(), DCHECK_LT(delta, interpreter::Bytecodes::NumberOfOperands(bytecode_));
RegisterFrameOffset(index), value); Node* load = raw_assembler_->Load(
kMachInt8, BytecodeArrayTaggedPointer(),
raw_assembler_->IntPtrAdd(BytecodeOffset(), Int32Constant(1 + delta)));
// Ensure that we sign extend to full pointer size
if (kPointerSize == 8) {
load = raw_assembler_->ChangeInt32ToInt64(load);
}
return load;
} }
...@@ -132,14 +136,15 @@ void InterpreterAssembler::Return() { ...@@ -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) { ...@@ -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) { ...@@ -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() { ...@@ -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) { ...@@ -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; ...@@ -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 { ...@@ -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();
protected: Node* BytecodeOperand(int index);
static const int kFirstRegisterOffsetFromFp = Node* BytecodeOperandSignExtended(int index);
-kPointerSize - StandardFrameConstants::kFixedFrameSizeFromFp;
// TODO(rmcilroy): Increase this when required.
static const int kMaxRegisterIndex = 255;
protected:
// Close the graph. // Close the graph.
void End(); void End();
...@@ -73,17 +67,16 @@ class InterpreterAssembler { ...@@ -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 { ...@@ -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, ...@@ -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 { ...@@ -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( ...@@ -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 { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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}; ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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}; ...@@ -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 { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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}; ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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}; ...@@ -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) { ...@@ -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 @@ ...@@ -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) { ...@@ -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) { ...@@ -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,48 +152,65 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { ...@@ -146,48 +152,65 @@ 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, LoadRegister) { TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerForTest m(this, bytecode); InterpreterAssemblerForTest m(this, bytecode);
Node* reg_index_node = m.Int32Constant(44); // Should be incoming accumulator if not set.
Node* load_reg_node = m.LoadRegister(reg_index_node); EXPECT_THAT(m.GetAccumulator(),
EXPECT_THAT( IsParameter(Linkage::kInterpreterAccumulatorParameter));
load_reg_node,
m.IsLoad(kMachPtr, IsLoadFramePointer(), // Should be set by SedtAccumulator.
IsIntPtrSub(IsInt32Constant(m.kFirstRegisterOffsetFromFp), Node* accumulator_value_1 = m.Int32Constant(0xdeadbeef);
IsWordShl(reg_index_node, m.SetAccumulator(accumulator_value_1);
IsInt32Constant(kPointerSizeLog2))))); 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, StoreRegisterFixed) { 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);
Node* store_value = m.Int32Constant(0xdeadbeef); Node* reg_index_node = m.Int32Constant(44);
for (int i = 0; i < m.kMaxRegisterIndex; i++) { Node* load_reg_node = m.LoadRegister(reg_index_node);
Node* store_reg_node = m.StoreRegister(store_value, i); EXPECT_THAT(
EXPECT_THAT(store_reg_node, load_reg_node,
m.IsStore(StoreRepresentation(kMachPtr, kNoWriteBarrier), m.IsLoad(kMachPtr,
IsLoadFramePointer(), IsParameter(Linkage::kInterpreterRegisterFileParameter),
IsInt32Constant(m.kFirstRegisterOffsetFromFp - IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2))));
(i << kPointerSizeLog2)),
store_value));
}
} }
} }
...@@ -201,10 +224,8 @@ TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) { ...@@ -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 { ...@@ -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( ...@@ -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( ...@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment