Chromium Code Reviews| Index: runtime/vm/deopt_instructions.cc |
| =================================================================== |
| --- runtime/vm/deopt_instructions.cc (revision 28225) |
| +++ runtime/vm/deopt_instructions.cc (working copy) |
| @@ -18,30 +18,94 @@ |
| DECLARE_FLAG(bool, trace_deoptimization); |
| DECLARE_FLAG(bool, trace_deoptimization_verbose); |
| -DeoptContext::DeoptContext(const Array& object_table, |
| - intptr_t num_args, |
| - DeoptReasonId deopt_reason) |
| - : object_table_(object_table.raw()), |
| + |
| +DeoptContext::DeoptContext(const StackFrame* frame, |
| + const Code& code, |
| + DestFrameOptions dest_options, |
| + fpu_register_t* fpu_registers, |
| + intptr_t* cpu_registers) |
| + : code_(code.raw()), |
| + object_table_(Array::null()), |
| + deopt_info_(DeoptInfo::null()), |
| + dest_frame_is_allocated_(false), |
| dest_frame_(NULL), |
| dest_frame_size_(0), |
| - source_frame_is_copy_(false), |
| + source_frame_is_allocated_(false), |
| source_frame_(NULL), |
| source_frame_size_(0), |
| - cpu_registers_(NULL), |
| - fpu_registers_(NULL), |
| - num_args_(num_args), |
| - deopt_reason_(deopt_reason), |
| + cpu_registers_(cpu_registers), |
| + fpu_registers_(fpu_registers), |
| + num_args_(0), |
| + deopt_reason_(kDeoptUnknown), |
| isolate_(Isolate::Current()), |
| deferred_boxes_(NULL), |
| deferred_object_refs_(NULL), |
| deferred_objects_count_(0), |
| deferred_objects_(NULL) { |
| + object_table_ = code.object_table(); |
| + |
| + intptr_t deopt_reason = kDeoptUnknown; |
| + const DeoptInfo& deopt_info = |
| + DeoptInfo::Handle(code.GetDeoptInfoAtPc(frame->pc(), &deopt_reason)); |
| + ASSERT(!deopt_info.IsNull()); |
| + deopt_info_ = deopt_info.raw(); |
| + deopt_reason_ = static_cast<DeoptReasonId>(deopt_reason); |
| + |
| + const Function& function = Function::Handle(code.function()); |
| + num_args_ = |
|
srdjan
2013/10/07 21:36:53
Please add comment why it is 0 with optional param
turnidge
2013/10/08 17:29:12
Copied the old comment from code_generator.cc.
|
| + function.HasOptionalParameters() ? 0 : function.num_fixed_parameters(); |
| + |
| + // The fixed size section of the (fake) Dart frame called via a stub by the |
| + // optimized function contains FP, PP (ARM and MIPS only), PC-marker and |
| + // return-address. This section is copied as well, so that its contained |
| + // values can be updated before returning to the deoptimized function. |
| + source_frame_size_ = |
| + + kDartFrameFixedSize // For saved values below sp. |
| + + ((frame->fp() - frame->sp()) / kWordSize) // For frame size incl. sp. |
| + + 1 // For fp. |
| + + kParamEndSlotFromFp // For saved values above fp. |
| + + num_args_; // For arguments. |
| + source_frame_ = reinterpret_cast<intptr_t*>( |
| + frame->sp() - (kDartFrameFixedSize * kWordSize)); |
| + |
| + if (dest_options == kDestIsOriginalFrame) { |
| + // Work from a copy of the source frame. |
| + intptr_t* original_frame = source_frame_; |
| + source_frame_ = new intptr_t[source_frame_size_]; |
| + ASSERT(source_frame_ != NULL); |
| + for (intptr_t i = 0; i < source_frame_size_; i++) { |
| + source_frame_[i] = original_frame[i]; |
| + } |
| + source_frame_is_allocated_ = true; |
| + } |
| + caller_fp_ = GetSourceFp(); |
| + |
| + dest_frame_size_ = deopt_info.FrameSize(); |
| + |
| + if (dest_options == kDestIsAllocated) { |
| + dest_frame_ = new intptr_t[dest_frame_size_]; |
| + ASSERT(source_frame_ != NULL); |
| + for (intptr_t i = 0; i < source_frame_size_; i++) { |
| + dest_frame_[i] = 0; |
| + } |
| + dest_frame_is_allocated_ = true; |
| + } |
| + |
| + if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) { |
| + OS::PrintErr( |
| + "Deoptimizing (reason %" Pd " '%s') at pc %#" Px " '%s' (count %d)\n", |
| + deopt_reason, |
| + DeoptReasonToText(deopt_reason_), |
| + frame->pc(), |
| + function.ToFullyQualifiedCString(), |
| + function.deoptimization_counter()); |
| + } |
| } |
| DeoptContext::~DeoptContext() { |
| // Delete memory for source frame and registers. |
| - if (source_frame_is_copy_) { |
| + if (source_frame_is_allocated_) { |
| delete[] source_frame_; |
| } |
| source_frame_ = NULL; |
| @@ -49,6 +113,10 @@ |
| delete[] cpu_registers_; |
| fpu_registers_ = NULL; |
| cpu_registers_ = NULL; |
| + if (dest_frame_is_allocated_) { |
| + delete[] dest_frame_; |
| + } |
| + dest_frame_ = NULL; |
| // Delete all deferred objects. |
| for (intptr_t i = 0; i < deferred_objects_count_; i++) { |
| @@ -60,36 +128,27 @@ |
| } |
| -void DeoptContext::SetSourceArgs(intptr_t* frame_start, |
| - intptr_t frame_size, |
| - fpu_register_t* fpu_registers, |
| - intptr_t* cpu_registers, |
| - bool source_frame_is_copy) { |
| - ASSERT(frame_start != NULL); |
| - ASSERT(frame_size >= 0); |
| - ASSERT(source_frame_ == NULL); |
| - ASSERT(cpu_registers_ == NULL && fpu_registers_ == NULL); |
| - source_frame_ = frame_start; |
| - source_frame_size_ = frame_size; |
| - caller_fp_ = GetSourceFp(); |
| - cpu_registers_ = cpu_registers; |
| - fpu_registers_ = fpu_registers; |
| - source_frame_is_copy_ = source_frame_is_copy; |
| -} |
| +void DeoptContext::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| + visitor->VisitPointer(reinterpret_cast<RawObject**>(&object_table_)); |
| + visitor->VisitPointer(reinterpret_cast<RawObject**>(&deopt_info_)); |
| - |
| -void DeoptContext::SetDestArgs(intptr_t* frame_start, |
| - intptr_t frame_size) { |
| - ASSERT(frame_start != NULL); |
| - ASSERT(frame_size >= 0); |
| - ASSERT(dest_frame_ == NULL); |
| - dest_frame_ = frame_start; |
| - dest_frame_size_ = frame_size; |
| + // Visit any object pointers on the destination stack. |
| + if (dest_frame_is_allocated_) { |
| + for (int i = 0; i < dest_frame_size_; i++) { |
| + if (dest_frame_[i] != 0) { |
| + visitor->VisitPointer(reinterpret_cast<RawObject**>(&dest_frame_[i])); |
| + } |
| + } |
| + } |
| } |
| -void DeoptContext::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| - visitor->VisitPointer(reinterpret_cast<RawObject**>(&object_table_)); |
| +intptr_t DeoptContext::DestStackAdjustment() const { |
| + return (dest_frame_size_ |
| + - kDartFrameFixedSize |
| + - num_args_ |
| + - kParamEndSlotFromFp |
| + - 1); // For fp. |
| } |
| @@ -121,6 +180,104 @@ |
| } |
| +static bool IsObjectInstruction(DeoptInstr::Kind kind) { |
| + switch (kind) { |
| + case DeoptInstr::kConstant: |
| + case DeoptInstr::kRegister: |
| + case DeoptInstr::kFpuRegister: |
| + case DeoptInstr::kInt64FpuRegister: |
| + case DeoptInstr::kFloat32x4FpuRegister: |
| + case DeoptInstr::kUint32x4FpuRegister: |
| + case DeoptInstr::kStackSlot: |
| + case DeoptInstr::kDoubleStackSlot: |
| + case DeoptInstr::kInt64StackSlot: |
| + case DeoptInstr::kFloat32x4StackSlot: |
| + case DeoptInstr::kUint32x4StackSlot: |
| + case DeoptInstr::kPp: |
| + case DeoptInstr::kCallerPp: |
| + case DeoptInstr::kMaterializedObjectRef: |
| + return true; |
| + |
| + case DeoptInstr::kRetAddress: |
| + case DeoptInstr::kPcMarker: |
| + case DeoptInstr::kCallerFp: |
| + case DeoptInstr::kCallerPc: |
| + return false; |
| + |
| + case DeoptInstr::kSuffix: |
| + case DeoptInstr::kMaterializeObject: |
| + // We should not encounter these instructions when filling stack slots. |
| + UNIMPLEMENTED(); |
| + return false; |
| + } |
| +} |
| + |
| + |
| +void DeoptContext::FillDestFrame() { |
| + const Code& code = Code::Handle(code_); |
| + const DeoptInfo& deopt_info = DeoptInfo::Handle(deopt_info_); |
| + |
| + const intptr_t len = deopt_info.TranslationLength(); |
| + GrowableArray<DeoptInstr*> deopt_instructions(len); |
| + const Array& deopt_table = Array::Handle(code.deopt_info_array()); |
| + ASSERT(!deopt_table.IsNull()); |
| + deopt_info.ToInstructions(deopt_table, &deopt_instructions); |
| + |
| + const intptr_t frame_size = deopt_info.FrameSize(); |
| + |
| + // For now, we never place non-objects in the deoptimized frame if |
| + // the destination frame is a copy. This allows us to copy the |
| + // deoptimized frame into an Array. |
| + const bool objects_only = dest_frame_is_allocated_; |
| + |
| + // All kMaterializeObject instructions are emitted before the instructions |
| + // that describe stack frames. Skip them and defer materialization of |
| + // objects until the frame is fully reconstructed and it is safe to perform |
| + // GC. |
| + // Arguments (class of the instance to allocate and field-value pairs) are |
| + // described as part of the expression stack for the bottom-most deoptimized |
| + // frame. They will be used during materialization and removed from the stack |
| + // right before control switches to the unoptimized code. |
| + const intptr_t num_materializations = len - frame_size; |
| + PrepareForDeferredMaterialization(num_materializations); |
| + for (intptr_t from_index = 0, to_index = kDartFrameFixedSize; |
| + from_index < num_materializations; |
| + from_index++) { |
| + const intptr_t field_count = |
| + DeoptInstr::GetFieldCount(deopt_instructions[from_index]); |
| + intptr_t* args = GetDestFrameAddressAt(to_index); |
| + DeferredObject* obj = new DeferredObject(field_count, args); |
| + SetDeferredObjectAt(from_index, obj); |
| + to_index += obj->ArgumentCount(); |
| + } |
| + |
| + // Populate stack frames. |
| + for (intptr_t to_index = frame_size - 1, from_index = len - 1; |
| + to_index >= 0; |
| + to_index--, from_index--) { |
| + intptr_t* to_addr = GetDestFrameAddressAt(to_index); |
| + DeoptInstr* instr = deopt_instructions[from_index]; |
| + if (!objects_only || IsObjectInstruction(instr->kind())) { |
| + instr->Execute(this, to_addr); |
| + } else { |
| + *to_addr = 0; |
| + } |
| + } |
| + |
| + if (FLAG_trace_deoptimization_verbose) { |
| + intptr_t* start = dest_frame_; |
| + for (intptr_t i = 0; i < frame_size; i++) { |
| + // OS::PrintErr("*%" Pd ". [%" Px "] %#014" Px " [%s]\n", |
| + OS::Print("*%" Pd ". [%" Px "] %#014" Px " [%s]\n", |
| + i, |
| + reinterpret_cast<uword>(&start[i]), |
| + start[i], |
| + deopt_instructions[i + (len - frame_size)]->ToCString()); |
| + } |
| + } |
| +} |
| + |
| + |
| static void FillDeferredSlots(DeferredSlot** slot_list) { |
| DeferredSlot* slot = *slot_list; |
| *slot_list = NULL; |
| @@ -149,14 +306,46 @@ |
| FillDeferredSlots(&deferred_object_refs_); |
| // Compute total number of artificial arguments used during deoptimization. |
| - intptr_t deopt_arguments = 0; |
| + intptr_t deopt_arg_count = 0; |
| for (intptr_t i = 0; i < DeferredObjectsCount(); i++) { |
| - deopt_arguments += GetDeferredObject(i)->ArgumentCount(); |
| + deopt_arg_count += GetDeferredObject(i)->ArgumentCount(); |
| } |
| - return deopt_arguments; |
| + |
| + // Since this is the only step where GC can occur during deoptimization, |
| + // use it to report the source line where deoptimization occured. |
| + if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) { |
| + DartFrameIterator iterator; |
| + StackFrame* top_frame = iterator.NextFrame(); |
| + ASSERT(top_frame != NULL); |
| + const Code& code = Code::Handle(top_frame->LookupDartCode()); |
| + const Function& top_function = Function::Handle(code.function()); |
| + const Script& script = Script::Handle(top_function.script()); |
| + const intptr_t token_pos = code.GetTokenIndexOfPC(top_frame->pc()); |
| + intptr_t line, column; |
| + script.GetTokenLocation(token_pos, &line, &column); |
| + String& line_string = String::Handle(script.GetLine(line)); |
| + OS::PrintErr(" Function: %s\n", top_function.ToFullyQualifiedCString()); |
| + OS::PrintErr(" Line %" Pd ": '%s'\n", line, line_string.ToCString()); |
| + OS::PrintErr(" Deopt args: %" Pd "\n", deopt_arg_count); |
| + } |
| + |
| + return deopt_arg_count; |
| } |
| +RawArray* DeoptContext::DestFrameAsArray() { |
| + ASSERT(dest_frame_ != NULL && dest_frame_is_allocated_); |
| + const Array& dest_array = |
| + Array::Handle(Array::New(dest_frame_size_)); |
| + Instance& obj = Instance::Handle(); |
| + for (intptr_t i = 0; i < dest_frame_size_; i++) { |
| + obj ^= reinterpret_cast<RawObject*>(dest_frame_[i]); |
| + dest_array.SetAt(i, obj); |
| + } |
| + return dest_array.raw(); |
| +} |
| + |
| + |
| // Deoptimization instruction moving value from optimized frame at |
| // 'source_index' to specified slots in the unoptimized frame. |
| // 'source_index' represents the slot index of the frame (0 being |