Commit b0a852e8 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Add new JSFrameSpecialization reducer.

The JSFrameSpecialization specializes an OSR graph to the current
unoptimized frame on which we will perform the on-stack replacement.
This is used for asm.js functions, where we cannot reuse the OSR code
object anyway because of context specialization, and so we could as well
specialize to the max instead.

It works by replacing all OsrValues in the graph with their values in
the JavaScriptFrame.

The idea is that using this trick we get better performance without
doing the unsound backpropagation of types to OsrValues later. This is
the first step towards fixing OSR for TurboFan.

R=jarin@chromium.org
BUG=v8:4273
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#29476}
parent 9bb82645
......@@ -672,6 +672,8 @@ source_set("v8_base") {
"src/compiler/js-builtin-reducer.h",
"src/compiler/js-context-specialization.cc",
"src/compiler/js-context-specialization.h",
"src/compiler/js-frame-specialization.cc",
"src/compiler/js-frame-specialization.h",
"src/compiler/js-generic-lowering.cc",
"src/compiler/js-generic-lowering.h",
"src/compiler/js-graph.cc",
......
......@@ -394,6 +394,7 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
}
if (info()->shared_info()->asm_function()) {
if (info()->osr_frame()) info()->MarkAsFrameSpecializing();
info()->MarkAsContextSpecializing();
} else if (FLAG_turbo_type_feedback) {
info()->MarkAsTypeFeedbackEnabled();
......@@ -712,7 +713,9 @@ static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) {
if (code->kind() != Code::OPTIMIZED_FUNCTION) return; // Nothing to do.
// Context specialization folds-in the context, so no sharing can occur.
if (code->is_turbofanned() && info->is_context_specializing()) return;
if (info->is_context_specializing()) return;
// Frame specialization implies context specialization.
DCHECK(!info->is_frame_specializing());
// Do not cache bound functions.
Handle<JSFunction> function = info->closure();
......@@ -1469,7 +1472,8 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
MaybeHandle<Code> Compiler::GetOptimizedCode(Handle<JSFunction> function,
Handle<Code> current_code,
ConcurrencyMode mode,
BailoutId osr_ast_id) {
BailoutId osr_ast_id,
JavaScriptFrame* osr_frame) {
Handle<Code> cached_code;
if (GetCodeFromOptimizedCodeMap(
function, osr_ast_id).ToHandle(&cached_code)) {
......@@ -1527,6 +1531,7 @@ MaybeHandle<Code> Compiler::GetOptimizedCode(Handle<JSFunction> function,
return isolate->builtins()->InOptimizationQueue();
}
} else {
info->set_osr_frame(osr_frame);
if (GetOptimizedCodeNow(info.get())) return info->code();
}
......
......@@ -17,6 +17,7 @@ namespace internal {
class AstValueFactory;
class HydrogenCodeStub;
class JavaScriptFrame;
class ParseInfo;
class ScriptData;
......@@ -122,14 +123,15 @@ class CompilationInfo {
kCompilingForDebugging = 1 << 7,
kSerializing = 1 << 8,
kContextSpecializing = 1 << 9,
kInliningEnabled = 1 << 10,
kTypingEnabled = 1 << 11,
kDisableFutureOptimization = 1 << 12,
kSplittingEnabled = 1 << 13,
kTypeFeedbackEnabled = 1 << 14,
kDeoptimizationEnabled = 1 << 15,
kSourcePositionsEnabled = 1 << 16,
kFirstCompile = 1 << 17,
kFrameSpecializing = 1 << 10,
kInliningEnabled = 1 << 11,
kTypingEnabled = 1 << 12,
kDisableFutureOptimization = 1 << 13,
kSplittingEnabled = 1 << 14,
kTypeFeedbackEnabled = 1 << 15,
kDeoptimizationEnabled = 1 << 16,
kSourcePositionsEnabled = 1 << 17,
kFirstCompile = 1 << 18,
};
explicit CompilationInfo(ParseInfo* parse_info);
......@@ -217,6 +219,10 @@ class CompilationInfo {
bool is_context_specializing() const { return GetFlag(kContextSpecializing); }
void MarkAsFrameSpecializing() { SetFlag(kFrameSpecializing); }
bool is_frame_specializing() const { return GetFlag(kFrameSpecializing); }
void MarkAsTypeFeedbackEnabled() { SetFlag(kTypeFeedbackEnabled); }
bool is_type_feedback_enabled() const {
......@@ -388,6 +394,8 @@ class CompilationInfo {
DCHECK(height >= 0);
osr_expr_stack_height_ = height;
}
JavaScriptFrame* osr_frame() const { return osr_frame_; }
void set_osr_frame(JavaScriptFrame* osr_frame) { osr_frame_ = osr_frame; }
#if DEBUG
void PrintAstForTesting();
......@@ -492,6 +500,9 @@ class CompilationInfo {
int osr_expr_stack_height_;
// The current OSR frame for specialization or {nullptr}.
JavaScriptFrame* osr_frame_ = nullptr;
Type::FunctionType* function_type_;
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
......@@ -662,10 +673,9 @@ class Compiler : public AllStatic {
// In the latter case, return the InOptimizationQueue builtin. On failure,
// return the empty handle.
MUST_USE_RESULT static MaybeHandle<Code> GetOptimizedCode(
Handle<JSFunction> function,
Handle<Code> current_code,
ConcurrencyMode mode,
BailoutId osr_ast_id = BailoutId::None());
Handle<JSFunction> function, Handle<Code> current_code,
ConcurrencyMode mode, BailoutId osr_ast_id = BailoutId::None(),
JavaScriptFrame* osr_frame = nullptr);
// Generate and return code from previously queued optimization job.
// On failure, return the empty handle.
......
// 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/js-frame-specialization.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/linkage.h"
#include "src/frames-inl.h"
namespace v8 {
namespace internal {
namespace compiler {
Reduction JSFrameSpecialization::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kOsrValue:
return ReduceOsrValue(node);
case IrOpcode::kParameter:
return ReduceParameter(node);
default:
break;
}
return NoChange();
}
Reduction JSFrameSpecialization::ReduceOsrValue(Node* node) {
DCHECK_EQ(IrOpcode::kOsrValue, node->opcode());
DisallowHeapAllocation no_gc;
Object* object;
int const index = OpParameter<int>(node);
int const parameters_count = frame()->ComputeParametersCount() + 1;
if (index == Linkage::kOsrContextSpillSlotIndex) {
object = frame()->context();
} else if (index >= parameters_count) {
object = frame()->GetExpression(index - parameters_count);
} else {
// The OsrValue index 0 is the receiver.
object = index ? frame()->GetParameter(index - 1) : frame()->receiver();
}
return Replace(jsgraph()->Constant(handle(object, isolate())));
}
Reduction JSFrameSpecialization::ReduceParameter(Node* node) {
DCHECK_EQ(IrOpcode::kParameter, node->opcode());
DisallowHeapAllocation no_gc;
Object* object;
int const index = ParameterIndexOf(node->op());
int const parameters_count = frame()->ComputeParametersCount() + 1;
if (index == Linkage::kJSFunctionCallClosureParamIndex) {
object = frame()->function();
} else if (index == parameters_count) {
// The Parameter index (arity + 1) is the context.
object = frame()->context();
} else {
// The Parameter index 0 is the receiver.
object = index ? frame()->GetParameter(index - 1) : frame()->receiver();
}
return Replace(jsgraph()->Constant(handle(object, isolate())));
}
Isolate* JSFrameSpecialization::isolate() const { return jsgraph()->isolate(); }
} // namespace compiler
} // namespace internal
} // namespace v8
// 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.
#ifndef V8_COMPILER_JS_FRAME_SPECIALIZATION_H_
#define V8_COMPILER_JS_FRAME_SPECIALIZATION_H_
#include "src/compiler/graph-reducer.h"
namespace v8 {
namespace internal {
namespace compiler {
// Forward declarations.
class JSGraph;
class JSFrameSpecialization final : public Reducer {
public:
JSFrameSpecialization(JavaScriptFrame const* frame, JSGraph* jsgraph)
: frame_(frame), jsgraph_(jsgraph) {}
~JSFrameSpecialization() final {}
Reduction Reduce(Node* node) final;
private:
Reduction ReduceOsrValue(Node* node);
Reduction ReduceParameter(Node* node);
Isolate* isolate() const;
JavaScriptFrame const* frame() const { return frame_; }
JSGraph* jsgraph() const { return jsgraph_; }
JavaScriptFrame const* const frame_;
JSGraph* const jsgraph_;
DISALLOW_COPY_AND_ASSIGN(JSFrameSpecialization);
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_JS_FRAME_SPECIALIZATION_H_
......@@ -26,6 +26,7 @@
#include "src/compiler/instruction-selector.h"
#include "src/compiler/js-builtin-reducer.h"
#include "src/compiler/js-context-specialization.h"
#include "src/compiler/js-frame-specialization.h"
#include "src/compiler/js-generic-lowering.h"
#include "src/compiler/js-inlining.h"
#include "src/compiler/js-intrinsic-lowering.h"
......@@ -496,12 +497,17 @@ struct InliningPhase {
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
data->common(), data->machine());
JSContextSpecializer context_specializer(&graph_reducer, data->jsgraph());
JSFrameSpecialization frame_specialization(data->info()->osr_frame(),
data->jsgraph());
JSInliner inliner(&graph_reducer, data->info()->is_inlining_enabled()
? JSInliner::kGeneralInlining
: JSInliner::kRestrictedInlining,
temp_zone, data->info(), data->jsgraph());
AddReducer(data, &graph_reducer, &dead_code_elimination);
AddReducer(data, &graph_reducer, &common_reducer);
if (data->info()->is_frame_specializing()) {
AddReducer(data, &graph_reducer, &frame_specialization);
}
if (data->info()->is_context_specializing()) {
AddReducer(data, &graph_reducer, &context_specializer);
}
......
......@@ -219,11 +219,12 @@ RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset);
DCHECK(!ast_id.IsNone());
Compiler::ConcurrencyMode mode =
isolate->concurrent_osr_enabled() &&
(function->shared()->ast_node_count() > 512)
? Compiler::CONCURRENT
: Compiler::NOT_CONCURRENT;
// Disable concurrent OSR for asm.js, to enable frame specialization.
Compiler::ConcurrencyMode mode = (isolate->concurrent_osr_enabled() &&
!function->shared()->asm_function() &&
function->shared()->ast_node_count() > 512)
? Compiler::CONCURRENT
: Compiler::NOT_CONCURRENT;
Handle<Code> result = Handle<Code>::null();
OptimizedCompileJob* job = NULL;
......@@ -258,8 +259,9 @@ RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
function->PrintName();
PrintF(" at AST id %d]\n", ast_id.ToInt());
}
MaybeHandle<Code> maybe_result =
Compiler::GetOptimizedCode(function, caller_code, mode, ast_id);
MaybeHandle<Code> maybe_result = Compiler::GetOptimizedCode(
function, caller_code, mode, ast_id,
(mode == Compiler::NOT_CONCURRENT) ? frame : nullptr);
if (maybe_result.ToHandle(&result) &&
result.is_identical_to(isolate->builtins()->InOptimizationQueue())) {
// Optimization is queued. Return to check later.
......
......@@ -505,6 +505,8 @@
'../../src/compiler/js-builtin-reducer.h',
'../../src/compiler/js-context-specialization.cc',
'../../src/compiler/js-context-specialization.h',
'../../src/compiler/js-frame-specialization.cc',
'../../src/compiler/js-frame-specialization.h',
'../../src/compiler/js-generic-lowering.cc',
'../../src/compiler/js-generic-lowering.h',
'../../src/compiler/js-graph.cc',
......
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