| // Copyright 2014 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/compiler/pipeline.h" |
| |
| #include <fstream> // NOLINT(readability/streams) |
| #include <sstream> |
| |
| #include "src/base/platform/elapsed-timer.h" |
| #include "src/compiler/ast-graph-builder.h" |
| #include "src/compiler/basic-block-instrumentor.h" |
| #include "src/compiler/change-lowering.h" |
| #include "src/compiler/code-generator.h" |
| #include "src/compiler/control-reducer.h" |
| #include "src/compiler/graph-replay.h" |
| #include "src/compiler/graph-visualizer.h" |
| #include "src/compiler/instruction.h" |
| #include "src/compiler/instruction-selector.h" |
| #include "src/compiler/js-context-specialization.h" |
| #include "src/compiler/js-generic-lowering.h" |
| #include "src/compiler/js-inlining.h" |
| #include "src/compiler/js-typed-lowering.h" |
| #include "src/compiler/machine-operator-reducer.h" |
| #include "src/compiler/pipeline-statistics.h" |
| #include "src/compiler/register-allocator.h" |
| #include "src/compiler/schedule.h" |
| #include "src/compiler/scheduler.h" |
| #include "src/compiler/simplified-lowering.h" |
| #include "src/compiler/simplified-operator-reducer.h" |
| #include "src/compiler/typer.h" |
| #include "src/compiler/value-numbering-reducer.h" |
| #include "src/compiler/verifier.h" |
| #include "src/compiler/zone-pool.h" |
| #include "src/ostreams.h" |
| #include "src/utils.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace compiler { |
| |
| class PipelineData { |
| public: |
| explicit PipelineData(CompilationInfo* info, ZonePool* zone_pool, |
| PipelineStatistics* pipeline_statistics) |
| : isolate_(info->zone()->isolate()), |
| outer_zone_(info->zone()), |
| zone_pool_(zone_pool), |
| pipeline_statistics_(pipeline_statistics), |
| graph_zone_scope_(zone_pool_), |
| graph_zone_(graph_zone_scope_.zone()), |
| graph_(new (graph_zone()) Graph(graph_zone())), |
| source_positions_(new SourcePositionTable(graph())), |
| machine_(new (graph_zone()) MachineOperatorBuilder( |
| kMachPtr, InstructionSelector::SupportedMachineOperatorFlags())), |
| common_(new (graph_zone()) CommonOperatorBuilder(graph_zone())), |
| javascript_(new (graph_zone()) JSOperatorBuilder(graph_zone())), |
| jsgraph_(new (graph_zone()) |
| JSGraph(graph(), common(), javascript(), machine())), |
| typer_(new Typer(graph(), info->context())), |
| schedule_(NULL), |
| instruction_zone_scope_(zone_pool_), |
| instruction_zone_(instruction_zone_scope_.zone()) {} |
| |
| // For machine graph testing only. |
| PipelineData(Graph* graph, Schedule* schedule, ZonePool* zone_pool) |
| : isolate_(graph->zone()->isolate()), |
| outer_zone_(NULL), |
| zone_pool_(zone_pool), |
| pipeline_statistics_(NULL), |
| graph_zone_scope_(zone_pool_), |
| graph_zone_(NULL), |
| graph_(graph), |
| source_positions_(new SourcePositionTable(graph)), |
| machine_(NULL), |
| common_(NULL), |
| javascript_(NULL), |
| jsgraph_(NULL), |
| typer_(NULL), |
| schedule_(schedule), |
| instruction_zone_scope_(zone_pool_), |
| instruction_zone_(instruction_zone_scope_.zone()) {} |
| |
| ~PipelineData() { |
| DeleteInstructionZone(); |
| DeleteGraphZone(); |
| } |
| |
| Isolate* isolate() const { return isolate_; } |
| ZonePool* zone_pool() const { return zone_pool_; } |
| PipelineStatistics* pipeline_statistics() { return pipeline_statistics_; } |
| |
| Zone* graph_zone() const { return graph_zone_; } |
| Graph* graph() const { return graph_; } |
| SourcePositionTable* source_positions() const { |
| return source_positions_.get(); |
| } |
| MachineOperatorBuilder* machine() const { return machine_; } |
| CommonOperatorBuilder* common() const { return common_; } |
| JSOperatorBuilder* javascript() const { return javascript_; } |
| JSGraph* jsgraph() const { return jsgraph_; } |
| Typer* typer() const { return typer_.get(); } |
| Schedule* schedule() const { return schedule_; } |
| void set_schedule(Schedule* schedule) { |
| DCHECK_EQ(NULL, schedule_); |
| schedule_ = schedule; |
| } |
| |
| Zone* instruction_zone() const { return instruction_zone_; } |
| |
| void DeleteGraphZone() { |
| // Destroy objects with destructors first. |
| source_positions_.Reset(NULL); |
| typer_.Reset(NULL); |
| if (graph_zone_ == NULL) return; |
| // Destroy zone and clear pointers. |
| graph_zone_scope_.Destroy(); |
| graph_zone_ = NULL; |
| graph_ = NULL; |
| machine_ = NULL; |
| common_ = NULL; |
| javascript_ = NULL; |
| jsgraph_ = NULL; |
| schedule_ = NULL; |
| } |
| |
| void DeleteInstructionZone() { |
| if (instruction_zone_ == NULL) return; |
| instruction_zone_scope_.Destroy(); |
| instruction_zone_ = NULL; |
| } |
| |
| private: |
| Isolate* isolate_; |
| Zone* outer_zone_; |
| ZonePool* zone_pool_; |
| PipelineStatistics* pipeline_statistics_; |
| |
| ZonePool::Scope graph_zone_scope_; |
| Zone* graph_zone_; |
| // All objects in the following group of fields are allocated in graph_zone_. |
| // They are all set to NULL when the graph_zone_ is destroyed. |
| Graph* graph_; |
| // TODO(dcarney): make this into a ZoneObject. |
| SmartPointer<SourcePositionTable> source_positions_; |
| MachineOperatorBuilder* machine_; |
| CommonOperatorBuilder* common_; |
| JSOperatorBuilder* javascript_; |
| JSGraph* jsgraph_; |
| // TODO(dcarney): make this into a ZoneObject. |
| SmartPointer<Typer> typer_; |
| Schedule* schedule_; |
| |
| // All objects in the following group of fields are allocated in |
| // instruction_zone_. They are all set to NULL when the instruction_zone_ is |
| // destroyed. |
| ZonePool::Scope instruction_zone_scope_; |
| Zone* instruction_zone_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PipelineData); |
| }; |
| |
| |
| static inline bool VerifyGraphs() { |
| #ifdef DEBUG |
| return true; |
| #else |
| return FLAG_turbo_verify; |
| #endif |
| } |
| |
| |
| struct TurboCfgFile : public std::ofstream { |
| explicit TurboCfgFile(Isolate* isolate) |
| : std::ofstream(isolate->GetTurboCfgFileName().c_str(), |
| std::ios_base::app) {} |
| }; |
| |
| |
| void Pipeline::VerifyAndPrintGraph( |
| Graph* graph, const char* phase, bool untyped) { |
| if (FLAG_trace_turbo) { |
| char buffer[256]; |
| Vector<char> filename(buffer, sizeof(buffer)); |
| SmartArrayPointer<char> functionname; |
| if (!info_->shared_info().is_null()) { |
| functionname = info_->shared_info()->DebugName()->ToCString(); |
| if (strlen(functionname.get()) > 0) { |
| SNPrintF(filename, "turbo-%s-%s", functionname.get(), phase); |
| } else { |
| SNPrintF(filename, "turbo-%p-%s", static_cast<void*>(info_), phase); |
| } |
| } else { |
| SNPrintF(filename, "turbo-none-%s", phase); |
| } |
| std::replace(filename.start(), filename.start() + filename.length(), ' ', |
| '_'); |
| |
| char dot_buffer[256]; |
| Vector<char> dot_filename(dot_buffer, sizeof(dot_buffer)); |
| SNPrintF(dot_filename, "%s.dot", filename.start()); |
| FILE* dot_file = base::OS::FOpen(dot_filename.start(), "w+"); |
| OFStream dot_of(dot_file); |
| dot_of << AsDOT(*graph); |
| fclose(dot_file); |
| |
| char json_buffer[256]; |
| Vector<char> json_filename(json_buffer, sizeof(json_buffer)); |
| SNPrintF(json_filename, "%s.json", filename.start()); |
| FILE* json_file = base::OS::FOpen(json_filename.start(), "w+"); |
| OFStream json_of(json_file); |
| json_of << AsJSON(*graph); |
| fclose(json_file); |
| |
| OFStream os(stdout); |
| os << "-- " << phase << " graph printed to file " << filename.start() |
| << "\n"; |
| } |
| if (VerifyGraphs()) { |
| Verifier::Run(graph, |
| FLAG_turbo_types && !untyped ? Verifier::TYPED : Verifier::UNTYPED); |
| } |
| } |
| |
| |
| class AstGraphBuilderWithPositions : public AstGraphBuilder { |
| public: |
| explicit AstGraphBuilderWithPositions(Zone* local_zone, CompilationInfo* info, |
| JSGraph* jsgraph, |
| SourcePositionTable* source_positions) |
| : AstGraphBuilder(local_zone, info, jsgraph), |
| source_positions_(source_positions) {} |
| |
| bool CreateGraph() { |
| SourcePositionTable::Scope pos(source_positions_, |
| SourcePosition::Unknown()); |
| return AstGraphBuilder::CreateGraph(); |
| } |
| |
| #define DEF_VISIT(type) \ |
| virtual void Visit##type(type* node) OVERRIDE { \ |
| SourcePositionTable::Scope pos(source_positions_, \ |
| SourcePosition(node->position())); \ |
| AstGraphBuilder::Visit##type(node); \ |
| } |
| AST_NODE_LIST(DEF_VISIT) |
| #undef DEF_VISIT |
| |
| private: |
| SourcePositionTable* source_positions_; |
| }; |
| |
| |
| static void TraceSchedule(Schedule* schedule) { |
| if (!FLAG_trace_turbo) return; |
| OFStream os(stdout); |
| os << "-- Schedule --------------------------------------\n" << *schedule; |
| } |
| |
| |
| static SmartArrayPointer<char> GetDebugName(CompilationInfo* info) { |
| SmartArrayPointer<char> name; |
| if (info->IsStub()) { |
| if (info->code_stub() != NULL) { |
| CodeStub::Major major_key = info->code_stub()->MajorKey(); |
| const char* major_name = CodeStub::MajorName(major_key, false); |
| size_t len = strlen(major_name); |
| name.Reset(new char[len]); |
| memcpy(name.get(), major_name, len); |
| } |
| } else { |
| AllowHandleDereference allow_deref; |
| name = info->function()->debug_name()->ToCString(); |
| } |
| return name; |
| } |
| |
| |
| Handle<Code> Pipeline::GenerateCode() { |
| // This list must be kept in sync with DONT_TURBOFAN_NODE in ast.cc. |
| if (info()->function()->dont_optimize_reason() == kTryCatchStatement || |
| info()->function()->dont_optimize_reason() == kTryFinallyStatement || |
| // TODO(turbofan): Make ES6 for-of work and remove this bailout. |
| info()->function()->dont_optimize_reason() == kForOfStatement || |
| // TODO(turbofan): Make super work and remove this bailout. |
| info()->function()->dont_optimize_reason() == kSuperReference || |
| // TODO(turbofan): Make class literals work and remove this bailout. |
| info()->function()->dont_optimize_reason() == kClassLiteral || |
| // TODO(turbofan): Make OSR work and remove this bailout. |
| info()->is_osr()) { |
| return Handle<Code>::null(); |
| } |
| |
| ZonePool zone_pool(isolate()); |
| |
| SmartPointer<PipelineStatistics> pipeline_statistics; |
| if (FLAG_turbo_stats) { |
| pipeline_statistics.Reset(new PipelineStatistics(info(), &zone_pool)); |
| pipeline_statistics->BeginPhaseKind("graph creation"); |
| } |
| |
| if (FLAG_trace_turbo) { |
| OFStream os(stdout); |
| os << "---------------------------------------------------\n" |
| << "Begin compiling method " << GetDebugName(info()).get() |
| << " using Turbofan" << std::endl; |
| TurboCfgFile tcf(isolate()); |
| tcf << AsC1VCompilation(info()); |
| } |
| |
| // Initialize the graph and builders. |
| PipelineData data(info(), &zone_pool, pipeline_statistics.get()); |
| |
| data.source_positions()->AddDecorator(); |
| |
| Node* context_node; |
| { |
| PhaseScope phase_scope(pipeline_statistics.get(), "graph builder"); |
| ZonePool::Scope zone_scope(data.zone_pool()); |
| AstGraphBuilderWithPositions graph_builder( |
| zone_scope.zone(), info(), data.jsgraph(), data.source_positions()); |
| graph_builder.CreateGraph(); |
| context_node = graph_builder.GetFunctionContext(); |
| } |
| |
| VerifyAndPrintGraph(data.graph(), "Initial untyped", true); |
| |
| { |
| PhaseScope phase_scope(pipeline_statistics.get(), |
| "early control reduction"); |
| SourcePositionTable::Scope pos(data.source_positions(), |
| SourcePosition::Unknown()); |
| ZonePool::Scope zone_scope(data.zone_pool()); |
| ControlReducer::ReduceGraph(zone_scope.zone(), data.jsgraph(), |
| data.common()); |
| |
| VerifyAndPrintGraph(data.graph(), "Early Control reduced", true); |
| } |
| |
| if (info()->is_context_specializing()) { |
| SourcePositionTable::Scope pos(data.source_positions(), |
| SourcePosition::Unknown()); |
| // Specialize the code to the context as aggressively as possible. |
| JSContextSpecializer spec(info(), data.jsgraph(), context_node); |
| spec.SpecializeToContext(); |
| VerifyAndPrintGraph(data.graph(), "Context specialized", true); |
| } |
| |
| if (info()->is_inlining_enabled()) { |
| PhaseScope phase_scope(pipeline_statistics.get(), "inlining"); |
| SourcePositionTable::Scope pos(data.source_positions(), |
| SourcePosition::Unknown()); |
| ZonePool::Scope zone_scope(data.zone_pool()); |
| JSInliner inliner(zone_scope.zone(), info(), data.jsgraph()); |
| inliner.Inline(); |
| VerifyAndPrintGraph(data.graph(), "Inlined", true); |
| } |
| |
| // Print a replay of the initial graph. |
| if (FLAG_print_turbo_replay) { |
| GraphReplayPrinter::PrintReplay(data.graph()); |
| } |
| |
| // Bailout here in case target architecture is not supported. |
| if (!SupportedTarget()) return Handle<Code>::null(); |
| |
| if (info()->is_typing_enabled()) { |
| { |
| // Type the graph. |
| PhaseScope phase_scope(pipeline_statistics.get(), "typer"); |
| data.typer()->Run(); |
| VerifyAndPrintGraph(data.graph(), "Typed"); |
| } |
| } |
| |
| if (!pipeline_statistics.is_empty()) { |
| pipeline_statistics->BeginPhaseKind("lowering"); |
| } |
| |
| if (info()->is_typing_enabled()) { |
| { |
| // Lower JSOperators where we can determine types. |
| PhaseScope phase_scope(pipeline_statistics.get(), "typed lowering"); |
| SourcePositionTable::Scope pos(data.source_positions(), |
| SourcePosition::Unknown()); |
| ValueNumberingReducer vn_reducer(data.graph_zone()); |
| JSTypedLowering lowering(data.jsgraph()); |
| SimplifiedOperatorReducer simple_reducer(data.jsgraph()); |
| GraphReducer graph_reducer(data.graph()); |
| graph_reducer.AddReducer(&vn_reducer); |
| graph_reducer.AddReducer(&lowering); |
| graph_reducer.AddReducer(&simple_reducer); |
| graph_reducer.ReduceGraph(); |
| |
| VerifyAndPrintGraph(data.graph(), "Lowered typed"); |
| } |
| { |
| // Lower simplified operators and insert changes. |
| PhaseScope phase_scope(pipeline_statistics.get(), "simplified lowering"); |
| SourcePositionTable::Scope pos(data.source_positions(), |
| SourcePosition::Unknown()); |
| SimplifiedLowering lowering(data.jsgraph()); |
| lowering.LowerAllNodes(); |
| ValueNumberingReducer vn_reducer(data.graph_zone()); |
| SimplifiedOperatorReducer simple_reducer(data.jsgraph()); |
| GraphReducer graph_reducer(data.graph()); |
| graph_reducer.AddReducer(&vn_reducer); |
| graph_reducer.AddReducer(&simple_reducer); |
| graph_reducer.ReduceGraph(); |
| |
| VerifyAndPrintGraph(data.graph(), "Lowered simplified"); |
| } |
| { |
| // Lower changes that have been inserted before. |
| PhaseScope phase_scope(pipeline_statistics.get(), "change lowering"); |
| SourcePositionTable::Scope pos(data.source_positions(), |
| SourcePosition::Unknown()); |
| Linkage linkage(data.graph_zone(), info()); |
| ValueNumberingReducer vn_reducer(data.graph_zone()); |
| SimplifiedOperatorReducer simple_reducer(data.jsgraph()); |
| ChangeLowering lowering(data.jsgraph(), &linkage); |
| MachineOperatorReducer mach_reducer(data.jsgraph()); |
| GraphReducer graph_reducer(data.graph()); |
| // TODO(titzer): Figure out if we should run all reducers at once here. |
| graph_reducer.AddReducer(&vn_reducer); |
| graph_reducer.AddReducer(&simple_reducer); |
| graph_reducer.AddReducer(&lowering); |
| graph_reducer.AddReducer(&mach_reducer); |
| graph_reducer.ReduceGraph(); |
| |
| // TODO(jarin, rossberg): Remove UNTYPED once machine typing works. |
| VerifyAndPrintGraph(data.graph(), "Lowered changes", true); |
| } |
| |
| { |
| PhaseScope phase_scope(pipeline_statistics.get(), |
| "late control reduction"); |
| SourcePositionTable::Scope pos(data.source_positions(), |
| SourcePosition::Unknown()); |
| ZonePool::Scope zone_scope(data.zone_pool()); |
| ControlReducer::ReduceGraph(zone_scope.zone(), data.jsgraph(), |
| data.common()); |
| |
| VerifyAndPrintGraph(data.graph(), "Late Control reduced"); |
| } |
| } |
| |
| { |
| // Lower any remaining generic JSOperators. |
| PhaseScope phase_scope(pipeline_statistics.get(), "generic lowering"); |
| SourcePositionTable::Scope pos(data.source_positions(), |
| SourcePosition::Unknown()); |
| JSGenericLowering lowering(info(), data.jsgraph()); |
| GraphReducer graph_reducer(data.graph()); |
| graph_reducer.AddReducer(&lowering); |
| graph_reducer.ReduceGraph(); |
| |
| // TODO(jarin, rossberg): Remove UNTYPED once machine typing works. |
| VerifyAndPrintGraph(data.graph(), "Lowered generic", true); |
| } |
| |
| if (!pipeline_statistics.is_empty()) { |
| pipeline_statistics->BeginPhaseKind("block building"); |
| } |
| |
| data.source_positions()->RemoveDecorator(); |
| |
| // Compute a schedule. |
| ComputeSchedule(&data); |
| |
| Handle<Code> code = Handle<Code>::null(); |
| { |
| // Generate optimized code. |
| Linkage linkage(data.instruction_zone(), info()); |
| code = GenerateCode(&linkage, &data); |
| info()->SetCode(code); |
| } |
| |
| // Print optimized code. |
| v8::internal::CodeGenerator::PrintCode(code, info()); |
| |
| if (FLAG_trace_turbo) { |
| OFStream os(stdout); |
| os << "--------------------------------------------------\n" |
| << "Finished compiling method " << GetDebugName(info()).get() |
| << " using Turbofan" << std::endl; |
| } |
| |
| return code; |
| } |
| |
| |
| void Pipeline::ComputeSchedule(PipelineData* data) { |
| PhaseScope phase_scope(data->pipeline_statistics(), "scheduling"); |
| Schedule* schedule = |
| Scheduler::ComputeSchedule(data->zone_pool(), data->graph()); |
| TraceSchedule(schedule); |
| if (VerifyGraphs()) ScheduleVerifier::Run(schedule); |
| data->set_schedule(schedule); |
| } |
| |
| |
| Handle<Code> Pipeline::GenerateCodeForMachineGraph(Linkage* linkage, |
| Graph* graph, |
| Schedule* schedule) { |
| ZonePool zone_pool(isolate()); |
| CHECK(SupportedBackend()); |
| PipelineData data(graph, schedule, &zone_pool); |
| if (schedule == NULL) { |
| // TODO(rossberg): Should this really be untyped? |
| VerifyAndPrintGraph(graph, "Machine", true); |
| ComputeSchedule(&data); |
| } else { |
| TraceSchedule(schedule); |
| } |
| |
| Handle<Code> code = GenerateCode(linkage, &data); |
| #if ENABLE_DISASSEMBLER |
| if (!code.is_null() && FLAG_print_opt_code) { |
| CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); |
| OFStream os(tracing_scope.file()); |
| code->Disassemble("test code", os); |
| } |
| #endif |
| return code; |
| } |
| |
| |
| Handle<Code> Pipeline::GenerateCode(Linkage* linkage, PipelineData* data) { |
| DCHECK_NOT_NULL(linkage); |
| DCHECK_NOT_NULL(data->graph()); |
| DCHECK_NOT_NULL(data->schedule()); |
| CHECK(SupportedBackend()); |
| |
| BasicBlockProfiler::Data* profiler_data = NULL; |
| if (FLAG_turbo_profiling) { |
| profiler_data = BasicBlockInstrumentor::Instrument(info(), data->graph(), |
| data->schedule()); |
| } |
| |
| InstructionSequence sequence(data->instruction_zone(), data->schedule()); |
| |
| // Select and schedule instructions covering the scheduled graph. |
| { |
| PhaseScope phase_scope(data->pipeline_statistics(), "select instructions"); |
| ZonePool::Scope zone_scope(data->zone_pool()); |
| InstructionSelector selector(zone_scope.zone(), data->graph(), linkage, |
| &sequence, data->schedule(), |
| data->source_positions()); |
| selector.SelectInstructions(); |
| } |
| |
| if (FLAG_trace_turbo) { |
| OFStream os(stdout); |
| os << "----- Instruction sequence before register allocation -----\n" |
| << sequence; |
| TurboCfgFile tcf(isolate()); |
| tcf << AsC1V("CodeGen", data->schedule(), data->source_positions(), |
| &sequence); |
| } |
| |
| data->DeleteGraphZone(); |
| |
| if (data->pipeline_statistics() != NULL) { |
| data->pipeline_statistics()->BeginPhaseKind("register allocation"); |
| } |
| |
| // Allocate registers. |
| Frame frame; |
| { |
| int node_count = sequence.VirtualRegisterCount(); |
| if (node_count > UnallocatedOperand::kMaxVirtualRegisters) { |
| info()->AbortOptimization(kNotEnoughVirtualRegistersForValues); |
| return Handle<Code>::null(); |
| } |
| ZonePool::Scope zone_scope(data->zone_pool()); |
| |
| SmartArrayPointer<char> debug_name; |
| #ifdef DEBUG |
| debug_name = GetDebugName(info()); |
| #endif |
| |
| |
| RegisterAllocator allocator(RegisterAllocator::PlatformConfig(), |
| zone_scope.zone(), &frame, &sequence, |
| debug_name.get()); |
| if (!allocator.Allocate(data->pipeline_statistics())) { |
| info()->AbortOptimization(kNotEnoughVirtualRegistersRegalloc); |
| return Handle<Code>::null(); |
| } |
| if (FLAG_trace_turbo) { |
| TurboCfgFile tcf(isolate()); |
| tcf << AsC1VAllocator("CodeGen", &allocator); |
| } |
| } |
| |
| if (FLAG_trace_turbo) { |
| OFStream os(stdout); |
| os << "----- Instruction sequence after register allocation -----\n" |
| << sequence; |
| } |
| |
| if (data->pipeline_statistics() != NULL) { |
| data->pipeline_statistics()->BeginPhaseKind("code generation"); |
| } |
| |
| // Generate native sequence. |
| Handle<Code> code; |
| { |
| PhaseScope phase_scope(data->pipeline_statistics(), "generate code"); |
| CodeGenerator generator(&frame, linkage, &sequence, info()); |
| code = generator.GenerateCode(); |
| } |
| if (profiler_data != NULL) { |
| #if ENABLE_DISASSEMBLER |
| std::ostringstream os; |
| code->Disassemble(NULL, os); |
| profiler_data->SetCode(&os); |
| #endif |
| } |
| return code; |
| } |
| |
| |
| void Pipeline::SetUp() { |
| InstructionOperand::SetUpCaches(); |
| } |
| |
| |
| void Pipeline::TearDown() { |
| InstructionOperand::TearDownCaches(); |
| } |
| |
| } // namespace compiler |
| } // namespace internal |
| } // namespace v8 |