| 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
 | 
| 
 |