Commit dea67cf0 authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[compiler] Make OptimizedCompileJob agnostic from backend.

This refactors the OptimizedCompileJob class to be agnostic from the
actual underlying compiler. Instead it represents a base class for all
compilation jobs. The implementation is provided by the backend by just
overriding the phase methods.

Also note that this contains the semantics change of not falling back to
Crankshaft when TurboFan optimization fails. This fallback is no longer
needed and will not be supported going forward.

R=bmeurer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#35377}
parent 8764f87a
...@@ -88,6 +88,7 @@ namespace internal { ...@@ -88,6 +88,7 @@ namespace internal {
V(kGenerator, "Generator") \ V(kGenerator, "Generator") \
V(kGlobalFunctionsMustHaveInitialMap, \ V(kGlobalFunctionsMustHaveInitialMap, \
"Global functions must have initial map") \ "Global functions must have initial map") \
V(kGraphBuildingFailed, "Optimized graph construction failed") \
V(kHeapNumberMapRegisterClobbered, "HeapNumberMap register clobbered") \ V(kHeapNumberMapRegisterClobbered, "HeapNumberMap register clobbered") \
V(kHydrogenFilter, "Optimization disabled by filter") \ V(kHydrogenFilter, "Optimization disabled by filter") \
V(kImportDeclaration, "Import declaration") \ V(kImportDeclaration, "Import declaration") \
......
...@@ -15,13 +15,10 @@ ...@@ -15,13 +15,10 @@
#include "src/compilation-cache.h" #include "src/compilation-cache.h"
#include "src/compiler/pipeline.h" #include "src/compiler/pipeline.h"
#include "src/crankshaft/hydrogen.h" #include "src/crankshaft/hydrogen.h"
#include "src/crankshaft/lithium.h"
#include "src/crankshaft/typing.h"
#include "src/debug/debug.h" #include "src/debug/debug.h"
#include "src/debug/liveedit.h" #include "src/debug/liveedit.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/gdb-jit.h"
#include "src/interpreter/interpreter.h" #include "src/interpreter/interpreter.h"
#include "src/isolate-inl.h" #include "src/isolate-inl.h"
#include "src/log-inl.h" #include "src/log-inl.h"
...@@ -101,6 +98,19 @@ class CompilationInfoWithZone : public CompilationInfo { ...@@ -101,6 +98,19 @@ class CompilationInfoWithZone : public CompilationInfo {
Zone zone_; Zone zone_;
}; };
// Helper that times a scoped region and records the elapsed time.
struct ScopedTimer {
explicit ScopedTimer(base::TimeDelta* location) : location_(location) {
DCHECK(location_ != NULL);
timer_.Start();
}
~ScopedTimer() { *location_ += timer_.Elapsed(); }
base::ElapsedTimer timer_;
base::TimeDelta* location_;
};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Implementation of CompilationInfo // Implementation of CompilationInfo
...@@ -302,51 +312,6 @@ void CompilationInfo::PrintAstForTesting() { ...@@ -302,51 +312,6 @@ void CompilationInfo::PrintAstForTesting() {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Implementation of OptimizedCompileJob // Implementation of OptimizedCompileJob
class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder {
public:
explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info)
: HOptimizedGraphBuilder(info) {
}
#define DEF_VISIT(type) \
void Visit##type(type* node) override { \
SourcePosition old_position = SourcePosition::Unknown(); \
if (node->position() != RelocInfo::kNoPosition) { \
old_position = source_position(); \
SetSourcePosition(node->position()); \
} \
HOptimizedGraphBuilder::Visit##type(node); \
if (!old_position.IsUnknown()) { \
set_source_position(old_position); \
} \
}
EXPRESSION_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
#define DEF_VISIT(type) \
void Visit##type(type* node) override { \
SourcePosition old_position = SourcePosition::Unknown(); \
if (node->position() != RelocInfo::kNoPosition) { \
old_position = source_position(); \
SetSourcePosition(node->position()); \
} \
HOptimizedGraphBuilder::Visit##type(node); \
if (!old_position.IsUnknown()) { \
set_source_position(old_position); \
} \
}
STATEMENT_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
#define DEF_VISIT(type) \
void Visit##type(type* node) override { \
HOptimizedGraphBuilder::Visit##type(node); \
}
DECLARATION_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
};
OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() { OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
DCHECK(info()->IsOptimizing()); DCHECK(info()->IsOptimizing());
...@@ -389,126 +354,10 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() { ...@@ -389,126 +354,10 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
DCHECK(info()->shared_info()->has_deoptimization_support()); DCHECK(info()->shared_info()->has_deoptimization_support());
DCHECK(!info()->is_first_compile()); DCHECK(!info()->is_first_compile());
bool optimization_disabled = info()->shared_info()->optimization_disabled(); // Delegate to the underlying implementation.
bool dont_crankshaft = info()->shared_info()->dont_crankshaft(); DCHECK_EQ(SUCCEEDED, last_status());
ScopedTimer t(&time_taken_to_create_graph_);
// Check the enabling conditions for Turbofan. return SetLastStatus(CreateGraphImpl());
// 1. "use asm" code.
bool is_turbofanable_asm = FLAG_turbo_asm &&
info()->shared_info()->asm_function() &&
!optimization_disabled;
// 2. Fallback for features unsupported by Crankshaft.
bool is_unsupported_by_crankshaft_but_turbofanable =
dont_crankshaft && strcmp(FLAG_turbo_filter, "~~") == 0 &&
!optimization_disabled;
// 3. Explicitly enabled by the command-line filter.
bool passes_turbo_filter =
info()->shared_info()->PassesFilter(FLAG_turbo_filter);
// If this is OSR request, OSR must be enabled by Turbofan.
bool passes_osr_test = FLAG_turbo_osr || !info()->is_osr();
if ((is_turbofanable_asm || is_unsupported_by_crankshaft_but_turbofanable ||
passes_turbo_filter) &&
passes_osr_test) {
// Use TurboFan for the compilation.
if (FLAG_trace_opt) {
OFStream os(stdout);
os << "[compiling method " << Brief(*info()->closure())
<< " using TurboFan";
if (info()->is_osr()) os << " OSR";
os << "]" << std::endl;
}
if (info()->shared_info()->asm_function()) {
if (info()->osr_frame()) info()->MarkAsFrameSpecializing();
info()->MarkAsFunctionContextSpecializing();
} else {
if (!FLAG_always_opt) {
info()->MarkAsBailoutOnUninitialized();
}
if (FLAG_native_context_specialization) {
info()->MarkAsNativeContextSpecializing();
info()->MarkAsTypingEnabled();
}
}
if (!info()->shared_info()->asm_function() ||
FLAG_turbo_asm_deoptimization) {
info()->MarkAsDeoptimizationEnabled();
}
Timer t(this, &time_taken_to_create_graph_);
compiler::Pipeline pipeline(info());
pipeline.GenerateCode();
if (!info()->code().is_null()) {
return SetLastStatus(SUCCEEDED);
}
}
if (!isolate()->use_crankshaft() || dont_crankshaft) {
// Crankshaft is entirely disabled.
return SetLastStatus(FAILED);
}
Scope* scope = info()->scope();
if (LUnallocated::TooManyParameters(scope->num_parameters())) {
// Crankshaft would require too many Lithium operands.
return AbortOptimization(kTooManyParameters);
}
if (info()->is_osr() &&
LUnallocated::TooManyParametersOrStackSlots(scope->num_parameters(),
scope->num_stack_slots())) {
// Crankshaft would require too many Lithium operands.
return AbortOptimization(kTooManyParametersLocals);
}
if (FLAG_trace_opt) {
OFStream os(stdout);
os << "[compiling method " << Brief(*info()->closure())
<< " using Crankshaft";
if (info()->is_osr()) os << " OSR";
os << "]" << std::endl;
}
if (FLAG_trace_hydrogen) {
isolate()->GetHTracer()->TraceCompilation(info());
}
// Type-check the function.
AstTyper(info()->isolate(), info()->zone(), info()->closure(),
info()->scope(), info()->osr_ast_id(), info()->literal())
.Run();
// Optimization could have been disabled by the parser. Note that this check
// is only needed because the Hydrogen graph builder is missing some bailouts.
if (info()->shared_info()->optimization_disabled()) {
return AbortOptimization(
info()->shared_info()->disable_optimization_reason());
}
HOptimizedGraphBuilder* graph_builder =
(info()->is_tracking_positions() || FLAG_trace_ic)
? new (info()->zone()) HOptimizedGraphBuilderWithPositions(info())
: new (info()->zone()) HOptimizedGraphBuilder(info());
Timer t(this, &time_taken_to_create_graph_);
graph_ = graph_builder->CreateGraph();
if (isolate()->has_pending_exception()) {
return SetLastStatus(FAILED);
}
if (graph_ == NULL) return SetLastStatus(BAILED_OUT);
if (info()->dependencies()->HasAborted()) {
// Dependency has changed during graph creation. Let's try again later.
return RetryOptimization(kBailedOutDueToDependencyChange);
}
return SetLastStatus(SUCCEEDED);
} }
...@@ -518,24 +367,21 @@ OptimizedCompileJob::Status OptimizedCompileJob::OptimizeGraph() { ...@@ -518,24 +367,21 @@ OptimizedCompileJob::Status OptimizedCompileJob::OptimizeGraph() {
DisallowHandleDereference no_deref; DisallowHandleDereference no_deref;
DisallowCodeDependencyChange no_dependency_change; DisallowCodeDependencyChange no_dependency_change;
DCHECK(last_status() == SUCCEEDED); // Delegate to the underlying implementation.
// TODO(turbofan): Currently everything is done in the first phase. DCHECK_EQ(SUCCEEDED, last_status());
if (!info()->code().is_null()) { ScopedTimer t(&time_taken_to_optimize_);
return last_status(); return SetLastStatus(OptimizeGraphImpl());
} }
Timer t(this, &time_taken_to_optimize_);
DCHECK(graph_ != NULL);
BailoutReason bailout_reason = kNoReason;
if (graph_->Optimize(&bailout_reason)) { OptimizedCompileJob::Status OptimizedCompileJob::GenerateCode() {
chunk_ = LChunk::NewChunk(graph_); DisallowCodeDependencyChange no_dependency_change;
if (chunk_ != NULL) return SetLastStatus(SUCCEEDED); DisallowJavascriptExecution no_js(isolate());
} else if (bailout_reason != kNoReason) { DCHECK(!info()->dependencies()->HasAborted());
info_->AbortOptimization(bailout_reason);
}
return SetLastStatus(BAILED_OUT); // Delegate to the underlying implementation.
DCHECK_EQ(SUCCEEDED, last_status());
ScopedTimer t(&time_taken_to_codegen_);
return SetLastStatus(GenerateCodeImpl());
} }
...@@ -550,8 +396,10 @@ void AddWeakObjectToCodeDependency(Isolate* isolate, Handle<HeapObject> object, ...@@ -550,8 +396,10 @@ void AddWeakObjectToCodeDependency(Isolate* isolate, Handle<HeapObject> object,
heap->AddWeakObjectToCodeDependency(object, dep); heap->AddWeakObjectToCodeDependency(object, dep);
} }
} // namespace
void RegisterWeakObjectsInOptimizedCode(Handle<Code> code) { void OptimizedCompileJob::RegisterWeakObjectsInOptimizedCode(
Handle<Code> code) {
// TODO(turbofan): Move this to pipeline.cc once Crankshaft dies. // TODO(turbofan): Move this to pipeline.cc once Crankshaft dies.
Isolate* const isolate = code->GetIsolate(); Isolate* const isolate = code->GetIsolate();
DCHECK(code->is_optimized_code()); DCHECK(code->is_optimized_code());
...@@ -591,51 +439,6 @@ void RegisterWeakObjectsInOptimizedCode(Handle<Code> code) { ...@@ -591,51 +439,6 @@ void RegisterWeakObjectsInOptimizedCode(Handle<Code> code) {
code->set_can_have_weak_objects(true); code->set_can_have_weak_objects(true);
} }
} // namespace
OptimizedCompileJob::Status OptimizedCompileJob::GenerateCode() {
DCHECK(last_status() == SUCCEEDED);
// TODO(turbofan): Currently everything is done in the first phase.
if (!info()->code().is_null()) {
info()->dependencies()->Commit(info()->code());
if (info()->is_deoptimization_enabled()) {
info()->parse_info()->context()->native_context()->AddOptimizedCode(
*info()->code());
RegisterWeakObjectsInOptimizedCode(info()->code());
}
RecordOptimizationStats();
return last_status();
}
DCHECK(!info()->dependencies()->HasAborted());
DisallowCodeDependencyChange no_dependency_change;
DisallowJavascriptExecution no_js(isolate());
{ // Scope for timer.
Timer timer(this, &time_taken_to_codegen_);
DCHECK(chunk_ != NULL);
DCHECK(graph_ != NULL);
// Deferred handles reference objects that were accessible during
// graph creation. To make sure that we don't encounter inconsistencies
// between graph creation and code generation, we disallow accessing
// objects through deferred handles during the latter, with exceptions.
DisallowDeferredHandleDereference no_deferred_handle_deref;
Handle<Code> optimized_code = chunk_->Codegen();
if (optimized_code.is_null()) {
if (info()->bailout_reason() == kNoReason) {
return AbortOptimization(kCodeGenerationFailed);
}
return SetLastStatus(BAILED_OUT);
}
RegisterWeakObjectsInOptimizedCode(optimized_code);
info()->SetCode(optimized_code);
}
RecordOptimizationStats();
// Add to the weak list of optimized code objects.
info()->context()->native_context()->AddOptimizedCode(*info()->code());
return SetLastStatus(SUCCEEDED);
}
void OptimizedCompileJob::RecordOptimizationStats() { void OptimizedCompileJob::RecordOptimizationStats() {
Handle<JSFunction> function = info()->closure(); Handle<JSFunction> function = info()->closure();
...@@ -935,6 +738,34 @@ bool Renumber(ParseInfo* parse_info) { ...@@ -935,6 +738,34 @@ bool Renumber(ParseInfo* parse_info) {
return true; return true;
} }
bool UseTurboFan(CompilationInfo* info) {
bool optimization_disabled = info->shared_info()->optimization_disabled();
bool dont_crankshaft = info->shared_info()->dont_crankshaft();
// Check the enabling conditions for Turbofan.
// 1. "use asm" code.
bool is_turbofanable_asm = FLAG_turbo_asm &&
info->shared_info()->asm_function() &&
!optimization_disabled;
// 2. Fallback for features unsupported by Crankshaft.
bool is_unsupported_by_crankshaft_but_turbofanable =
dont_crankshaft && strcmp(FLAG_turbo_filter, "~~") == 0 &&
!optimization_disabled;
// 3. Explicitly enabled by the command-line filter.
bool passes_turbo_filter =
info->shared_info()->PassesFilter(FLAG_turbo_filter);
// If this is OSR request, OSR must be enabled by Turbofan.
bool passes_osr_test = FLAG_turbo_osr || !info->is_osr();
return (is_turbofanable_asm ||
is_unsupported_by_crankshaft_but_turbofanable ||
passes_turbo_filter) &&
passes_osr_test;
}
bool GetOptimizedCodeNow(CompilationInfo* info) { bool GetOptimizedCodeNow(CompilationInfo* info) {
Isolate* isolate = info->isolate(); Isolate* isolate = info->isolate();
CanonicalHandleScope canonical(isolate); CanonicalHandleScope canonical(isolate);
...@@ -946,10 +777,12 @@ bool GetOptimizedCodeNow(CompilationInfo* info) { ...@@ -946,10 +777,12 @@ bool GetOptimizedCodeNow(CompilationInfo* info) {
TimerEventScope<TimerEventRecompileSynchronous> timer(isolate); TimerEventScope<TimerEventRecompileSynchronous> timer(isolate);
TRACE_EVENT0("v8", "V8.RecompileSynchronous"); TRACE_EVENT0("v8", "V8.RecompileSynchronous");
OptimizedCompileJob job(info); OptimizedCompileJob* job = UseTurboFan(info)
if (job.CreateGraph() != OptimizedCompileJob::SUCCEEDED || ? compiler::Pipeline::NewCompilationJob(info)
job.OptimizeGraph() != OptimizedCompileJob::SUCCEEDED || : new (info->zone()) HCompilationJob(info);
job.GenerateCode() != OptimizedCompileJob::SUCCEEDED) { if (job->CreateGraph() != OptimizedCompileJob::SUCCEEDED ||
job->OptimizeGraph() != OptimizedCompileJob::SUCCEEDED ||
job->GenerateCode() != OptimizedCompileJob::SUCCEEDED) {
if (FLAG_trace_opt) { if (FLAG_trace_opt) {
PrintF("[aborted optimizing "); PrintF("[aborted optimizing ");
info->closure()->ShortPrint(); info->closure()->ShortPrint();
...@@ -959,6 +792,7 @@ bool GetOptimizedCodeNow(CompilationInfo* info) { ...@@ -959,6 +792,7 @@ bool GetOptimizedCodeNow(CompilationInfo* info) {
} }
// Success! // Success!
job->RecordOptimizationStats();
DCHECK(!isolate->has_pending_exception()); DCHECK(!isolate->has_pending_exception());
InsertCodeIntoOptimizedCodeMap(info); InsertCodeIntoOptimizedCodeMap(info);
RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info,
...@@ -991,7 +825,9 @@ bool GetOptimizedCodeLater(CompilationInfo* info) { ...@@ -991,7 +825,9 @@ bool GetOptimizedCodeLater(CompilationInfo* info) {
TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate()); TimerEventScope<TimerEventRecompileSynchronous> timer(info->isolate());
TRACE_EVENT0("v8", "V8.RecompileSynchronous"); TRACE_EVENT0("v8", "V8.RecompileSynchronous");
OptimizedCompileJob* job = new (info->zone()) OptimizedCompileJob(info); OptimizedCompileJob* job = UseTurboFan(info)
? compiler::Pipeline::NewCompilationJob(info)
: new (info->zone()) HCompilationJob(info);
OptimizedCompileJob::Status status = job->CreateGraph(); OptimizedCompileJob::Status status = job->CreateGraph();
if (status != OptimizedCompileJob::SUCCEEDED) return false; if (status != OptimizedCompileJob::SUCCEEDED) return false;
isolate->optimizing_compile_dispatcher()->QueueForOptimization(job); isolate->optimizing_compile_dispatcher()->QueueForOptimization(job);
...@@ -1841,6 +1677,7 @@ void Compiler::FinalizeOptimizedCompileJob(OptimizedCompileJob* job) { ...@@ -1841,6 +1677,7 @@ void Compiler::FinalizeOptimizedCompileJob(OptimizedCompileJob* job) {
} else if (info->dependencies()->HasAborted()) { } else if (info->dependencies()->HasAborted()) {
job->RetryOptimization(kBailedOutDueToDependencyChange); job->RetryOptimization(kBailedOutDueToDependencyChange);
} else if (job->GenerateCode() == OptimizedCompileJob::SUCCEEDED) { } else if (job->GenerateCode() == OptimizedCompileJob::SUCCEEDED) {
job->RecordOptimizationStats();
RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info.get(), shared); RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info.get(), shared);
if (shared->SearchOptimizedCodeMap(info->context()->native_context(), if (shared->SearchOptimizedCodeMap(info->context()->native_context(),
info->osr_ast_id()).code == nullptr) { info->osr_ast_id()).code == nullptr) {
......
...@@ -569,20 +569,21 @@ class CompilationInfo { ...@@ -569,20 +569,21 @@ class CompilationInfo {
DISALLOW_COPY_AND_ASSIGN(CompilationInfo); DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
}; };
// A base class for compilation jobs intended to run concurrent to the main
class HGraph; // thread. The job is split into three phases which are called in sequence on
class LChunk; // different threads and with different limitations:
// 1) CreateGraph: Runs on main thread. No major limitations.
// A helper class that calls the three compilation phases in // 2) OptimizeGraph: Runs concurrently. No heap allocation or handle derefs.
// Crankshaft and keeps track of its state. The three phases // 3) GenerateCode: Runs on main thread. No dependency changes.
// CreateGraph, OptimizeGraph and GenerateAndInstallCode can either //
// fail, bail-out to the full code generator or succeed. Apart from // Each of the three phases can either fail, bail-out to full code generator or
// their return value, the status of the phase last run can be checked // succeed. Apart from their return value, the status of the phase last run can
// using last_status(). // be checked using {last_status()} as well.
class OptimizedCompileJob: public ZoneObject { class OptimizedCompileJob: public ZoneObject {
public: public:
explicit OptimizedCompileJob(CompilationInfo* info) explicit OptimizedCompileJob(CompilationInfo* info)
: info_(info), graph_(NULL), chunk_(NULL), last_status_(FAILED) {} : info_(info), last_status_(SUCCEEDED) {}
virtual ~OptimizedCompileJob() {}
enum Status { enum Status {
FAILED, BAILED_OUT, SUCCEEDED FAILED, BAILED_OUT, SUCCEEDED
...@@ -606,10 +607,18 @@ class OptimizedCompileJob: public ZoneObject { ...@@ -606,10 +607,18 @@ class OptimizedCompileJob: public ZoneObject {
return SetLastStatus(BAILED_OUT); return SetLastStatus(BAILED_OUT);
} }
void RecordOptimizationStats();
protected:
void RegisterWeakObjectsInOptimizedCode(Handle<Code> code);
// Overridden by the actual implementation.
virtual Status CreateGraphImpl() = 0;
virtual Status OptimizeGraphImpl() = 0;
virtual Status GenerateCodeImpl() = 0;
private: private:
CompilationInfo* info_; CompilationInfo* info_;
HGraph* graph_;
LChunk* chunk_;
base::TimeDelta time_taken_to_create_graph_; base::TimeDelta time_taken_to_create_graph_;
base::TimeDelta time_taken_to_optimize_; base::TimeDelta time_taken_to_optimize_;
base::TimeDelta time_taken_to_codegen_; base::TimeDelta time_taken_to_codegen_;
...@@ -619,23 +628,6 @@ class OptimizedCompileJob: public ZoneObject { ...@@ -619,23 +628,6 @@ class OptimizedCompileJob: public ZoneObject {
last_status_ = status; last_status_ = status;
return last_status_; return last_status_;
} }
void RecordOptimizationStats();
struct Timer {
Timer(OptimizedCompileJob* job, base::TimeDelta* location)
: job_(job), location_(location) {
DCHECK(location_ != NULL);
timer_.Start();
}
~Timer() {
*location_ += timer_.Elapsed();
}
OptimizedCompileJob* job_;
base::ElapsedTimer timer_;
base::TimeDelta* location_;
};
}; };
} // namespace internal } // namespace internal
......
...@@ -19,15 +19,15 @@ ...@@ -19,15 +19,15 @@
#include "src/compiler/common-operator-reducer.h" #include "src/compiler/common-operator-reducer.h"
#include "src/compiler/control-flow-optimizer.h" #include "src/compiler/control-flow-optimizer.h"
#include "src/compiler/dead-code-elimination.h" #include "src/compiler/dead-code-elimination.h"
#include "src/compiler/escape-analysis.h"
#include "src/compiler/escape-analysis-reducer.h" #include "src/compiler/escape-analysis-reducer.h"
#include "src/compiler/escape-analysis.h"
#include "src/compiler/frame-elider.h" #include "src/compiler/frame-elider.h"
#include "src/compiler/graph-replay.h" #include "src/compiler/graph-replay.h"
#include "src/compiler/graph-trimmer.h" #include "src/compiler/graph-trimmer.h"
#include "src/compiler/graph-visualizer.h" #include "src/compiler/graph-visualizer.h"
#include "src/compiler/greedy-allocator.h" #include "src/compiler/greedy-allocator.h"
#include "src/compiler/instruction.h"
#include "src/compiler/instruction-selector.h" #include "src/compiler/instruction-selector.h"
#include "src/compiler/instruction.h"
#include "src/compiler/js-builtin-reducer.h" #include "src/compiler/js-builtin-reducer.h"
#include "src/compiler/js-call-reducer.h" #include "src/compiler/js-call-reducer.h"
#include "src/compiler/js-context-specialization.h" #include "src/compiler/js-context-specialization.h"
...@@ -48,20 +48,21 @@ ...@@ -48,20 +48,21 @@
#include "src/compiler/move-optimizer.h" #include "src/compiler/move-optimizer.h"
#include "src/compiler/osr.h" #include "src/compiler/osr.h"
#include "src/compiler/pipeline-statistics.h" #include "src/compiler/pipeline-statistics.h"
#include "src/compiler/register-allocator.h"
#include "src/compiler/register-allocator-verifier.h" #include "src/compiler/register-allocator-verifier.h"
#include "src/compiler/register-allocator.h"
#include "src/compiler/schedule.h" #include "src/compiler/schedule.h"
#include "src/compiler/scheduler.h" #include "src/compiler/scheduler.h"
#include "src/compiler/select-lowering.h" #include "src/compiler/select-lowering.h"
#include "src/compiler/simplified-lowering.h" #include "src/compiler/simplified-lowering.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/simplified-operator-reducer.h" #include "src/compiler/simplified-operator-reducer.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/tail-call-optimization.h" #include "src/compiler/tail-call-optimization.h"
#include "src/compiler/type-hint-analyzer.h" #include "src/compiler/type-hint-analyzer.h"
#include "src/compiler/typer.h" #include "src/compiler/typer.h"
#include "src/compiler/value-numbering-reducer.h" #include "src/compiler/value-numbering-reducer.h"
#include "src/compiler/verifier.h" #include "src/compiler/verifier.h"
#include "src/compiler/zone-pool.h" #include "src/compiler/zone-pool.h"
#include "src/isolate-inl.h"
#include "src/ostreams.h" #include "src/ostreams.h"
#include "src/register-configuration.h" #include "src/register-configuration.h"
#include "src/type-info.h" #include "src/type-info.h"
...@@ -476,6 +477,67 @@ class PipelineRunScope { ...@@ -476,6 +477,67 @@ class PipelineRunScope {
ZonePool::Scope zone_scope_; ZonePool::Scope zone_scope_;
}; };
class PipelineCompilationJob : public OptimizedCompileJob {
public:
explicit PipelineCompilationJob(CompilationInfo* info)
: OptimizedCompileJob(info) {}
protected:
virtual Status CreateGraphImpl();
virtual Status OptimizeGraphImpl();
virtual Status GenerateCodeImpl();
};
PipelineCompilationJob::Status PipelineCompilationJob::CreateGraphImpl() {
if (FLAG_trace_opt) {
OFStream os(stdout);
os << "[compiling method " << Brief(*info()->closure())
<< " using TurboFan";
if (info()->is_osr()) os << " OSR";
os << "]" << std::endl;
}
if (info()->shared_info()->asm_function()) {
if (info()->osr_frame()) info()->MarkAsFrameSpecializing();
info()->MarkAsFunctionContextSpecializing();
} else {
if (!FLAG_always_opt) {
info()->MarkAsBailoutOnUninitialized();
}
if (FLAG_native_context_specialization) {
info()->MarkAsNativeContextSpecializing();
info()->MarkAsTypingEnabled();
}
}
if (!info()->shared_info()->asm_function() || FLAG_turbo_asm_deoptimization) {
info()->MarkAsDeoptimizationEnabled();
}
Pipeline pipeline(info());
pipeline.GenerateCode();
if (isolate()->has_pending_exception()) return FAILED; // Stack overflowed.
if (info()->code().is_null()) return AbortOptimization(kGraphBuildingFailed);
return SUCCEEDED;
}
PipelineCompilationJob::Status PipelineCompilationJob::OptimizeGraphImpl() {
// TODO(turbofan): Currently everything is done in the first phase.
DCHECK(!info()->code().is_null());
return SUCCEEDED;
}
PipelineCompilationJob::Status PipelineCompilationJob::GenerateCodeImpl() {
// TODO(turbofan): Currently everything is done in the first phase.
DCHECK(!info()->code().is_null());
info()->dependencies()->Commit(info()->code());
if (info()->is_deoptimization_enabled()) {
info()->context()->native_context()->AddOptimizedCode(*info()->code());
RegisterWeakObjectsInOptimizedCode(info()->code());
}
return SUCCEEDED;
}
} // namespace } // namespace
...@@ -1313,6 +1375,9 @@ Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info, ...@@ -1313,6 +1375,9 @@ Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
return pipeline.ScheduleAndGenerateCode(call_descriptor); return pipeline.ScheduleAndGenerateCode(call_descriptor);
} }
OptimizedCompileJob* Pipeline::NewCompilationJob(CompilationInfo* info) {
return new (info->zone()) PipelineCompilationJob(info);
}
bool Pipeline::AllocateRegistersForTesting(const RegisterConfiguration* config, bool Pipeline::AllocateRegistersForTesting(const RegisterConfiguration* config,
InstructionSequence* sequence, InstructionSequence* sequence,
......
...@@ -13,6 +13,7 @@ namespace v8 { ...@@ -13,6 +13,7 @@ namespace v8 {
namespace internal { namespace internal {
class CompilationInfo; class CompilationInfo;
class OptimizedCompileJob;
class RegisterConfiguration; class RegisterConfiguration;
namespace compiler { namespace compiler {
...@@ -26,7 +27,7 @@ class Schedule; ...@@ -26,7 +27,7 @@ class Schedule;
class Pipeline { class Pipeline {
public: public:
explicit Pipeline(CompilationInfo* info) : info_(info) {} explicit Pipeline(CompilationInfo* info) : info_(info), data_(nullptr) {}
// Run the entire pipeline and generate a handle to a code object. // Run the entire pipeline and generate a handle to a code object.
Handle<Code> GenerateCode(); Handle<Code> GenerateCode();
...@@ -57,6 +58,9 @@ class Pipeline { ...@@ -57,6 +58,9 @@ class Pipeline {
Graph* graph, Graph* graph,
Schedule* schedule = nullptr); Schedule* schedule = nullptr);
// Returns a new compilation job for the given compilation info.
static OptimizedCompileJob* NewCompilationJob(CompilationInfo* info);
private: private:
// Helpers for executing pipeline phases. // Helpers for executing pipeline phases.
template <typename Phase> template <typename Phase>
......
...@@ -68,6 +68,153 @@ ...@@ -68,6 +68,153 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class HOptimizedGraphBuilderWithPositions : public HOptimizedGraphBuilder {
public:
explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info)
: HOptimizedGraphBuilder(info) {}
#define DEF_VISIT(type) \
void Visit##type(type* node) override { \
SourcePosition old_position = SourcePosition::Unknown(); \
if (node->position() != RelocInfo::kNoPosition) { \
old_position = source_position(); \
SetSourcePosition(node->position()); \
} \
HOptimizedGraphBuilder::Visit##type(node); \
if (!old_position.IsUnknown()) { \
set_source_position(old_position); \
} \
}
EXPRESSION_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
#define DEF_VISIT(type) \
void Visit##type(type* node) override { \
SourcePosition old_position = SourcePosition::Unknown(); \
if (node->position() != RelocInfo::kNoPosition) { \
old_position = source_position(); \
SetSourcePosition(node->position()); \
} \
HOptimizedGraphBuilder::Visit##type(node); \
if (!old_position.IsUnknown()) { \
set_source_position(old_position); \
} \
}
STATEMENT_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
#define DEF_VISIT(type) \
void Visit##type(type* node) override { \
HOptimizedGraphBuilder::Visit##type(node); \
}
DECLARATION_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
};
HCompilationJob::Status HCompilationJob::CreateGraphImpl() {
bool dont_crankshaft = info()->shared_info()->dont_crankshaft();
if (!isolate()->use_crankshaft() || dont_crankshaft) {
// Crankshaft is entirely disabled.
return FAILED;
}
Scope* scope = info()->scope();
if (LUnallocated::TooManyParameters(scope->num_parameters())) {
// Crankshaft would require too many Lithium operands.
return AbortOptimization(kTooManyParameters);
}
if (info()->is_osr() &&
LUnallocated::TooManyParametersOrStackSlots(scope->num_parameters(),
scope->num_stack_slots())) {
// Crankshaft would require too many Lithium operands.
return AbortOptimization(kTooManyParametersLocals);
}
if (FLAG_trace_opt) {
OFStream os(stdout);
os << "[compiling method " << Brief(*info()->closure())
<< " using Crankshaft";
if (info()->is_osr()) os << " OSR";
os << "]" << std::endl;
}
if (FLAG_trace_hydrogen) {
isolate()->GetHTracer()->TraceCompilation(info());
}
// Type-check the function.
AstTyper(info()->isolate(), info()->zone(), info()->closure(),
info()->scope(), info()->osr_ast_id(), info()->literal())
.Run();
// Optimization could have been disabled by the parser. Note that this check
// is only needed because the Hydrogen graph builder is missing some bailouts.
if (info()->shared_info()->optimization_disabled()) {
return AbortOptimization(
info()->shared_info()->disable_optimization_reason());
}
HOptimizedGraphBuilder* graph_builder =
(info()->is_tracking_positions() || FLAG_trace_ic)
? new (info()->zone()) HOptimizedGraphBuilderWithPositions(info())
: new (info()->zone()) HOptimizedGraphBuilder(info());
graph_ = graph_builder->CreateGraph();
if (isolate()->has_pending_exception()) {
return FAILED;
}
if (graph_ == NULL) return BAILED_OUT;
if (info()->dependencies()->HasAborted()) {
// Dependency has changed during graph creation. Let's try again later.
return RetryOptimization(kBailedOutDueToDependencyChange);
}
return SUCCEEDED;
}
HCompilationJob::Status HCompilationJob::OptimizeGraphImpl() {
DCHECK(graph_ != NULL);
BailoutReason bailout_reason = kNoReason;
if (graph_->Optimize(&bailout_reason)) {
chunk_ = LChunk::NewChunk(graph_);
if (chunk_ != NULL) return SUCCEEDED;
} else if (bailout_reason != kNoReason) {
info()->AbortOptimization(bailout_reason);
}
return BAILED_OUT;
}
HCompilationJob::Status HCompilationJob::GenerateCodeImpl() {
DCHECK(chunk_ != NULL);
DCHECK(graph_ != NULL);
{
// Deferred handles reference objects that were accessible during
// graph creation. To make sure that we don't encounter inconsistencies
// between graph creation and code generation, we disallow accessing
// objects through deferred handles during the latter, with exceptions.
DisallowDeferredHandleDereference no_deferred_handle_deref;
Handle<Code> optimized_code = chunk_->Codegen();
if (optimized_code.is_null()) {
if (info()->bailout_reason() == kNoReason) {
return AbortOptimization(kCodeGenerationFailed);
}
return BAILED_OUT;
}
RegisterWeakObjectsInOptimizedCode(optimized_code);
info()->SetCode(optimized_code);
}
// Add to the weak list of optimized code objects.
info()->context()->native_context()->AddOptimizedCode(*info()->code());
return SUCCEEDED;
}
HBasicBlock::HBasicBlock(HGraph* graph) HBasicBlock::HBasicBlock(HGraph* graph)
: block_id_(graph->GetNextBlockID()), : block_id_(graph->GetNextBlockID()),
graph_(graph), graph_(graph),
......
...@@ -30,6 +30,20 @@ class LAllocator; ...@@ -30,6 +30,20 @@ class LAllocator;
class LChunk; class LChunk;
class LiveRange; class LiveRange;
class HCompilationJob final : public OptimizedCompileJob {
public:
explicit HCompilationJob(CompilationInfo* info)
: OptimizedCompileJob(info), graph_(nullptr), chunk_(nullptr) {}
protected:
virtual Status CreateGraphImpl();
virtual Status OptimizeGraphImpl();
virtual Status GenerateCodeImpl();
private:
HGraph* graph_;
LChunk* chunk_;
};
class HBasicBlock final : public ZoneObject { class HBasicBlock final : public ZoneObject {
public: public:
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class HGraph;
class LChunk;
class LEnvironment; class LEnvironment;
class LInstruction; class LInstruction;
class LPlatformChunk; class LPlatformChunk;
......
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