Index: src/deoptimizer.cc |
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc |
index 23f26c724ab4d69931bfe0c0eedf73ba4e7adf79..d214aeae354393267182aecefd23f478d6c45313 100644 |
--- a/src/deoptimizer.cc |
+++ b/src/deoptimizer.cc |
@@ -763,6 +763,10 @@ void Deoptimizer::DoComputeOutputFrames() { |
DoComputeJSFrame(frame_index); |
jsframe_count_++; |
break; |
+ case TranslatedFrame::kInterpretedFunction: |
+ DoComputeInterpretedFrame(frame_index); |
+ jsframe_count_++; |
+ break; |
case TranslatedFrame::kArgumentsAdaptor: |
DoComputeArgumentsAdaptorFrame(frame_index); |
break; |
@@ -828,7 +832,7 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) { |
// The 'fixed' part of the frame consists of the incoming parameters and |
// the part described by JavaScriptFrameConstants. |
- unsigned fixed_frame_size = ComputeFixedSize(function); |
+ unsigned fixed_frame_size = ComputeJavascriptFixedSize(function); |
unsigned input_frame_size = input_->GetFrameSize(); |
unsigned output_frame_size = height_in_bytes + fixed_frame_size; |
@@ -1022,6 +1026,222 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) { |
} |
+void Deoptimizer::DoComputeInterpretedFrame(int frame_index) { |
+ TranslatedFrame* translated_frame = |
+ &(translated_state_.frames()[frame_index]); |
+ TranslatedFrame::iterator value_iterator = translated_frame->begin(); |
+ int input_index = 0; |
+ |
+ BailoutId bytecode_offset = translated_frame->node_id(); |
+ unsigned height = translated_frame->height(); |
+ unsigned height_in_bytes = height * kPointerSize; |
+ JSFunction* function = JSFunction::cast(value_iterator->GetRawValue()); |
+ value_iterator++; |
+ input_index++; |
+ if (trace_scope_ != NULL) { |
+ PrintF(trace_scope_->file(), " translating interpreted frame "); |
+ function->PrintName(trace_scope_->file()); |
+ PrintF(trace_scope_->file(), " => bytecode_offset=%d, height=%d\n", |
+ bytecode_offset.ToInt(), height_in_bytes); |
+ } |
+ |
+ // The 'fixed' part of the frame consists of the incoming parameters and |
+ // the part described by InterpreterFrameConstants. |
+ unsigned fixed_frame_size = ComputeInterpretedFixedSize(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::INTERPRETED); |
+ |
+ bool is_bottommost = (0 == frame_index); |
+ bool is_topmost = (output_count_ - 1 == frame_index); |
+ CHECK(frame_index >= 0 && frame_index < output_count_); |
+ CHECK_NULL(output_[frame_index]); |
+ 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 = 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; |
+ } 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()->internal_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; |
+ 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 |
+ // 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 -= kPCOnStackSize; |
+ input_offset -= kPCOnStackSize; |
+ intptr_t value; |
+ if (is_bottommost) { |
+ value = input_->GetFrameSlot(input_offset); |
+ } else { |
+ value = output_[frame_index - 1]->GetPc(); |
+ } |
+ output_frame->SetCallerPc(output_offset, value); |
+ DebugPrintOutputSlot(value, frame_index, output_offset, "caller's pc\n"); |
+ |
+ // 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 -= kFPOnStackSize; |
+ input_offset -= kFPOnStackSize; |
+ if (is_bottommost) { |
+ value = input_->GetFrameSlot(input_offset); |
+ } 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()) + |
+ has_alignment_padding_ * kPointerSize) == 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"); |
+ DCHECK(!is_bottommost || !has_alignment_padding_ || |
+ (fp_value & kPointerSize) != 0); |
+ |
+ if (FLAG_enable_embedded_constant_pool) { |
+ // For the bottommost output frame the constant pool pointer can be gotten |
+ // 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); |
+ } else { |
+ value = output_[frame_index - 1]->GetConstantPool(); |
+ } |
+ output_frame->SetCallerConstantPool(output_offset, value); |
+ DebugPrintOutputSlot(value, frame_index, output_offset, |
+ "caller's constant_pool\n"); |
+ } |
+ |
+ // 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 = InterpretedFrame::context_register(); |
+ output_offset -= kPointerSize; |
+ input_offset -= kPointerSize; |
+ // Read the context from the translations. |
+ Object* context = value_iterator->GetRawValue(); |
+ // The context should not be a placeholder for a materialized object. |
+ CHECK(context != isolate_->heap()->arguments_marker()); |
+ value = reinterpret_cast<intptr_t>(context); |
+ output_frame->SetContext(value); |
+ if (is_topmost) output_frame->SetRegister(context_reg.code(), value); |
+ WriteValueToOutput(context, input_index, frame_index, output_offset, |
+ "context "); |
+ value_iterator++; |
+ input_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); |
+ WriteValueToOutput(function, 0, frame_index, output_offset, "function "); |
+ |
+ // TODO(rmcilroy): Deal with new.target correctly - currently 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 "); |
+ |
+ // 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.ToInt(); |
+ Smi* smi_bytecode_offset = Smi::FromInt(raw_bytecode_offset); |
+ WriteValueToOutput(smi_bytecode_offset, 0, frame_index, output_offset, |
+ "bytecode offset "); |
+ |
+ // Translate the rest of the interpreter registers in the frame. |
+ for (unsigned i = 0; i < height; ++i) { |
+ output_offset -= kPointerSize; |
+ WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, |
+ output_offset); |
+ } |
+ CHECK_EQ(0u, output_offset); |
+ |
+ // Set the accumulator register. |
+ output_frame->SetRegister( |
+ kInterpreterAccumulatorRegister.code(), |
+ reinterpret_cast<intptr_t>(value_iterator->GetRawValue())); |
+ value_iterator++; |
+ |
+ Builtins* builtins = isolate_->builtins(); |
+ Code* trampoline = builtins->builtin(Builtins::kInterpreterEntryTrampoline); |
+ output_frame->SetPc(reinterpret_cast<intptr_t>(trampoline->entry())); |
+ output_frame->SetState(0); |
+ |
+ // Update constant pool. |
+ if (FLAG_enable_embedded_constant_pool) { |
+ intptr_t constant_pool_value = |
+ reinterpret_cast<intptr_t>(trampoline->constant_pool()); |
+ output_frame->SetConstantPool(constant_pool_value); |
+ if (is_topmost) { |
+ Register constant_pool_reg = |
+ InterpretedFrame::constant_pool_pointer_register(); |
+ output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value); |
+ } |
+ } |
+ |
+ // Set the continuation for the topmost frame. |
+ if (is_topmost && bailout_type_ != DEBUGGER) { |
+ Code* continuation = |
+ builtins->builtin(Builtins::kInterpreterNotifyDeoptimized); |
+ if (bailout_type_ == LAZY) { |
+ continuation = |
+ builtins->builtin(Builtins::kInterpreterNotifyLazyDeoptimized); |
+ } else if (bailout_type_ == SOFT) { |
+ continuation = |
+ builtins->builtin(Builtins::kInterpreterNotifySoftDeoptimized); |
+ } else { |
+ CHECK_EQ(bailout_type_, EAGER); |
+ } |
+ output_frame->SetContinuation( |
+ reinterpret_cast<intptr_t>(continuation->entry())); |
+ } |
+} |
+ |
+ |
void Deoptimizer::DoComputeArgumentsAdaptorFrame(int frame_index) { |
TranslatedFrame* translated_frame = |
&(translated_state_.frames()[frame_index]); |
@@ -1756,7 +1976,7 @@ void Deoptimizer::DebugPrintOutputSlot(intptr_t value, int frame_index, |
unsigned Deoptimizer::ComputeInputFrameSize() const { |
- unsigned fixed_size = ComputeFixedSize(function_); |
+ unsigned fixed_size = ComputeJavascriptFixedSize(function_); |
// 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_ - |
@@ -1771,7 +1991,7 @@ unsigned Deoptimizer::ComputeInputFrameSize() const { |
} |
-unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const { |
+unsigned Deoptimizer::ComputeJavascriptFixedSize(JSFunction* function) const { |
// The fixed part of the frame consists of the return address, frame |
// pointer, function, context, and all the incoming arguments. |
return ComputeIncomingArgumentSize(function) + |
@@ -1779,6 +1999,15 @@ unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const { |
} |
+unsigned Deoptimizer::ComputeInterpretedFixedSize(JSFunction* function) const { |
+ // The fixed part of the frame consists of the return address, frame |
+ // pointer, function, context, new.target, bytecode offset and all the |
+ // incoming arguments. |
+ return ComputeIncomingArgumentSize(function) + |
+ InterpreterFrameConstants::kFixedFrameSize; |
+} |
+ |
+ |
unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const { |
// The incoming arguments is the values for formal parameters and |
// the receiver. Every slot contains a pointer. |
@@ -1872,8 +2101,13 @@ FrameDescription::FrameDescription(uint32_t frame_size, |
int FrameDescription::ComputeFixedSize() { |
- return StandardFrameConstants::kFixedFrameSize + |
- (ComputeParametersCount() + 1) * kPointerSize; |
+ if (type_ == StackFrame::INTERPRETED) { |
+ return InterpreterFrameConstants::kFixedFrameSize + |
+ (ComputeParametersCount() + 1) * kPointerSize; |
+ } else { |
+ return StandardFrameConstants::kFixedFrameSize + |
+ (ComputeParametersCount() + 1) * kPointerSize; |
+ } |
} |
@@ -2011,6 +2245,15 @@ void Translation::BeginJSFrame(BailoutId node_id, |
} |
+void Translation::BeginInterpretedFrame(BailoutId bytecode_offset, |
+ int literal_id, unsigned height) { |
+ buffer_->Add(INTERPRETED_FRAME, zone()); |
+ buffer_->Add(bytecode_offset.ToInt(), zone()); |
+ buffer_->Add(literal_id, zone()); |
+ buffer_->Add(height, zone()); |
+} |
+ |
+ |
void Translation::BeginCompiledStubFrame(int height) { |
buffer_->Add(COMPILED_STUB_FRAME, zone()); |
buffer_->Add(height, zone()); |
@@ -2143,6 +2386,7 @@ int Translation::NumberOfOperandsFor(Opcode opcode) { |
case CONSTRUCT_STUB_FRAME: |
return 2; |
case JS_FRAME: |
+ case INTERPRETED_FRAME: |
return 3; |
} |
FATAL("Unexpected translation type"); |
@@ -2616,6 +2860,15 @@ TranslatedFrame TranslatedFrame::JSFrame(BailoutId node_id, |
} |
+TranslatedFrame TranslatedFrame::InterpretedFrame( |
+ BailoutId bytecode_offset, SharedFunctionInfo* shared_info, int height) { |
+ TranslatedFrame frame(kInterpretedFunction, shared_info->GetIsolate(), |
+ shared_info, height); |
+ frame.node_id_ = bytecode_offset; |
+ return frame; |
+} |
+ |
+ |
TranslatedFrame TranslatedFrame::AccessorFrame( |
Kind kind, SharedFunctionInfo* shared_info) { |
DCHECK(kind == kSetter || kind == kGetter); |
@@ -2642,9 +2895,17 @@ int TranslatedFrame::GetValueCount() { |
case kFunction: { |
int parameter_count = |
raw_shared_info_->internal_formal_parameter_count() + 1; |
+ // + 1 for function. |
return height_ + parameter_count + 1; |
} |
+ case kInterpretedFunction: { |
+ int parameter_count = |
+ raw_shared_info_->internal_formal_parameter_count() + 1; |
+ // + 3 for function, context and accumulator. |
+ return height_ + parameter_count + 3; |
+ } |
+ |
case kGetter: |
return 2; // Function and receiver. |
@@ -2700,6 +2961,24 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame( |
return TranslatedFrame::JSFrame(node_id, shared_info, height); |
} |
+ case Translation::INTERPRETED_FRAME: { |
+ BailoutId bytecode_offset = BailoutId(iterator->Next()); |
+ SharedFunctionInfo* shared_info = |
+ SharedFunctionInfo::cast(literal_array->get(iterator->Next())); |
+ int height = iterator->Next(); |
+ if (trace_file != nullptr) { |
+ base::SmartArrayPointer<char> name = |
+ shared_info->DebugName()->ToCString(); |
+ PrintF(trace_file, " reading input frame %s", name.get()); |
+ int arg_count = shared_info->internal_formal_parameter_count() + 1; |
+ PrintF(trace_file, |
+ " => bytecode_offset=%d, args=%d, height=%d; inputs:\n", |
+ bytecode_offset.ToInt(), arg_count, height); |
+ } |
+ return TranslatedFrame::InterpretedFrame(bytecode_offset, shared_info, |
+ height); |
+ } |
+ |
case Translation::ARGUMENTS_ADAPTOR_FRAME: { |
SharedFunctionInfo* shared_info = |
SharedFunctionInfo::cast(literal_array->get(iterator->Next())); |
@@ -2812,6 +3091,7 @@ TranslatedValue TranslatedState::CreateNextTranslatedValue( |
switch (opcode) { |
case Translation::BEGIN: |
case Translation::JS_FRAME: |
+ case Translation::INTERPRETED_FRAME: |
case Translation::ARGUMENTS_ADAPTOR_FRAME: |
case Translation::CONSTRUCT_STUB_FRAME: |
case Translation::GETTER_STUB_FRAME: |