From 8ccb47f57eb81c67767fe2c8b22b955d30b69372 Mon Sep 17 00:00:00 2001 From: "sgjesse@chromium.org" Date: Thu, 7 Jul 2011 14:29:16 +0000 Subject: [PATCH] Add inspection of arguments for optimized frames R=svenpanne@chromium.org BUG=v8:1140 TEST=test/mjsunit/debug-evaluate-locals-optimized.js,test/mjsunit/debug- evaluate-locals-optimized-doubles.js Review URL: http://codereview.chromium.org//7310027 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8566 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/deoptimizer.cc | 43 ++++++++++++++++--- src/deoptimizer.h | 23 ++++++++++ src/runtime.cc | 27 +++++++----- .../debug-evaluate-locals-optimized-double.js | 10 ++++- .../debug-evaluate-locals-optimized.js | 8 +++- 5 files changed, 92 insertions(+), 19 deletions(-) diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc index 1151449ead..7eebef85d6 100644 --- a/src/deoptimizer.cc +++ b/src/deoptimizer.cc @@ -161,8 +161,7 @@ DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame( // Get the "simulated" top and size for the requested frame. Address top = reinterpret_cast
(deoptimizer->output_[frame_index]->GetTop()); - unsigned size = - deoptimizer->output_[frame_index]->GetFrameSize() / kPointerSize; + unsigned size = deoptimizer->output_[frame_index]->GetFrameSize(); // Done with the GC-unsafe frame descriptions. This re-enables allocation. deoptimizer->DeleteFrameDescriptions(); @@ -557,17 +556,27 @@ void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame( Address slot = d.slot_address(); if (top <= slot && slot < top + size) { Handle num = isolate_->factory()->NewNumber(d.value()); - int expression_index = static_cast( + // Calculate the index with the botton of the expression stack + // at index 0, and the fixed part (including incoming arguments) + // at negative indexes. + int index = static_cast( info->expression_count_ - (slot - top) / kPointerSize - 1); if (FLAG_trace_deopt) { PrintF("Materializing a new heap number %p [%e] in slot %p" - "for expression stack index %d\n", + "for stack index %d\n", reinterpret_cast(*num), d.value(), d.slot_address(), - expression_index); + index); + } + if (index >=0) { + info->SetExpression(index, *num); + } else { + // Calculate parameter index subtracting one for the receiver. + int parameter_index = + index + size / kPointerSize - info->expression_count_ - 1; + info->SetParameter(parameter_index, *num); } - info->SetExpression(expression_index, *num); } } } @@ -1126,6 +1135,22 @@ unsigned FrameDescription::GetOffsetFromSlotIndex(Deoptimizer* deoptimizer, } +int FrameDescription::ComputeParametersCount() { + return function_->shared()->formal_parameter_count(); +} + + +Object* FrameDescription::GetParameter(Deoptimizer* deoptimizer, int index) { + ASSERT_EQ(Code::FUNCTION, kind_); + ASSERT(index >= 0); + ASSERT(index < ComputeParametersCount()); + // The slot indexes for incoming arguments are negative. + unsigned offset = GetOffsetFromSlotIndex(deoptimizer, + index - ComputeParametersCount()); + return reinterpret_cast(*GetFrameSlotPointer(offset)); +} + + unsigned FrameDescription::GetExpressionCount(Deoptimizer* deoptimizer) { ASSERT_EQ(Code::FUNCTION, kind_); unsigned size = GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction()); @@ -1417,6 +1442,11 @@ DeoptimizedFrameInfo::DeoptimizedFrameInfo( FrameDescription* output_frame = deoptimizer->output_[frame_index]; SetFunction(output_frame->GetFunction()); expression_count_ = output_frame->GetExpressionCount(deoptimizer); + parameters_count_ = output_frame->ComputeParametersCount(); + parameters_ = new Object*[expression_count_]; + for (int i = 0; i < parameters_count_; i++) { + SetParameter(i, output_frame->GetParameter(deoptimizer, i)); + } expression_stack_ = new Object*[expression_count_]; for (int i = 0; i < expression_count_; i++) { SetExpression(i, output_frame->GetExpression(deoptimizer, i)); @@ -1430,6 +1460,7 @@ DeoptimizedFrameInfo::~DeoptimizedFrameInfo() { void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) { v->VisitPointer(reinterpret_cast(&function_)); + v->VisitPointers(parameters_, parameters_ + parameters_count_); v->VisitPointers(expression_stack_, expression_stack_ + expression_count_); } diff --git a/src/deoptimizer.h b/src/deoptimizer.h index 8f368b44ad..27ff8ddcce 100644 --- a/src/deoptimizer.h +++ b/src/deoptimizer.h @@ -400,6 +400,12 @@ class FrameDescription { void SetKind(Code::Kind kind) { kind_ = kind; } #endif + // Get the incoming arguments count. + int ComputeParametersCount(); + + // Get a parameter value for an unoptimized frame. + Object* GetParameter(Deoptimizer* deoptimizer, int index); + // Get the expression stack height for a unoptimized frame. unsigned GetExpressionCount(Deoptimizer* deoptimizer); @@ -662,6 +668,9 @@ class DeoptimizedFrameInfo : public Malloced { // GC support. void Iterate(ObjectVisitor* v); + // Return the number of incoming arguments. + int parameters_count() { return parameters_count_; } + // Return the height of the expression stack. int expression_count() { return expression_count_; } @@ -670,6 +679,12 @@ class DeoptimizedFrameInfo : public Malloced { return function_; } + // Get an incoming argument. + Object* GetParameter(int index) { + ASSERT(0 <= index && index < parameters_count()); + return parameters_[index]; + } + // Get an expression from the expression stack. Object* GetExpression(int index) { ASSERT(0 <= index && index < expression_count()); @@ -682,6 +697,12 @@ class DeoptimizedFrameInfo : public Malloced { function_ = function; } + // Set an incoming argument. + void SetParameter(int index, Object* obj) { + ASSERT(0 <= index && index < parameters_count()); + parameters_[index] = obj; + } + // Set an expression on the expression stack. void SetExpression(int index, Object* obj) { ASSERT(0 <= index && index < expression_count()); @@ -689,7 +710,9 @@ class DeoptimizedFrameInfo : public Malloced { } JSFunction* function_; + int parameters_count_; int expression_count_; + Object** parameters_; Object** expression_stack_; friend class Deoptimizer; diff --git a/src/runtime.cc b/src/runtime.cc index bddc37d5ea..2e0df5001b 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -10150,8 +10150,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { // Find the number of arguments to fill. At least fill the number of // parameters for the function and fill more if more parameters are provided. int argument_count = info.number_of_parameters(); - if (argument_count < it.frame()->ComputeParametersCount()) { - argument_count = it.frame()->ComputeParametersCount(); + if (it.frame()->is_optimized()) { + ASSERT_EQ(argument_count, deoptimized_frame->parameters_count()); + } else { + if (argument_count < it.frame()->ComputeParametersCount()) { + argument_count = it.frame()->ComputeParametersCount(); + } } // Calculate the size of the result. @@ -10220,16 +10224,17 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { details->set(details_index++, heap->undefined_value()); } - // Parameter value. If we are inspecting an optimized frame, use - // undefined as the value. - // - // TODO(3141533): We should be able to get the actual parameter - // value for optimized frames. - if (!it.frame()->is_optimized() && - (i < it.frame()->ComputeParametersCount())) { - details->set(details_index++, it.frame()->GetParameter(i)); + // Parameter value. + if (it.frame()->is_optimized()) { + // Get the value from the deoptimized frame. + details->set(details_index++, deoptimized_frame->GetParameter(i)); } else { - details->set(details_index++, heap->undefined_value()); + if (i < it.frame()->ComputeParametersCount()) { + // Get the value from the stack. + details->set(details_index++, it.frame()->GetParameter(i)); + } else { + details->set(details_index++, heap->undefined_value()); + } } } diff --git a/test/mjsunit/debug-evaluate-locals-optimized-double.js b/test/mjsunit/debug-evaluate-locals-optimized-double.js index 781e3ac821..bbe78d6236 100644 --- a/test/mjsunit/debug-evaluate-locals-optimized-double.js +++ b/test/mjsunit/debug-evaluate-locals-optimized-double.js @@ -41,14 +41,22 @@ function listener(event, exec_state, event_data, data) { for (var i = 0; i < exec_state.frameCount(); i++) { var frame = exec_state.frame(i); - // All frames except the bottom one has normal variables a and b. if (i < exec_state.frameCount() - 1) { + // All frames except the bottom one has normal variables a and b. assertEquals('a', frame.localName(0)); assertEquals('b', frame.localName(1)); assertEquals(i * 2 + 1 + (i * 2 + 1) / 100, frame.localValue(0).value()); assertEquals(i * 2 + 2 + (i * 2 + 2) / 100, frame.localValue(1).value()); + + // All frames except the bottom one has arguments variables x and y. + assertEquals('x', frame.argumentName(0)); + assertEquals('y', frame.argumentName(1)); + assertEquals((i + 1) * 2 + 1 + ((i + 1) * 2 + 1) / 100, + frame.argumentValue(0).value()); + assertEquals((i + 1) * 2 + 2 + ((i + 1) * 2 + 2) / 100, + frame.argumentValue(1).value()); } // Check the frame function. diff --git a/test/mjsunit/debug-evaluate-locals-optimized.js b/test/mjsunit/debug-evaluate-locals-optimized.js index 3cf311d668..7a77c0d32a 100644 --- a/test/mjsunit/debug-evaluate-locals-optimized.js +++ b/test/mjsunit/debug-evaluate-locals-optimized.js @@ -41,12 +41,18 @@ function listener(event, exec_state, event_data, data) { for (var i = 0; i < exec_state.frameCount(); i++) { var frame = exec_state.frame(i); - // All frames except the bottom one has normal variables a and b. if (i < exec_state.frameCount() - 1) { + // All frames except the bottom one has normal variables a and b. assertEquals('a', frame.localName(0)); assertEquals('b', frame.localName(1)); assertEquals(i * 2 + 1, frame.localValue(0).value()); assertEquals(i * 2 + 2, frame.localValue(1).value()); + + // All frames except the bottom one has arguments variables x and y. + assertEquals('x', frame.argumentName(0)); + assertEquals('y', frame.argumentName(1)); + assertEquals((i + 1) * 2 + 1, frame.argumentValue(0).value()); + assertEquals((i + 1) * 2 + 2, frame.argumentValue(1).value()); } // Check the frame function.