Index: src/debug/debug-scopes.cc |
diff --git a/src/debug/debug-scopes.cc b/src/debug/debug-scopes.cc |
index 20df4f164307ad7ace15a69ff87a74ff30e1af06..6a356177f6d8a517e2444e89d2c4c9fab51556af 100644 |
--- a/src/debug/debug-scopes.cc |
+++ b/src/debug/debug-scopes.cc |
@@ -15,10 +15,11 @@ namespace v8 { |
namespace internal { |
ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector, |
- bool ignore_nested_scopes) |
+ ScopeIterator::Option option) |
: isolate_(isolate), |
frame_inspector_(frame_inspector), |
nested_scope_chain_(4), |
+ non_locals_(nullptr), |
seen_script_scope_(false), |
failed_(false) { |
if (!frame_inspector->GetContext()->IsContext() || |
@@ -46,7 +47,8 @@ ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector, |
// 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. |
- |
+ bool ignore_nested_scopes = (option == IGNORE_NESTED_SCOPES); |
+ bool collect_non_locals = (option == COLLECT_NON_LOCALS); |
if (!ignore_nested_scopes && shared_info->HasDebugInfo()) { |
// The source position at return is always the end of the function, |
// which is not consistent with the current scope chain. Therefore all |
@@ -78,35 +80,37 @@ ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector, |
if (scope_info->scope_type() == FUNCTION_SCOPE) { |
nested_scope_chain_.Add(scope_info); |
} |
- } else { |
- // Reparse the code and analyze the scopes. |
+ if (!collect_non_locals) return; |
+ } |
+ |
+ // Reparse the code and analyze the scopes. |
+ Scope* scope = NULL; |
+ // Check whether we are in global, eval or function code. |
+ Zone zone; |
+ if (scope_info->scope_type() != FUNCTION_SCOPE) { |
+ // Global or eval code. |
Handle<Script> script(Script::cast(shared_info->script())); |
- Scope* scope = NULL; |
- |
- // Check whether we are in global, eval or function code. |
- Zone zone; |
- if (scope_info->scope_type() != FUNCTION_SCOPE) { |
- // Global or eval code. |
- ParseInfo info(&zone, script); |
- if (scope_info->scope_type() == SCRIPT_SCOPE) { |
- info.set_global(); |
- } else { |
- DCHECK(scope_info->scope_type() == EVAL_SCOPE); |
- info.set_eval(); |
- info.set_context(Handle<Context>(function->context())); |
- } |
- if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) { |
- scope = info.literal()->scope(); |
- } |
- RetrieveScopeChain(scope, shared_info); |
+ ParseInfo info(&zone, script); |
+ if (scope_info->scope_type() == SCRIPT_SCOPE) { |
+ info.set_global(); |
} else { |
- // Function code |
- ParseInfo info(&zone, function); |
- if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) { |
- scope = info.literal()->scope(); |
- } |
- RetrieveScopeChain(scope, shared_info); |
+ DCHECK(scope_info->scope_type() == EVAL_SCOPE); |
+ info.set_eval(); |
+ info.set_context(Handle<Context>(function->context())); |
+ } |
+ if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) { |
+ scope = info.literal()->scope(); |
+ } |
+ if (!ignore_nested_scopes) RetrieveScopeChain(scope); |
+ if (collect_non_locals) CollectNonLocals(scope); |
+ } else { |
+ // Function code |
+ ParseInfo info(&zone, function); |
+ if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) { |
+ scope = info.literal()->scope(); |
} |
+ if (!ignore_nested_scopes) RetrieveScopeChain(scope); |
+ if (collect_non_locals) CollectNonLocals(scope); |
} |
} |
@@ -115,6 +119,7 @@ ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function) |
: isolate_(isolate), |
frame_inspector_(NULL), |
context_(function->context()), |
+ non_locals_(nullptr), |
seen_script_scope_(false), |
failed_(false) { |
if (!function->shared()->IsSubjectToDebugging()) context_ = Handle<Context>(); |
@@ -320,6 +325,27 @@ Handle<Context> ScopeIterator::CurrentContext() { |
} |
} |
+ |
+void ScopeIterator::GetNonLocals(List<Handle<String> >* list_out) { |
+ Handle<String> this_string = isolate_->factory()->this_string(); |
+ for (HashMap::Entry* entry = non_locals_->Start(); entry != nullptr; |
+ entry = non_locals_->Next(entry)) { |
+ Handle<String> name(reinterpret_cast<String**>(entry->key)); |
+ // We need to treat "this" differently. |
+ if (name.is_identical_to(this_string)) continue; |
+ list_out->Add(Handle<String>(reinterpret_cast<String**>(entry->key))); |
+ } |
+} |
+ |
+ |
+bool ScopeIterator::ThisIsNonLocal() { |
+ Handle<String> this_string = isolate_->factory()->this_string(); |
+ void* key = reinterpret_cast<void*>(this_string.location()); |
+ HashMap::Entry* entry = non_locals_->Lookup(key, this_string->Hash()); |
+ return entry != nullptr; |
+} |
+ |
+ |
#ifdef DEBUG |
// Debug print of the content of the current scope. |
void ScopeIterator::DebugPrint() { |
@@ -385,8 +411,7 @@ void ScopeIterator::DebugPrint() { |
#endif |
-void ScopeIterator::RetrieveScopeChain(Scope* scope, |
- Handle<SharedFunctionInfo> shared_info) { |
+void ScopeIterator::RetrieveScopeChain(Scope* scope) { |
if (scope != NULL) { |
int source_position = frame_inspector_->GetSourcePosition(); |
scope->GetNestedScopeChain(isolate_, &nested_scope_chain_, source_position); |
@@ -403,6 +428,15 @@ void ScopeIterator::RetrieveScopeChain(Scope* scope, |
} |
+void ScopeIterator::CollectNonLocals(Scope* scope) { |
+ if (scope != NULL) { |
+ DCHECK_NULL(non_locals_); |
+ non_locals_ = new HashMap(InternalizedStringMatch); |
+ scope->CollectNonLocals(non_locals_); |
+ } |
+} |
+ |
+ |
MaybeHandle<JSObject> ScopeIterator::MaterializeScriptScope() { |
Handle<JSGlobalObject> global(CurrentContext()->global_object()); |
Handle<ScriptContextTable> script_contexts( |