Commit 1314406c authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[interpreter] Implement OSR graph construction from bytecode.

This implements graph construction for entry via on-stack replacement
within the {BytecodeGraphBuilder}. Entry points are at loop headers
similar to previous OSR implementations. All interpreter registers are
addressable via {OsrValue} nodes in the graph. Currently we rely on
{OsrPoll} bytecodes to be placed right after loop headers (i.e. at the
targets of back edges).

R=jarin@chromium.org
BUG=v8:4764

Review-Url: https://codereview.chromium.org/2171083004
Cr-Commit-Position: refs/heads/master@{#38083}
parent 0bb05780
...@@ -587,6 +587,10 @@ void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) { ...@@ -587,6 +587,10 @@ void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) {
// Frame specialization implies function context specialization. // Frame specialization implies function context specialization.
DCHECK(!info->is_frame_specializing()); DCHECK(!info->is_frame_specializing());
// TODO(4764): When compiling for OSR from bytecode, BailoutId might derive
// from bytecode offset and overlap with actual BailoutId. No caching!
if (info->is_osr() && info->is_optimizing_from_bytecode()) return;
// Cache optimized context-specific code. // Cache optimized context-specific code.
Handle<JSFunction> function = info->closure(); Handle<JSFunction> function = info->closure();
Handle<SharedFunctionInfo> shared(function->shared()); Handle<SharedFunctionInfo> shared(function->shared());
...@@ -747,13 +751,18 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, ...@@ -747,13 +751,18 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
Isolate* isolate = function->GetIsolate(); Isolate* isolate = function->GetIsolate();
Handle<SharedFunctionInfo> shared(function->shared(), isolate); Handle<SharedFunctionInfo> shared(function->shared(), isolate);
// TODO(4764): Remove this guard once OSR graph construction works. bool ignition_osr = osr_frame && osr_frame->is_interpreted();
if (!osr_ast_id.IsNone() && osr_frame->is_interpreted()) { DCHECK_IMPLIES(ignition_osr, !osr_ast_id.IsNone());
return MaybeHandle<Code>(); DCHECK_IMPLIES(ignition_osr, FLAG_ignition_osr);
}
// Flag combination --ignition-osr --no-turbo-from-bytecode is unsupported.
if (ignition_osr && !FLAG_turbo_from_bytecode) return MaybeHandle<Code>();
Handle<Code> cached_code; Handle<Code> cached_code;
if (GetCodeFromOptimizedCodeMap(function, osr_ast_id) // TODO(4764): When compiling for OSR from bytecode, BailoutId might derive
// from bytecode offset and overlap with actual BailoutId. No lookup!
if (!ignition_osr &&
GetCodeFromOptimizedCodeMap(function, osr_ast_id)
.ToHandle(&cached_code)) { .ToHandle(&cached_code)) {
if (FLAG_trace_opt) { if (FLAG_trace_opt) {
PrintF("[found optimized code for "); PrintF("[found optimized code for ");
...@@ -774,7 +783,7 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, ...@@ -774,7 +783,7 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
VMState<COMPILER> state(isolate); VMState<COMPILER> state(isolate);
DCHECK(!isolate->has_pending_exception()); DCHECK(!isolate->has_pending_exception());
PostponeInterruptsScope postpone(isolate); PostponeInterruptsScope postpone(isolate);
bool use_turbofan = UseTurboFan(shared); bool use_turbofan = UseTurboFan(shared) || ignition_osr;
std::unique_ptr<CompilationJob> job( std::unique_ptr<CompilationJob> job(
use_turbofan ? compiler::Pipeline::NewCompilationJob(function) use_turbofan ? compiler::Pipeline::NewCompilationJob(function)
: new HCompilationJob(function)); : new HCompilationJob(function));
......
...@@ -60,6 +60,7 @@ class BytecodeGraphBuilder::Environment : public ZoneObject { ...@@ -60,6 +60,7 @@ class BytecodeGraphBuilder::Environment : public ZoneObject {
Environment* CopyForConditional() const; Environment* CopyForConditional() const;
Environment* CopyForLoop(); Environment* CopyForLoop();
void Merge(Environment* other); void Merge(Environment* other);
void PrepareForOsr();
private: private:
explicit Environment(const Environment* copy); explicit Environment(const Environment* copy);
...@@ -358,6 +359,36 @@ void BytecodeGraphBuilder::Environment::PrepareForLoop() { ...@@ -358,6 +359,36 @@ void BytecodeGraphBuilder::Environment::PrepareForLoop() {
builder()->exit_controls_.push_back(terminate); builder()->exit_controls_.push_back(terminate);
} }
void BytecodeGraphBuilder::Environment::PrepareForOsr() {
DCHECK_EQ(IrOpcode::kLoop, GetControlDependency()->opcode());
DCHECK_EQ(1, GetControlDependency()->InputCount());
Node* start = graph()->start();
// Create a control node for the OSR entry point and merge it into the loop
// header. Update the current environment's control dependency accordingly.
Node* entry = graph()->NewNode(common()->OsrLoopEntry(), start, start);
Node* control = builder()->MergeControl(GetControlDependency(), entry);
UpdateControlDependency(control);
// Create a merge of the effect from the OSR entry and the existing effect
// dependency. Update the current environment's effect dependency accordingly.
Node* effect = builder()->MergeEffect(GetEffectDependency(), entry, control);
UpdateEffectDependency(effect);
// Rename all values in the environment which will extend or introduce Phi
// nodes to contain the OSR values available at the entry point.
Node* osr_context = graph()->NewNode(
common()->OsrValue(Linkage::kOsrContextSpillSlotIndex), entry);
context_ = builder()->MergeValue(context_, osr_context, control);
int size = static_cast<int>(values()->size());
for (int i = 0; i < size; i++) {
int idx = i; // Indexing scheme follows {StandardFrame}, adapt accordingly.
if (i >= register_base()) idx += InterpreterFrameConstants::kExtraSlotCount;
if (i >= accumulator_base()) idx = Linkage::kOsrAccumulatorRegisterIndex;
Node* osr_value = graph()->NewNode(common()->OsrValue(idx), entry);
values_[i] = builder()->MergeValue(values_[i], osr_value, control);
}
}
bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate( bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate(
Node** state_values, int offset, int count) { Node** state_values, int offset, int count) {
...@@ -447,6 +478,7 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone, ...@@ -447,6 +478,7 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone,
FrameStateType::kInterpretedFunction, FrameStateType::kInterpretedFunction,
bytecode_array()->parameter_count(), bytecode_array()->parameter_count(),
bytecode_array()->register_count(), info->shared_info())), bytecode_array()->register_count(), info->shared_info())),
osr_ast_id_(info->osr_ast_id()),
merge_environments_(local_zone), merge_environments_(local_zone),
exception_handlers_(local_zone), exception_handlers_(local_zone),
current_exception_handler_(0), current_exception_handler_(0),
...@@ -521,6 +553,10 @@ bool BytecodeGraphBuilder::CreateGraph() { ...@@ -521,6 +553,10 @@ bool BytecodeGraphBuilder::CreateGraph() {
GetFunctionContext()); GetFunctionContext());
set_environment(&env); set_environment(&env);
// For OSR add an {OsrNormalEntry} as the start of the top-level environment.
// It will be replaced with {Dead} after typing and optimizations.
if (!osr_ast_id_.IsNone()) NewNode(common()->OsrNormalEntry());
VisitBytecodes(); VisitBytecodes();
// Finish the basic structure of the graph. // Finish the basic structure of the graph.
...@@ -1393,8 +1429,12 @@ void BytecodeGraphBuilder::VisitStackCheck() { ...@@ -1393,8 +1429,12 @@ void BytecodeGraphBuilder::VisitStackCheck() {
} }
void BytecodeGraphBuilder::VisitOsrPoll() { void BytecodeGraphBuilder::VisitOsrPoll() {
// TODO(4764): Implement OSR graph construction. Not marked UNIMPLEMENTED to // TODO(4764): This should be moved into the {VisitBytecodes} once we merge
// ensure the --ignition-osr flag can already be fuzzed without crashing. // the polling with existing bytecode. This will also guarantee that we are
// not missing the OSR entry point, which we wouldn't catch right now.
if (osr_ast_id_.ToInt() == bytecode_iterator().current_offset()) {
environment()->PrepareForOsr();
}
} }
void BytecodeGraphBuilder::VisitReturn() { void BytecodeGraphBuilder::VisitReturn() {
......
...@@ -219,6 +219,7 @@ class BytecodeGraphBuilder { ...@@ -219,6 +219,7 @@ class BytecodeGraphBuilder {
const interpreter::BytecodeArrayIterator* bytecode_iterator_; const interpreter::BytecodeArrayIterator* bytecode_iterator_;
const BytecodeBranchAnalysis* branch_analysis_; const BytecodeBranchAnalysis* branch_analysis_;
Environment* environment_; Environment* environment_;
BailoutId osr_ast_id_;
// Merge environments are snapshots of the environment at points where the // Merge environments are snapshots of the environment at points where the
// control flow merges. This models a forward data flow propagation of all // control flow merges. This models a forward data flow propagation of all
......
...@@ -422,6 +422,9 @@ class Linkage : public ZoneObject { ...@@ -422,6 +422,9 @@ class Linkage : public ZoneObject {
// A special {OsrValue} index to indicate the context spill slot. // A special {OsrValue} index to indicate the context spill slot.
static const int kOsrContextSpillSlotIndex = -1; static const int kOsrContextSpillSlotIndex = -1;
// A special {OsrValue} index to indicate the accumulator register.
static const int kOsrAccumulatorRegisterIndex = -1;
private: private:
CallDescriptor* const incoming_; CallDescriptor* const incoming_;
......
...@@ -24,11 +24,17 @@ namespace internal { ...@@ -24,11 +24,17 @@ namespace internal {
namespace compiler { namespace compiler {
OsrHelper::OsrHelper(CompilationInfo* info) OsrHelper::OsrHelper(CompilationInfo* info)
: parameter_count_(info->scope()->num_parameters()), : parameter_count_(
stack_slot_count_(info->scope()->num_stack_slots() + info->is_optimizing_from_bytecode()
? info->shared_info()->bytecode_array()->parameter_count()
: info->scope()->num_parameters()),
stack_slot_count_(
info->is_optimizing_from_bytecode()
? info->shared_info()->bytecode_array()->register_count() +
InterpreterFrameConstants::kExtraSlotCount
: info->scope()->num_stack_slots() +
info->osr_expr_stack_height()) {} info->osr_expr_stack_height()) {}
#ifdef DEBUG #ifdef DEBUG
#define TRACE_COND (FLAG_trace_turbo_graph && FLAG_trace_osr) #define TRACE_COND (FLAG_trace_turbo_graph && FLAG_trace_osr)
#else #else
......
...@@ -1820,6 +1820,7 @@ void PipelineImpl::AllocateRegisters(const RegisterConfiguration* config, ...@@ -1820,6 +1820,7 @@ void PipelineImpl::AllocateRegisters(const RegisterConfiguration* config,
data->InitializeRegisterAllocationData(config, descriptor); data->InitializeRegisterAllocationData(config, descriptor);
if (info()->is_osr()) { if (info()->is_osr()) {
AllowHandleDereference allow_deref;
OsrHelper osr_helper(info()); OsrHelper osr_helper(info());
osr_helper.SetupFrame(data->frame()); osr_helper.SetupFrame(data->frame());
} }
......
...@@ -334,7 +334,7 @@ class BuiltinExitFrameConstants : public CommonFrameConstants { ...@@ -334,7 +334,7 @@ class BuiltinExitFrameConstants : public CommonFrameConstants {
class InterpreterFrameConstants : public AllStatic { class InterpreterFrameConstants : public AllStatic {
public: public:
// Fixed frame includes new.target and bytecode offset. // Fixed frame includes new.target, bytecode array, and bytecode offset.
static const int kFixedFrameSize = static const int kFixedFrameSize =
StandardFrameConstants::kFixedFrameSize + 3 * kPointerSize; StandardFrameConstants::kFixedFrameSize + 3 * kPointerSize;
static const int kFixedFrameSizeFromFp = static const int kFixedFrameSizeFromFp =
...@@ -355,6 +355,11 @@ class InterpreterFrameConstants : public AllStatic { ...@@ -355,6 +355,11 @@ class InterpreterFrameConstants : public AllStatic {
static const int kExpressionsOffset = kRegisterFileFromFp; static const int kExpressionsOffset = kRegisterFileFromFp;
// Number of fixed slots in addition to a {StandardFrame}.
static const int kExtraSlotCount =
InterpreterFrameConstants::kFixedFrameSize / kPointerSize -
StandardFrameConstants::kFixedFrameSize / kPointerSize;
// Expression index for {StandardFrame::GetExpressionAddress}. // Expression index for {StandardFrame::GetExpressionAddress}.
static const int kBytecodeArrayExpressionIndex = -2; static const int kBytecodeArrayExpressionIndex = -2;
static const int kBytecodeOffsetExpressionIndex = -1; static const int kBytecodeOffsetExpressionIndex = -1;
......
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