| Index: src/deoptimizer.cc
|
| diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
|
| index 1bf27f17b41bc972846eefce018180b2390e772e..6b77e51ef16b82c21dc63544a2344ae811401bdd 100644
|
| --- a/src/deoptimizer.cc
|
| +++ b/src/deoptimizer.cc
|
| @@ -820,6 +820,193 @@ void Deoptimizer::DoComputeOutputFrames() {
|
| }
|
|
|
|
|
| +void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
|
| + int frame_index) {
|
| + BailoutId node_id = BailoutId(iterator->Next());
|
| + JSFunction* function;
|
| + if (frame_index != 0) {
|
| + function = JSFunction::cast(ComputeLiteral(iterator->Next()));
|
| + } else {
|
| + int closure_id = iterator->Next();
|
| + USE(closure_id);
|
| + ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
|
| + function = function_;
|
| + }
|
| + unsigned height = iterator->Next();
|
| + unsigned height_in_bytes = height * kPointerSize;
|
| + if (trace_) {
|
| + PrintF(" translating ");
|
| + function->PrintName();
|
| + PrintF(" => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
|
| + }
|
| +
|
| + // The 'fixed' part of the frame consists of the incoming parameters and
|
| + // the part described by JavaScriptFrameConstants.
|
| + unsigned fixed_frame_size = ComputeFixedSize(function);
|
| + unsigned input_frame_size = input_->GetFrameSize();
|
| + unsigned output_frame_size = height_in_bytes + fixed_frame_size;
|
| +
|
| + // Allocate and store the output frame description.
|
| + FrameDescription* output_frame =
|
| + new(output_frame_size) FrameDescription(output_frame_size, function);
|
| + output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
|
| +
|
| + bool is_bottommost = (0 == frame_index);
|
| + bool is_topmost = (output_count_ - 1 == frame_index);
|
| + ASSERT(frame_index >= 0 && frame_index < output_count_);
|
| + ASSERT(output_[frame_index] == NULL);
|
| + output_[frame_index] = output_frame;
|
| +
|
| + // The top address for the bottommost output frame can be computed from
|
| + // the input frame pointer and the output frame's height. For all
|
| + // subsequent output frames, it can be computed from the previous one's
|
| + // top address and the current frame's size.
|
| + Register fp_reg = JavaScriptFrame::fp_register();
|
| + intptr_t top_address;
|
| + if (is_bottommost) {
|
| + // Determine whether the input frame contains alignment padding.
|
| + has_alignment_padding_ = HasAlignmentPadding(function) ? 1 : 0;
|
| + // 2 = context and function in the frame.
|
| + // If the optimized frame had alignment padding, adjust the frame pointer
|
| + // to point to the new position of the old frame pointer after padding
|
| + // is removed. Subtract 2 * kPointerSize for the context and function slots.
|
| + top_address = input_->GetRegister(fp_reg.code()) - (2 * kPointerSize) -
|
| + height_in_bytes + has_alignment_padding_ * kPointerSize;
|
| + } else {
|
| + top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
|
| + }
|
| + output_frame->SetTop(top_address);
|
| +
|
| + // Compute the incoming parameter translation.
|
| + int parameter_count = function->shared()->formal_parameter_count() + 1;
|
| + unsigned output_offset = output_frame_size;
|
| + unsigned input_offset = input_frame_size;
|
| + for (int i = 0; i < parameter_count; ++i) {
|
| + output_offset -= kPointerSize;
|
| + DoTranslateCommand(iterator, frame_index, output_offset);
|
| + }
|
| + input_offset -= (parameter_count * kPointerSize);
|
| +
|
| + // There are no translation commands for the caller's pc and fp, the
|
| + // context, and the function. Synthesize their values and set them up
|
| + // explicitly.
|
| + //
|
| + // The caller's pc for the bottommost output frame is the same as in the
|
| + // input frame. For all subsequent output frames, it can be read from the
|
| + // previous one. This frame's pc can be computed from the non-optimized
|
| + // function code and AST id of the bailout.
|
| + output_offset -= kPointerSize;
|
| + input_offset -= kPointerSize;
|
| + intptr_t value;
|
| + if (is_bottommost) {
|
| + value = input_->GetFrameSlot(input_offset);
|
| + } else {
|
| + value = output_[frame_index - 1]->GetPc();
|
| + }
|
| + output_frame->SetFrameSlot(output_offset, value);
|
| + if (trace_) {
|
| + PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
|
| + V8PRIxPTR " ; caller's pc\n",
|
| + top_address + output_offset, output_offset, value);
|
| + }
|
| +
|
| + // The caller's frame pointer for the bottommost output frame is the same
|
| + // as in the input frame. For all subsequent output frames, it can be
|
| + // read from the previous one. Also compute and set this frame's frame
|
| + // pointer.
|
| + output_offset -= kPointerSize;
|
| + input_offset -= kPointerSize;
|
| + if (is_bottommost) {
|
| + value = input_->GetFrameSlot(input_offset);
|
| + } else {
|
| + value = output_[frame_index - 1]->GetFp();
|
| + }
|
| + output_frame->SetFrameSlot(output_offset, value);
|
| + intptr_t fp_value = top_address + output_offset;
|
| + ASSERT(!is_bottommost || (input_->GetRegister(fp_reg.code()) +
|
| + has_alignment_padding_ * kPointerSize) == fp_value);
|
| + output_frame->SetFp(fp_value);
|
| + if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value);
|
| + if (trace_) {
|
| + PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
|
| + V8PRIxPTR " ; caller's fp\n",
|
| + fp_value, output_offset, value);
|
| + }
|
| + ASSERT(!is_bottommost || !has_alignment_padding_ ||
|
| + (fp_value & kPointerSize) != 0);
|
| +
|
| + // For the bottommost output frame the context can be gotten from the input
|
| + // frame. For all subsequent output frames it can be gotten from the function
|
| + // so long as we don't inline functions that need local contexts.
|
| + Register context_reg = JavaScriptFrame::context_register();
|
| + output_offset -= kPointerSize;
|
| + input_offset -= kPointerSize;
|
| + if (is_bottommost) {
|
| + value = input_->GetFrameSlot(input_offset);
|
| + } else {
|
| + value = reinterpret_cast<intptr_t>(function->context());
|
| + }
|
| + output_frame->SetFrameSlot(output_offset, value);
|
| + output_frame->SetContext(value);
|
| + if (is_topmost) output_frame->SetRegister(context_reg.code(), value);
|
| + if (trace_) {
|
| + PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
|
| + V8PRIxPTR "; context\n",
|
| + top_address + output_offset, output_offset, value);
|
| + }
|
| +
|
| + // The function was mentioned explicitly in the BEGIN_FRAME.
|
| + output_offset -= kPointerSize;
|
| + input_offset -= kPointerSize;
|
| + value = reinterpret_cast<intptr_t>(function);
|
| + // The function for the bottommost output frame should also agree with the
|
| + // input frame.
|
| + ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
|
| + output_frame->SetFrameSlot(output_offset, value);
|
| + if (trace_) {
|
| + PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
|
| + V8PRIxPTR "; function\n",
|
| + top_address + output_offset, output_offset, value);
|
| + }
|
| +
|
| + // Translate the rest of the frame.
|
| + for (unsigned i = 0; i < height; ++i) {
|
| + output_offset -= kPointerSize;
|
| + DoTranslateCommand(iterator, frame_index, output_offset);
|
| + }
|
| + ASSERT(0 == output_offset);
|
| +
|
| + // Compute this frame's PC, state, and continuation.
|
| + Code* non_optimized_code = function->shared()->code();
|
| + FixedArray* raw_data = non_optimized_code->deoptimization_data();
|
| + DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
|
| + Address start = non_optimized_code->instruction_start();
|
| + unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
|
| + unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
|
| + intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset);
|
| + output_frame->SetPc(pc_value);
|
| +
|
| + FullCodeGenerator::State state =
|
| + FullCodeGenerator::StateField::decode(pc_and_state);
|
| + output_frame->SetState(Smi::FromInt(state));
|
| +
|
| + // Set the continuation for the topmost frame.
|
| + if (is_topmost && bailout_type_ != DEBUGGER) {
|
| + Builtins* builtins = isolate_->builtins();
|
| + Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized);
|
| + if (bailout_type_ == LAZY) {
|
| + continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized);
|
| + } else if (bailout_type_ == SOFT) {
|
| + continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized);
|
| + } else {
|
| + ASSERT(bailout_type_ == EAGER);
|
| + }
|
| + output_frame->SetContinuation(
|
| + reinterpret_cast<intptr_t>(continuation->entry()));
|
| + }
|
| +}
|
| +
|
| +
|
| void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
|
| int frame_index) {
|
| JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
|
|
|