| Index: src/deoptimizer.cc
|
| diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
|
| index e2e8a65e2eaf72d49f99b61d85c40837f13b75e2..7bbfa1815e2d60cca57ba058c87868246e60eee0 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,92 @@ 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();
|
| +
|
| + // Allocate a heap number for the doubles belonging to this frame.
|
| + deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame(
|
| + top, size, info);
|
| +
|
| + // Finished using the deoptimizer instance.
|
| + delete deoptimizer;
|
| +
|
| + 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 +309,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 +354,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 +529,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 +545,35 @@ void Deoptimizer::MaterializeHeapNumbers() {
|
| }
|
|
|
|
|
| +#ifdef ENABLE_DEBUGGER_SUPPORT
|
| +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 belong to the frame
|
| + // being extracted.
|
| + Address slot = d.slot_address();
|
| + if (top <= slot && slot < top + size) {
|
| + Handle<Object> num = isolate_->factory()->NewNumber(d.value());
|
| + int expression_index =
|
| + info->expression_count_ - (slot - top) / kPointerSize - 1;
|
| + if (FLAG_trace_deopt) {
|
| + PrintF("Materializing a new heap number %p [%e] in slot %p"
|
| + "for expression stack index %d\n",
|
| + reinterpret_cast<void*>(*num),
|
| + d.value(),
|
| + d.slot_address(),
|
| + expression_index);
|
| + }
|
| + info->SetExpression(expression_index, *num);
|
| + }
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +
|
| void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
| int frame_index,
|
| unsigned output_offset) {
|
| @@ -984,6 +1126,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 +1412,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
|
|
|