| Index: src/deoptimizer.cc
|
| diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
|
| index 942b5284a377a811c367ce76618e3765bbc1197e..7f4ace092aea6e91c6dc6e3d831466ffd380a979 100644
|
| --- a/src/deoptimizer.cc
|
| +++ b/src/deoptimizer.cc
|
| @@ -481,6 +481,12 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function,
|
| output_count_(0),
|
| jsframe_count_(0),
|
| output_(nullptr),
|
| + caller_frame_top_(0),
|
| + caller_fp_(0),
|
| + caller_pc_(0),
|
| + caller_constant_pool_(0),
|
| + input_frame_context_(0),
|
| + stack_fp_(0),
|
| trace_scope_(nullptr) {
|
| if (isolate->deoptimizer_lazy_throw()) {
|
| isolate->set_deoptimizer_lazy_throw(false);
|
| @@ -762,8 +768,27 @@ void Deoptimizer::DoComputeOutputFrames() {
|
| }
|
| output_count_ = static_cast<int>(count);
|
|
|
| - Register fp_reg = JavaScriptFrame::fp_register();
|
| - stack_fp_ = reinterpret_cast<Address>(input_->GetRegister(fp_reg.code()));
|
| + {
|
| + // Read caller's PC, caller's FP and caller's constant pool values
|
| + // from input frame. Compute caller's frame top address.
|
| +
|
| + Register fp_reg = JavaScriptFrame::fp_register();
|
| + stack_fp_ = input_->GetRegister(fp_reg.code());
|
| +
|
| + caller_frame_top_ = stack_fp_ + ComputeInputFrameAboveFpFixedSize();
|
| +
|
| + Address fp_address = input_->GetFramePointerAddress();
|
| + caller_fp_ = Memory::intptr_at(fp_address);
|
| + caller_pc_ =
|
| + Memory::intptr_at(fp_address + StandardFrameConstants::kCallerPCOffset);
|
| + input_frame_context_ =
|
| + Memory::intptr_at(fp_address + StandardFrameConstants::kContextOffset);
|
| +
|
| + if (FLAG_enable_embedded_constant_pool) {
|
| + caller_constant_pool_ = Memory::intptr_at(
|
| + fp_address + StandardFrameConstants::kConstantPoolOffset);
|
| + }
|
| + }
|
|
|
| // Translate each output frame.
|
| for (size_t i = 0; i < count; ++i) {
|
| @@ -855,7 +880,6 @@ void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
|
| // The 'fixed' part of the frame consists of the incoming parameters and
|
| // the part described by JavaScriptFrameConstants.
|
| unsigned fixed_frame_size = ComputeJavascriptFixedSize(shared);
|
| - unsigned input_frame_size = input_->GetFrameSize();
|
| unsigned output_frame_size = height_in_bytes + fixed_frame_size;
|
|
|
| // Allocate and store the output frame description.
|
| @@ -875,13 +899,7 @@ void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
|
| Register fp_reg = JavaScriptFrame::fp_register();
|
| intptr_t top_address;
|
| if (is_bottommost) {
|
| - // 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()) -
|
| - StandardFrameConstants::kFixedFrameSizeFromFp -
|
| - height_in_bytes;
|
| + top_address = caller_frame_top_ - output_frame_size;
|
| } else {
|
| top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
|
| }
|
| @@ -889,13 +907,11 @@ void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
|
|
|
| // Compute the incoming parameter translation.
|
| unsigned output_offset = output_frame_size;
|
| - unsigned input_offset = input_frame_size;
|
| for (int i = 0; i < parameter_count; ++i) {
|
| output_offset -= kPointerSize;
|
| WriteTranslatedValueToOutput(&value_iterator, &input_index, 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
|
| @@ -906,10 +922,9 @@ void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
|
| // previous one. This frame's pc can be computed from the non-optimized
|
| // function code and AST id of the bailout.
|
| output_offset -= kPCOnStackSize;
|
| - input_offset -= kPCOnStackSize;
|
| intptr_t value;
|
| if (is_bottommost) {
|
| - value = input_->GetFrameSlot(input_offset);
|
| + value = caller_pc_;
|
| } else {
|
| value = output_[frame_index - 1]->GetPc();
|
| }
|
| @@ -921,15 +936,14 @@ void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
|
| // read from the previous one. Also compute and set this frame's frame
|
| // pointer.
|
| output_offset -= kFPOnStackSize;
|
| - input_offset -= kFPOnStackSize;
|
| if (is_bottommost) {
|
| - value = input_->GetFrameSlot(input_offset);
|
| + value = caller_fp_;
|
| } else {
|
| value = output_[frame_index - 1]->GetFp();
|
| }
|
| output_frame->SetCallerFp(output_offset, value);
|
| intptr_t fp_value = top_address + output_offset;
|
| - DCHECK(!is_bottommost || input_->GetRegister(fp_reg.code()) == fp_value);
|
| + DCHECK(!is_bottommost || stack_fp_ == fp_value);
|
| output_frame->SetFp(fp_value);
|
| if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value);
|
| DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n");
|
| @@ -939,9 +953,8 @@ void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
|
| // from the input frame. For subsequent output frames, it can be read from
|
| // the previous frame.
|
| output_offset -= kPointerSize;
|
| - input_offset -= kPointerSize;
|
| if (is_bottommost) {
|
| - value = input_->GetFrameSlot(input_offset);
|
| + value = caller_constant_pool_;
|
| } else {
|
| value = output_[frame_index - 1]->GetConstantPool();
|
| }
|
| @@ -955,7 +968,6 @@ void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
|
| // so long as we don't inline functions that need local contexts.
|
| Register context_reg = JavaScriptFrame::context_register();
|
| output_offset -= kPointerSize;
|
| - input_offset -= kPointerSize;
|
|
|
| TranslatedFrame::iterator context_pos = value_iterator;
|
| int context_input_index = input_index;
|
| @@ -974,10 +986,8 @@ void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
|
| // If the context was optimized away, just use the context from
|
| // the activation. This should only apply to Crankshaft code.
|
| CHECK(!compiled_code_->is_turbofanned());
|
| - context =
|
| - is_bottommost
|
| - ? reinterpret_cast<Object*>(input_->GetFrameSlot(input_offset))
|
| - : function->context();
|
| + context = is_bottommost ? reinterpret_cast<Object*>(input_frame_context_)
|
| + : function->context();
|
| }
|
| value = reinterpret_cast<intptr_t>(context);
|
| output_frame->SetContext(value);
|
| @@ -995,11 +1005,10 @@ void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
|
|
|
| // 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.
|
| - DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
|
| + DCHECK(!is_bottommost || reinterpret_cast<intptr_t>(function_) == value);
|
| WriteValueToOutput(function, 0, frame_index, output_offset, "function ");
|
|
|
| // Translate the rest of the frame.
|
| @@ -1096,7 +1105,6 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
|
| // The 'fixed' part of the frame consists of the incoming parameters and
|
| // the part described by InterpreterFrameConstants.
|
| unsigned fixed_frame_size = ComputeInterpretedFixedSize(shared);
|
| - unsigned input_frame_size = input_->GetFrameSize();
|
| unsigned output_frame_size = height_in_bytes + fixed_frame_size;
|
|
|
| // Allocate and store the output frame description.
|
| @@ -1118,11 +1126,7 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
|
| Register fp_reg = InterpretedFrame::fp_register();
|
| intptr_t top_address;
|
| if (is_bottommost) {
|
| - // Subtract interpreter fixed frame size for the context function slots,
|
| - // new,target and bytecode offset.
|
| - top_address = input_->GetRegister(fp_reg.code()) -
|
| - InterpreterFrameConstants::kFixedFrameSizeFromFp -
|
| - height_in_bytes;
|
| + top_address = caller_frame_top_ - output_frame_size;
|
| } else {
|
| top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
|
| }
|
| @@ -1130,13 +1134,11 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
|
|
|
| // Compute the incoming parameter translation.
|
| unsigned output_offset = output_frame_size;
|
| - unsigned input_offset = input_frame_size;
|
| for (int i = 0; i < parameter_count; ++i) {
|
| output_offset -= kPointerSize;
|
| WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index,
|
| output_offset);
|
| }
|
| - input_offset -= (parameter_count * kPointerSize);
|
|
|
| // There are no translation commands for the caller's pc and fp, the
|
| // context, the function, new.target and the bytecode offset. Synthesize
|
| @@ -1148,10 +1150,9 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
|
| // previous one. This frame's pc can be computed from the non-optimized
|
| // function code and AST id of the bailout.
|
| output_offset -= kPCOnStackSize;
|
| - input_offset -= kPCOnStackSize;
|
| intptr_t value;
|
| if (is_bottommost) {
|
| - value = input_->GetFrameSlot(input_offset);
|
| + value = caller_pc_;
|
| } else {
|
| value = output_[frame_index - 1]->GetPc();
|
| }
|
| @@ -1163,15 +1164,14 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
|
| // read from the previous one. Also compute and set this frame's frame
|
| // pointer.
|
| output_offset -= kFPOnStackSize;
|
| - input_offset -= kFPOnStackSize;
|
| if (is_bottommost) {
|
| - value = input_->GetFrameSlot(input_offset);
|
| + value = caller_fp_;
|
| } else {
|
| value = output_[frame_index - 1]->GetFp();
|
| }
|
| output_frame->SetCallerFp(output_offset, value);
|
| intptr_t fp_value = top_address + output_offset;
|
| - DCHECK(!is_bottommost || input_->GetRegister(fp_reg.code()) == fp_value);
|
| + DCHECK(!is_bottommost || stack_fp_ == fp_value);
|
| output_frame->SetFp(fp_value);
|
| if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value);
|
| DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n");
|
| @@ -1181,9 +1181,8 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
|
| // from the input frame. For subsequent output frames, it can be read from
|
| // the previous frame.
|
| output_offset -= kPointerSize;
|
| - input_offset -= kPointerSize;
|
| if (is_bottommost) {
|
| - value = input_->GetFrameSlot(input_offset);
|
| + value = caller_constant_pool_;
|
| } else {
|
| value = output_[frame_index - 1]->GetConstantPool();
|
| }
|
| @@ -1197,7 +1196,6 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
|
| // so long as we don't inline functions that need local contexts.
|
| Register context_reg = InterpretedFrame::context_register();
|
| output_offset -= kPointerSize;
|
| - input_offset -= kPointerSize;
|
|
|
| // When deoptimizing into a catch block, we need to take the context
|
| // from a register that was specified in the handler table.
|
| @@ -1225,31 +1223,27 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
|
|
|
| // 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.
|
| - DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
|
| + DCHECK(!is_bottommost || reinterpret_cast<intptr_t>(function_) == value);
|
| WriteValueToOutput(function, 0, frame_index, output_offset, "function ");
|
|
|
| // The new.target slot is only used during function activiation which is
|
| // before the first deopt point, so should never be needed. Just set it to
|
| // undefined.
|
| output_offset -= kPointerSize;
|
| - input_offset -= kPointerSize;
|
| Object* new_target = isolate_->heap()->undefined_value();
|
| WriteValueToOutput(new_target, 0, frame_index, output_offset, "new_target ");
|
|
|
| // Set the bytecode array pointer.
|
| output_offset -= kPointerSize;
|
| - input_offset -= kPointerSize;
|
| Object* bytecode_array = shared->bytecode_array();
|
| WriteValueToOutput(bytecode_array, 0, frame_index, output_offset,
|
| "bytecode array ");
|
|
|
| // The bytecode offset was mentioned explicitly in the BEGIN_FRAME.
|
| output_offset -= kPointerSize;
|
| - input_offset -= kPointerSize;
|
| int raw_bytecode_offset =
|
| BytecodeArray::kHeaderSize - kHeapObjectTag + bytecode_offset;
|
| Smi* smi_bytecode_offset = Smi::FromInt(raw_bytecode_offset);
|
| @@ -1736,7 +1730,6 @@ void Deoptimizer::DoComputeCompiledStubFrame(int frame_index) {
|
| int height_in_bytes = kPointerSize * (param_count + stack_param_count) +
|
| sizeof(Arguments) + kPointerSize;
|
| int fixed_frame_size = StandardFrameConstants::kFixedFrameSize;
|
| - int input_frame_size = input_->GetFrameSize();
|
| int output_frame_size = height_in_bytes + fixed_frame_size;
|
| if (trace_scope_ != NULL) {
|
| PrintF(trace_scope_->file(),
|
| @@ -1756,24 +1749,23 @@ void Deoptimizer::DoComputeCompiledStubFrame(int frame_index) {
|
| // frame pointer and the output frame's height. Subtract space for the
|
| // context and function slots.
|
| Register fp_reg = StubFailureTrampolineFrame::fp_register();
|
| - intptr_t top_address = input_->GetRegister(fp_reg.code()) -
|
| - StandardFrameConstants::kFixedFrameSizeFromFp - height_in_bytes;
|
| + intptr_t top_address = stack_fp_ - // input_->GetRegister(fp_reg.code()) -
|
| + StandardFrameConstants::kFixedFrameSizeFromFp -
|
| + height_in_bytes;
|
| output_frame->SetTop(top_address);
|
|
|
| - // Read caller's PC (JSFunction continuation) from the input frame.
|
| - unsigned input_frame_offset = input_frame_size - kPCOnStackSize;
|
| + // Set caller's PC (JSFunction continuation).
|
| unsigned output_frame_offset = output_frame_size - kFPOnStackSize;
|
| - intptr_t value = input_->GetFrameSlot(input_frame_offset);
|
| + intptr_t value = caller_pc_;
|
| output_frame->SetCallerPc(output_frame_offset, value);
|
| DebugPrintOutputSlot(value, frame_index, output_frame_offset,
|
| "caller's pc\n");
|
|
|
| - // Read caller's FP from the input frame, and set this frame's FP.
|
| - input_frame_offset -= kFPOnStackSize;
|
| - value = input_->GetFrameSlot(input_frame_offset);
|
| + // Set caller's FP from the input frame, and set this frame's FP.
|
| + value = caller_fp_;
|
| output_frame_offset -= kFPOnStackSize;
|
| output_frame->SetCallerFp(output_frame_offset, value);
|
| - intptr_t frame_ptr = input_->GetRegister(fp_reg.code());
|
| + intptr_t frame_ptr = stack_fp_;
|
| output_frame->SetRegister(fp_reg.code(), frame_ptr);
|
| output_frame->SetFp(frame_ptr);
|
| DebugPrintOutputSlot(value, frame_index, output_frame_offset,
|
| @@ -1781,8 +1773,7 @@ void Deoptimizer::DoComputeCompiledStubFrame(int frame_index) {
|
|
|
| if (FLAG_enable_embedded_constant_pool) {
|
| // Read the caller's constant pool from the input frame.
|
| - input_frame_offset -= kPointerSize;
|
| - value = input_->GetFrameSlot(input_frame_offset);
|
| + value = caller_constant_pool_;
|
| output_frame_offset -= kPointerSize;
|
| output_frame->SetCallerConstantPool(output_frame_offset, value);
|
| DebugPrintOutputSlot(value, frame_index, output_frame_offset,
|
| @@ -1931,7 +1922,8 @@ void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
|
| for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
|
| if (frame_index != 0) it->Advance();
|
| }
|
| - translated_state_.Prepare(it->frame()->has_adapted_arguments(), stack_fp_);
|
| + translated_state_.Prepare(it->frame()->has_adapted_arguments(),
|
| + reinterpret_cast<Address>(stack_fp_));
|
|
|
| for (auto& materialization : values_to_materialize_) {
|
| Handle<Object> value = materialization.value_->GetValue();
|
| @@ -1948,7 +1940,8 @@ void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
|
| reinterpret_cast<intptr_t>(*value);
|
| }
|
|
|
| - isolate_->materialized_object_store()->Remove(stack_fp_);
|
| + isolate_->materialized_object_store()->Remove(
|
| + reinterpret_cast<Address>(stack_fp_));
|
| }
|
|
|
|
|
| @@ -2006,25 +1999,28 @@ void Deoptimizer::DebugPrintOutputSlot(intptr_t value, int frame_index,
|
| }
|
| }
|
|
|
| -
|
| -unsigned Deoptimizer::ComputeInputFrameSize() const {
|
| - unsigned fixed_size = StandardFrameConstants::kFixedFrameSize;
|
| +unsigned Deoptimizer::ComputeInputFrameAboveFpFixedSize() const {
|
| + unsigned fixed_size = StandardFrameConstants::kFixedFrameSizeAboveFp;
|
| if (!function_->IsSmi()) {
|
| fixed_size += ComputeIncomingArgumentSize(function_->shared());
|
| } else {
|
| CHECK_EQ(Smi::cast(function_), Smi::FromInt(StackFrame::STUB));
|
| }
|
| + return fixed_size;
|
| +}
|
| +
|
| +unsigned Deoptimizer::ComputeInputFrameSize() const {
|
| // The fp-to-sp delta already takes the context, constant pool pointer and the
|
| // function into account so we have to avoid double counting them.
|
| - unsigned result = fixed_size + fp_to_sp_delta_ -
|
| - StandardFrameConstants::kFixedFrameSizeFromFp;
|
| + unsigned fixed_size_from_fp = ComputeInputFrameAboveFpFixedSize();
|
| + unsigned result = fixed_size_from_fp + fp_to_sp_delta_;
|
| if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
|
| unsigned stack_slots = compiled_code_->stack_slots();
|
| unsigned outgoing_size =
|
| ComputeOutgoingArgumentSize(compiled_code_, bailout_id_);
|
| CHECK(result ==
|
| - fixed_size + (stack_slots * kPointerSize) -
|
| - StandardFrameConstants::kFixedFrameSize + outgoing_size);
|
| + fixed_size_from_fp + (stack_slots * kPointerSize) -
|
| + StandardFrameConstants::kFixedFrameSizeAboveFp + outgoing_size);
|
| }
|
| return result;
|
| }
|
|
|