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