Commit 54bee830 authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[deoptimizer] Support materialization in frame summary.

This adds support to materialize objects when generating a frame summary
for an optimized frame via {OptimizedFrame::Summarize}. Note that this
means each summary might re-materialize objects and hence produce new
object identities every time. All use sites need to be able to cope with
such semantics.

R=jarin@chromium.org
BUG=v8:6586

Change-Id: I85c66ad3e7d247cd40f37a0a6e4391c0ee279706
Reviewed-on: https://chromium-review.googlesource.com/595745Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47067}
parent 895c3219
......@@ -822,7 +822,6 @@ static Handle<Object> ArgumentsForInlinedFunction(
static int FindFunctionInFrame(JavaScriptFrame* frame,
Handle<JSFunction> function) {
DisallowHeapAllocation no_allocation;
List<FrameSummary> frames(2);
frame->Summarize(&frames);
for (int i = frames.length() - 1; i >= 0; i--) {
......
......@@ -3402,11 +3402,12 @@ int TranslatedState::CreateNextTranslatedValue(
return translated_value.GetChildrenCount();
}
TranslatedState::TranslatedState(JavaScriptFrame* frame)
TranslatedState::TranslatedState(const JavaScriptFrame* frame)
: isolate_(nullptr), stack_frame_pointer_(nullptr) {
int deopt_index = Safepoint::kNoDeoptimizationIndex;
DeoptimizationInputData* data =
static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index);
static_cast<const OptimizedFrame*>(frame)->GetDeoptimizationData(
&deopt_index);
DCHECK(data != nullptr && deopt_index != Safepoint::kNoDeoptimizationIndex);
TranslationIterator it(data->TranslationByteArray(),
data->TranslationIndex(deopt_index)->value());
......
......@@ -244,7 +244,7 @@ class TranslatedFrame {
class TranslatedState {
public:
TranslatedState();
explicit TranslatedState(JavaScriptFrame* frame);
explicit TranslatedState(const JavaScriptFrame* frame);
void Prepare(Address stack_frame_pointer);
......
......@@ -1370,98 +1370,68 @@ void OptimizedFrame::Summarize(List<FrameSummary>* frames,
return JavaScriptFrame::Summarize(frames);
}
DisallowHeapAllocation no_gc;
int deopt_index = Safepoint::kNoDeoptimizationIndex;
DeoptimizationInputData* const data = GetDeoptimizationData(&deopt_index);
if (deopt_index == Safepoint::kNoDeoptimizationIndex) {
DCHECK(data == nullptr);
CHECK_NULL(data);
if (mode == FrameSummary::kApproximateSummary) {
return JavaScriptFrame::Summarize(frames, mode);
}
FATAL("Missing deoptimization information for OptimizedFrame::Summarize.");
}
FixedArray* const literal_array = data->LiteralArray();
TranslationIterator it(data->TranslationByteArray(),
data->TranslationIndex(deopt_index)->value());
Translation::Opcode frame_opcode =
static_cast<Translation::Opcode>(it.Next());
DCHECK_EQ(Translation::BEGIN, frame_opcode);
it.Next(); // Drop frame count.
int jsframe_count = it.Next();
// Prepare iteration over translation. Note that the below iteration might
// materialize objects without storing them back to the Isolate, this will
// lead to objects being re-materialized again for each summary.
TranslatedState translated(this);
translated.Prepare(fp());
// We create the summary in reverse order because the frames
// in the deoptimization translation are ordered bottom-to-top.
bool is_constructor = IsConstructor();
while (jsframe_count != 0) {
frame_opcode = static_cast<Translation::Opcode>(it.Next());
if (frame_opcode == Translation::INTERPRETED_FRAME ||
frame_opcode == Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME) {
jsframe_count--;
BailoutId const bailout_id = BailoutId(it.Next());
SharedFunctionInfo* const shared_info =
SharedFunctionInfo::cast(literal_array->get(it.Next()));
it.Next(); // Skip height.
for (auto it = translated.begin(); it != translated.end(); it++) {
if (it->kind() == TranslatedFrame::kInterpretedFunction ||
it->kind() == TranslatedFrame::kJavaScriptBuiltinContinuation) {
Handle<SharedFunctionInfo> shared_info = it->shared_info();
// The translation commands are ordered and the function is always
// at the first position, and the receiver is next.
Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
TranslatedFrame::iterator translated_values = it->begin();
// Get the correct function in the optimized frame.
JSFunction* function;
if (opcode == Translation::LITERAL) {
function = JSFunction::cast(literal_array->get(it.Next()));
} else {
CHECK_EQ(opcode, Translation::STACK_SLOT);
function = JSFunction::cast(StackSlotAt(it.Next()));
}
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 {
// The receiver is not in a stack slot nor in a literal. We give up.
it.Skip(Translation::NumberOfOperandsFor(opcode));
// TODO(6586): 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();
}
// Get or materialize the correct function in the optimized frame.
Handle<JSFunction> function =
Handle<JSFunction>::cast(translated_values->GetValue());
translated_values++;
AbstractCode* abstract_code;
// Get or materialize the correct receiver in the optimized frame.
Handle<Object> receiver = translated_values->GetValue();
translated_values++;
// Determine the underlying code object and the position within it from
// the translation corresponding to the frame type in question.
Handle<AbstractCode> abstract_code;
unsigned code_offset;
if (frame_opcode == Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME) {
if (it->kind() == TranslatedFrame::kJavaScriptBuiltinContinuation) {
code_offset = 0;
abstract_code = AbstractCode::cast(isolate()->builtins()->builtin(
Builtins::GetBuiltinFromBailoutId(bailout_id)));
abstract_code =
handle(AbstractCode::cast(isolate()->builtins()->builtin(
Builtins::GetBuiltinFromBailoutId(it->node_id()))),
isolate());
} else {
DCHECK_EQ(frame_opcode, Translation::INTERPRETED_FRAME);
code_offset = bailout_id.ToInt(); // Points to current bytecode.
abstract_code = AbstractCode::cast(shared_info->bytecode_array());
DCHECK_EQ(it->kind(), TranslatedFrame::kInterpretedFunction);
code_offset = it->node_id().ToInt(); // Points to current bytecode.
abstract_code = handle(shared_info->abstract_code(), isolate());
}
FrameSummary::JavaScriptFrameSummary summary(isolate(), receiver,
function, abstract_code,
// Append full summary of the encountered JS frame.
FrameSummary::JavaScriptFrameSummary summary(isolate(), *receiver,
*function, *abstract_code,
code_offset, is_constructor);
frames->Add(summary);
is_constructor = false;
} else if (frame_opcode == Translation::CONSTRUCT_STUB_FRAME) {
// The next encountered JS_FRAME will be marked as a constructor call.
it.Skip(Translation::NumberOfOperandsFor(frame_opcode));
DCHECK(!is_constructor);
} else if (it->kind() == TranslatedFrame::kConstructStub) {
// The next encountered JS frame will be marked as a constructor call.
is_constructor = true;
} else {
// Skip over operands to advance to the next opcode.
it.Skip(Translation::NumberOfOperandsFor(frame_opcode));
}
}
DCHECK(!is_constructor);
......
......@@ -26,7 +26,6 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-gc
// Flags: --inline-construct
Debug = debug.Debug
......
......@@ -26,7 +26,6 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-gc
// Flags: --inline-construct
Debug = debug.Debug
......
......@@ -249,9 +249,7 @@ var c = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25];
})();
(function() {
// TODO(6586): Once we fixed the materailization of receivers for stack trace
// computation, this should be /Array\.forEach/ again.
var re = /forEach/;
var re = /Array\.forEach/;
var lazyDeopt = function foobar(deopt) {
var b = [1,2,3];
var result = 0;
......
......@@ -259,7 +259,7 @@ var c = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25];
})();
(function() {
var re = /map/;
var re = /Array\.map/;
var lazyDeopt = function(deopt) {
var b = [1,2,3];
var result = 0;
......
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