Permalink
Browse files

[interpreter] Add basic framework for bytecode handler code generation.

Adds basic support for generation of interpreter bytecode handler code
snippets. The InterpreterAssembler class exposes a set of low level,
interpreter specific operations which can be used to build a Turbofan
graph. The Interpreter class generates a bytecode handler snippet for
each bytecode by assembling operations using an InterpreterAssembler.

Currently only two simple bytecodes are supported: LoadLiteral0 and Return.

BUG=v8:4280
LOG=N

Review URL: https://codereview.chromium.org/1239793002

Cr-Commit-Position: refs/heads/master@{#29814}
  • Loading branch information...
rmcilroy authored and Commit bot committed Jul 23, 2015
1 parent 3334b83 commit 7877c4e0c77b5c2b97678406eab7e9ad6eba4a4d
View
@@ -712,6 +712,8 @@ source_set("v8_base") {
"src/compiler/instruction-selector.h",
"src/compiler/instruction.cc",
"src/compiler/instruction.h",
"src/compiler/interpreter-assembler.cc",
"src/compiler/interpreter-assembler.h",
"src/compiler/js-builtin-reducer.cc",
"src/compiler/js-builtin-reducer.h",
"src/compiler/js-context-relaxation.cc",
@@ -995,6 +997,10 @@ source_set("v8_base") {
"src/interface-descriptors.h",
"src/interpreter-irregexp.cc",
"src/interpreter-irregexp.h",
"src/interpreter/bytecodes.cc",
"src/interpreter/bytecodes.h",
"src/interpreter/interpreter.cc",
"src/interpreter/interpreter.h",
"src/isolate.cc",
"src/isolate.h",
"src/json-parser.h",
View
@@ -2,6 +2,9 @@ include_rules = [
"+src",
"-src/compiler",
"+src/compiler/pipeline.h",
"-src/interpreter",
"+src/interpreter/bytecodes.h",
"+src/interpreter/interpreter.h",
"-src/libplatform",
"-include/libplatform"
]
@@ -17,6 +17,8 @@ struct ArmLinkageHelperTraits {
static Register ReturnValue2Reg() { return r1; }
static Register JSCallFunctionReg() { return r1; }
static Register ContextReg() { return cp; }
static Register InterpreterBytecodePointerReg() { return r6; }
static Register InterpreterDispatchTableReg() { return r8; }
static Register RuntimeCallFunctionReg() { return r1; }
static Register RuntimeCallArgCountReg() { return r0; }
static RegList CCalleeSaveRegisters() {
@@ -70,9 +72,8 @@ CallDescriptor* Linkage::GetSimplifiedCDescriptor(Zone* zone,
}
CallDescriptor* Linkage::GetInterpreterDispatchDescriptor(
Zone* zone, const MachineSignature* sig) {
return LH::GetInterpreterDispatchDescriptor(zone, sig);
CallDescriptor* Linkage::GetInterpreterDispatchDescriptor(Zone* zone) {
return LH::GetInterpreterDispatchDescriptor(zone);
}
} // namespace compiler
@@ -17,6 +17,8 @@ struct Arm64LinkageHelperTraits {
static Register ReturnValue2Reg() { return x1; }
static Register JSCallFunctionReg() { return x1; }
static Register ContextReg() { return cp; }
static Register InterpreterBytecodePointerReg() { return x19; }
static Register InterpreterDispatchTableReg() { return x20; }
static Register RuntimeCallFunctionReg() { return x1; }
static Register RuntimeCallArgCountReg() { return x0; }
static RegList CCalleeSaveRegisters() {
@@ -72,9 +74,8 @@ CallDescriptor* Linkage::GetSimplifiedCDescriptor(Zone* zone,
}
CallDescriptor* Linkage::GetInterpreterDispatchDescriptor(
Zone* zone, const MachineSignature* sig) {
return LH::GetInterpreterDispatchDescriptor(zone, sig);
CallDescriptor* Linkage::GetInterpreterDispatchDescriptor(Zone* zone) {
return LH::GetInterpreterDispatchDescriptor(zone);
}
} // namespace compiler
@@ -17,6 +17,8 @@ struct IA32LinkageHelperTraits {
static Register ReturnValue2Reg() { return edx; }
static Register JSCallFunctionReg() { return edi; }
static Register ContextReg() { return esi; }
static Register InterpreterBytecodePointerReg() { return edi; }
static Register InterpreterDispatchTableReg() { return ebx; }
static Register RuntimeCallFunctionReg() { return ebx; }
static Register RuntimeCallArgCountReg() { return eax; }
static RegList CCalleeSaveRegisters() {
@@ -61,9 +63,8 @@ CallDescriptor* Linkage::GetSimplifiedCDescriptor(Zone* zone,
}
CallDescriptor* Linkage::GetInterpreterDispatchDescriptor(
Zone* zone, const MachineSignature* sig) {
return LH::GetInterpreterDispatchDescriptor(zone, sig);
CallDescriptor* Linkage::GetInterpreterDispatchDescriptor(Zone* zone) {
return LH::GetInterpreterDispatchDescriptor(zone);
}
} // namespace compiler
@@ -0,0 +1,207 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/interpreter-assembler.h"
#include <ostream>
#include "src/compiler/graph.h"
#include "src/compiler/instruction-selector.h"
#include "src/compiler/linkage.h"
#include "src/compiler/machine-type.h"
#include "src/compiler/pipeline.h"
#include "src/compiler/raw-machine-assembler.h"
#include "src/compiler/schedule.h"
#include "src/frames.h"
#include "src/interpreter/bytecodes.h"
#include "src/macro-assembler.h"
#include "src/zone.h"
namespace v8 {
namespace internal {
namespace compiler {
InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone,
interpreter::Bytecode bytecode)
: bytecode_(bytecode),
raw_assembler_(new RawMachineAssembler(
isolate, new (zone) Graph(zone),
Linkage::GetInterpreterDispatchDescriptor(zone), kMachPtr,
InstructionSelector::SupportedMachineOperatorFlags())),
end_node_(nullptr),
code_generated_(false) {}
InterpreterAssembler::~InterpreterAssembler() {}
Handle<Code> InterpreterAssembler::GenerateCode() {
DCHECK(!code_generated_);
End();
Schedule* schedule = raw_assembler_->Export();
// TODO(rmcilroy): use a non-testing code generator.
Handle<Code> code = Pipeline::GenerateCodeForTesting(
isolate(), raw_assembler_->call_descriptor(), graph(), schedule);
#ifdef ENABLE_DISASSEMBLER
if (FLAG_trace_ignition_codegen) {
OFStream os(stdout);
code->Disassemble(interpreter::Bytecodes::ToString(bytecode_), os);
os << std::flush;
}
#endif
code_generated_ = true;
return code;
}
Node* InterpreterAssembler::BytecodePointer() {
return raw_assembler_->Parameter(Linkage::kInterpreterBytecodeParameter);
}
Node* InterpreterAssembler::DispatchTablePointer() {
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) {
return raw_assembler_->Int32Sub(
Int32Constant(kFirstRegisterOffsetFromFp),
raw_assembler_->Word32Shl(index, Int32Constant(kPointerSizeLog2)));
}
Node* InterpreterAssembler::BytecodeArg(int delta) {
DCHECK_LT(delta, interpreter::Bytecodes::NumberOfArguments(bytecode_));
return raw_assembler_->Load(kMachUint8, BytecodePointer(),
Int32Constant(1 + delta));
}
Node* InterpreterAssembler::LoadRegister(int index) {
return raw_assembler_->Load(kMachPtr, FramePointer(),
RegisterFrameOffset(index));
}
Node* InterpreterAssembler::LoadRegister(Node* index) {
return raw_assembler_->Load(kMachPtr, FramePointer(),
RegisterFrameOffset(index));
}
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);
}
Node* InterpreterAssembler::Advance(int delta) {
return raw_assembler_->IntPtrAdd(BytecodePointer(), Int32Constant(delta));
}
void InterpreterAssembler::Dispatch() {
Node* new_bytecode_pointer = Advance(interpreter::Bytecodes::Size(bytecode_));
Node* target_bytecode =
raw_assembler_->Load(kMachUint8, new_bytecode_pointer);
// TODO(rmcilroy): Create a code target dispatch table to avoid conversion
// from code object on every dispatch.
Node* target_code_object = raw_assembler_->Load(
kMachPtr, DispatchTablePointer(),
raw_assembler_->Word32Shl(target_bytecode,
Int32Constant(kPointerSizeLog2)));
// If the order of the parameters you need to change the call signature below.
STATIC_ASSERT(0 == Linkage::kInterpreterBytecodeParameter);
STATIC_ASSERT(1 == Linkage::kInterpreterDispatchTableParameter);
Node* tail_call = graph()->NewNode(common()->TailCall(call_descriptor()),
target_code_object, new_bytecode_pointer,
DispatchTablePointer(), graph()->start(),
graph()->start());
schedule()->AddTailCall(raw_assembler_->CurrentBlock(), tail_call);
// This should always be the end node.
SetEndInput(tail_call);
}
void InterpreterAssembler::SetEndInput(Node* input) {
DCHECK(!end_node_);
end_node_ = input;
}
void InterpreterAssembler::End() {
DCHECK(end_node_);
// TODO(rmcilroy): Support more than 1 end input.
Node* end = graph()->NewNode(common()->End(1), end_node_);
graph()->SetEnd(end);
}
// RawMachineAssembler delegate helpers:
Isolate* InterpreterAssembler::isolate() { return raw_assembler_->isolate(); }
Graph* InterpreterAssembler::graph() { return raw_assembler_->graph(); }
CallDescriptor* InterpreterAssembler::call_descriptor() const {
return raw_assembler_->call_descriptor();
}
Schedule* InterpreterAssembler::schedule() {
return raw_assembler_->schedule();
}
MachineOperatorBuilder* InterpreterAssembler::machine() {
return raw_assembler_->machine();
}
CommonOperatorBuilder* InterpreterAssembler::common() {
return raw_assembler_->common();
}
Node* InterpreterAssembler::Int32Constant(int value) {
return raw_assembler_->Int32Constant(value);
}
Node* InterpreterAssembler::NumberConstant(double value) {
return raw_assembler_->NumberConstant(value);
}
} // namespace interpreter
} // namespace internal
} // namespace v8
Oops, something went wrong.

0 comments on commit 7877c4e

Please sign in to comment.