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
This commit is contained in:
ulan@chromium.org 2014-03-21 12:30:58 +00:00
parent 90b1077e31
commit 50ca2eb9f6
4 changed files with 54 additions and 19 deletions

View File

@ -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_,
this.details_.frameId(),
this.details_.inlinedFrameIndex());
this.details_.inlinedFrameIndex(),
!!opt_ignore_nested_scopes);
var result = [];
for (var i = 0; i < scopeDetails.length; ++i) {
result.push(new ScopeMirror(this, UNDEFINED, i, scopeDetails[i]));

View File

@ -11815,7 +11815,8 @@ class ScopeIterator {
ScopeIterator(Isolate* isolate,
JavaScriptFrame* frame,
int inlined_jsframe_index)
int inlined_jsframe_index,
bool ignore_nested_scopes = false)
: isolate_(isolate),
frame_(frame),
inlined_jsframe_index_(inlined_jsframe_index),
@ -11839,19 +11840,31 @@ class ScopeIterator {
// Return if ensuring debug info failed.
return;
}
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);
if (break_location_iterator.IsExit()) {
// We are within the return sequence. At the momemt it is not possible to
// Currently it takes too much time to find nested scopes due to script
// parsing. Sometimes we want to run the ScopeIterator as fast as possible
// (for example, while collecting async call stacks on every
// addEventListener call), even if we drop some nested scopes.
// Later we may optimize getting the nested scopes (cache the result?)
// and include nested scopes into the "fast" iteration case as well.
if (!ignore_nested_scopes) {
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.
// Thus all nested with, catch and block contexts are skipped and we only
// provide the function scope.
ignore_nested_scopes = break_location_iterator.IsExit();
}
if (ignore_nested_scopes) {
if (scope_info->HasContext()) {
context_ = Handle<Context>(context_->declaration_context(), isolate_);
} else {
@ -11859,7 +11872,7 @@ class ScopeIterator {
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);
}
} else {
@ -12327,13 +12340,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
// args[0]: number: break id
// args[1]: number: frame index
// args[2]: number: inlined frame index
// args[3]: boolean: ignore nested scopes
//
// The array returned contains arrays with the following information:
// 0: Scope type
// 1: Scope object
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAllScopesDetails) {
HandleScope scope(isolate);
ASSERT(args.length() == 3);
ASSERT(args.length() == 3 || args.length() == 4);
// Check arguments.
Object* check;
@ -12344,13 +12358,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAllScopesDetails) {
CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
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.
StackFrame::Id id = UnwrapFrameId(wrapped_id);
JavaScriptFrameIterator frame_it(isolate, id);
JavaScriptFrame* frame = frame_it.frame();
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()) {
Handle<JSObject> details = MaterializeScopeDetails(isolate, &it);
RETURN_IF_EMPTY_HANDLE(isolate, details);

View File

@ -495,7 +495,7 @@ namespace internal {
F(GetScopeCount, 2, 1) \
F(GetStepInPositions, 2, 1) \
F(GetScopeDetails, 4, 1) \
F(GetAllScopesDetails, 3, 1) \
F(GetAllScopesDetails, 4, 1) \
F(GetFunctionScopeCount, 1, 1) \
F(GetFunctionScopeDetails, 2, 1) \
F(SetScopeVariableValue, 6, 1) \

View File

@ -71,16 +71,29 @@ function BeginTest(name) {
// Check result of a test.
function EndTest() {
assertTrue(listener_called, "listerner not called for " + test_name);
assertNull(exception, test_name);
assertNull(exception, test_name + " / " + exception);
end_test_count++;
}
// Check that two scope are the same.
function CheckScopeMirrors(scope1, scope2) {
function assertScopeMirrorEquals(scope1, scope2) {
assertEquals(scope1.scopeType(), scope2.scopeType());
assertEquals(scope1.frameIndex(), scope2.frameIndex());
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) {
var scope = exec_state.frame().scope(i);
assertTrue(scope.isScope());
assertEquals(scopes[i], scope.scopeType());
CheckScopeMirrors(all_scopes[i], scope);
assertScopeMirrorEquals(all_scopes[i], scope);
// Check the global object when hitting the global scope.
if (scopes[i] == debug.ScopeType.Global) {
@ -102,6 +115,7 @@ function CheckScopeChain(scopes, exec_state) {
assertPropertiesEqual(this, scope.scopeObject().value());
}
}
CheckFastAllScopes(scopes, exec_state);
// Get the debug command processor.
var dcp = exec_state.debugCommandProcessor("unspecified_running_state");