Commit 50ca2eb9 authored by ulan@chromium.org's avatar ulan@chromium.org

Add option to run ScopeIterator faster giving up nested scope chain.

We'd like to be able to trade nested scope chain info (consisting of with, block and catch scopes) in favor of speed in some cases.

BUG=chromium:340285
LOG=N
R=ulan@chromium.org, pfeldman, ulan, yangguo

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

Patch from Andrey Adaykin <aandrey@chromium.org>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20162 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 90b1077e
...@@ -1692,10 +1692,11 @@ FrameMirror.prototype.scope = function(index) { ...@@ -1692,10 +1692,11 @@ FrameMirror.prototype.scope = function(index) {
}; };
FrameMirror.prototype.allScopes = function() { FrameMirror.prototype.allScopes = function(opt_ignore_nested_scopes) {
var scopeDetails = %GetAllScopesDetails(this.break_id_, var scopeDetails = %GetAllScopesDetails(this.break_id_,
this.details_.frameId(), this.details_.frameId(),
this.details_.inlinedFrameIndex()); this.details_.inlinedFrameIndex(),
!!opt_ignore_nested_scopes);
var result = []; var result = [];
for (var i = 0; i < scopeDetails.length; ++i) { for (var i = 0; i < scopeDetails.length; ++i) {
result.push(new ScopeMirror(this, UNDEFINED, i, scopeDetails[i])); result.push(new ScopeMirror(this, UNDEFINED, i, scopeDetails[i]));
......
...@@ -11815,7 +11815,8 @@ class ScopeIterator { ...@@ -11815,7 +11815,8 @@ class ScopeIterator {
ScopeIterator(Isolate* isolate, ScopeIterator(Isolate* isolate,
JavaScriptFrame* frame, JavaScriptFrame* frame,
int inlined_jsframe_index) int inlined_jsframe_index,
bool ignore_nested_scopes = false)
: isolate_(isolate), : isolate_(isolate),
frame_(frame), frame_(frame),
inlined_jsframe_index_(inlined_jsframe_index), inlined_jsframe_index_(inlined_jsframe_index),
...@@ -11839,19 +11840,31 @@ class ScopeIterator { ...@@ -11839,19 +11840,31 @@ class ScopeIterator {
// Return if ensuring debug info failed. // Return if ensuring debug info failed.
return; return;
} }
Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
// Find the break point where execution has stopped. // Currently it takes too much time to find nested scopes due to script
BreakLocationIterator break_location_iterator(debug_info, // parsing. Sometimes we want to run the ScopeIterator as fast as possible
ALL_BREAK_LOCATIONS); // (for example, while collecting async call stacks on every
// pc points to the instruction after the current one, possibly a break // addEventListener call), even if we drop some nested scopes.
// location as well. So the "- 1" to exclude it from the search. // Later we may optimize getting the nested scopes (cache the result?)
break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); // and include nested scopes into the "fast" iteration case as well.
if (break_location_iterator.IsExit()) { if (!ignore_nested_scopes) {
// We are within the return sequence. At the momemt it is not possible to Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
// Find the break point where execution has stopped.
BreakLocationIterator break_location_iterator(debug_info,
ALL_BREAK_LOCATIONS);
// pc points to the instruction after the current one, possibly a break
// location as well. So the "- 1" to exclude it from the search.
break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
// Within the return sequence at the moment it is not possible to
// get a source position which is consistent with the current scope chain. // get a source position which is consistent with the current scope chain.
// Thus all nested with, catch and block contexts are skipped and we only // Thus all nested with, catch and block contexts are skipped and we only
// provide the function scope. // provide the function scope.
ignore_nested_scopes = break_location_iterator.IsExit();
}
if (ignore_nested_scopes) {
if (scope_info->HasContext()) { if (scope_info->HasContext()) {
context_ = Handle<Context>(context_->declaration_context(), isolate_); context_ = Handle<Context>(context_->declaration_context(), isolate_);
} else { } else {
...@@ -11859,7 +11872,7 @@ class ScopeIterator { ...@@ -11859,7 +11872,7 @@ class ScopeIterator {
context_ = Handle<Context>(context_->previous(), isolate_); context_ = Handle<Context>(context_->previous(), isolate_);
} }
} }
if (scope_info->scope_type() != EVAL_SCOPE) { if (scope_info->scope_type() == FUNCTION_SCOPE) {
nested_scope_chain_.Add(scope_info); nested_scope_chain_.Add(scope_info);
} }
} else { } else {
...@@ -12327,13 +12340,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) { ...@@ -12327,13 +12340,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
// args[0]: number: break id // args[0]: number: break id
// args[1]: number: frame index // args[1]: number: frame index
// args[2]: number: inlined frame index // args[2]: number: inlined frame index
// args[3]: boolean: ignore nested scopes
// //
// The array returned contains arrays with the following information: // The array returned contains arrays with the following information:
// 0: Scope type // 0: Scope type
// 1: Scope object // 1: Scope object
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAllScopesDetails) { RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAllScopesDetails) {
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 3); ASSERT(args.length() == 3 || args.length() == 4);
// Check arguments. // Check arguments.
Object* check; Object* check;
...@@ -12344,13 +12358,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAllScopesDetails) { ...@@ -12344,13 +12358,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAllScopesDetails) {
CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
bool ignore_nested_scopes = false;
if (args.length() == 4) {
CONVERT_BOOLEAN_ARG_CHECKED(flag, 3);
ignore_nested_scopes = flag;
}
// Get the frame where the debugging is performed. // Get the frame where the debugging is performed.
StackFrame::Id id = UnwrapFrameId(wrapped_id); StackFrame::Id id = UnwrapFrameId(wrapped_id);
JavaScriptFrameIterator frame_it(isolate, id); JavaScriptFrameIterator frame_it(isolate, id);
JavaScriptFrame* frame = frame_it.frame(); JavaScriptFrame* frame = frame_it.frame();
List<Handle<JSObject> > result(4); List<Handle<JSObject> > result(4);
ScopeIterator it(isolate, frame, inlined_jsframe_index); ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes);
for (; !it.Done(); it.Next()) { for (; !it.Done(); it.Next()) {
Handle<JSObject> details = MaterializeScopeDetails(isolate, &it); Handle<JSObject> details = MaterializeScopeDetails(isolate, &it);
RETURN_IF_EMPTY_HANDLE(isolate, details); RETURN_IF_EMPTY_HANDLE(isolate, details);
......
...@@ -495,7 +495,7 @@ namespace internal { ...@@ -495,7 +495,7 @@ namespace internal {
F(GetScopeCount, 2, 1) \ F(GetScopeCount, 2, 1) \
F(GetStepInPositions, 2, 1) \ F(GetStepInPositions, 2, 1) \
F(GetScopeDetails, 4, 1) \ F(GetScopeDetails, 4, 1) \
F(GetAllScopesDetails, 3, 1) \ F(GetAllScopesDetails, 4, 1) \
F(GetFunctionScopeCount, 1, 1) \ F(GetFunctionScopeCount, 1, 1) \
F(GetFunctionScopeDetails, 2, 1) \ F(GetFunctionScopeDetails, 2, 1) \
F(SetScopeVariableValue, 6, 1) \ F(SetScopeVariableValue, 6, 1) \
......
...@@ -71,16 +71,29 @@ function BeginTest(name) { ...@@ -71,16 +71,29 @@ function BeginTest(name) {
// Check result of a test. // Check result of a test.
function EndTest() { function EndTest() {
assertTrue(listener_called, "listerner not called for " + test_name); assertTrue(listener_called, "listerner not called for " + test_name);
assertNull(exception, test_name); assertNull(exception, test_name + " / " + exception);
end_test_count++; end_test_count++;
} }
// Check that two scope are the same. // Check that two scope are the same.
function CheckScopeMirrors(scope1, scope2) { function assertScopeMirrorEquals(scope1, scope2) {
assertEquals(scope1.scopeType(), scope2.scopeType()); assertEquals(scope1.scopeType(), scope2.scopeType());
assertEquals(scope1.frameIndex(), scope2.frameIndex()); assertEquals(scope1.frameIndex(), scope2.frameIndex());
assertEquals(scope1.scopeIndex(), scope2.scopeIndex()); assertEquals(scope1.scopeIndex(), scope2.scopeIndex());
assertPropertiesEqual(scope1.scopeObject().value(), scope2.scopeObject().value());
}
function CheckFastAllScopes(scopes, exec_state)
{
var fast_all_scopes = exec_state.frame().allScopes(true);
var length = fast_all_scopes.length;
assertTrue(scopes.length >= length);
for (var i = 0; i < scopes.length && i < length; i++) {
var scope = fast_all_scopes[length - i - 1];
assertTrue(scope.isScope());
assertEquals(scopes[scopes.length - i - 1], scope.scopeType());
}
} }
...@@ -93,7 +106,7 @@ function CheckScopeChain(scopes, exec_state) { ...@@ -93,7 +106,7 @@ function CheckScopeChain(scopes, exec_state) {
var scope = exec_state.frame().scope(i); var scope = exec_state.frame().scope(i);
assertTrue(scope.isScope()); assertTrue(scope.isScope());
assertEquals(scopes[i], scope.scopeType()); assertEquals(scopes[i], scope.scopeType());
CheckScopeMirrors(all_scopes[i], scope); assertScopeMirrorEquals(all_scopes[i], scope);
// Check the global object when hitting the global scope. // Check the global object when hitting the global scope.
if (scopes[i] == debug.ScopeType.Global) { if (scopes[i] == debug.ScopeType.Global) {
...@@ -102,6 +115,7 @@ function CheckScopeChain(scopes, exec_state) { ...@@ -102,6 +115,7 @@ function CheckScopeChain(scopes, exec_state) {
assertPropertiesEqual(this, scope.scopeObject().value()); assertPropertiesEqual(this, scope.scopeObject().value());
} }
} }
CheckFastAllScopes(scopes, exec_state);
// Get the debug command processor. // Get the debug command processor.
var dcp = exec_state.debugCommandProcessor("unspecified_running_state"); var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
......
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