| Index: src/deoptimizer.cc
|
| ===================================================================
|
| --- src/deoptimizer.cc (revision 8618)
|
| +++ src/deoptimizer.cc (working copy)
|
| @@ -1,4 +1,4 @@
|
| -// Copyright 2010 the V8 project authors. All rights reserved.
|
| +// Copyright 2011 the V8 project authors. All rights reserved.
|
| // Redistribution and use in source and binary forms, with or without
|
| // modification, are permitted provided that the following conditions are
|
| // met:
|
| @@ -44,6 +44,9 @@
|
| lazy_deoptimization_entry_code_ = NULL;
|
| current_ = NULL;
|
| deoptimizing_code_list_ = NULL;
|
| +#ifdef ENABLE_DEBUGGER_SUPPORT
|
| + deoptimized_frame_info_ = NULL;
|
| +#endif
|
| }
|
|
|
|
|
| @@ -60,6 +63,16 @@
|
| }
|
| }
|
|
|
| +
|
| +#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,
|
| @@ -72,7 +85,8 @@
|
| 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;
|
| @@ -88,7 +102,92 @@
|
| 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());
|
| + uint32_t size = deoptimizer->output_[frame_index]->GetFrameSize();
|
| +
|
| + // 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,
|
| BailoutType type) {
|
| @@ -211,18 +310,24 @@
|
| 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,
|
| @@ -250,10 +355,16 @@
|
| 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
|
| }
|
|
|
|
|
| @@ -419,6 +530,7 @@
|
|
|
|
|
| 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());
|
| @@ -434,6 +546,47 @@
|
| }
|
|
|
|
|
| +#ifdef ENABLE_DEBUGGER_SUPPORT
|
| +void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
|
| + Address top, uint32_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());
|
| + // Calculate the index with the botton of the expression stack
|
| + // at index 0, and the fixed part (including incoming arguments)
|
| + // at negative indexes.
|
| + int index = static_cast<int>(
|
| + info->expression_count_ - (slot - top) / kPointerSize - 1);
|
| + if (FLAG_trace_deopt) {
|
| + PrintF("Materializing a new heap number %p [%e] in slot %p"
|
| + "for stack index %d\n",
|
| + reinterpret_cast<void*>(*num),
|
| + d.value(),
|
| + d.slot_address(),
|
| + index);
|
| + }
|
| + if (index >=0) {
|
| + info->SetExpression(index, *num);
|
| + } else {
|
| + // Calculate parameter index subtracting one for the receiver.
|
| + int parameter_index =
|
| + index +
|
| + static_cast<int>(size) / kPointerSize -
|
| + info->expression_count_ - 1;
|
| + info->SetParameter(parameter_index, *num);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +
|
| void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
| int frame_index,
|
| unsigned output_offset) {
|
| @@ -909,6 +1062,9 @@
|
| Isolate::Current()->memory_allocator()->AllocateChunk(desc.instr_size,
|
| EXECUTABLE,
|
| NULL);
|
| + if (chunk == NULL) {
|
| + V8::FatalProcessOutOfMemory("Not enough memory for deoptimization table");
|
| + }
|
| memcpy(chunk->body(), desc.buffer, desc.instr_size);
|
| CPU::FlushICache(chunk->body(), desc.instr_size);
|
| return chunk;
|
| @@ -977,18 +1133,48 @@
|
| if (slot_index >= 0) {
|
| // Local or spill slots. Skip the fixed part of the frame
|
| // including all arguments.
|
| - unsigned base = static_cast<unsigned>(
|
| - GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction()));
|
| + unsigned base =
|
| + GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction());
|
| return base - ((slot_index + 1) * kPointerSize);
|
| } else {
|
| // Incoming parameter.
|
| - unsigned base = static_cast<unsigned>(GetFrameSize() -
|
| - deoptimizer->ComputeIncomingArgumentSize(GetFunction()));
|
| + unsigned base = GetFrameSize() -
|
| + deoptimizer->ComputeIncomingArgumentSize(GetFunction());
|
| return base - ((slot_index + 1) * kPointerSize);
|
| }
|
| }
|
|
|
|
|
| +int FrameDescription::ComputeParametersCount() {
|
| + return function_->shared()->formal_parameter_count();
|
| +}
|
| +
|
| +
|
| +Object* FrameDescription::GetParameter(Deoptimizer* deoptimizer, int index) {
|
| + ASSERT_EQ(Code::FUNCTION, kind_);
|
| + ASSERT(index >= 0);
|
| + ASSERT(index < ComputeParametersCount());
|
| + // The slot indexes for incoming arguments are negative.
|
| + unsigned offset = GetOffsetFromSlotIndex(deoptimizer,
|
| + index - ComputeParametersCount());
|
| + return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset));
|
| +}
|
| +
|
| +
|
| +unsigned FrameDescription::GetExpressionCount(Deoptimizer* deoptimizer) {
|
| + ASSERT_EQ(Code::FUNCTION, kind_);
|
| + unsigned size = GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction());
|
| + return size / 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);
|
| @@ -1112,7 +1298,7 @@
|
| }
|
|
|
|
|
| -#ifdef OBJECT_PRINT
|
| +#if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
|
|
|
| const char* Translation::StringFor(Opcode opcode) {
|
| switch (opcode) {
|
| @@ -1261,4 +1447,33 @@
|
| }
|
|
|
|
|
| +DeoptimizedFrameInfo::DeoptimizedFrameInfo(
|
| + Deoptimizer* deoptimizer, int frame_index) {
|
| + FrameDescription* output_frame = deoptimizer->output_[frame_index];
|
| + SetFunction(output_frame->GetFunction());
|
| + expression_count_ = output_frame->GetExpressionCount(deoptimizer);
|
| + parameters_count_ = output_frame->ComputeParametersCount();
|
| + parameters_ = new Object*[parameters_count_];
|
| + for (int i = 0; i < parameters_count_; i++) {
|
| + SetParameter(i, output_frame->GetParameter(deoptimizer, i));
|
| + }
|
| + 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_;
|
| + delete[] parameters_;
|
| +}
|
| +
|
| +void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
|
| + v->VisitPointer(reinterpret_cast<Object**>(&function_));
|
| + v->VisitPointers(parameters_, parameters_ + parameters_count_);
|
| + v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
|
| +}
|
| +
|
| +
|
| } } // namespace v8::internal
|
|
|