Index: src/frames.cc |
diff --git a/src/frames.cc b/src/frames.cc |
index 53ae5079f0caff31d06750b518a5867c967c1bd0..c031971d5aff69f4339783a3ac00b5e243a05505 100644 |
--- a/src/frames.cc |
+++ b/src/frames.cc |
@@ -891,61 +891,88 @@ void OptimizedFrame::Summarize(List<FrameSummary>* frames) { |
return JavaScriptFrame::Summarize(frames); |
} |
+ DisallowHeapAllocation no_gc; |
+ int deopt_index = Safepoint::kNoDeoptimizationIndex; |
+ DeoptimizationInputData* const data = GetDeoptimizationData(&deopt_index); |
+ FixedArray* const literal_array = data->LiteralArray(); |
+ |
+ TranslationIterator it(data->TranslationByteArray(), |
+ data->TranslationIndex(deopt_index)->value()); |
+ Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next()); |
+ DCHECK_EQ(Translation::BEGIN, opcode); |
+ it.Next(); // Drop frame count. |
+ int jsframe_count = it.Next(); |
+ |
// We create the summary in reverse order because the frames |
// in the deoptimization translation are ordered bottom-to-top. |
- DisallowHeapAllocation no_gc; |
- TranslatedState state(this); |
bool is_constructor = IsConstructor(); |
- for (TranslatedFrame& frame : state) { |
- switch (frame.kind()) { |
- case TranslatedFrame::kFunction: { |
- BailoutId const ast_id = frame.node_id(); |
- TranslatedFrame::iterator it = frame.begin(); |
- |
- // Get the correct function in the optimized frame. |
- JSFunction* function = JSFunction::cast(it->GetRawValue()); |
- it++; |
- |
- // Get the correct receiver in the optimized frame. |
- Object* receiver = it->GetRawValue(); |
- if (receiver == isolate()->heap()->arguments_marker()) { |
- // TODO(jarin): Materializing a captured object (or duplicated |
- // object) is hard, we return undefined for now. This breaks the |
- // produced stack trace, as constructor frames aren't marked as |
- // such anymore. |
- receiver = isolate()->heap()->undefined_value(); |
- } |
- |
- Code* code = function->shared()->code(); |
- DeoptimizationOutputData* output_data = |
- DeoptimizationOutputData::cast(code->deoptimization_data()); |
- unsigned entry = |
- Deoptimizer::GetOutputInfo(output_data, ast_id, function->shared()); |
- unsigned pc_offset = |
- FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize; |
- DCHECK(pc_offset > 0); |
- |
- FrameSummary summary(receiver, function, code, pc_offset, |
- is_constructor); |
- frames->Add(summary); |
- is_constructor = false; |
- break; |
+ while (jsframe_count != 0) { |
+ opcode = static_cast<Translation::Opcode>(it.Next()); |
+ if (opcode == Translation::JS_FRAME) { |
+ jsframe_count--; |
+ BailoutId const ast_id = BailoutId(it.Next()); |
+ SharedFunctionInfo* const shared_info = |
+ SharedFunctionInfo::cast(literal_array->get(it.Next())); |
+ it.Next(); // Skip height. |
+ |
+ // The translation commands are ordered and the function is always |
+ // at the first position, and the receiver is next. |
+ opcode = static_cast<Translation::Opcode>(it.Next()); |
+ |
+ // Get the correct function in the optimized frame. |
+ JSFunction* function; |
+ if (opcode == Translation::LITERAL) { |
+ function = JSFunction::cast(literal_array->get(it.Next())); |
+ } else if (opcode == Translation::STACK_SLOT) { |
+ function = JSFunction::cast(StackSlotAt(it.Next())); |
+ } else { |
+ CHECK_EQ(Translation::JS_FRAME_FUNCTION, opcode); |
+ function = this->function(); |
} |
- |
- case TranslatedFrame::kConstructStub: { |
- // The next encountered JS_FRAME will be marked as a constructor call. |
- DCHECK(!is_constructor); |
- is_constructor = true; |
- break; |
+ DCHECK_EQ(shared_info, function->shared()); |
+ |
+ // If we are at a call, the receiver is always in a stack slot. |
+ // Otherwise we are not guaranteed to get the receiver value. |
+ opcode = static_cast<Translation::Opcode>(it.Next()); |
+ |
+ // Get the correct receiver in the optimized frame. |
+ Object* receiver; |
+ if (opcode == Translation::LITERAL) { |
+ receiver = literal_array->get(it.Next()); |
+ } else if (opcode == Translation::STACK_SLOT) { |
+ receiver = StackSlotAt(it.Next()); |
+ } else if (opcode == Translation::JS_FRAME_FUNCTION) { |
+ receiver = this->function(); |
+ } else { |
+ // The receiver is not in a stack slot nor in a literal. We give up. |
+ it.Skip(Translation::NumberOfOperandsFor(opcode)); |
+ // TODO(3029): Materializing a captured object (or duplicated |
+ // object) is hard, we return undefined for now. This breaks the |
+ // produced stack trace, as constructor frames aren't marked as |
+ // such anymore. |
+ receiver = isolate()->heap()->undefined_value(); |
} |
- case TranslatedFrame::kInvalid: |
- UNREACHABLE(); |
- case TranslatedFrame::kArgumentsAdaptor: |
- case TranslatedFrame::kCompiledStub: |
- case TranslatedFrame::kGetter: |
- case TranslatedFrame::kSetter: |
- break; |
+ Code* const code = shared_info->code(); |
+ DeoptimizationOutputData* const output_data = |
+ DeoptimizationOutputData::cast(code->deoptimization_data()); |
+ unsigned const entry = |
+ Deoptimizer::GetOutputInfo(output_data, ast_id, shared_info); |
+ unsigned const pc_offset = |
+ FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize; |
+ DCHECK_NE(0, pc_offset); |
+ |
+ FrameSummary summary(receiver, function, code, pc_offset, is_constructor); |
+ frames->Add(summary); |
+ is_constructor = false; |
+ } else if (opcode == Translation::CONSTRUCT_STUB_FRAME) { |
+ // The next encountered JS_FRAME will be marked as a constructor call. |
+ it.Skip(Translation::NumberOfOperandsFor(opcode)); |
+ DCHECK(!is_constructor); |
+ is_constructor = true; |
+ } else { |
+ // Skip over operands to advance to the next opcode. |
+ it.Skip(Translation::NumberOfOperandsFor(opcode)); |
} |
} |
DCHECK(!is_constructor); |
@@ -1000,15 +1027,61 @@ void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) { |
} |
DisallowHeapAllocation no_gc; |
- TranslatedState state(this); |
- for (TranslatedFrame const& frame : state) { |
- if (frame.kind() == TranslatedFrame::kFunction) { |
- functions->Add(JSFunction::cast(frame.front().GetRawValue())); |
+ int deopt_index = Safepoint::kNoDeoptimizationIndex; |
+ DeoptimizationInputData* const data = GetDeoptimizationData(&deopt_index); |
+ FixedArray* const literal_array = data->LiteralArray(); |
+ |
+ TranslationIterator it(data->TranslationByteArray(), |
+ data->TranslationIndex(deopt_index)->value()); |
+ Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next()); |
+ DCHECK_EQ(Translation::BEGIN, opcode); |
+ it.Next(); // Skip frame count. |
+ int jsframe_count = it.Next(); |
+ |
+ // We insert the frames in reverse order because the frames |
+ // in the deoptimization translation are ordered bottom-to-top. |
+ while (jsframe_count != 0) { |
+ opcode = static_cast<Translation::Opcode>(it.Next()); |
+ // Skip over operands to advance to the next opcode. |
+ it.Skip(Translation::NumberOfOperandsFor(opcode)); |
+ if (opcode == Translation::JS_FRAME) { |
+ jsframe_count--; |
+ |
+ // The translation commands are ordered and the function is always at the |
+ // first position. |
+ opcode = static_cast<Translation::Opcode>(it.Next()); |
+ |
+ // Get the correct function in the optimized frame. |
+ Object* function; |
+ if (opcode == Translation::LITERAL) { |
+ function = literal_array->get(it.Next()); |
+ } else if (opcode == Translation::STACK_SLOT) { |
+ function = StackSlotAt(it.Next()); |
+ } else { |
+ CHECK_EQ(Translation::JS_FRAME_FUNCTION, opcode); |
+ function = this->function(); |
+ } |
+ functions->Add(JSFunction::cast(function)); |
} |
} |
} |
+Object* OptimizedFrame::StackSlotAt(int index) const { |
+ // Positive index means the value is spilled to the locals |
+ // area. Negative means it is stored in the incoming parameter |
+ // area. |
+ if (index >= 0) return GetExpression(index); |
+ |
+ // Index -1 overlaps with last parameter, -n with the first parameter, |
+ // (-n - 1) with the receiver with n being the number of parameters |
+ // of the outermost, optimized frame. |
+ int const parameter_count = ComputeParametersCount(); |
+ int const parameter_index = index + parameter_count; |
+ return (parameter_index == -1) ? receiver() : GetParameter(parameter_index); |
+} |
+ |
+ |
int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const { |
return Smi::cast(GetExpression(0))->value(); |
} |