Index: runtime/vm/compiler.cc |
=================================================================== |
--- runtime/vm/compiler.cc (revision 25620) |
+++ runtime/vm/compiler.cc (working copy) |
@@ -488,52 +488,75 @@ |
} |
} |
- Assembler assembler; |
- FlowGraphCompiler graph_compiler(&assembler, |
- *flow_graph, |
- optimized); |
- { |
- TimerScope timer(FLAG_compiler_stats, |
- &CompilerStats::graphcompiler_timer, |
- isolate); |
- graph_compiler.CompileGraph(); |
- } |
- { |
- TimerScope timer(FLAG_compiler_stats, |
- &CompilerStats::codefinalizer_timer, |
- isolate); |
- const Code& code = Code::Handle( |
- Code::FinalizeCode(function, &assembler, optimized)); |
- code.set_is_optimized(optimized); |
- graph_compiler.FinalizePcDescriptors(code); |
- graph_compiler.FinalizeDeoptInfo(code); |
- graph_compiler.FinalizeStackmaps(code); |
- graph_compiler.FinalizeVarDescriptors(code); |
- graph_compiler.FinalizeExceptionHandlers(code); |
- graph_compiler.FinalizeComments(code); |
- graph_compiler.FinalizeStaticCallTargetsTable(code); |
+ // First, try to assemble the function using only near branches. If that |
+ // fails, we'll longjmp back here, set the needs_far_branches bit in the |
+ // function and try again. |
+ bool assembled = false; |
+ while (!assembled) { |
+ const intptr_t prev_deopt_id = isolate->deopt_id(); |
+ isolate->set_deopt_id(0); |
+ LongJump* assembler_old_base = isolate->long_jump_base(); |
+ LongJump assembler_jump; |
+ isolate->set_long_jump_base(&assembler_jump); |
+ if (setjmp(*assembler_jump.Set()) == 0) { |
+ Assembler assembler(flow_graph->use_far_branches()); |
+ FlowGraphCompiler graph_compiler(&assembler, |
+ *flow_graph, |
+ optimized); |
+ { |
+ TimerScope timer(FLAG_compiler_stats, |
+ &CompilerStats::graphcompiler_timer, |
+ isolate); |
+ graph_compiler.CompileGraph(); |
+ assembled = true; |
+ } |
+ { |
+ TimerScope timer(FLAG_compiler_stats, |
+ &CompilerStats::codefinalizer_timer, |
+ isolate); |
+ const Code& code = Code::Handle( |
+ Code::FinalizeCode(function, &assembler, optimized)); |
+ code.set_is_optimized(optimized); |
+ graph_compiler.FinalizePcDescriptors(code); |
+ graph_compiler.FinalizeDeoptInfo(code); |
+ graph_compiler.FinalizeStackmaps(code); |
+ graph_compiler.FinalizeVarDescriptors(code); |
+ graph_compiler.FinalizeExceptionHandlers(code); |
+ graph_compiler.FinalizeComments(code); |
+ graph_compiler.FinalizeStaticCallTargetsTable(code); |
- if (optimized) { |
- if (osr_id == Isolate::kNoDeoptId) { |
- CodePatcher::PatchEntry(Code::Handle(function.CurrentCode())); |
- if (FLAG_trace_compiler) { |
- OS::Print("--> patching entry %#"Px"\n", |
- Code::Handle(function.unoptimized_code()).EntryPoint()); |
+ if (optimized) { |
+ if (osr_id == Isolate::kNoDeoptId) { |
+ CodePatcher::PatchEntry(Code::Handle(function.CurrentCode())); |
+ if (FLAG_trace_compiler) { |
+ OS::Print("--> patching entry %#"Px"\n", |
+ Code::Handle(function.unoptimized_code()).EntryPoint()); |
+ } |
+ } |
+ function.SetCode(code); |
+ |
+ for (intptr_t i = 0; i < guarded_fields.length(); i++) { |
+ const Field& field = *guarded_fields[i]; |
+ field.RegisterDependentCode(code); |
+ } |
+ } else { |
+ function.set_unoptimized_code(code); |
+ function.SetCode(code); |
+ ASSERT(CodePatcher::CodeIsPatchable(code)); |
} |
} |
- function.SetCode(code); |
+ is_compiled = true; |
+ } else { |
+ isolate->object_store()->clear_sticky_error(); |
- for (intptr_t i = 0; i < guarded_fields.length(); i++) { |
- const Field& field = *guarded_fields[i]; |
- field.RegisterDependentCode(code); |
- } |
- } else { |
- function.set_unoptimized_code(code); |
- function.SetCode(code); |
- ASSERT(CodePatcher::CodeIsPatchable(code)); |
+ // If far branches were enabled, assembly should not fail again. |
+ ASSERT(!flow_graph->use_far_branches()); |
+ flow_graph->set_use_far_branches(true); |
+ is_compiled = false; |
} |
+ isolate->set_long_jump_base(assembler_old_base); |
+ isolate->set_deopt_id(prev_deopt_id); |
} |
- is_compiled = true; |
} else { |
// We bailed out. |
Error& bailout_error = Error::Handle( |