Chromium Code Reviews| Index: src/deoptimizer.cc |
| diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc |
| index e2e8a65e2eaf72d49f99b61d85c40837f13b75e2..e7ece271a0f20503d4fbd10af7a79a8c66a3f50a 100644 |
| --- a/src/deoptimizer.cc |
| +++ b/src/deoptimizer.cc |
| @@ -44,6 +44,9 @@ DeoptimizerData::DeoptimizerData() { |
| lazy_deoptimization_entry_code_ = NULL; |
| current_ = NULL; |
| deoptimizing_code_list_ = NULL; |
| +#ifdef ENABLE_DEBUGGER_SUPPORT |
| + deoptimized_frame_info_ = NULL; |
| +#endif |
| } |
| @@ -58,6 +61,16 @@ DeoptimizerData::~DeoptimizerData() { |
| } |
| } |
| + |
| +#ifdef ENABLE_DEBUGGER_SUPPORT |
| +void DeoptimizerData::Iterate(ObjectVisitor* v) { |
| + if (deoptimized_frame_info_ != NULL) { |
| + deoptimized_frame_info_->Iterate(v); |
| + } |
| +} |
| +#endif |
| + |
| + |
| Deoptimizer* Deoptimizer::New(JSFunction* function, |
| BailoutType type, |
| unsigned bailout_id, |
| @@ -70,7 +83,8 @@ Deoptimizer* Deoptimizer::New(JSFunction* function, |
| type, |
| bailout_id, |
| from, |
| - fp_to_sp_delta); |
| + fp_to_sp_delta, |
| + NULL); |
| ASSERT(isolate->deoptimizer_data()->current_ == NULL); |
| isolate->deoptimizer_data()->current_ = deoptimizer; |
| return deoptimizer; |
| @@ -86,6 +100,89 @@ Deoptimizer* Deoptimizer::Grab(Isolate* isolate) { |
| return result; |
| } |
| +#ifdef ENABLE_DEBUGGER_SUPPORT |
| +DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame( |
| + JavaScriptFrame* frame, |
| + int frame_index, |
| + Isolate* isolate) { |
| + ASSERT(isolate == Isolate::Current()); |
| + ASSERT(frame->is_optimized()); |
| + ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == NULL); |
| + |
| + // Get the function and code from the frame. |
| + JSFunction* function = JSFunction::cast(frame->function()); |
| + Code* code = frame->LookupCode(); |
| + Address code_start_address = code->instruction_start(); |
| + |
| + // Locate the deoptimization point in the code. As we are at a call the |
| + // return address must be at a place in the code with deoptimization support. |
| + int deoptimization_index = Safepoint::kNoDeoptimizationIndex; |
| + // Scope this as the safe point constructor will disallow allocation. |
| + { |
| + SafepointTable table(code); |
| + for (unsigned i = 0; i < table.length(); ++i) { |
| + Address address = code_start_address + table.GetPcOffset(i); |
| + if (address == frame->pc()) { |
| + SafepointEntry safepoint_entry = table.GetEntry(i); |
| + ASSERT(safepoint_entry.deoptimization_index() != |
| + Safepoint::kNoDeoptimizationIndex); |
| + deoptimization_index = safepoint_entry.deoptimization_index(); |
| + break; |
| + } |
| + } |
| + } |
| + ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex); |
| + |
| + // Always use the actual stack slots when calculating the fp to sp |
| + // delta adding two for the function and context. |
| + unsigned stack_slots = code->stack_slots(); |
| + unsigned fp_to_sp_delta = ((stack_slots + 2) * kPointerSize); |
| + |
| + Deoptimizer* deoptimizer = new Deoptimizer(isolate, |
| + function, |
| + Deoptimizer::DEBUGGER, |
| + deoptimization_index, |
| + frame->pc(), |
| + fp_to_sp_delta, |
| + code); |
| + Address tos = frame->fp() - fp_to_sp_delta; |
| + deoptimizer->FillInputFrame(tos, frame); |
| + |
| + // Calculate the output frames. |
| + Deoptimizer::ComputeOutputFrames(deoptimizer); |
| + |
| + // Create the GC safe output frame information and register it for GC |
| + // handling. |
| + ASSERT_LT(frame_index, deoptimizer->output_count()); |
| + DeoptimizedFrameInfo* info = |
| + new DeoptimizedFrameInfo(deoptimizer, frame_index); |
| + isolate->deoptimizer_data()->deoptimized_frame_info_ = info; |
| + |
| + // Get the "simulated" top and size for the requested frame. |
| + Address top = |
| + reinterpret_cast<Address>(deoptimizer->output_[frame_index]->GetTop()); |
| + intptr_t size = |
| + deoptimizer->output_[frame_index]->GetFrameSize() / kPointerSize; |
| + |
| + // Done with the GC-unsafe frame descriptions. This re-enables allocation. |
| + deoptimizer->DeleteFrameDescriptions(); |
| + |
|
fschneider
2011/06/29 10:47:35
Maybe put the GC-unsafe part inside an AssertNoAll
Søren Thygesen Gjesse
2011/06/29 12:42:10
The already happens due to the Deoptimizer constru
|
| + // Allocate a heap number for the doubles belonging to this frame. |
| + deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame( |
| + top, size, info); |
| + |
|
fschneider
2011/06/29 10:47:35
Don't you have to de-allocate the deoptimizer? Or
Søren Thygesen Gjesse
2011/06/29 12:42:10
Good catch! Of cause.
|
| + return info; |
| +} |
| + |
| + |
| +void Deoptimizer::DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info, |
| + Isolate* isolate) { |
| + ASSERT(isolate == Isolate::Current()); |
| + ASSERT(isolate->deoptimizer_data()->deoptimized_frame_info_ == info); |
| + delete info; |
| + isolate->deoptimizer_data()->deoptimized_frame_info_ = NULL; |
| +} |
| +#endif |
| void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, |
| int count, |
| @@ -209,18 +306,24 @@ Deoptimizer::Deoptimizer(Isolate* isolate, |
| BailoutType type, |
| unsigned bailout_id, |
| Address from, |
| - int fp_to_sp_delta) |
| + int fp_to_sp_delta, |
| + Code* optimized_code) |
| : isolate_(isolate), |
| function_(function), |
| bailout_id_(bailout_id), |
| bailout_type_(type), |
| from_(from), |
| fp_to_sp_delta_(fp_to_sp_delta), |
| + input_(NULL), |
| output_count_(0), |
| output_(NULL), |
| deferred_heap_numbers_(0) { |
| if (FLAG_trace_deopt && type != OSR) { |
| - PrintF("**** DEOPT: "); |
| + if (type == DEBUGGER) { |
| + PrintF("**** DEOPT FOR DEBUGGER: "); |
| + } else { |
| + PrintF("**** DEOPT: "); |
| + } |
| function->PrintName(); |
| PrintF(" at bailout #%u, address 0x%" V8PRIxPTR ", frame size %d\n", |
| bailout_id, |
| @@ -248,10 +351,16 @@ Deoptimizer::Deoptimizer(Isolate* isolate, |
| optimized_code_ = function_->code(); |
| ASSERT(optimized_code_->kind() == Code::OPTIMIZED_FUNCTION); |
| ASSERT(!optimized_code_->contains(from)); |
| + } else if (type == DEBUGGER) { |
| + optimized_code_ = optimized_code; |
| + ASSERT(optimized_code_->contains(from)); |
| } |
| ASSERT(HEAP->allow_allocation(false)); |
| unsigned size = ComputeInputFrameSize(); |
| input_ = new(size) FrameDescription(size, function); |
| +#ifdef DEBUG |
| + input_->SetKind(Code::OPTIMIZED_FUNCTION); |
| +#endif |
| } |
| @@ -417,6 +526,7 @@ void Deoptimizer::DoComputeOutputFrames() { |
| void Deoptimizer::MaterializeHeapNumbers() { |
| + ASSERT_NE(DEBUGGER, bailout_type_); |
| for (int i = 0; i < deferred_heap_numbers_.length(); i++) { |
| HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i]; |
| Handle<Object> num = isolate_->factory()->NewNumber(d.value()); |
| @@ -432,6 +542,35 @@ void Deoptimizer::MaterializeHeapNumbers() { |
| } |
| +void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame( |
| + Address top, intptr_t size, DeoptimizedFrameInfo* info) { |
| + ASSERT_EQ(DEBUGGER, bailout_type_); |
| + for (int i = 0; i < deferred_heap_numbers_.length(); i++) { |
| + HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i]; |
| + |
| + // Check of the heap number to materialize actually belongd to the frame |
|
fschneider
2011/06/29 10:47:35
Check that the heap number to materialize actually
Søren Thygesen Gjesse
2011/06/29 12:42:10
Done.
|
| + // being extracted. |
| + Address slot = d.slot_address(); |
| + if (top <= slot && slot < top + size) { |
| + Handle<Object> num = isolate_->factory()->NewNumber(d.value()); |
| + if (FLAG_trace_deopt) { |
| + PrintF("Materializing a new heap number %p [%e] in slot %p\n", |
| + reinterpret_cast<void*>(*num), |
| + d.value(), |
| + d.slot_address()); |
| + } |
| + int expression_index = |
| + info->expression_count_ - (slot - top) / kPointerSize - 1; |
| + PrintF("Materializing a new heap number %p [%e] in index %d\n", |
|
fschneider
2011/06/29 10:47:35
Remove duplicate PrintF, maybe add the expression
Søren Thygesen Gjesse
2011/06/29 12:42:10
Done.
|
| + reinterpret_cast<void*>(*num), |
| + d.value(), |
| + expression_index); |
| + info->SetExpression(expression_index, *num); |
| + } |
| + } |
| +} |
| + |
| + |
| void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, |
| int frame_index, |
| unsigned output_offset) { |
| @@ -984,6 +1123,20 @@ unsigned FrameDescription::GetOffsetFromSlotIndex(Deoptimizer* deoptimizer, |
| } |
| +unsigned FrameDescription::GetExpressionCount(Deoptimizer* deoptimizer) { |
| + ASSERT_EQ(Code::FUNCTION, kind_); |
| + return (GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction())) |
| + / kPointerSize; |
| +} |
| + |
| + |
| +Object* FrameDescription::GetExpression(Deoptimizer* deoptimizer, int index) { |
| + ASSERT_EQ(Code::FUNCTION, kind_); |
| + unsigned offset = GetOffsetFromSlotIndex(deoptimizer, index); |
| + return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset)); |
| +} |
| + |
| + |
| void TranslationBuffer::Add(int32_t value) { |
| // Encode the sign bit in the least significant bit. |
| bool is_negative = (value < 0); |
| @@ -1256,4 +1409,24 @@ void SlotRef::ComputeSlotMappingForArguments(JavaScriptFrame* frame, |
| } |
| +DeoptimizedFrameInfo::DeoptimizedFrameInfo( |
| + Deoptimizer* deoptimizer, int frame_index) { |
| + FrameDescription* output_frame = deoptimizer->output_[frame_index]; |
| + expression_count_ = output_frame->GetExpressionCount(deoptimizer); |
| + expression_stack_ = new Object*[expression_count_]; |
| + for (int i = 0; i < expression_count_; i++) { |
| + SetExpression(i, output_frame->GetExpression(deoptimizer, i)); |
| + } |
| +} |
| + |
| + |
| +DeoptimizedFrameInfo::~DeoptimizedFrameInfo() { |
| + delete expression_stack_; |
| +} |
| + |
| +void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) { |
| + v->VisitPointers(expression_stack_, expression_stack_ + expression_count_); |
| +} |
| + |
| + |
| } } // namespace v8::internal |