Index: runtime/vm/simulator_dbc.cc |
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc |
index 86ca930a41aaaa0c5d639f206872e2fb6d65326c..d16a5a375869ea3c06faeb2d7826d0b627feec63 100644 |
--- a/runtime/vm/simulator_dbc.cc |
+++ b/runtime/vm/simulator_dbc.cc |
@@ -1104,6 +1104,64 @@ static DART_NOINLINE bool InvokeNativeWrapper(Thread* thread, |
#define LOAD_CONSTANT(index) (pp->data()[(index)].raw_obj_) |
+ |
+// Returns true if deoptimization succeeds. |
+DART_FORCE_INLINE bool Simulator::Deoptimize(Thread* thread, |
+ RawObjectPool** pp, |
+ uint32_t** pc, |
+ RawObject*** FP, |
+ RawObject*** SP, |
+ bool is_lazy) { |
+ // Note: frame translation will take care of preserving result at the |
+ // top of the stack. See CompilerDeoptInfo::CreateDeoptInfo. |
+ |
+ // Make sure we preserve SP[0] when entering synthetic frame below. |
+ (*SP)++; |
+ |
+ // Leaf runtime function DeoptimizeCopyFrame expects a Dart frame. |
+ // The code in this frame may not cause GC. |
+ // DeoptimizeCopyFrame and DeoptimizeFillFrame are leaf runtime calls. |
+ EnterSyntheticFrame(FP, SP, *pc - (is_lazy ? 1 : 0)); |
+ const intptr_t frame_size_in_bytes = |
+ DLRT_DeoptimizeCopyFrame(reinterpret_cast<uword>(*FP), is_lazy ? 1 : 0); |
+ LeaveSyntheticFrame(FP, SP); |
+ |
+ *SP = *FP + (frame_size_in_bytes / kWordSize); |
+ EnterSyntheticFrame(FP, SP, *pc - (is_lazy ? 1 : 0)); |
+ DLRT_DeoptimizeFillFrame(reinterpret_cast<uword>(*FP)); |
+ |
+ // We are now inside a valid frame. |
+ { |
+ *++(*SP) = 0; // Space for the result: number of materialization args. |
+ Exit(thread, *FP, *SP + 1, /*pc=*/0); |
+ NativeArguments native_args(thread, 0, *SP, *SP); |
+ if (!InvokeRuntime(thread, this, DRT_DeoptimizeMaterialize, native_args)) { |
+ return false; |
+ } |
+ } |
+ const intptr_t materialization_arg_count = |
+ Smi::Value(RAW_CAST(Smi, *(*SP)--)) / kWordSize; |
+ |
+ // Restore caller PC. |
+ *pc = SavedCallerPC(*FP); |
+ pc_ = reinterpret_cast<uword>(*pc); // For the profiler. |
+ |
+ // Check if it is a fake PC marking the entry frame. |
+ ASSERT((reinterpret_cast<uword>(*pc) & 2) == 0); |
+ |
+ // Restore SP, FP and PP. |
+ // Unoptimized frame SP is one below FrameArguments(...) because |
+ // FrameArguments(...) returns a pointer to the first argument. |
+ *SP = FrameArguments(*FP, materialization_arg_count) - 1; |
+ *FP = SavedCallerFP(*FP); |
+ |
+ // Restore pp. |
+ *pp = SimulatorHelpers::FrameCode(*FP)->ptr()->object_pool_->ptr(); |
+ |
+ return true; |
+} |
+ |
+ |
RawObject* Simulator::Call(const Code& code, |
const Array& arguments_descriptor, |
const Array& arguments, |
@@ -3573,50 +3631,25 @@ RawObject* Simulator::Call(const Code& code, |
{ |
BYTECODE(Deopt, A_D); |
- |
- // Note: frame translation will take care of preserving result at the |
- // top of the stack. See CompilerDeoptInfo::CreateDeoptInfo. |
const bool is_lazy = rD == 0; |
+ if (!Deoptimize(thread, &pp, &pc, &FP, &SP, is_lazy)) { |
+ HANDLE_EXCEPTION; |
+ } |
+ DISPATCH(); |
+ } |
- // Make sure we preserve SP[0] when entering synthetic frame below. |
- SP++; |
- |
- // Leaf runtime function DeoptimizeCopyFrame expects a Dart frame. |
- // The code in this frame may not cause GC. |
- // DeoptimizeCopyFrame and DeoptimizeFillFrame are leaf runtime calls. |
- EnterSyntheticFrame(&FP, &SP, pc - (is_lazy ? 1 : 0)); |
- const intptr_t frame_size_in_bytes = |
- DLRT_DeoptimizeCopyFrame(reinterpret_cast<uword>(FP), is_lazy ? 1 : 0); |
- LeaveSyntheticFrame(&FP, &SP); |
- |
- SP = FP + (frame_size_in_bytes / kWordSize); |
- EnterSyntheticFrame(&FP, &SP, pc - (is_lazy ? 1 : 0)); |
- DLRT_DeoptimizeFillFrame(reinterpret_cast<uword>(FP)); |
- |
- // We are now inside a valid frame. |
+ { |
+ BYTECODE(DeoptRewind, 0); |
+ pc = reinterpret_cast<uint32_t*>(thread->resume_pc()); |
+ if (!Deoptimize(thread, &pp, &pc, &FP, &SP, false /* eager */)) { |
+ HANDLE_EXCEPTION; |
+ } |
{ |
- *++SP = 0; // Space for the result: number of materialization args. |
- Exit(thread, FP, SP + 1, /*pc=*/0); |
- NativeArguments native_args(thread, 0, SP, SP); |
- INVOKE_RUNTIME(DRT_DeoptimizeMaterialize, native_args); |
+ Exit(thread, FP, SP + 1, pc); |
+ NativeArguments args(thread, 0, NULL, NULL); |
+ INVOKE_RUNTIME(DRT_RewindPostDeopt, args); |
} |
- const intptr_t materialization_arg_count = |
- Smi::Value(RAW_CAST(Smi, *SP--)) / kWordSize; |
- |
- // Restore caller PC. |
- pc = SavedCallerPC(FP); |
- pc_ = reinterpret_cast<uword>(pc); // For the profiler. |
- |
- // Check if it is a fake PC marking the entry frame. |
- ASSERT((reinterpret_cast<uword>(pc) & 2) == 0); |
- |
- // Restore SP, FP and PP. |
- // Unoptimized frame SP is one below FrameArguments(...) because |
- // FrameArguments(...) returns a pointer to the first argument. |
- SP = FrameArguments(FP, materialization_arg_count) - 1; |
- FP = SavedCallerFP(FP); |
- pp = SimulatorHelpers::FrameCode(FP)->ptr()->object_pool_->ptr(); |
- |
+ UNREACHABLE(); // DRT_RewindPostDeopt does not exit normally. |
DISPATCH(); |
} |
@@ -3699,7 +3732,7 @@ RawObject* Simulator::Call(const Code& code, |
void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) { |
// Walk over all setjmp buffers (simulated --> C++ transitions) |
- // and try to find the setjmp associated with the simulated stack pointer. |
+ // and try to find the setjmp associated with the simulated frame pointer. |
SimulatorSetjmpBuffer* buf = last_setjmp_buffer(); |
while ((buf->link() != NULL) && (buf->link()->fp() > fp)) { |
buf = buf->link(); |
@@ -3728,17 +3761,6 @@ void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) { |
special_[kExceptionSpecialIndex] = raw_exception; |
special_[kStackTraceSpecialIndex] = raw_stacktrace; |
pc_ = thread->resume_pc(); |
- } else if (pc == StubCode::DeoptForRewind_entry()->EntryPoint()) { |
- // The DeoptForRewind stub is a placeholder. We will eventually |
- // implement its behavior here. |
- // |
- // TODO(turnidge): Refactor the Deopt bytecode so that we can use |
- // the implementation here too. The deopt pc is stored in |
- // Thread::resume_pc(). After invoking deoptimization, we usually |
- // call into Debugger::RewindPostDeopt(), but I need to figure out |
- // if that makes any sense (it would JumpToFrame during a |
- // JumpToFrame, which seems wrong). |
- UNIMPLEMENTED(); |
} else { |
pc_ = pc; |
} |