Commit 2c44f4f9 authored by bmeurer's avatar bmeurer Committed by Commit bot

[deoptimizer] Use TranslationIterator for OptimizedFrame again.

Using TranslatedState and friends is too expensive compared to the low
level TranslationIterator, because some code (i.e. in Speedometer)
depends on the OptimizedFrame summary/function listing to be very fast.

BUG=chromium:499338
LOG=n
R=jarin@chromium.org

Review URL: https://codereview.chromium.org/1181373003

Cr-Commit-Position: refs/heads/master@{#29037}
parent 65b6cef8
......@@ -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();
}
......
......@@ -643,6 +643,8 @@ class OptimizedFrame : public JavaScriptFrame {
private:
friend class StackFrameIteratorBase;
Object* StackSlotAt(int index) const;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment