Index: runtime/vm/code_generator.cc |
=================================================================== |
--- runtime/vm/code_generator.cc (revision 10463) |
+++ runtime/vm/code_generator.cc (working copy) |
@@ -11,11 +11,13 @@ |
#include "vm/dart_api_impl.h" |
#include "vm/dart_entry.h" |
#include "vm/debugger.h" |
+#include "vm/deopt_instructions.h" |
#include "vm/exceptions.h" |
#include "vm/intermediate_language.h" |
#include "vm/object_store.h" |
#include "vm/message.h" |
#include "vm/message_handler.h" |
+#include "vm/parser.h" |
#include "vm/resolver.h" |
#include "vm/runtime_entry.h" |
#include "vm/stack_frame.h" |
@@ -1388,10 +1390,11 @@ |
} |
-static void GetDeoptInfo(const Code& code, |
- uword pc, |
- intptr_t* deopt_id, |
- intptr_t* deopt_reason) { |
+static void GetDeoptIxDescrAtPc(const Code& code, |
+ uword pc, |
+ intptr_t* deopt_id, |
+ intptr_t* deopt_reason, |
+ intptr_t* deopt_index) { |
const PcDescriptors& descriptors = |
PcDescriptors::Handle(code.pc_descriptors()); |
ASSERT(!descriptors.IsNull()); |
@@ -1401,27 +1404,19 @@ |
(descriptors.DescriptorKind(i) == PcDescriptors::kDeoptIndex)) { |
*deopt_id = descriptors.DeoptId(i); |
*deopt_reason = descriptors.DeoptReason(i); |
+ *deopt_index = descriptors.DeoptIndex(i); |
return; |
} |
} |
*deopt_id = Isolate::kNoDeoptId; |
*deopt_reason = kDeoptUnknown; |
+ *deopt_index = -1; |
} |
-// Copy saved registers and caller's frame into temporary buffers. |
-// Access the deopt information for the deoptimization point. |
-// Return the new stack size (including PC marker and deopt return address, |
-// excluding FP). |
-DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, |
- intptr_t* saved_registers_address) { |
- Isolate* isolate = Isolate::Current(); |
- Zone zone(isolate); |
- HANDLESCOPE(isolate); |
- const uword last_fp = |
- reinterpret_cast<uword>(saved_registers_address + kNumberOfCpuRegisters); |
- // Copy saved registers. |
+// Copy saved registers into the isolate buffer. |
+static void CopySavedRegisters(intptr_t* saved_registers_address) { |
intptr_t* registers_copy = new intptr_t[kNumberOfCpuRegisters]; |
ASSERT(registers_copy != NULL); |
ASSERT(saved_registers_address != NULL); |
@@ -1429,55 +1424,137 @@ |
registers_copy[i] = *saved_registers_address; |
saved_registers_address++; |
} |
- isolate->set_deopt_registers_copy(registers_copy); |
- ASSERT(reinterpret_cast<uword>(saved_registers_address) == last_fp); |
- DartFrameIterator iterator(last_fp); |
- StackFrame* caller_frame = iterator.NextFrame(); |
- ASSERT(caller_frame != NULL); |
- const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); |
- ASSERT(optimized_code.is_optimized()); |
+ Isolate::Current()->set_deopt_registers_copy(registers_copy); |
+} |
- intptr_t deopt_id, deopt_reason; |
- GetDeoptInfo(optimized_code, caller_frame->pc(), &deopt_id, &deopt_reason); |
- ASSERT(deopt_id != Isolate::kNoDeoptId); |
- // Add incoming arguments. |
+// Copy optimized frame into the isolate buffer. |
+// The first incoming argument is stored at the last entry in the |
+// copied frame buffer. |
+static void CopyFrame(const Code& optimized_code, const StackFrame& frame) { |
const Function& function = Function::Handle(optimized_code.function()); |
- // Think of copied arguments. |
+ // Do not copy incoming arguments if there are optional arguments (they |
+ // are copied into local space at method entry). |
const intptr_t num_args = (function.num_optional_parameters() > 0) ? |
0 : function.num_fixed_parameters(); |
- // FP, PC marker and return address will all be copied. |
+ // FP, PC-marker and return-address will be copied as well. |
const intptr_t frame_copy_size = |
1 // Deoptimized function's return address: caller_frame->pc(). |
- + ((caller_frame->fp() - caller_frame->sp()) / kWordSize) |
+ + ((frame.fp() - frame.sp()) / kWordSize) |
+ 1 // PC marker. |
+ 1 // Caller return address. |
+ num_args; |
intptr_t* frame_copy = new intptr_t[frame_copy_size]; |
ASSERT(frame_copy != NULL); |
- // Include the return address of deoptimized code. |
- intptr_t* start = reinterpret_cast<intptr_t*>(caller_frame->sp() - kWordSize); |
+ // Include the return address of optimized code. |
+ intptr_t* start = reinterpret_cast<intptr_t*>(frame.sp() - kWordSize); |
for (intptr_t i = 0; i < frame_copy_size; i++) { |
frame_copy[i] = *(start + i); |
} |
- isolate->SetDeoptFrameCopy(frame_copy, frame_copy_size); |
+ Isolate::Current()->SetDeoptFrameCopy(frame_copy, frame_copy_size); |
+} |
+ |
+ |
+// Copies saved registers and caller's frame into temporary buffers. |
+// Returns the stack size of unoptimzied frame. |
+DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, |
+ intptr_t* saved_registers_address) { |
+ Isolate* isolate = Isolate::Current(); |
+ Zone zone(isolate); |
+ HANDLESCOPE(isolate); |
+ |
+ // All registers have been saved below last-fp. |
+ const uword last_fp = |
+ reinterpret_cast<uword>(saved_registers_address + kNumberOfCpuRegisters); |
+ CopySavedRegisters(saved_registers_address); |
+ |
+ // Get optimized code and frame that need to be deoptimized. |
+ DartFrameIterator iterator(last_fp); |
+ StackFrame* caller_frame = iterator.NextFrame(); |
+ ASSERT(caller_frame != NULL); |
+ const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); |
+ ASSERT(optimized_code.is_optimized()); |
+ |
+ intptr_t deopt_id, deopt_reason, deopt_index; |
+ GetDeoptIxDescrAtPc(optimized_code, caller_frame->pc(), |
+ &deopt_id, &deopt_reason, &deopt_index); |
+ ASSERT(deopt_id != Isolate::kNoDeoptId); |
+ |
+ CopyFrame(optimized_code, *caller_frame); |
if (FLAG_trace_deopt) { |
+ intptr_t deopt_id, deopt_reason, deopt_index; |
+ GetDeoptIxDescrAtPc(optimized_code, caller_frame->pc(), |
+ &deopt_id, &deopt_reason, &deopt_index); |
OS::Print("Deoptimizing (reason %d '%s') at pc 0x%x id %d '%s'\n", |
deopt_reason, |
DeoptReasonToText(deopt_reason), |
caller_frame->pc(), |
deopt_id, |
- function.ToFullyQualifiedCString()); |
+ Function::Handle(optimized_code.function()).ToFullyQualifiedCString()); |
} |
- // TODO(srdjan): find deopt info and the size of stack, currently stack size |
- // is the same as before. |
- const intptr_t stack_size_in_bytes = caller_frame->fp() - caller_frame->sp(); |
- // Include the space for return address. |
- return stack_size_in_bytes + kWordSize; |
+ |
+ // Compute the stack size of unoptimized frame |
+ const Array& deopt_info_array = |
+ Array::Handle(optimized_code.deopt_info_array()); |
+ ASSERT(!deopt_info_array.IsNull()); |
+ DeoptInfo& deopt_info = DeoptInfo::Handle(); |
+ deopt_info ^= deopt_info_array.At(deopt_index); |
+ if (deopt_info.IsNull()) { |
+ // TODO(srdjan): Deprecate. |
+ // Include the space for return address. |
+ intptr_t stack_size_in_bytes = caller_frame->fp() - caller_frame->sp(); |
+ return stack_size_in_bytes + kWordSize; |
+ } else { |
+ // For functions with optional argument deoptimization info does not |
+ // describe incoming arguments. |
+ const Function& function = Function::Handle(optimized_code.function()); |
+ const intptr_t num_args = (function.num_optional_parameters() > 0) ? |
+ 0 : function.num_fixed_parameters(); |
+ intptr_t unoptimized_stack_size = |
+ + deopt_info.Length() - num_args |
+ - 2; // Subtract caller FP and PC. |
+ return unoptimized_stack_size * kWordSize; |
+ } |
} |
END_LEAF_RUNTIME_ENTRY |
+ |
+static void DeoptimizeWithDeoptInfo(const Code& code, |
+ const DeoptInfo& deopt_info, |
+ const StackFrame& caller_frame) { |
+ const intptr_t len = deopt_info.Length(); |
+ GrowableArray<DeoptInstr*> deopt_instructions(len); |
+ for (intptr_t i = 0; i < len; i++) { |
+ deopt_instructions.Add(DeoptInstr::Create(deopt_info.Instruction(i), |
+ deopt_info.FromIndex(i))); |
+ } |
+ |
+ intptr_t* start = reinterpret_cast<intptr_t*>(caller_frame.sp() - kWordSize); |
+ const Function& function = Function::Handle(code.function()); |
+ const intptr_t num_args = (function.num_optional_parameters() > 0) ? |
+ 0 : function.num_fixed_parameters(); |
+ intptr_t to_frame_size = |
+ 1 // Deoptimized function's return address. |
+ + (caller_frame.fp() - caller_frame.sp()) / kWordSize |
+ + 3 // caller-fp, pc, pc-marker. |
+ + num_args; |
+ DeoptimizationContext deopt_context(start, |
+ to_frame_size, |
+ Array::Handle(code.object_table()), |
+ num_args); |
+ for (intptr_t to_index = 0; to_index < len; to_index++) { |
+ deopt_instructions[to_index]->Execute(&deopt_context, to_index); |
+ } |
+ if (FLAG_trace_deopt) { |
+ for (intptr_t i = 0; i < len; i++) { |
+ OS::Print("*%d. 0x%x [%s]\n", |
+ i, start[i], deopt_instructions[i]->ToCString()); |
+ } |
+ } |
+} |
+ |
+ |
// The stack has been adjusted to fit all values for unoptimized frame. |
// Fill the unoptimized frame. |
DEFINE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp) { |
@@ -1498,8 +1575,9 @@ |
intptr_t* frame_copy = isolate->deopt_frame_copy(); |
intptr_t* registers_copy = isolate->deopt_registers_copy(); |
- intptr_t deopt_id, deopt_reason; |
- GetDeoptInfo(optimized_code, caller_frame->pc(), &deopt_id, &deopt_reason); |
+ intptr_t deopt_id, deopt_reason, deopt_index; |
+ GetDeoptIxDescrAtPc(optimized_code, caller_frame->pc(), |
+ &deopt_id, &deopt_reason, &deopt_index); |
ASSERT(deopt_id != Isolate::kNoDeoptId); |
uword continue_at_pc = unoptimized_code.GetDeoptPcAtDeoptId(deopt_id); |
if (FLAG_trace_deopt) { |
@@ -1507,19 +1585,34 @@ |
// TODO(srdjan): If we could allow GC, we could print the line where |
// deoptimization occured. |
} |
- const intptr_t deopt_frame_copy_size = isolate->deopt_frame_copy_size(); |
- // TODO(srdjan): Use deopt info to copy the values to right place. |
- const intptr_t pc_marker_index = |
- ((caller_frame->fp() - caller_frame->sp()) / kWordSize); |
- // Patch the return PC and saved PC marker in frame to point to the |
- // unoptimized version. |
- frame_copy[0] = continue_at_pc; |
- frame_copy[pc_marker_index] = unoptimized_code.EntryPoint() + |
- AssemblerMacros::kOffsetOfSavedPCfromEntrypoint; |
- intptr_t* start = reinterpret_cast<intptr_t*>(caller_frame->sp() - kWordSize); |
- for (intptr_t i = 0; i < deopt_frame_copy_size; i++) { |
- *(start + i) = frame_copy[i]; |
+ const Array& deopt_info_array = |
+ Array::Handle(optimized_code.deopt_info_array()); |
+ ASSERT(!deopt_info_array.IsNull()); |
+ DeoptInfo& deopt_info = DeoptInfo::Handle(); |
+ deopt_info ^= deopt_info_array.At(deopt_index); |
+ if (deopt_info.IsNull()) { |
+ // TODO(srdjan): Deprecate. |
+ const intptr_t deopt_frame_copy_size = isolate->deopt_frame_copy_size(); |
+ const intptr_t pc_marker_index = |
+ ((caller_frame->fp() - caller_frame->sp()) / kWordSize); |
+ // Patch the return PC and saved PC marker in frame to point to the |
+ // unoptimized version. |
+ frame_copy[0] = continue_at_pc; |
+ frame_copy[pc_marker_index] = |
+ unoptimized_code.EntryPoint() + |
+ AssemblerMacros::kOffsetOfSavedPCfromEntrypoint; |
+ intptr_t* start = |
+ reinterpret_cast<intptr_t*>(caller_frame->sp() - kWordSize); |
+ for (intptr_t i = 0; i < deopt_frame_copy_size; i++) { |
+ if (FLAG_trace_deopt) { |
+ OS::Print("%d. 0x%x\n", i, frame_copy[i]); |
+ } |
+ *(start + i) = frame_copy[i]; |
+ } |
+ } else { |
+ DeoptimizeWithDeoptInfo(optimized_code, deopt_info, *caller_frame); |
} |
+ |
isolate->SetDeoptFrameCopy(NULL, 0); |
isolate->set_deopt_registers_copy(NULL); |
delete[] frame_copy; |