[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");
bool use_turbofan = UseTurboFan(info);
OptimizedCompileJob* job = use_turbofan
? compiler::Pipeline::NewCompilationJob(info)
: new (info->zone()) HCompilationJob(info);
base::SmartPointer<OptimizedCompileJob> job(
use_turbofan ? compiler::Pipeline::NewCompilationJob(info)
: new HCompilationJob(info));
// Parsing is not required when optimizing from existing bytecode.
if (!use_turbofan || !info->shared_info()->HasBytecodeArray()) {
@ -755,9 +755,9 @@ bool GetOptimizedCodeLater(CompilationInfo* info) {
}
bool use_turbofan = UseTurboFan(info);
OptimizedCompileJob* job = use_turbofan
? compiler::Pipeline::NewCompilationJob(info)
: new (info->zone()) HCompilationJob(info);
base::SmartPointer<OptimizedCompileJob> job(
use_turbofan ? compiler::Pipeline::NewCompilationJob(info)
: new HCompilationJob(info));
// 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.
@ -778,7 +778,8 @@ bool GetOptimizedCodeLater(CompilationInfo* info) {
TRACE_EVENT0("v8", "V8.RecompileSynchronous");
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) {
PrintF(" ** Queued ");
@ -1725,7 +1726,7 @@ MaybeHandle<Code> Compiler::GetOptimizedCodeForOSR(Handle<JSFunction> function,
void Compiler::FinalizeOptimizedCompileJob(OptimizedCompileJob* job) {
// 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());
Isolate* isolate = info->isolate();
@ -1761,6 +1762,7 @@ void Compiler::FinalizeOptimizedCompileJob(OptimizedCompileJob* job) {
PrintF("]\n");
}
info->closure()->ReplaceCode(*info->code());
delete job;
return;
}
}
@ -1772,6 +1774,7 @@ void Compiler::FinalizeOptimizedCompileJob(OptimizedCompileJob* job) {
PrintF(" because: %s]\n", GetBailoutReason(info->bailout_reason()));
}
info->closure()->ReplaceCode(shared->code());
delete job;
}
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
// succeed. Apart from their return value, the status of the phase last run can
// be checked using {last_status()} as well.
class OptimizedCompileJob: public ZoneObject {
// TODO(mstarzinger): Make CompilationInfo base embedded.
class OptimizedCompileJob {
public:
explicit OptimizedCompileJob(CompilationInfo* info, const char* compiler_name)
: info_(info), compiler_name_(compiler_name), last_status_(SUCCEEDED) {}

View File

@ -60,11 +60,16 @@ class IA32OperandGenerator final : public OperandGenerator {
case IrOpcode::kRelocatableInt64Constant:
return true;
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
// the GC does not scan code objects when collecting the new generation.
Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(node);
Isolate* isolate = value->GetIsolate();
return !isolate->heap()->InNewSpace(*value);
#endif
}
default:
return false;

View File

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

View File

@ -73,13 +73,14 @@ namespace v8 {
namespace internal {
namespace compiler {
class PipelineData : public ZoneObject {
class PipelineData {
public:
// For main entry point.
PipelineData(ZonePool* zone_pool, CompilationInfo* info,
PipelineStatistics* pipeline_statistics)
: isolate_(info->isolate()),
info_(info),
debug_name_(info_->GetDebugName()),
outer_zone_(info_->zone()),
zone_pool_(zone_pool),
pipeline_statistics_(pipeline_statistics),
@ -107,6 +108,7 @@ class PipelineData : public ZoneObject {
SourcePositionTable* source_positions)
: isolate_(info->isolate()),
info_(info),
debug_name_(info_->GetDebugName()),
zone_pool_(zone_pool),
graph_zone_scope_(zone_pool_),
graph_(graph),
@ -121,6 +123,7 @@ class PipelineData : public ZoneObject {
Schedule* schedule)
: isolate_(info->isolate()),
info_(info),
debug_name_(info_->GetDebugName()),
zone_pool_(zone_pool),
graph_zone_scope_(zone_pool_),
graph_(graph),
@ -136,6 +139,7 @@ class PipelineData : public ZoneObject {
InstructionSequence* sequence)
: isolate_(info->isolate()),
info_(info),
debug_name_(info_->GetDebugName()),
zone_pool_(zone_pool),
graph_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_(register_allocation_zone_scope_.zone()) {}
void Destroy() {
~PipelineData() {
DeleteRegisterAllocationZone();
DeleteInstructionZone();
DeleteGraphZone();
}
~PipelineData() { Destroy(); }
Isolate* isolate() const { return isolate_; }
CompilationInfo* info() const { return info_; }
ZonePool* zone_pool() const { return zone_pool_; }
@ -163,22 +165,13 @@ class PipelineData : public ZoneObject {
DCHECK(code_.is_null());
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.
bool MayHaveUnverifiableGraph() const { return outer_zone_ == nullptr; }
Zone* graph_zone() const { return graph_zone_; }
Graph* graph() const { return graph_; }
SourcePositionTable* source_positions() const {
DCHECK_NOT_NULL(source_positions_);
return source_positions_;
}
SourcePositionTable* source_positions() const { return source_positions_; }
MachineOperatorBuilder* machine() const { return machine_; }
CommonOperatorBuilder* common() const { return common_; }
JSOperatorBuilder* javascript() const { return javascript_; }
@ -218,6 +211,18 @@ class PipelineData : public ZoneObject {
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() {
if (graph_zone_ == nullptr) return;
graph_zone_scope_.Destroy();
@ -274,24 +279,22 @@ class PipelineData : public ZoneObject {
}
void InitializeRegisterAllocationData(const RegisterConfiguration* config,
CallDescriptor* descriptor,
const char* debug_name) {
CallDescriptor* descriptor) {
DCHECK(register_allocation_data_ == nullptr);
register_allocation_data_ = new (register_allocation_zone())
RegisterAllocationData(config, register_allocation_zone(), frame(),
sequence(), debug_name);
sequence(), debug_name_.get());
}
private:
Isolate* isolate_;
CompilationInfo* info_;
Isolate* const isolate_;
CompilationInfo* const info_;
base::SmartArrayPointer<char> debug_name_;
Zone* outer_zone_ = nullptr;
ZonePool* const zone_pool_;
PipelineStatistics* pipeline_statistics_ = nullptr;
bool compilation_failed_ = false;
Handle<Code> code_;
BasicBlockProfiler::Data* profiler_data_ = nullptr;
std::ostringstream source_position_output_;
Handle<Code> code_ = Handle<Code>::null();
// 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.
@ -324,6 +327,12 @@ class PipelineData : public ZoneObject {
Zone* register_allocation_zone_;
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) {
if (descriptor->IsJSFunctionCall()) {
return StandardFrameConstants::kFixedSlotCount;
@ -459,15 +468,59 @@ class PipelineRunScope {
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:
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:
virtual Status CreateGraphImpl();
virtual Status OptimizeGraphImpl();
virtual Status GenerateCodeImpl();
Status CreateGraphImpl() final;
Status OptimizeGraphImpl() final;
Status GenerateCodeImpl() final;
private:
ZonePool zone_pool_;
base::SmartPointer<PipelineStatistics> pipeline_statistics_;
PipelineData data_;
Pipeline pipeline_;
Linkage linkage_;
};
PipelineCompilationJob::Status PipelineCompilationJob::CreateGraphImpl() {
@ -489,28 +542,73 @@ PipelineCompilationJob::Status PipelineCompilationJob::CreateGraphImpl() {
if (!Compiler::EnsureDeoptimizationSupport(info())) return FAILED;
}
Pipeline pipeline(info());
pipeline.GenerateCode();
if (isolate()->has_pending_exception()) return FAILED; // Stack overflowed.
if (info()->code().is_null()) return AbortOptimization(kGraphBuildingFailed);
if (!pipeline_.CreateGraph()) {
if (isolate()->has_pending_exception()) return FAILED; // Stack overflowed.
return AbortOptimization(kGraphBuildingFailed);
}
return SUCCEEDED;
}
PipelineCompilationJob::Status PipelineCompilationJob::OptimizeGraphImpl() {
// TODO(turbofan): Currently everything is done in the first phase.
DCHECK(!info()->code().is_null());
if (!pipeline_.OptimizeGraph(&linkage_)) return FAILED;
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());
Handle<Code> code = pipeline_.GenerateCode(&linkage_);
if (code.is_null()) {
if (info()->bailout_reason() == kNoReason) {
return AbortOptimization(kCodeGenerationFailed);
}
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;
}
@ -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) {
if (FLAG_trace_turbo) {
@ -1150,42 +1253,8 @@ void Pipeline::RunPrintAndVerify(const char* phase, bool untyped) {
}
}
Handle<Code> Pipeline::GenerateCode() {
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;
bool Pipeline::CreateGraph() {
PipelineData* data = this->data_;
BeginPhaseKind("graph creation");
@ -1198,7 +1267,7 @@ Handle<Code> Pipeline::GenerateCode() {
tcf << AsC1VCompilation(info());
}
data.source_positions()->AddDecorator();
data->source_positions()->AddDecorator();
if (FLAG_loop_assignment_analysis) {
Run<LoopAssignmentAnalysisPhase>();
@ -1207,7 +1276,10 @@ Handle<Code> Pipeline::GenerateCode() {
Run<TypeHintAnalysisPhase>();
Run<GraphBuilderPhase>();
if (data.compilation_failed()) return Handle<Code>::null();
if (data->compilation_failed()) {
EndPhaseKind();
return false;
}
RunPrintAndVerify("Initial untyped", true);
// Perform OSR deconstruction.
@ -1226,12 +1298,12 @@ Handle<Code> Pipeline::GenerateCode() {
if (FLAG_print_turbo_replay) {
// Print a replay of the initial graph.
GraphReplayPrinter::PrintReplay(data.graph());
GraphReplayPrinter::PrintReplay(data->graph());
}
// Type the graph.
base::SmartPointer<Typer> typer;
typer.Reset(new Typer(isolate(), data.graph(),
typer.Reset(new Typer(isolate(), data->graph(),
info()->is_deoptimization_enabled()
? Typer::kDeoptimizationEnabled
: Typer::kNoFlags,
@ -1280,19 +1352,36 @@ Handle<Code> Pipeline::GenerateCode() {
// TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
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>();
// TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
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).
typer.Reset(nullptr);
Handle<Code> Pipeline::GenerateCode() {
PipelineData* data = this->data_;
return ScheduleAndGenerateCode(
Linkage::ComputeIncoming(data.instruction_zone(), info()));
Linkage linkage(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,
@ -1311,8 +1400,7 @@ Handle<Code> Pipeline::GenerateCodeForCodeStub(Isolate* isolate,
pipeline_statistics->BeginPhaseKind("stub codegen");
}
Pipeline pipeline(&info);
pipeline.data_ = &data;
Pipeline pipeline(&data);
DCHECK_NOT_NULL(data.schedule());
if (FLAG_trace_turbo) {
@ -1330,7 +1418,17 @@ Handle<Code> Pipeline::GenerateCodeForCodeStub(Isolate* isolate,
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,
Graph* graph,
Schedule* schedule) {
@ -1339,7 +1437,7 @@ Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
return GenerateCodeForTesting(info, call_descriptor, graph, schedule);
}
// static
Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
CallDescriptor* call_descriptor,
Graph* graph,
@ -1353,8 +1451,7 @@ Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
pipeline_statistics->BeginPhaseKind("test codegen");
}
Pipeline pipeline(info);
pipeline.data_ = &data;
Pipeline pipeline(&data);
if (data.schedule() == nullptr) {
// TODO(rossberg): Should this really be untyped?
pipeline.RunPrintAndVerify("Machine", true);
@ -1363,26 +1460,17 @@ Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
return pipeline.ScheduleAndGenerateCode(call_descriptor);
}
void Pipeline::InitializeWasmCompilation(
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;
}
// static
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,
@ -1392,25 +1480,16 @@ bool Pipeline::AllocateRegistersForTesting(const RegisterConfiguration* config,
sequence->zone());
ZonePool zone_pool(sequence->isolate()->allocator());
PipelineData data(&zone_pool, &info, sequence);
Pipeline pipeline(&info);
pipeline.data_ = &data;
Pipeline pipeline(&data);
pipeline.data_->InitializeFrameData(nullptr);
pipeline.AllocateRegisters(config, nullptr, run_verifier);
return !data.compilation_failed();
}
Handle<Code> Pipeline::ScheduleAndGenerateCode(
CallDescriptor* call_descriptor) {
if (ScheduleGraph(call_descriptor)) {
return GenerateCode(call_descriptor);
} else {
return Handle<Code>::null();
}
}
bool Pipeline::ScheduleGraph(CallDescriptor* call_descriptor) {
bool Pipeline::ScheduleAndSelectInstructions(Linkage* linkage) {
CallDescriptor* call_descriptor = linkage->GetIncomingDescriptor();
PipelineData* data = this->data_;
DCHECK_NOT_NULL(data);
DCHECK_NOT_NULL(data->graph());
if (data->schedule() == nullptr) Run<ComputeSchedulePhase>();
@ -1425,8 +1504,7 @@ bool Pipeline::ScheduleGraph(CallDescriptor* call_descriptor) {
data->InitializeFrameData(call_descriptor);
// Select and schedule instructions covering the scheduled graph.
Linkage linkage(call_descriptor);
Run<InstructionSelectionPhase>(&linkage);
Run<InstructionSelectionPhase>(linkage);
if (FLAG_trace_turbo && !data->MayHaveUnverifiableGraph()) {
TurboCfgFile tcf(isolate());
@ -1435,8 +1513,10 @@ bool Pipeline::ScheduleGraph(CallDescriptor* call_descriptor) {
}
if (FLAG_trace_turbo) {
std::ostringstream source_position_output;
// 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();
@ -1452,10 +1532,10 @@ bool Pipeline::ScheduleGraph(CallDescriptor* call_descriptor) {
Run<FrameElisionPhase>();
if (data->compilation_failed()) {
info()->AbortOptimization(kNotEnoughVirtualRegistersRegalloc);
EndPhaseKind();
return false;
}
BeginPhaseKind("code generation");
// TODO(mtrofin): move this off to the register allocator.
bool generate_frame_at_start =
data_->sequence()->instruction_blocks().front()->must_construct_frame();
@ -1463,17 +1543,22 @@ bool Pipeline::ScheduleGraph(CallDescriptor* call_descriptor) {
if (FLAG_turbo_jt) {
Run<JumpThreadingPhase>(generate_frame_at_start);
}
EndPhaseKind();
return true;
}
Handle<Code> Pipeline::GenerateCode(CallDescriptor* call_descriptor) {
Handle<Code> Pipeline::GenerateCode(Linkage* linkage) {
PipelineData* data = this->data_;
Linkage linkage(call_descriptor);
BeginPhaseKind("code generation");
// Generate final machine code.
Run<GenerateCodePhase>(&linkage);
Run<GenerateCodePhase>(linkage);
Handle<Code> code = data->code();
if (data->profiler_data() != nullptr) {
if (data->profiler_data()) {
#if ENABLE_DISASSEMBLER
std::ostringstream os;
code->Disassemble(nullptr, os);
@ -1500,7 +1585,7 @@ Handle<Code> Pipeline::GenerateCode(CallDescriptor* call_descriptor) {
#endif // ENABLE_DISASSEMBLER
json_of << "\"}\n],\n";
json_of << "\"nodePositions\":";
json_of << data->source_position_output()->str();
json_of << data->source_position_output();
json_of << "}";
fclose(json_file);
}
@ -1509,9 +1594,21 @@ Handle<Code> Pipeline::GenerateCode(CallDescriptor* call_descriptor) {
<< "Finished compiling method " << info()->GetDebugName().get()
<< " using Turbofan" << std::endl;
}
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,
CallDescriptor* descriptor,
bool run_verifier) {
@ -1525,15 +1622,13 @@ void Pipeline::AllocateRegisters(const RegisterConfiguration* config,
verifier_zone.get(), config, data->sequence());
}
base::SmartArrayPointer<char> debug_name;
#ifdef DEBUG
debug_name = info()->GetDebugName();
data_->sequence()->ValidateEdgeSplitForm();
data_->sequence()->ValidateDeferredBlockEntryPaths();
data_->sequence()->ValidateDeferredBlockExitPaths();
#endif
data->InitializeRegisterAllocationData(config, descriptor, debug_name.get());
data->InitializeRegisterAllocationData(config, descriptor);
if (info()->is_osr()) {
OsrHelper osr_helper(info());
osr_helper.SetupFrame(data->frame());
@ -1603,6 +1698,8 @@ void Pipeline::AllocateRegisters(const RegisterConfiguration* config,
data->DeleteRegisterAllocationZone();
}
CompilationInfo* Pipeline::info() const { return data_->info(); }
Isolate* Pipeline::isolate() const { return info()->isolate(); }
} // namespace compiler

View File

@ -15,7 +15,6 @@ namespace internal {
class CompilationInfo;
class OptimizedCompileJob;
class RegisterConfiguration;
class Zone;
namespace compiler {
@ -26,11 +25,19 @@ class Linkage;
class PipelineData;
class Schedule;
class SourcePositionTable;
class ZonePool;
class Pipeline {
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.
Handle<Code> GenerateCode();
@ -43,6 +50,10 @@ class Pipeline {
Code::Flags flags,
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
// {nullptr}, then compute a new schedule for code generation.
static Handle<Code> GenerateCodeForTesting(CompilationInfo* info,
@ -64,11 +75,13 @@ class Pipeline {
// Returns a new compilation job for the given compilation info.
static OptimizedCompileJob* NewCompilationJob(CompilationInfo* info);
void InitializeWasmCompilation(Zone* pipeline_zone, ZonePool* zone_pool,
Graph* graph,
SourcePositionTable* source_positions);
bool ExecuteWasmCompilation(CallDescriptor* descriptor);
Handle<Code> FinalizeWasmCompilation(CallDescriptor* descriptor);
// Returns a new compilation job for the WebAssembly compilation info.
static OptimizedCompileJob* NewWasmCompilationJob(
CompilationInfo* info, Graph* graph, CallDescriptor* descriptor,
SourcePositionTable* source_positions);
// TODO(mstarzinger, bmeurer): This shouldn't be public!
bool ScheduleAndSelectInstructions(Linkage* linkage);
private:
// Helpers for executing pipeline phases.
@ -80,17 +93,16 @@ class Pipeline {
void Run(Arg0 arg_0, Arg1 arg_1);
void BeginPhaseKind(const char* phase_kind);
void EndPhaseKind();
void RunPrintAndVerify(const char* phase, bool untyped = false);
Handle<Code> ScheduleAndGenerateCode(CallDescriptor* call_descriptor);
void AllocateRegisters(const RegisterConfiguration* config,
CallDescriptor* descriptor, bool run_verifier);
bool ScheduleGraph(CallDescriptor* call_descriptor);
Handle<Code> GenerateCode(CallDescriptor* descriptor);
Handle<Code> ScheduleAndGenerateCode(CallDescriptor* call_descriptor);
CompilationInfo* info() const { return info_; }
CompilationInfo* info() const;
Isolate* isolate() const;
CompilationInfo* const info_;
PipelineData* data_;
PipelineData* const data_;
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);
compiler::ZonePool::Scope pipeline_zone_scope(&zone_pool);
Pipeline pipeline(&info);
pipeline.InitializeWasmCompilation(pipeline_zone_scope.zone(), &zone_pool,
jsgraph->graph(), source_positions);
Handle<Code> code;
if (pipeline.ExecuteWasmCompilation(descriptor)) {
code = pipeline.FinalizeWasmCompilation(descriptor);
} else {
code = Handle<Code>::null();
base::SmartPointer<OptimizedCompileJob> job(Pipeline::NewWasmCompilationJob(
&info, jsgraph->graph(), descriptor, source_positions));
Handle<Code> code = Handle<Code>::null();
if (job->OptimizeGraph() == OptimizedCompileJob::SUCCEEDED &&
job->GenerateCode() == OptimizedCompileJob::SUCCEEDED) {
code = info.code();
}
buffer.Dispose();

View File

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

View File

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

View File

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

View File

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