| Index: runtime/vm/compiler.cc
|
| diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
|
| index a0f01ac3b62f97618d0b08c754ed0fdd5604eb01..55c44922ddbdb9b758f6a4cdda2ca9b42c6a892d 100644
|
| --- a/runtime/vm/compiler.cc
|
| +++ b/runtime/vm/compiler.cc
|
| @@ -16,6 +16,7 @@
|
| #include "vm/dart_entry.h"
|
| #include "vm/debugger.h"
|
| #include "vm/deopt_instructions.h"
|
| +#include "vm/disassembler.h"
|
| #include "vm/exceptions.h"
|
| #include "vm/flags.h"
|
| #include "vm/flow_graph.h"
|
| @@ -31,10 +32,10 @@
|
| #include "vm/object_store.h"
|
| #include "vm/os.h"
|
| #include "vm/parser.h"
|
| +#include "vm/precompiler.h"
|
| #include "vm/redundancy_elimination.h"
|
| #include "vm/regexp_parser.h"
|
| #include "vm/regexp_assembler.h"
|
| -#include "vm/scanner.h"
|
| #include "vm/symbols.h"
|
| #include "vm/tags.h"
|
| #include "vm/thread_registry.h"
|
| @@ -66,105 +67,76 @@ DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from ssa compiler.");
|
| DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining");
|
| DEFINE_FLAG(bool, verify_compiler, false,
|
| "Enable compiler verification assertions");
|
| -DEFINE_FLAG(int, max_speculative_inlining_attempts, 1,
|
| - "Max number of attempts with speculative inlining (precompilation only)");
|
|
|
| DECLARE_FLAG(bool, background_compilation);
|
| DECLARE_FLAG(bool, huge_method_cutoff_in_code_size);
|
| DECLARE_FLAG(bool, load_deferred_eagerly);
|
| DECLARE_FLAG(bool, trace_failed_optimization_attempts);
|
| -DECLARE_FLAG(bool, trace_inlining_intervals);
|
| DECLARE_FLAG(bool, trace_irregexp);
|
| DECLARE_FLAG(bool, precompilation);
|
|
|
|
|
| #ifndef DART_PRECOMPILED_RUNTIME
|
|
|
| -// TODO(zerny): Factor out unoptimizing/optimizing pipelines and remove
|
| -// separate helpers functions & `optimizing` args.
|
| -class CompilationPipeline : public ZoneAllocated {
|
| - public:
|
| - static CompilationPipeline* New(Zone* zone, const Function& function);
|
| -
|
| - virtual void ParseFunction(ParsedFunction* parsed_function) = 0;
|
| - virtual FlowGraph* BuildFlowGraph(
|
| - Zone* zone,
|
| - ParsedFunction* parsed_function,
|
| - const ZoneGrowableArray<const ICData*>& ic_data_array,
|
| - intptr_t osr_id) = 0;
|
| - virtual void FinalizeCompilation() = 0;
|
| - virtual ~CompilationPipeline() { }
|
| -};
|
| -
|
| +void DartCompilationPipeline::ParseFunction(ParsedFunction* parsed_function) {
|
| + Parser::ParseFunction(parsed_function);
|
| + parsed_function->AllocateVariables();
|
| +}
|
|
|
| -class DartCompilationPipeline : public CompilationPipeline {
|
| - public:
|
| - virtual void ParseFunction(ParsedFunction* parsed_function) {
|
| - Parser::ParseFunction(parsed_function);
|
| - parsed_function->AllocateVariables();
|
| - }
|
|
|
| - virtual FlowGraph* BuildFlowGraph(
|
| - Zone* zone,
|
| - ParsedFunction* parsed_function,
|
| - const ZoneGrowableArray<const ICData*>& ic_data_array,
|
| - intptr_t osr_id) {
|
| - // Build the flow graph.
|
| - FlowGraphBuilder builder(*parsed_function,
|
| - ic_data_array,
|
| - NULL, // NULL = not inlining.
|
| - osr_id);
|
| -
|
| - return builder.BuildGraph();
|
| - }
|
| +FlowGraph* DartCompilationPipeline::BuildFlowGraph(
|
| + Zone* zone,
|
| + ParsedFunction* parsed_function,
|
| + const ZoneGrowableArray<const ICData*>& ic_data_array,
|
| + intptr_t osr_id) {
|
| + // Build the flow graph.
|
| + FlowGraphBuilder builder(*parsed_function,
|
| + ic_data_array,
|
| + NULL, // NULL = not inlining.
|
| + osr_id);
|
|
|
| - virtual void FinalizeCompilation() { }
|
| -};
|
| + return builder.BuildGraph();
|
| +}
|
|
|
|
|
| -class IrregexpCompilationPipeline : public CompilationPipeline {
|
| - public:
|
| - IrregexpCompilationPipeline() : backtrack_goto_(NULL) { }
|
| +void DartCompilationPipeline::FinalizeCompilation() { }
|
|
|
| - virtual void ParseFunction(ParsedFunction* parsed_function) {
|
| - RegExpParser::ParseFunction(parsed_function);
|
| - // Variables are allocated after compilation.
|
| - }
|
|
|
| - virtual FlowGraph* BuildFlowGraph(
|
| - Zone* zone,
|
| - ParsedFunction* parsed_function,
|
| - const ZoneGrowableArray<const ICData*>& ic_data_array,
|
| - intptr_t osr_id) {
|
| - // Compile to the dart IR.
|
| - RegExpEngine::CompilationResult result =
|
| - RegExpEngine::CompileIR(parsed_function->regexp_compile_data(),
|
| - parsed_function,
|
| - ic_data_array);
|
| - backtrack_goto_ = result.backtrack_goto;
|
| -
|
| - // Allocate variables now that we know the number of locals.
|
| - parsed_function->AllocateIrregexpVariables(result.num_stack_locals);
|
| -
|
| - // Build the flow graph.
|
| - FlowGraphBuilder builder(*parsed_function,
|
| - ic_data_array,
|
| - NULL, // NULL = not inlining.
|
| - osr_id);
|
| -
|
| - return new(zone) FlowGraph(*parsed_function,
|
| - result.graph_entry,
|
| - result.num_blocks);
|
| - }
|
| -
|
| - virtual void FinalizeCompilation() {
|
| - backtrack_goto_->ComputeOffsetTable();
|
| - }
|
| +void IrregexpCompilationPipeline::ParseFunction(
|
| + ParsedFunction* parsed_function) {
|
| + RegExpParser::ParseFunction(parsed_function);
|
| + // Variables are allocated after compilation.
|
| +}
|
|
|
| - private:
|
| - IndirectGotoInstr* backtrack_goto_;
|
| -};
|
| +FlowGraph* IrregexpCompilationPipeline::BuildFlowGraph(
|
| + Zone* zone,
|
| + ParsedFunction* parsed_function,
|
| + const ZoneGrowableArray<const ICData*>& ic_data_array,
|
| + intptr_t osr_id) {
|
| + // Compile to the dart IR.
|
| + RegExpEngine::CompilationResult result =
|
| + RegExpEngine::CompileIR(parsed_function->regexp_compile_data(),
|
| + parsed_function,
|
| + ic_data_array);
|
| + backtrack_goto_ = result.backtrack_goto;
|
| +
|
| + // Allocate variables now that we know the number of locals.
|
| + parsed_function->AllocateIrregexpVariables(result.num_stack_locals);
|
| +
|
| + // Build the flow graph.
|
| + FlowGraphBuilder builder(*parsed_function,
|
| + ic_data_array,
|
| + NULL, // NULL = not inlining.
|
| + osr_id);
|
| +
|
| + return new(zone) FlowGraph(*parsed_function,
|
| + result.graph_entry,
|
| + result.num_blocks);
|
| +}
|
|
|
| +void IrregexpCompilationPipeline::FinalizeCompilation() {
|
| + backtrack_goto_->ComputeOffsetTable();
|
| +}
|
|
|
| CompilationPipeline* CompilationPipeline::New(Zone* zone,
|
| const Function& function) {
|
| @@ -445,6 +417,7 @@ void CompileParsedFunctionHelper::FinalizeCompilation(
|
| Assembler* assembler,
|
| FlowGraphCompiler* graph_compiler,
|
| FlowGraph* flow_graph) {
|
| + ASSERT(!FLAG_precompilation);
|
| const Function& function = parsed_function()->function();
|
| Zone* const zone = thread()->zone();
|
|
|
| @@ -543,35 +516,31 @@ void CompileParsedFunctionHelper::FinalizeCompilation(
|
| }
|
|
|
| // Register code with the classes it depends on because of CHA and
|
| - // fields it depends on because of store guards, unless we cannot
|
| - // deopt.
|
| - if (!FLAG_precompilation) {
|
| - // Deoptimize field dependent code first, before registering
|
| - // this yet uninstalled code as dependent on a field.
|
| - // TODO(srdjan): Debugging dart2js crashes;
|
| - // FlowGraphOptimizer::VisitStoreInstanceField populates
|
| - // deoptimize_dependent_code() list, currently disabled.
|
| - for (intptr_t i = 0;
|
| - i < flow_graph->deoptimize_dependent_code().length();
|
| - i++) {
|
| - const Field* field = flow_graph->deoptimize_dependent_code()[i];
|
| - field->DeoptimizeDependentCode();
|
| - }
|
| - for (intptr_t i = 0;
|
| - i < thread()->cha()->leaf_classes().length();
|
| - ++i) {
|
| - thread()->cha()->leaf_classes()[i]->RegisterCHACode(code);
|
| - }
|
| - for (intptr_t i = 0;
|
| - i < flow_graph->guarded_fields()->length();
|
| - i++) {
|
| - const Field* field = (*flow_graph->guarded_fields())[i];
|
| - field->RegisterDependentCode(code);
|
| - }
|
| + // fields it depends on because of store guards.
|
| + // Deoptimize field dependent code first, before registering
|
| + // this yet uninstalled code as dependent on a field.
|
| + // TODO(srdjan): Debugging dart2js crashes;
|
| + // FlowGraphOptimizer::VisitStoreInstanceField populates
|
| + // deoptimize_dependent_code() list, currently disabled.
|
| + for (intptr_t i = 0;
|
| + i < flow_graph->deoptimize_dependent_code().length();
|
| + i++) {
|
| + const Field* field = flow_graph->deoptimize_dependent_code()[i];
|
| + field->DeoptimizeDependentCode();
|
| + }
|
| + for (intptr_t i = 0;
|
| + i < thread()->cha()->leaf_classes().length();
|
| + ++i) {
|
| + thread()->cha()->leaf_classes()[i]->RegisterCHACode(code);
|
| + }
|
| + for (intptr_t i = 0;
|
| + i < flow_graph->guarded_fields()->length();
|
| + i++) {
|
| + const Field* field = (*flow_graph->guarded_fields())[i];
|
| + field->RegisterDependentCode(code);
|
| }
|
| } else { // not optimized.
|
| - if (!FLAG_precompilation &&
|
| - (function.ic_data_array() == Array::null())) {
|
| + if (function.ic_data_array() == Array::null()) {
|
| function.SaveICDataMap(
|
| graph_compiler->deopt_id_to_ic_data(),
|
| Array::Handle(zone, graph_compiler->edge_counters_array()));
|
| @@ -594,6 +563,7 @@ void CompileParsedFunctionHelper::FinalizeCompilation(
|
| // If optimized_result_code is not NULL then it is caller's responsibility
|
| // to install code.
|
| bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
|
| + ASSERT(!FLAG_precompilation);
|
| const Function& function = parsed_function()->function();
|
| if (optimized() && !function.IsOptimizable()) {
|
| return false;
|
| @@ -613,9 +583,7 @@ bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
|
| bool done = false;
|
| // volatile because the variable may be clobbered by a longjmp.
|
| volatile bool use_far_branches = false;
|
| - volatile bool use_speculative_inlining =
|
| - FLAG_max_speculative_inlining_attempts > 0;
|
| - GrowableArray<intptr_t> inlining_black_list;
|
| + const bool use_speculative_inlining = false;
|
|
|
| while (!done) {
|
| const intptr_t prev_deopt_id = thread()->deopt_id();
|
| @@ -724,16 +692,7 @@ bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
|
|
|
| FlowGraphOptimizer optimizer(flow_graph,
|
| use_speculative_inlining,
|
| - &inlining_black_list);
|
| - if (FLAG_precompilation) {
|
| - optimizer.PopulateWithICData();
|
| -
|
| - optimizer.ApplyClassIds();
|
| - DEBUG_ASSERT(flow_graph->VerifyUseLists());
|
| -
|
| - FlowGraphTypePropagator::Propagate(flow_graph);
|
| - DEBUG_ASSERT(flow_graph->VerifyUseLists());
|
| - }
|
| + NULL);
|
| optimizer.ApplyICData();
|
| DEBUG_ASSERT(flow_graph->VerifyUseLists());
|
|
|
| @@ -762,7 +721,7 @@ bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
|
| &inline_id_to_function,
|
| &caller_inline_id,
|
| use_speculative_inlining,
|
| - &inlining_black_list);
|
| + NULL);
|
| inliner.Inline();
|
| // Use lists are maintained and validated by the inliner.
|
| DEBUG_ASSERT(flow_graph->VerifyUseLists());
|
| @@ -1085,25 +1044,8 @@ bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
|
| ASSERT(!use_far_branches);
|
| use_far_branches = true;
|
| } else if (error.raw() == Object::speculative_inlining_error().raw()) {
|
| - // The return value of setjmp is the deopt id of the check instruction
|
| - // that caused the bailout.
|
| - done = false;
|
| -#if defined(DEBUG)
|
| - ASSERT(FLAG_precompilation);
|
| - ASSERT(use_speculative_inlining);
|
| - for (intptr_t i = 0; i < inlining_black_list.length(); ++i) {
|
| - ASSERT(inlining_black_list[i] != val);
|
| - }
|
| -#endif
|
| - inlining_black_list.Add(val);
|
| - const intptr_t max_attempts = FLAG_max_speculative_inlining_attempts;
|
| - if (inlining_black_list.length() >= max_attempts) {
|
| - use_speculative_inlining = false;
|
| - if (FLAG_trace_compiler || FLAG_trace_optimizing_compiler) {
|
| - THR_Print("Disabled speculative inlining after %" Pd " attempts.\n",
|
| - inlining_black_list.length());
|
| - }
|
| - }
|
| + // Can only happen with precompilation.
|
| + UNREACHABLE();
|
| } else {
|
| // If the error isn't due to an out of range branch offset, we don't
|
| // try again (done = true), and indicate that we did not finish
|
| @@ -1128,147 +1070,6 @@ bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
|
| }
|
|
|
|
|
| -static void DisassembleCode(const Function& function, bool optimized) {
|
| - const char* function_fullname = function.ToFullyQualifiedCString();
|
| - THR_Print("Code for %sfunction '%s' {\n",
|
| - optimized ? "optimized " : "",
|
| - function_fullname);
|
| - const Code& code = Code::Handle(function.CurrentCode());
|
| - code.Disassemble();
|
| - THR_Print("}\n");
|
| -
|
| - THR_Print("Pointer offsets for function: {\n");
|
| - // Pointer offsets are stored in descending order.
|
| - Object& obj = Object::Handle();
|
| - for (intptr_t i = code.pointer_offsets_length() - 1; i >= 0; i--) {
|
| - const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint();
|
| - obj = *reinterpret_cast<RawObject**>(addr);
|
| - THR_Print(" %d : %#" Px " '%s'\n",
|
| - code.GetPointerOffsetAt(i), addr, obj.ToCString());
|
| - }
|
| - THR_Print("}\n");
|
| -
|
| - THR_Print("PC Descriptors for function '%s' {\n", function_fullname);
|
| - PcDescriptors::PrintHeaderString();
|
| - const PcDescriptors& descriptors =
|
| - PcDescriptors::Handle(code.pc_descriptors());
|
| - THR_Print("%s}\n", descriptors.ToCString());
|
| -
|
| - uword start = Instructions::Handle(code.instructions()).EntryPoint();
|
| - const Array& deopt_table = Array::Handle(code.deopt_info_array());
|
| - intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table);
|
| - if (deopt_table_length > 0) {
|
| - THR_Print("DeoptInfo: {\n");
|
| - Smi& offset = Smi::Handle();
|
| - TypedData& info = TypedData::Handle();
|
| - Smi& reason_and_flags = Smi::Handle();
|
| - for (intptr_t i = 0; i < deopt_table_length; ++i) {
|
| - DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason_and_flags);
|
| - const intptr_t reason =
|
| - DeoptTable::ReasonField::decode(reason_and_flags.Value());
|
| - ASSERT((0 <= reason) && (reason < ICData::kDeoptNumReasons));
|
| - THR_Print("%4" Pd ": 0x%" Px " %s (%s)\n",
|
| - i,
|
| - start + offset.Value(),
|
| - DeoptInfo::ToCString(deopt_table, info),
|
| - DeoptReasonToCString(
|
| - static_cast<ICData::DeoptReasonId>(reason)));
|
| - }
|
| - THR_Print("}\n");
|
| - }
|
| -
|
| - const ObjectPool& object_pool = ObjectPool::Handle(code.GetObjectPool());
|
| - object_pool.DebugPrint();
|
| -
|
| - THR_Print("Stackmaps for function '%s' {\n", function_fullname);
|
| - if (code.stackmaps() != Array::null()) {
|
| - const Array& stackmap_table = Array::Handle(code.stackmaps());
|
| - Stackmap& map = Stackmap::Handle();
|
| - for (intptr_t i = 0; i < stackmap_table.Length(); ++i) {
|
| - map ^= stackmap_table.At(i);
|
| - THR_Print("%s\n", map.ToCString());
|
| - }
|
| - }
|
| - THR_Print("}\n");
|
| -
|
| - THR_Print("Variable Descriptors for function '%s' {\n",
|
| - function_fullname);
|
| - const LocalVarDescriptors& var_descriptors =
|
| - LocalVarDescriptors::Handle(code.GetLocalVarDescriptors());
|
| - intptr_t var_desc_length =
|
| - var_descriptors.IsNull() ? 0 : var_descriptors.Length();
|
| - String& var_name = String::Handle();
|
| - for (intptr_t i = 0; i < var_desc_length; i++) {
|
| - var_name = var_descriptors.GetName(i);
|
| - RawLocalVarDescriptors::VarInfo var_info;
|
| - var_descriptors.GetInfo(i, &var_info);
|
| - const int8_t kind = var_info.kind();
|
| - if (kind == RawLocalVarDescriptors::kSavedCurrentContext) {
|
| - THR_Print(" saved current CTX reg offset %d\n", var_info.index());
|
| - } else {
|
| - if (kind == RawLocalVarDescriptors::kContextLevel) {
|
| - THR_Print(" context level %d scope %d", var_info.index(),
|
| - var_info.scope_id);
|
| - } else if (kind == RawLocalVarDescriptors::kStackVar) {
|
| - THR_Print(" stack var '%s' offset %d",
|
| - var_name.ToCString(), var_info.index());
|
| - } else {
|
| - ASSERT(kind == RawLocalVarDescriptors::kContextVar);
|
| - THR_Print(" context var '%s' level %d offset %d",
|
| - var_name.ToCString(), var_info.scope_id, var_info.index());
|
| - }
|
| - THR_Print(" (valid %s-%s)\n", var_info.begin_pos.ToCString(),
|
| - var_info.end_pos.ToCString());
|
| - }
|
| - }
|
| - THR_Print("}\n");
|
| -
|
| - THR_Print("Exception Handlers for function '%s' {\n", function_fullname);
|
| - const ExceptionHandlers& handlers =
|
| - ExceptionHandlers::Handle(code.exception_handlers());
|
| - THR_Print("%s}\n", handlers.ToCString());
|
| -
|
| - {
|
| - THR_Print("Static call target functions {\n");
|
| - const Array& table = Array::Handle(code.static_calls_target_table());
|
| - Smi& offset = Smi::Handle();
|
| - Function& function = Function::Handle();
|
| - Code& code = Code::Handle();
|
| - for (intptr_t i = 0; i < table.Length();
|
| - i += Code::kSCallTableEntryLength) {
|
| - offset ^= table.At(i + Code::kSCallTableOffsetEntry);
|
| - function ^= table.At(i + Code::kSCallTableFunctionEntry);
|
| - code ^= table.At(i + Code::kSCallTableCodeEntry);
|
| - if (function.IsNull()) {
|
| - Class& cls = Class::Handle();
|
| - cls ^= code.owner();
|
| - if (cls.IsNull()) {
|
| - const String& code_name = String::Handle(code.Name());
|
| - THR_Print(" 0x%" Px ": %s, %p\n",
|
| - start + offset.Value(),
|
| - code_name.ToCString(),
|
| - code.raw());
|
| - } else {
|
| - THR_Print(" 0x%" Px ": allocation stub for %s, %p\n",
|
| - start + offset.Value(),
|
| - cls.ToCString(),
|
| - code.raw());
|
| - }
|
| - } else {
|
| - THR_Print(" 0x%" Px ": %s, %p\n",
|
| - start + offset.Value(),
|
| - function.ToFullyQualifiedCString(),
|
| - code.raw());
|
| - }
|
| - }
|
| - THR_Print("}\n");
|
| - }
|
| - if (optimized && FLAG_trace_inlining_intervals) {
|
| - code.DumpInlinedIntervals();
|
| - }
|
| -}
|
| -
|
| -
|
| #if defined(DEBUG)
|
| // Verifies that the inliner is always in the list of inlined functions.
|
| // If this fails run with --trace-inlining-intervals to get more information.
|
| @@ -1294,11 +1095,7 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline,
|
| const Function& function,
|
| bool optimized,
|
| intptr_t osr_id) {
|
| - // Check that we optimize if 'FLAG_precompilation' is set to true,
|
| - // except if the function is marked as not optimizable.
|
| - ASSERT(!function.IsOptimizable() ||
|
| - !FLAG_precompilation || optimized);
|
| - ASSERT(!FLAG_precompilation || !function.HasCode());
|
| + ASSERT(!FLAG_precompilation);
|
| LongJumpScope jump;
|
| if (setjmp(*jump.Set()) == 0) {
|
| Thread* const thread = Thread::Current();
|
| @@ -1340,7 +1137,7 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline,
|
| CompileParsedFunctionHelper helper(parsed_function, optimized, osr_id);
|
| const bool success = helper.Compile(pipeline);
|
| if (!success) {
|
| - if (optimized && !FLAG_precompilation) {
|
| + if (optimized) {
|
| // Optimizer bailed out. Disable optimizations and never try again.
|
| if (trace_compiler) {
|
| THR_Print("--> disabling optimizations for '%s'\n",
|
| @@ -1378,13 +1175,13 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline,
|
| }
|
|
|
| if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) {
|
| - DisassembleCode(function, optimized);
|
| + Disassembler::DisassembleCode(function, optimized);
|
| } else if (FLAG_disassemble_optimized &&
|
| optimized &&
|
| FlowGraphPrinter::ShouldPrint(function)) {
|
| // TODO(fschneider): Print unoptimized code along with the optimized code.
|
| THR_Print("*** BEGIN CODE\n");
|
| - DisassembleCode(function, true);
|
| + Disassembler::DisassembleCode(function, true);
|
| THR_Print("*** END CODE\n");
|
| }
|
| #if defined(DEBUG)
|
| @@ -1400,7 +1197,7 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline,
|
| thread->clear_sticky_error();
|
| // Unoptimized compilation or precompilation may encounter compile-time
|
| // errors, but regular optimized compilation should not.
|
| - ASSERT(!optimized || FLAG_precompilation);
|
| + ASSERT(!optimized);
|
| // Do not attempt to optimize functions that can cause errors.
|
| function.set_is_optimizable(false);
|
| return error.raw();
|
| @@ -1412,6 +1209,11 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline,
|
|
|
| RawError* Compiler::CompileFunction(Thread* thread,
|
| const Function& function) {
|
| +#ifdef DART_PRECOMPILER
|
| + if (FLAG_precompilation) {
|
| + return Precompiler::CompileFunction(thread, function);
|
| + }
|
| +#endif
|
| Isolate* isolate = thread->isolate();
|
| VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId);
|
| TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "Function", function);
|
| @@ -1426,12 +1228,9 @@ RawError* Compiler::CompileFunction(Thread* thread,
|
| CompilationPipeline* pipeline =
|
| CompilationPipeline::New(thread->zone(), function);
|
|
|
| - const bool optimized =
|
| - FLAG_precompilation && function.IsOptimizable();
|
| -
|
| return CompileFunctionHelper(pipeline,
|
| function,
|
| - optimized,
|
| + /* optimized = */ false,
|
| kNoOSRDeoptId);
|
| }
|
|
|
| @@ -1499,7 +1298,7 @@ RawError* Compiler::CompileParsedFunction(
|
| CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
|
| helper.Compile(&pipeline);
|
| if (FLAG_disassemble) {
|
| - DisassembleCode(parsed_function->function(), false);
|
| + Disassembler::DisassembleCode(parsed_function->function(), false);
|
| }
|
| return Error::null();
|
| } else {
|
| @@ -1566,58 +1365,35 @@ RawError* Compiler::CompileAllFunctions(const Class& cls) {
|
| }
|
|
|
|
|
| -void Compiler::CompileStaticInitializer(const Field& field) {
|
| - ASSERT(field.is_static());
|
| - if (field.HasPrecompiledInitializer()) {
|
| - // TODO(rmacnak): Investigate why this happens for _enum_names.
|
| - OS::Print("Warning: Ignoring repeated request for initializer for %s\n",
|
| - field.ToCString());
|
| - return;
|
| - }
|
| - Thread* thread = Thread::Current();
|
| - StackZone zone(thread);
|
| -
|
| - ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field);
|
| -
|
| - parsed_function->AllocateVariables();
|
| - // Non-optimized code generator.
|
| - DartCompilationPipeline pipeline;
|
| - CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
|
| - helper.Compile(&pipeline);
|
| - const Function& initializer = parsed_function->function();
|
| - field.SetPrecompiledInitializer(initializer);
|
| -}
|
| -
|
| -
|
| RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
|
| +#ifdef DART_PRECOMPILER
|
| + if (FLAG_precompilation) {
|
| + return Precompiler::EvaluateStaticInitializer(field);
|
| + }
|
| +#endif
|
| ASSERT(field.is_static());
|
| // The VM sets the field's value to transiton_sentinel prior to
|
| // evaluating the initializer value.
|
| ASSERT(field.StaticValue() == Object::transition_sentinel().raw());
|
| LongJumpScope jump;
|
| if (setjmp(*jump.Set()) == 0) {
|
| - // Under precompilation, the initializer may have already been compiled, in
|
| - // which case use it. Under lazy compilation or early in precompilation, the
|
| - // initializer has not yet been created, so create it now, but don't bother
|
| - // remembering it because it won't be used again.
|
| - Function& initializer = Function::Handle();
|
| - if (!field.HasPrecompiledInitializer()) {
|
| - Thread* const thread = Thread::Current();
|
| - StackZone zone(thread);
|
| - ParsedFunction* parsed_function =
|
| - Parser::ParseStaticFieldInitializer(field);
|
| -
|
| - parsed_function->AllocateVariables();
|
| - // Non-optimized code generator.
|
| - DartCompilationPipeline pipeline;
|
| - CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
|
| - helper.Compile(&pipeline);
|
| - initializer = parsed_function->function().raw();
|
| - Code::Handle(initializer.unoptimized_code()).set_var_descriptors(
|
| - Object::empty_var_descriptors());
|
| - } else {
|
| - initializer ^= field.PrecompiledInitializer();
|
| - }
|
| + // Under lazy compilation initializer has not yet been created, so create
|
| + // it now, but don't bother remembering it because it won't be used again.
|
| + ASSERT(!field.HasPrecompiledInitializer());
|
| + Thread* const thread = Thread::Current();
|
| + StackZone zone(thread);
|
| + ParsedFunction* parsed_function =
|
| + Parser::ParseStaticFieldInitializer(field);
|
| +
|
| + parsed_function->AllocateVariables();
|
| + // Non-optimized code generator.
|
| + DartCompilationPipeline pipeline;
|
| + CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
|
| + helper.Compile(&pipeline);
|
| + const Function& initializer =
|
| + Function::Handle(parsed_function->function().raw());
|
| + Code::Handle(initializer.unoptimized_code()).set_var_descriptors(
|
| + Object::empty_var_descriptors());
|
| // Invoke the function to evaluate the expression.
|
| return DartEntry::InvokeFunction(initializer, Object::empty_array());
|
| } else {
|
| @@ -1634,6 +1410,11 @@ RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
|
|
|
|
|
| RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
|
| +#ifdef DART_PRECOMPILER
|
| + if (FLAG_precompilation) {
|
| + return Precompiler::ExecuteOnce(fragment);
|
| + }
|
| +#endif
|
| LongJumpScope jump;
|
| if (setjmp(*jump.Set()) == 0) {
|
| Thread* const thread = Thread::Current();
|
| @@ -1946,6 +1727,13 @@ void BackgroundCompiler::EnsureInit(Thread* thread) {
|
| #else // DART_PRECOMPILED_RUNTIME
|
|
|
|
|
| +CompilationPipeline* CompilationPipeline::New(Zone* zone,
|
| + const Function& function) {
|
| + UNREACHABLE();
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| DEFINE_RUNTIME_ENTRY(CompileFunction, 1) {
|
| const Function& function = Function::CheckedHandle(arguments.ArgAt(0));
|
| FATAL3("Precompilation missed function %s (%" Pd ", %s)\n",
|
| @@ -2013,11 +1801,6 @@ RawError* Compiler::CompileAllFunctions(const Class& cls) {
|
| }
|
|
|
|
|
| -void Compiler::CompileStaticInitializer(const Field& field) {
|
| - UNREACHABLE();
|
| -}
|
| -
|
| -
|
| RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
|
| ASSERT(field.HasPrecompiledInitializer());
|
| const Function& initializer =
|
| @@ -2026,7 +1809,6 @@ RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
|
| }
|
|
|
|
|
| -
|
| RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
|
| UNREACHABLE();
|
| return Object::null();
|
|
|