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),
// 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 {
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 {
// 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;
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);
// 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());
+ }
}
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) {
assertPropertiesEqual(this, scope.scopeObject().value());
}
}
+ CheckFastAllScopes(scopes, exec_state);
// Get the debug command processor.
var dcp = exec_state.debugCommandProcessor("unspecified_running_state");