Index: runtime/vm/code_generator.cc |
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc |
index 6bfbdb8158e818cc13aa4517f7602d438c824626..216c2add585f3afa62d9330a345439c4afc7474b 100644 |
--- a/runtime/vm/code_generator.cc |
+++ b/runtime/vm/code_generator.cc |
@@ -1996,15 +1996,10 @@ DEOPT_REASONS(DEOPT_REASON_TO_TEXT) |
} |
-void DeoptimizeAt(const Code& optimized_code, uword pc) { |
+void DeoptimizeAt(const Code& optimized_code, StackFrame* frame) { |
ASSERT(optimized_code.is_optimized()); |
Thread* thread = Thread::Current(); |
Zone* zone = thread->zone(); |
- ICData::DeoptReasonId deopt_reason = ICData::kDeoptUnknown; |
- uint32_t deopt_flags = 0; |
- const TypedData& deopt_info = TypedData::Handle(zone, |
- optimized_code.GetDeoptInfoAtPc(pc, &deopt_reason, &deopt_flags)); |
- ASSERT(!deopt_info.IsNull()); |
const Function& function = Function::Handle(zone, optimized_code.function()); |
const Error& error = |
Error::Handle(zone, Compiler::EnsureUnoptimizedCode(thread, function)); |
@@ -2018,24 +2013,18 @@ void DeoptimizeAt(const Code& optimized_code, uword pc) { |
if (function.HasOptimizedCode()) { |
function.SwitchToUnoptimizedCode(); |
} |
- // Patch call site (lazy deoptimization is quite rare, patching it twice |
- // is not a performance issue). |
- uword lazy_deopt_jump_return = optimized_code.GetLazyDeoptReturnPc(); |
- uword lazy_deopt_jump_throw = optimized_code.GetLazyDeoptThrowPc(); |
-#if !defined(TARGET_ARCH_DBC) |
- ASSERT(lazy_deopt_jump_return != 0); |
- ASSERT(lazy_deopt_jump_throw != 0); |
-#endif |
+ |
+#if defined(TARGET_ARCH_DBC) |
const Instructions& instrs = |
Instructions::Handle(zone, optimized_code.instructions()); |
{ |
WritableInstructionsScope writable(instrs.PayloadStart(), instrs.size()); |
- CodePatcher::InsertDeoptimizationCallAt(pc, lazy_deopt_jump_return); |
+ CodePatcher::InsertDeoptimizationCallAt(frame->pc()); |
if (FLAG_trace_patching) { |
const String& name = String::Handle(function.name()); |
OS::PrintErr( |
- "InsertDeoptimizationCallAt: 0x%" Px " to 0x%" Px " for %s\n", |
- pc, lazy_deopt_jump_return, name.ToCString()); |
+ "InsertDeoptimizationCallAt: 0x%" Px " for %s\n", |
+ frame->pc(), name.ToCString()); |
} |
const ExceptionHandlers& handlers = |
ExceptionHandlers::Handle(zone, optimized_code.exception_handlers()); |
@@ -2043,12 +2032,34 @@ void DeoptimizeAt(const Code& optimized_code, uword pc) { |
for (intptr_t i = 0; i < handlers.num_entries(); ++i) { |
handlers.GetHandlerInfo(i, &info); |
const uword patch_pc = instrs.PayloadStart() + info.handler_pc_offset; |
- CodePatcher::InsertDeoptimizationCallAt(patch_pc, lazy_deopt_jump_throw); |
+ CodePatcher::InsertDeoptimizationCallAt(patch_pc); |
if (FLAG_trace_patching) { |
OS::PrintErr(" at handler 0x%" Px "\n", patch_pc); |
} |
} |
} |
+#else // !DBC |
+ uword lazy_deopt_entry = |
+ StubCode::DeoptimizeLazyFromReturn_entry()->EntryPoint(); |
+ if (frame->pc() == lazy_deopt_entry) { |
+ // Deopt already scheduled. |
+ if (FLAG_trace_deoptimization) { |
+ THR_Print("Lazy deopt already scheduled for fp=%" Pp "\n", frame->fp()); |
+ } |
+ } else { |
+ uword deopt_pc = frame->pc(); |
+ ASSERT(optimized_code.ContainsInstructionAt(deopt_pc)); |
+ PendingLazyDeopt pair(frame->fp(), deopt_pc); |
+ thread->isolate()->pending_deopts()->Add(pair); |
+ frame->set_pc(lazy_deopt_entry); |
+ |
+ if (FLAG_trace_deoptimization) { |
+ THR_Print("Lazy deopt scheduled for fp=%" Pp ", pc=%" Pp "\n", |
+ frame->fp(), deopt_pc); |
+ } |
+ } |
+#endif // !DBC |
+ |
// Mark code as dead (do not GC its embedded objects). |
optimized_code.set_is_alive(false); |
} |
@@ -2063,7 +2074,7 @@ void DeoptimizeFunctionsOnStack() { |
while (frame != NULL) { |
optimized_code = frame->LookupDartCode(); |
if (optimized_code.is_optimized()) { |
- DeoptimizeAt(optimized_code, frame->pc()); |
+ DeoptimizeAt(optimized_code, frame); |
} |
frame = iterator.NextFrame(); |
} |
@@ -2144,6 +2155,40 @@ DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, |
is_lazy_deopt ? "lazy-deopt" : ""); |
} |
+#if !defined(TARGET_ARCH_DBC) |
+ if (is_lazy_deopt) { |
+ uword deopt_pc = 0; |
+ MallocGrowableArray<PendingLazyDeopt>* pending_deopts = |
+ isolate->pending_deopts(); |
+ for (intptr_t i = pending_deopts->length() - 1; i >= 0; i--) { |
+ if ((*pending_deopts)[i].fp() == caller_frame->fp()) { |
+ deopt_pc = (*pending_deopts)[i].pc(); |
+ break; |
+ } |
+ } |
+ for (intptr_t i = pending_deopts->length() - 1; i >= 0; i--) { |
+ if ((*pending_deopts)[i].fp() <= caller_frame->fp()) { |
+ pending_deopts->RemoveAt(i); |
+ } |
+ } |
+ if (FLAG_trace_deoptimization) { |
+ THR_Print("Lazy deopt fp=%" Pp " pc=%" Pp "\n", |
+ caller_frame->fp(), deopt_pc); |
+ THR_Print("%" Pd " pending lazy deopts\n", |
+ pending_deopts->length()); |
+ } |
+ ASSERT(deopt_pc != 0); |
+ caller_frame->set_pc(deopt_pc); |
+ ASSERT(caller_frame->pc() == deopt_pc); |
+ } else { |
+ if (FLAG_trace_deoptimization) { |
+ THR_Print("Eager deopt fp=%" Pp " pc=%" Pp "\n", |
+ caller_frame->fp(), caller_frame->pc()); |
+ } |
+ } |
+ ASSERT(optimized_code.ContainsInstructionAt(caller_frame->pc())); |
+#endif // !DBC |
+ |
// Copy the saved registers from the stack. |
fpu_register_t* fpu_registers; |
intptr_t* cpu_registers; |
@@ -2204,6 +2249,7 @@ DEFINE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, 1, uword last_fp) { |
deopt_context->set_dest_frame(caller_frame); |
deopt_context->FillDestFrame(); |
+ |
#else |
UNREACHABLE(); |
#endif // !DART_PRECOMPILED_RUNTIME |