[turbofan] Enable concurrent (re)compilation.

Refactor the TurboFan pipeline to allow for concurrent recompilation in
the same way that Crankshaft does it. For now we limit the concurrent
phases to scheduling, instruction selection, register allocation and
jump threading.

R=mstarzinger@chromium.org, ahaas@chromium.org, jarin@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#35818}
This commit is contained in:
bmeurer 2016-04-27 05:38:19 -07:00 committed by Commit bot
parent 7f3954c57b
commit ff19726d80
11 changed files with 295 additions and 183 deletions

View File

@ -706,9 +706,9 @@ bool GetOptimizedCodeNow(CompilationInfo* info) {
TRACE_EVENT0("v8", "V8.OptimizeCode"); TRACE_EVENT0("v8", "V8.OptimizeCode");
bool use_turbofan = UseTurboFan(info); bool use_turbofan = UseTurboFan(info);
OptimizedCompileJob* job = use_turbofan base::SmartPointer<OptimizedCompileJob> job(
? compiler::Pipeline::NewCompilationJob(info) use_turbofan ? compiler::Pipeline::NewCompilationJob(info)
: new (info->zone()) HCompilationJob(info); : new HCompilationJob(info));
// Parsing is not required when optimizing from existing bytecode. // Parsing is not required when optimizing from existing bytecode.
if (!use_turbofan || !info->shared_info()->HasBytecodeArray()) { if (!use_turbofan || !info->shared_info()->HasBytecodeArray()) {
@ -755,9 +755,9 @@ bool GetOptimizedCodeLater(CompilationInfo* info) {
} }
bool use_turbofan = UseTurboFan(info); bool use_turbofan = UseTurboFan(info);
OptimizedCompileJob* job = use_turbofan base::SmartPointer<OptimizedCompileJob> job(
? compiler::Pipeline::NewCompilationJob(info) use_turbofan ? compiler::Pipeline::NewCompilationJob(info)
: new (info->zone()) HCompilationJob(info); : new HCompilationJob(info));
// All handles below this point will be allocated in a deferred handle scope // All handles below this point will be allocated in a deferred handle scope
// that is detached and handed off to the background thread when we return. // that is detached and handed off to the background thread when we return.
@ -778,7 +778,8 @@ bool GetOptimizedCodeLater(CompilationInfo* info) {
TRACE_EVENT0("v8", "V8.RecompileSynchronous"); TRACE_EVENT0("v8", "V8.RecompileSynchronous");
if (job->CreateGraph() != OptimizedCompileJob::SUCCEEDED) return false; if (job->CreateGraph() != OptimizedCompileJob::SUCCEEDED) return false;
isolate->optimizing_compile_dispatcher()->QueueForOptimization(job); isolate->optimizing_compile_dispatcher()->QueueForOptimization(job.get());
job.Detach(); // The background recompile job owns this now.
if (FLAG_trace_concurrent_recompilation) { if (FLAG_trace_concurrent_recompilation) {
PrintF(" ** Queued "); PrintF(" ** Queued ");
@ -1725,7 +1726,7 @@ MaybeHandle<Code> Compiler::GetOptimizedCodeForOSR(Handle<JSFunction> function,
void Compiler::FinalizeOptimizedCompileJob(OptimizedCompileJob* job) { void Compiler::FinalizeOptimizedCompileJob(OptimizedCompileJob* job) {
// Take ownership of compilation info. Deleting compilation info // Take ownership of compilation info. Deleting compilation info
// also tears down the zone and the recompile job. // also tears down the zone.
base::SmartPointer<CompilationInfo> info(job->info()); base::SmartPointer<CompilationInfo> info(job->info());
Isolate* isolate = info->isolate(); Isolate* isolate = info->isolate();
@ -1761,6 +1762,7 @@ void Compiler::FinalizeOptimizedCompileJob(OptimizedCompileJob* job) {
PrintF("]\n"); PrintF("]\n");
} }
info->closure()->ReplaceCode(*info->code()); info->closure()->ReplaceCode(*info->code());
delete job;
return; return;
} }
} }
@ -1772,6 +1774,7 @@ void Compiler::FinalizeOptimizedCompileJob(OptimizedCompileJob* job) {
PrintF(" because: %s]\n", GetBailoutReason(info->bailout_reason())); PrintF(" because: %s]\n", GetBailoutReason(info->bailout_reason()));
} }
info->closure()->ReplaceCode(shared->code()); info->closure()->ReplaceCode(shared->code());
delete job;
} }
void Compiler::PostInstantiation(Handle<JSFunction> function, void Compiler::PostInstantiation(Handle<JSFunction> function,

View File

@ -571,7 +571,8 @@ class CompilationInfo {
// Each of the three phases can either fail, bail-out to full code generator or // Each of the three phases can either fail, bail-out to full code generator or
// succeed. Apart from their return value, the status of the phase last run can // succeed. Apart from their return value, the status of the phase last run can
// be checked using {last_status()} as well. // be checked using {last_status()} as well.
class OptimizedCompileJob: public ZoneObject { // TODO(mstarzinger): Make CompilationInfo base embedded.
class OptimizedCompileJob {
public: public:
explicit OptimizedCompileJob(CompilationInfo* info, const char* compiler_name) explicit OptimizedCompileJob(CompilationInfo* info, const char* compiler_name)
: info_(info), compiler_name_(compiler_name), last_status_(SUCCEEDED) {} : info_(info), compiler_name_(compiler_name), last_status_(SUCCEEDED) {}

View File

@ -60,11 +60,16 @@ class IA32OperandGenerator final : public OperandGenerator {
case IrOpcode::kRelocatableInt64Constant: case IrOpcode::kRelocatableInt64Constant:
return true; return true;
case IrOpcode::kHeapConstant: { case IrOpcode::kHeapConstant: {
// TODO(bmeurer): We must not dereference handles concurrently. If we
// really have to this here, then we need to find a way to put this
// information on the HeapConstant node already.
#if 0
// Constants in new space cannot be used as immediates in V8 because // Constants in new space cannot be used as immediates in V8 because
// the GC does not scan code objects when collecting the new generation. // the GC does not scan code objects when collecting the new generation.
Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(node); Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(node);
Isolate* isolate = value->GetIsolate(); Isolate* isolate = value->GetIsolate();
return !isolate->heap()->InNewSpace(*value); return !isolate->heap()->InNewSpace(*value);
#endif
} }
default: default:
return false; return false;

View File

@ -7,6 +7,8 @@
#include <string> #include <string>
#include "src/base/platform/elapsed-timer.h"
#include "src/base/smart-pointers.h"
#include "src/compilation-statistics.h" #include "src/compilation-statistics.h"
#include "src/compiler/zone-pool.h" #include "src/compiler/zone-pool.h"
@ -22,6 +24,7 @@ class PipelineStatistics : public Malloced {
~PipelineStatistics(); ~PipelineStatistics();
void BeginPhaseKind(const char* phase_kind_name); void BeginPhaseKind(const char* phase_kind_name);
void EndPhaseKind();
private: private:
size_t OuterZoneSize() { size_t OuterZoneSize() {
@ -43,7 +46,6 @@ class PipelineStatistics : public Malloced {
}; };
bool InPhaseKind() { return !phase_kind_stats_.scope_.is_empty(); } bool InPhaseKind() { return !phase_kind_stats_.scope_.is_empty(); }
void EndPhaseKind();
friend class PhaseScope; friend class PhaseScope;
bool InPhase() { return !phase_stats_.scope_.is_empty(); } bool InPhase() { return !phase_stats_.scope_.is_empty(); }

View File

@ -73,13 +73,14 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
class PipelineData : public ZoneObject { class PipelineData {
public: public:
// For main entry point. // For main entry point.
PipelineData(ZonePool* zone_pool, CompilationInfo* info, PipelineData(ZonePool* zone_pool, CompilationInfo* info,
PipelineStatistics* pipeline_statistics) PipelineStatistics* pipeline_statistics)
: isolate_(info->isolate()), : isolate_(info->isolate()),
info_(info), info_(info),
debug_name_(info_->GetDebugName()),
outer_zone_(info_->zone()), outer_zone_(info_->zone()),
zone_pool_(zone_pool), zone_pool_(zone_pool),
pipeline_statistics_(pipeline_statistics), pipeline_statistics_(pipeline_statistics),
@ -107,6 +108,7 @@ class PipelineData : public ZoneObject {
SourcePositionTable* source_positions) SourcePositionTable* source_positions)
: isolate_(info->isolate()), : isolate_(info->isolate()),
info_(info), info_(info),
debug_name_(info_->GetDebugName()),
zone_pool_(zone_pool), zone_pool_(zone_pool),
graph_zone_scope_(zone_pool_), graph_zone_scope_(zone_pool_),
graph_(graph), graph_(graph),
@ -121,6 +123,7 @@ class PipelineData : public ZoneObject {
Schedule* schedule) Schedule* schedule)
: isolate_(info->isolate()), : isolate_(info->isolate()),
info_(info), info_(info),
debug_name_(info_->GetDebugName()),
zone_pool_(zone_pool), zone_pool_(zone_pool),
graph_zone_scope_(zone_pool_), graph_zone_scope_(zone_pool_),
graph_(graph), graph_(graph),
@ -136,6 +139,7 @@ class PipelineData : public ZoneObject {
InstructionSequence* sequence) InstructionSequence* sequence)
: isolate_(info->isolate()), : isolate_(info->isolate()),
info_(info), info_(info),
debug_name_(info_->GetDebugName()),
zone_pool_(zone_pool), zone_pool_(zone_pool),
graph_zone_scope_(zone_pool_), graph_zone_scope_(zone_pool_),
instruction_zone_scope_(zone_pool_), instruction_zone_scope_(zone_pool_),
@ -144,14 +148,12 @@ class PipelineData : public ZoneObject {
register_allocation_zone_scope_(zone_pool_), register_allocation_zone_scope_(zone_pool_),
register_allocation_zone_(register_allocation_zone_scope_.zone()) {} register_allocation_zone_(register_allocation_zone_scope_.zone()) {}
void Destroy() { ~PipelineData() {
DeleteRegisterAllocationZone(); DeleteRegisterAllocationZone();
DeleteInstructionZone(); DeleteInstructionZone();
DeleteGraphZone(); DeleteGraphZone();
} }
~PipelineData() { Destroy(); }
Isolate* isolate() const { return isolate_; } Isolate* isolate() const { return isolate_; }
CompilationInfo* info() const { return info_; } CompilationInfo* info() const { return info_; }
ZonePool* zone_pool() const { return zone_pool_; } ZonePool* zone_pool() const { return zone_pool_; }
@ -163,22 +165,13 @@ class PipelineData : public ZoneObject {
DCHECK(code_.is_null()); DCHECK(code_.is_null());
code_ = code; code_ = code;
} }
BasicBlockProfiler::Data* profiler_data() { return profiler_data_; }
void set_profiler_data(BasicBlockProfiler::Data* data) {
profiler_data_ = data;
}
std::ostringstream* source_position_output() {
return &source_position_output_;
}
// RawMachineAssembler generally produces graphs which cannot be verified. // RawMachineAssembler generally produces graphs which cannot be verified.
bool MayHaveUnverifiableGraph() const { return outer_zone_ == nullptr; } bool MayHaveUnverifiableGraph() const { return outer_zone_ == nullptr; }
Zone* graph_zone() const { return graph_zone_; } Zone* graph_zone() const { return graph_zone_; }
Graph* graph() const { return graph_; } Graph* graph() const { return graph_; }
SourcePositionTable* source_positions() const { SourcePositionTable* source_positions() const { return source_positions_; }
DCHECK_NOT_NULL(source_positions_);
return source_positions_;
}
MachineOperatorBuilder* machine() const { return machine_; } MachineOperatorBuilder* machine() const { return machine_; }
CommonOperatorBuilder* common() const { return common_; } CommonOperatorBuilder* common() const { return common_; }
JSOperatorBuilder* javascript() const { return javascript_; } JSOperatorBuilder* javascript() const { return javascript_; }
@ -218,6 +211,18 @@ class PipelineData : public ZoneObject {
return register_allocation_data_; return register_allocation_data_;
} }
BasicBlockProfiler::Data* profiler_data() const { return profiler_data_; }
void set_profiler_data(BasicBlockProfiler::Data* profiler_data) {
profiler_data_ = profiler_data;
}
std::string const& source_position_output() const {
return source_position_output_;
}
void set_source_position_output(std::string const& source_position_output) {
source_position_output_ = source_position_output;
}
void DeleteGraphZone() { void DeleteGraphZone() {
if (graph_zone_ == nullptr) return; if (graph_zone_ == nullptr) return;
graph_zone_scope_.Destroy(); graph_zone_scope_.Destroy();
@ -274,24 +279,22 @@ class PipelineData : public ZoneObject {
} }
void InitializeRegisterAllocationData(const RegisterConfiguration* config, void InitializeRegisterAllocationData(const RegisterConfiguration* config,
CallDescriptor* descriptor, CallDescriptor* descriptor) {
const char* debug_name) {
DCHECK(register_allocation_data_ == nullptr); DCHECK(register_allocation_data_ == nullptr);
register_allocation_data_ = new (register_allocation_zone()) register_allocation_data_ = new (register_allocation_zone())
RegisterAllocationData(config, register_allocation_zone(), frame(), RegisterAllocationData(config, register_allocation_zone(), frame(),
sequence(), debug_name); sequence(), debug_name_.get());
} }
private: private:
Isolate* isolate_; Isolate* const isolate_;
CompilationInfo* info_; CompilationInfo* const info_;
base::SmartArrayPointer<char> debug_name_;
Zone* outer_zone_ = nullptr; Zone* outer_zone_ = nullptr;
ZonePool* const zone_pool_; ZonePool* const zone_pool_;
PipelineStatistics* pipeline_statistics_ = nullptr; PipelineStatistics* pipeline_statistics_ = nullptr;
bool compilation_failed_ = false; bool compilation_failed_ = false;
Handle<Code> code_; Handle<Code> code_ = Handle<Code>::null();
BasicBlockProfiler::Data* profiler_data_ = nullptr;
std::ostringstream source_position_output_;
// All objects in the following group of fields are allocated in graph_zone_. // All objects in the following group of fields are allocated in graph_zone_.
// They are all set to nullptr when the graph_zone_ is destroyed. // They are all set to nullptr when the graph_zone_ is destroyed.
@ -324,6 +327,12 @@ class PipelineData : public ZoneObject {
Zone* register_allocation_zone_; Zone* register_allocation_zone_;
RegisterAllocationData* register_allocation_data_ = nullptr; RegisterAllocationData* register_allocation_data_ = nullptr;
// Basic block profiling support.
BasicBlockProfiler::Data* profiler_data_ = nullptr;
// Source position output for --trace-turbo.
std::string source_position_output_;
int CalculateFixedFrameSize(CallDescriptor* descriptor) { int CalculateFixedFrameSize(CallDescriptor* descriptor) {
if (descriptor->IsJSFunctionCall()) { if (descriptor->IsJSFunctionCall()) {
return StandardFrameConstants::kFixedSlotCount; return StandardFrameConstants::kFixedSlotCount;
@ -459,15 +468,59 @@ class PipelineRunScope {
ZonePool::Scope zone_scope_; ZonePool::Scope zone_scope_;
}; };
class PipelineCompilationJob : public OptimizedCompileJob { PipelineStatistics* CreatePipelineStatistics(CompilationInfo* info,
ZonePool* zone_pool) {
if (!FLAG_turbo_stats) return nullptr;
PipelineStatistics* pipeline_statistics =
new PipelineStatistics(info, zone_pool);
pipeline_statistics->BeginPhaseKind("initializing");
FILE* json_file = OpenVisualizerLogFile(info, nullptr, "json", "w+");
if (json_file != nullptr) {
OFStream json_of(json_file);
Handle<Script> script = info->script();
base::SmartArrayPointer<char> function_name = info->GetDebugName();
int pos = info->shared_info()->start_position();
json_of << "{\"function\":\"" << function_name.get()
<< "\", \"sourcePosition\":" << pos << ", \"source\":\"";
if (!script->IsUndefined() && !script->source()->IsUndefined()) {
DisallowHeapAllocation no_allocation;
int start = info->shared_info()->start_position();
int len = info->shared_info()->end_position() - start;
String::SubStringRange source(String::cast(script->source()), start, len);
for (const auto& c : source) {
json_of << AsEscapedUC16ForJSON(c);
}
}
json_of << "\",\n\"phases\":[";
fclose(json_file);
}
return pipeline_statistics;
}
class PipelineCompilationJob final : public OptimizedCompileJob {
public: public:
explicit PipelineCompilationJob(CompilationInfo* info) explicit PipelineCompilationJob(CompilationInfo* info)
: OptimizedCompileJob(info, "TurboFan") {} : OptimizedCompileJob(info, "TurboFan"),
zone_pool_(info->isolate()->allocator()),
pipeline_statistics_(CreatePipelineStatistics(info, &zone_pool_)),
data_(&zone_pool_, info, pipeline_statistics_.get()),
pipeline_(&data_),
linkage_(Linkage::ComputeIncoming(info->zone(), info)) {}
protected: protected:
virtual Status CreateGraphImpl(); Status CreateGraphImpl() final;
virtual Status OptimizeGraphImpl(); Status OptimizeGraphImpl() final;
virtual Status GenerateCodeImpl(); Status GenerateCodeImpl() final;
private:
ZonePool zone_pool_;
base::SmartPointer<PipelineStatistics> pipeline_statistics_;
PipelineData data_;
Pipeline pipeline_;
Linkage linkage_;
}; };
PipelineCompilationJob::Status PipelineCompilationJob::CreateGraphImpl() { PipelineCompilationJob::Status PipelineCompilationJob::CreateGraphImpl() {
@ -489,28 +542,73 @@ PipelineCompilationJob::Status PipelineCompilationJob::CreateGraphImpl() {
if (!Compiler::EnsureDeoptimizationSupport(info())) return FAILED; if (!Compiler::EnsureDeoptimizationSupport(info())) return FAILED;
} }
Pipeline pipeline(info()); if (!pipeline_.CreateGraph()) {
pipeline.GenerateCode();
if (isolate()->has_pending_exception()) return FAILED; // Stack overflowed. if (isolate()->has_pending_exception()) return FAILED; // Stack overflowed.
if (info()->code().is_null()) return AbortOptimization(kGraphBuildingFailed); return AbortOptimization(kGraphBuildingFailed);
}
return SUCCEEDED; return SUCCEEDED;
} }
PipelineCompilationJob::Status PipelineCompilationJob::OptimizeGraphImpl() { PipelineCompilationJob::Status PipelineCompilationJob::OptimizeGraphImpl() {
// TODO(turbofan): Currently everything is done in the first phase. if (!pipeline_.OptimizeGraph(&linkage_)) return FAILED;
DCHECK(!info()->code().is_null());
return SUCCEEDED; return SUCCEEDED;
} }
PipelineCompilationJob::Status PipelineCompilationJob::GenerateCodeImpl() { PipelineCompilationJob::Status PipelineCompilationJob::GenerateCodeImpl() {
// TODO(turbofan): Currently everything is done in the first phase. Handle<Code> code = pipeline_.GenerateCode(&linkage_);
DCHECK(!info()->code().is_null()); if (code.is_null()) {
info()->dependencies()->Commit(info()->code()); if (info()->bailout_reason() == kNoReason) {
if (info()->is_deoptimization_enabled()) { return AbortOptimization(kCodeGenerationFailed);
info()->context()->native_context()->AddOptimizedCode(*info()->code());
RegisterWeakObjectsInOptimizedCode(info()->code());
} }
return BAILED_OUT;
}
info()->dependencies()->Commit(code);
info()->SetCode(code);
if (info()->is_deoptimization_enabled()) {
info()->context()->native_context()->AddOptimizedCode(*code);
RegisterWeakObjectsInOptimizedCode(code);
}
return SUCCEEDED;
}
class PipelineWasmCompilationJob final : public OptimizedCompileJob {
public:
explicit PipelineWasmCompilationJob(CompilationInfo* info, Graph* graph,
CallDescriptor* descriptor,
SourcePositionTable* source_positions)
: OptimizedCompileJob(info, "TurboFan"),
zone_pool_(info->isolate()->allocator()),
data_(&zone_pool_, info, graph, source_positions),
pipeline_(&data_),
linkage_(descriptor) {}
protected:
Status CreateGraphImpl() final;
Status OptimizeGraphImpl() final;
Status GenerateCodeImpl() final;
private:
ZonePool zone_pool_;
PipelineData data_;
Pipeline pipeline_;
Linkage linkage_;
};
PipelineWasmCompilationJob::Status
PipelineWasmCompilationJob::CreateGraphImpl() {
return SUCCEEDED;
}
PipelineWasmCompilationJob::Status
PipelineWasmCompilationJob::OptimizeGraphImpl() {
if (!pipeline_.ScheduleAndSelectInstructions(&linkage_)) return FAILED;
return SUCCEEDED;
}
PipelineWasmCompilationJob::Status
PipelineWasmCompilationJob::GenerateCodeImpl() {
pipeline_.GenerateCode(&linkage_);
return SUCCEEDED; return SUCCEEDED;
} }
@ -1140,6 +1238,11 @@ void Pipeline::BeginPhaseKind(const char* phase_kind_name) {
} }
} }
void Pipeline::EndPhaseKind() {
if (data_->pipeline_statistics() != nullptr) {
data_->pipeline_statistics()->EndPhaseKind();
}
}
void Pipeline::RunPrintAndVerify(const char* phase, bool untyped) { void Pipeline::RunPrintAndVerify(const char* phase, bool untyped) {
if (FLAG_trace_turbo) { if (FLAG_trace_turbo) {
@ -1150,42 +1253,8 @@ void Pipeline::RunPrintAndVerify(const char* phase, bool untyped) {
} }
} }
bool Pipeline::CreateGraph() {
Handle<Code> Pipeline::GenerateCode() { PipelineData* data = this->data_;
ZonePool zone_pool(isolate()->allocator());
base::SmartPointer<PipelineStatistics> pipeline_statistics;
if (FLAG_turbo_stats) {
pipeline_statistics.Reset(new PipelineStatistics(info(), &zone_pool));
pipeline_statistics->BeginPhaseKind("initializing");
}
if (FLAG_trace_turbo) {
FILE* json_file = OpenVisualizerLogFile(info(), nullptr, "json", "w+");
if (json_file != nullptr) {
OFStream json_of(json_file);
Handle<Script> script = info()->script();
base::SmartArrayPointer<char> function_name = info()->GetDebugName();
int pos = info()->shared_info()->start_position();
json_of << "{\"function\":\"" << function_name.get()
<< "\", \"sourcePosition\":" << pos << ", \"source\":\"";
if (!script->IsUndefined() && !script->source()->IsUndefined()) {
DisallowHeapAllocation no_allocation;
int start = info()->shared_info()->start_position();
int len = info()->shared_info()->end_position() - start;
String::SubStringRange source(String::cast(script->source()), start,
len);
for (const auto& c : source) {
json_of << AsEscapedUC16ForJSON(c);
}
}
json_of << "\",\n\"phases\":[";
fclose(json_file);
}
}
PipelineData data(&zone_pool, info(), pipeline_statistics.get());
this->data_ = &data;
BeginPhaseKind("graph creation"); BeginPhaseKind("graph creation");
@ -1198,7 +1267,7 @@ Handle<Code> Pipeline::GenerateCode() {
tcf << AsC1VCompilation(info()); tcf << AsC1VCompilation(info());
} }
data.source_positions()->AddDecorator(); data->source_positions()->AddDecorator();
if (FLAG_loop_assignment_analysis) { if (FLAG_loop_assignment_analysis) {
Run<LoopAssignmentAnalysisPhase>(); Run<LoopAssignmentAnalysisPhase>();
@ -1207,7 +1276,10 @@ Handle<Code> Pipeline::GenerateCode() {
Run<TypeHintAnalysisPhase>(); Run<TypeHintAnalysisPhase>();
Run<GraphBuilderPhase>(); Run<GraphBuilderPhase>();
if (data.compilation_failed()) return Handle<Code>::null(); if (data->compilation_failed()) {
EndPhaseKind();
return false;
}
RunPrintAndVerify("Initial untyped", true); RunPrintAndVerify("Initial untyped", true);
// Perform OSR deconstruction. // Perform OSR deconstruction.
@ -1226,12 +1298,12 @@ Handle<Code> Pipeline::GenerateCode() {
if (FLAG_print_turbo_replay) { if (FLAG_print_turbo_replay) {
// Print a replay of the initial graph. // Print a replay of the initial graph.
GraphReplayPrinter::PrintReplay(data.graph()); GraphReplayPrinter::PrintReplay(data->graph());
} }
// Type the graph. // Type the graph.
base::SmartPointer<Typer> typer; base::SmartPointer<Typer> typer;
typer.Reset(new Typer(isolate(), data.graph(), typer.Reset(new Typer(isolate(), data->graph(),
info()->is_deoptimization_enabled() info()->is_deoptimization_enabled()
? Typer::kDeoptimizationEnabled ? Typer::kDeoptimizationEnabled
: Typer::kNoFlags, : Typer::kNoFlags,
@ -1280,19 +1352,36 @@ Handle<Code> Pipeline::GenerateCode() {
// TODO(jarin, rossberg): Remove UNTYPED once machine typing works. // TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
RunPrintAndVerify("Late optimized", true); RunPrintAndVerify("Late optimized", true);
// Kill the Typer and thereby uninstall the decorator (if any).
typer.Reset(nullptr);
EndPhaseKind();
return true;
}
bool Pipeline::OptimizeGraph(Linkage* linkage) {
PipelineData* data = this->data_;
BeginPhaseKind("block building");
Run<LateGraphTrimmingPhase>(); Run<LateGraphTrimmingPhase>();
// TODO(jarin, rossberg): Remove UNTYPED once machine typing works. // TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
RunPrintAndVerify("Late trimmed", true); RunPrintAndVerify("Late trimmed", true);
BeginPhaseKind("block building"); data->source_positions()->RemoveDecorator();
data.source_positions()->RemoveDecorator(); return ScheduleAndSelectInstructions(linkage);
}
// Kill the Typer and thereby uninstall the decorator (if any). Handle<Code> Pipeline::GenerateCode() {
typer.Reset(nullptr); PipelineData* data = this->data_;
return ScheduleAndGenerateCode( Linkage linkage(Linkage::ComputeIncoming(data->instruction_zone(), info()));
Linkage::ComputeIncoming(data.instruction_zone(), info()));
if (!CreateGraph()) return Handle<Code>::null();
if (!OptimizeGraph(&linkage)) return Handle<Code>::null();
return GenerateCode(&linkage);
} }
Handle<Code> Pipeline::GenerateCodeForCodeStub(Isolate* isolate, Handle<Code> Pipeline::GenerateCodeForCodeStub(Isolate* isolate,
@ -1311,8 +1400,7 @@ Handle<Code> Pipeline::GenerateCodeForCodeStub(Isolate* isolate,
pipeline_statistics->BeginPhaseKind("stub codegen"); pipeline_statistics->BeginPhaseKind("stub codegen");
} }
Pipeline pipeline(&info); Pipeline pipeline(&data);
pipeline.data_ = &data;
DCHECK_NOT_NULL(data.schedule()); DCHECK_NOT_NULL(data.schedule());
if (FLAG_trace_turbo) { if (FLAG_trace_turbo) {
@ -1330,7 +1418,17 @@ Handle<Code> Pipeline::GenerateCodeForCodeStub(Isolate* isolate,
return pipeline.ScheduleAndGenerateCode(call_descriptor); return pipeline.ScheduleAndGenerateCode(call_descriptor);
} }
// static
Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info) {
ZonePool zone_pool(info->isolate()->allocator());
base::SmartPointer<PipelineStatistics> pipeline_statistics(
CreatePipelineStatistics(info, &zone_pool));
PipelineData data(&zone_pool, info, pipeline_statistics.get());
Pipeline pipeline(&data);
return pipeline.GenerateCode();
}
// static
Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info, Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
Graph* graph, Graph* graph,
Schedule* schedule) { Schedule* schedule) {
@ -1339,7 +1437,7 @@ Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
return GenerateCodeForTesting(info, call_descriptor, graph, schedule); return GenerateCodeForTesting(info, call_descriptor, graph, schedule);
} }
// static
Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info, Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
CallDescriptor* call_descriptor, CallDescriptor* call_descriptor,
Graph* graph, Graph* graph,
@ -1353,8 +1451,7 @@ Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
pipeline_statistics->BeginPhaseKind("test codegen"); pipeline_statistics->BeginPhaseKind("test codegen");
} }
Pipeline pipeline(info); Pipeline pipeline(&data);
pipeline.data_ = &data;
if (data.schedule() == nullptr) { if (data.schedule() == nullptr) {
// TODO(rossberg): Should this really be untyped? // TODO(rossberg): Should this really be untyped?
pipeline.RunPrintAndVerify("Machine", true); pipeline.RunPrintAndVerify("Machine", true);
@ -1363,26 +1460,17 @@ Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
return pipeline.ScheduleAndGenerateCode(call_descriptor); return pipeline.ScheduleAndGenerateCode(call_descriptor);
} }
void Pipeline::InitializeWasmCompilation( // static
Zone* pipeline_zone, ZonePool* zone_pool, Graph* graph,
SourcePositionTable* source_positions) {
data_ = new (pipeline_zone)
PipelineData(zone_pool, info(), graph, source_positions);
RunPrintAndVerify("Machine", true);
}
bool Pipeline::ExecuteWasmCompilation(CallDescriptor* descriptor) {
return ScheduleGraph(descriptor);
}
Handle<Code> Pipeline::FinalizeWasmCompilation(CallDescriptor* descriptor) {
Handle<Code> result = GenerateCode(descriptor);
data_->Destroy();
return result;
}
OptimizedCompileJob* Pipeline::NewCompilationJob(CompilationInfo* info) { OptimizedCompileJob* Pipeline::NewCompilationJob(CompilationInfo* info) {
return new (info->zone()) PipelineCompilationJob(info); return new PipelineCompilationJob(info);
}
// static
OptimizedCompileJob* Pipeline::NewWasmCompilationJob(
CompilationInfo* info, Graph* graph, CallDescriptor* descriptor,
SourcePositionTable* source_positions) {
return new PipelineWasmCompilationJob(info, graph, descriptor,
source_positions);
} }
bool Pipeline::AllocateRegistersForTesting(const RegisterConfiguration* config, bool Pipeline::AllocateRegistersForTesting(const RegisterConfiguration* config,
@ -1392,25 +1480,16 @@ bool Pipeline::AllocateRegistersForTesting(const RegisterConfiguration* config,
sequence->zone()); sequence->zone());
ZonePool zone_pool(sequence->isolate()->allocator()); ZonePool zone_pool(sequence->isolate()->allocator());
PipelineData data(&zone_pool, &info, sequence); PipelineData data(&zone_pool, &info, sequence);
Pipeline pipeline(&info); Pipeline pipeline(&data);
pipeline.data_ = &data;
pipeline.data_->InitializeFrameData(nullptr); pipeline.data_->InitializeFrameData(nullptr);
pipeline.AllocateRegisters(config, nullptr, run_verifier); pipeline.AllocateRegisters(config, nullptr, run_verifier);
return !data.compilation_failed(); return !data.compilation_failed();
} }
Handle<Code> Pipeline::ScheduleAndGenerateCode( bool Pipeline::ScheduleAndSelectInstructions(Linkage* linkage) {
CallDescriptor* call_descriptor) { CallDescriptor* call_descriptor = linkage->GetIncomingDescriptor();
if (ScheduleGraph(call_descriptor)) {
return GenerateCode(call_descriptor);
} else {
return Handle<Code>::null();
}
}
bool Pipeline::ScheduleGraph(CallDescriptor* call_descriptor) {
PipelineData* data = this->data_; PipelineData* data = this->data_;
DCHECK_NOT_NULL(data);
DCHECK_NOT_NULL(data->graph()); DCHECK_NOT_NULL(data->graph());
if (data->schedule() == nullptr) Run<ComputeSchedulePhase>(); if (data->schedule() == nullptr) Run<ComputeSchedulePhase>();
@ -1425,8 +1504,7 @@ bool Pipeline::ScheduleGraph(CallDescriptor* call_descriptor) {
data->InitializeFrameData(call_descriptor); data->InitializeFrameData(call_descriptor);
// Select and schedule instructions covering the scheduled graph. // Select and schedule instructions covering the scheduled graph.
Linkage linkage(call_descriptor); Run<InstructionSelectionPhase>(linkage);
Run<InstructionSelectionPhase>(&linkage);
if (FLAG_trace_turbo && !data->MayHaveUnverifiableGraph()) { if (FLAG_trace_turbo && !data->MayHaveUnverifiableGraph()) {
TurboCfgFile tcf(isolate()); TurboCfgFile tcf(isolate());
@ -1435,8 +1513,10 @@ bool Pipeline::ScheduleGraph(CallDescriptor* call_descriptor) {
} }
if (FLAG_trace_turbo) { if (FLAG_trace_turbo) {
std::ostringstream source_position_output;
// Output source position information before the graph is deleted. // Output source position information before the graph is deleted.
data_->source_positions()->Print(*(data->source_position_output())); data_->source_positions()->Print(source_position_output);
data_->set_source_position_output(source_position_output.str());
} }
data->DeleteGraphZone(); data->DeleteGraphZone();
@ -1452,10 +1532,10 @@ bool Pipeline::ScheduleGraph(CallDescriptor* call_descriptor) {
Run<FrameElisionPhase>(); Run<FrameElisionPhase>();
if (data->compilation_failed()) { if (data->compilation_failed()) {
info()->AbortOptimization(kNotEnoughVirtualRegistersRegalloc); info()->AbortOptimization(kNotEnoughVirtualRegistersRegalloc);
EndPhaseKind();
return false; return false;
} }
BeginPhaseKind("code generation");
// TODO(mtrofin): move this off to the register allocator. // TODO(mtrofin): move this off to the register allocator.
bool generate_frame_at_start = bool generate_frame_at_start =
data_->sequence()->instruction_blocks().front()->must_construct_frame(); data_->sequence()->instruction_blocks().front()->must_construct_frame();
@ -1463,17 +1543,22 @@ bool Pipeline::ScheduleGraph(CallDescriptor* call_descriptor) {
if (FLAG_turbo_jt) { if (FLAG_turbo_jt) {
Run<JumpThreadingPhase>(generate_frame_at_start); Run<JumpThreadingPhase>(generate_frame_at_start);
} }
EndPhaseKind();
return true; return true;
} }
Handle<Code> Pipeline::GenerateCode(CallDescriptor* call_descriptor) { Handle<Code> Pipeline::GenerateCode(Linkage* linkage) {
PipelineData* data = this->data_; PipelineData* data = this->data_;
Linkage linkage(call_descriptor);
BeginPhaseKind("code generation");
// Generate final machine code. // Generate final machine code.
Run<GenerateCodePhase>(&linkage); Run<GenerateCodePhase>(linkage);
Handle<Code> code = data->code(); Handle<Code> code = data->code();
if (data->profiler_data() != nullptr) { if (data->profiler_data()) {
#if ENABLE_DISASSEMBLER #if ENABLE_DISASSEMBLER
std::ostringstream os; std::ostringstream os;
code->Disassemble(nullptr, os); code->Disassemble(nullptr, os);
@ -1500,7 +1585,7 @@ Handle<Code> Pipeline::GenerateCode(CallDescriptor* call_descriptor) {
#endif // ENABLE_DISASSEMBLER #endif // ENABLE_DISASSEMBLER
json_of << "\"}\n],\n"; json_of << "\"}\n],\n";
json_of << "\"nodePositions\":"; json_of << "\"nodePositions\":";
json_of << data->source_position_output()->str(); json_of << data->source_position_output();
json_of << "}"; json_of << "}";
fclose(json_file); fclose(json_file);
} }
@ -1509,9 +1594,21 @@ Handle<Code> Pipeline::GenerateCode(CallDescriptor* call_descriptor) {
<< "Finished compiling method " << info()->GetDebugName().get() << "Finished compiling method " << info()->GetDebugName().get()
<< " using Turbofan" << std::endl; << " using Turbofan" << std::endl;
} }
return code; return code;
} }
Handle<Code> Pipeline::ScheduleAndGenerateCode(
CallDescriptor* call_descriptor) {
Linkage linkage(call_descriptor);
// Schedule the graph, perform instruction selection and register allocation.
if (!ScheduleAndSelectInstructions(&linkage)) return Handle<Code>();
// Generate the final machine code.
return GenerateCode(&linkage);
}
void Pipeline::AllocateRegisters(const RegisterConfiguration* config, void Pipeline::AllocateRegisters(const RegisterConfiguration* config,
CallDescriptor* descriptor, CallDescriptor* descriptor,
bool run_verifier) { bool run_verifier) {
@ -1525,15 +1622,13 @@ void Pipeline::AllocateRegisters(const RegisterConfiguration* config,
verifier_zone.get(), config, data->sequence()); verifier_zone.get(), config, data->sequence());
} }
base::SmartArrayPointer<char> debug_name;
#ifdef DEBUG #ifdef DEBUG
debug_name = info()->GetDebugName();
data_->sequence()->ValidateEdgeSplitForm(); data_->sequence()->ValidateEdgeSplitForm();
data_->sequence()->ValidateDeferredBlockEntryPaths(); data_->sequence()->ValidateDeferredBlockEntryPaths();
data_->sequence()->ValidateDeferredBlockExitPaths(); data_->sequence()->ValidateDeferredBlockExitPaths();
#endif #endif
data->InitializeRegisterAllocationData(config, descriptor, debug_name.get()); data->InitializeRegisterAllocationData(config, descriptor);
if (info()->is_osr()) { if (info()->is_osr()) {
OsrHelper osr_helper(info()); OsrHelper osr_helper(info());
osr_helper.SetupFrame(data->frame()); osr_helper.SetupFrame(data->frame());
@ -1603,6 +1698,8 @@ void Pipeline::AllocateRegisters(const RegisterConfiguration* config,
data->DeleteRegisterAllocationZone(); data->DeleteRegisterAllocationZone();
} }
CompilationInfo* Pipeline::info() const { return data_->info(); }
Isolate* Pipeline::isolate() const { return info()->isolate(); } Isolate* Pipeline::isolate() const { return info()->isolate(); }
} // namespace compiler } // namespace compiler

View File

@ -15,7 +15,6 @@ namespace internal {
class CompilationInfo; class CompilationInfo;
class OptimizedCompileJob; class OptimizedCompileJob;
class RegisterConfiguration; class RegisterConfiguration;
class Zone;
namespace compiler { namespace compiler {
@ -26,11 +25,19 @@ class Linkage;
class PipelineData; class PipelineData;
class Schedule; class Schedule;
class SourcePositionTable; class SourcePositionTable;
class ZonePool;
class Pipeline { class Pipeline {
public: public:
explicit Pipeline(CompilationInfo* info) : info_(info), data_(nullptr) {} explicit Pipeline(PipelineData* data) : data_(data) {}
// Run the graph creation and initial optimization passes.
bool CreateGraph();
// Run the concurrent optimization passes.
bool OptimizeGraph(Linkage* linkage);
// Perform the actual code generation and return handle to a code object.
Handle<Code> GenerateCode(Linkage* linkage);
// 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();
@ -43,6 +50,10 @@ class Pipeline {
Code::Flags flags, Code::Flags flags,
const char* debug_name); const char* debug_name);
// Run the entire pipeline and generate a handle to a code object suitable for
// testing.
static Handle<Code> GenerateCodeForTesting(CompilationInfo* info);
// Run the pipeline on a machine graph and generate code. If {schedule} is // Run the pipeline on a machine graph and generate code. If {schedule} is
// {nullptr}, then compute a new schedule for code generation. // {nullptr}, then compute a new schedule for code generation.
static Handle<Code> GenerateCodeForTesting(CompilationInfo* info, static Handle<Code> GenerateCodeForTesting(CompilationInfo* info,
@ -64,11 +75,13 @@ class Pipeline {
// Returns a new compilation job for the given compilation info. // Returns a new compilation job for the given compilation info.
static OptimizedCompileJob* NewCompilationJob(CompilationInfo* info); static OptimizedCompileJob* NewCompilationJob(CompilationInfo* info);
void InitializeWasmCompilation(Zone* pipeline_zone, ZonePool* zone_pool, // Returns a new compilation job for the WebAssembly compilation info.
Graph* graph, static OptimizedCompileJob* NewWasmCompilationJob(
CompilationInfo* info, Graph* graph, CallDescriptor* descriptor,
SourcePositionTable* source_positions); SourcePositionTable* source_positions);
bool ExecuteWasmCompilation(CallDescriptor* descriptor);
Handle<Code> FinalizeWasmCompilation(CallDescriptor* descriptor); // TODO(mstarzinger, bmeurer): This shouldn't be public!
bool ScheduleAndSelectInstructions(Linkage* linkage);
private: private:
// Helpers for executing pipeline phases. // Helpers for executing pipeline phases.
@ -80,17 +93,16 @@ class Pipeline {
void Run(Arg0 arg_0, Arg1 arg_1); void Run(Arg0 arg_0, Arg1 arg_1);
void BeginPhaseKind(const char* phase_kind); void BeginPhaseKind(const char* phase_kind);
void EndPhaseKind();
void RunPrintAndVerify(const char* phase, bool untyped = false); void RunPrintAndVerify(const char* phase, bool untyped = false);
Handle<Code> ScheduleAndGenerateCode(CallDescriptor* call_descriptor);
void AllocateRegisters(const RegisterConfiguration* config, void AllocateRegisters(const RegisterConfiguration* config,
CallDescriptor* descriptor, bool run_verifier); CallDescriptor* descriptor, bool run_verifier);
bool ScheduleGraph(CallDescriptor* call_descriptor);
Handle<Code> GenerateCode(CallDescriptor* descriptor); CompilationInfo* info() const;
Handle<Code> ScheduleAndGenerateCode(CallDescriptor* call_descriptor);
CompilationInfo* info() const { return info_; }
Isolate* isolate() const; Isolate* isolate() const;
CompilationInfo* const info_; PipelineData* const data_;
PipelineData* data_;
DISALLOW_COPY_AND_ASSIGN(Pipeline); DISALLOW_COPY_AND_ASSIGN(Pipeline);
}; };

View File

@ -2968,15 +2968,12 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
} }
} }
CompilationInfo info(func_name, isolate, jsgraph->graph()->zone(), flags); CompilationInfo info(func_name, isolate, jsgraph->graph()->zone(), flags);
compiler::ZonePool::Scope pipeline_zone_scope(&zone_pool); base::SmartPointer<OptimizedCompileJob> job(Pipeline::NewWasmCompilationJob(
Pipeline pipeline(&info); &info, jsgraph->graph(), descriptor, source_positions));
pipeline.InitializeWasmCompilation(pipeline_zone_scope.zone(), &zone_pool, Handle<Code> code = Handle<Code>::null();
jsgraph->graph(), source_positions); if (job->OptimizeGraph() == OptimizedCompileJob::SUCCEEDED &&
Handle<Code> code; job->GenerateCode() == OptimizedCompileJob::SUCCEEDED) {
if (pipeline.ExecuteWasmCompilation(descriptor)) { code = info.code();
code = pipeline.FinalizeWasmCompilation(descriptor);
} else {
code = Handle<Code>::null();
} }
buffer.Dispose(); buffer.Dispose();

View File

@ -23,6 +23,7 @@ void DisposeOptimizedCompileJob(OptimizedCompileJob* job,
Handle<JSFunction> function = info->closure(); Handle<JSFunction> function = info->closure();
function->ReplaceCode(function->shared()->code()); function->ReplaceCode(function->shared()->code());
} }
delete job;
delete info; delete info;
} }

View File

@ -194,8 +194,7 @@ class FunctionTester : public InitializedHandleScope {
CHECK(Compiler::Analyze(info.parse_info())); CHECK(Compiler::Analyze(info.parse_info()));
CHECK(Compiler::EnsureDeoptimizationSupport(&info)); CHECK(Compiler::EnsureDeoptimizationSupport(&info));
Pipeline pipeline(&info); Handle<Code> code = Pipeline::GenerateCodeForTesting(&info);
Handle<Code> code = pipeline.GenerateCode();
CHECK(!code.is_null()); CHECK(!code.is_null());
info.dependencies()->Commit(code); info.dependencies()->Commit(code);
info.context()->native_context()->AddOptimizedCode(*code); info.context()->native_context()->AddOptimizedCode(*code);

View File

@ -129,8 +129,7 @@ class BytecodeGraphTester {
compilation_info.SetOptimizing(); compilation_info.SetOptimizing();
compilation_info.MarkAsDeoptimizationEnabled(); compilation_info.MarkAsDeoptimizationEnabled();
compilation_info.MarkAsOptimizeFromBytecode(); compilation_info.MarkAsOptimizeFromBytecode();
compiler::Pipeline pipeline(&compilation_info); Handle<Code> code = Pipeline::GenerateCodeForTesting(&compilation_info);
Handle<Code> code = pipeline.GenerateCode();
function->ReplaceCode(*code); function->ReplaceCode(*code);
return function; return function;

View File

@ -485,18 +485,14 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
} }
CompilationInfo info(debug_name_, this->isolate(), this->zone(), CompilationInfo info(debug_name_, this->isolate(), this->zone(),
Code::ComputeFlags(Code::WASM_FUNCTION)); Code::ComputeFlags(Code::WASM_FUNCTION));
compiler::ZonePool zone_pool(this->isolate()->allocator()); v8::base::SmartPointer<OptimizedCompileJob> job(
compiler::ZonePool::Scope pipeline_zone_scope(&zone_pool); Pipeline::NewWasmCompilationJob(&info, graph(), desc,
Pipeline pipeline(&info); &source_position_table_));
pipeline.InitializeWasmCompilation(this->zone(), &zone_pool, this->graph(), Handle<Code> code = Handle<Code>::null();
&source_position_table_); if (job->OptimizeGraph() == OptimizedCompileJob::SUCCEEDED &&
Handle<Code> code; job->GenerateCode() == OptimizedCompileJob::SUCCEEDED) {
if (pipeline.ExecuteWasmCompilation(desc)) { code = info.code();
code = pipeline.FinalizeWasmCompilation(desc);
} else {
code = Handle<Code>::null();
} }
pipeline_zone_scope.Destroy();
#ifdef ENABLE_DISASSEMBLER #ifdef ENABLE_DISASSEMBLER
if (!code.is_null() && FLAG_print_opt_code) { if (!code.is_null() && FLAG_print_opt_code) {
OFStream os(stdout); OFStream os(stdout);