Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(165)

Unified Diff: src/deoptimizer.cc

Issue 1528913003: [Interpreter] Add basic deoptimization support from TurboFan to Ignition. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@int_deopt_1
Patch Set: Add MIPS port and fix comment Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/deoptimizer.h ('k') | src/frames.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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:
« no previous file with comments | « src/deoptimizer.h ('k') | src/frames.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698