OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/debug/debug-scopes.h" | 5 #include "src/debug/debug-scopes.h" |
6 | 6 |
7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
8 #include "src/debug/debug.h" | 8 #include "src/debug/debug.h" |
9 #include "src/frames-inl.h" | 9 #include "src/frames-inl.h" |
10 #include "src/globals.h" | 10 #include "src/globals.h" |
11 #include "src/isolate-inl.h" | 11 #include "src/isolate-inl.h" |
12 #include "src/parsing/parser.h" | 12 #include "src/parsing/parser.h" |
13 | 13 |
14 namespace v8 { | 14 namespace v8 { |
15 namespace internal { | 15 namespace internal { |
16 | 16 |
17 ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector, | 17 ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector, |
18 bool ignore_nested_scopes) | 18 ScopeIterator::Option option) |
19 : isolate_(isolate), | 19 : isolate_(isolate), |
20 frame_inspector_(frame_inspector), | 20 frame_inspector_(frame_inspector), |
21 nested_scope_chain_(4), | 21 nested_scope_chain_(4), |
| 22 non_locals_(nullptr), |
22 seen_script_scope_(false), | 23 seen_script_scope_(false), |
23 failed_(false) { | 24 failed_(false) { |
24 if (!frame_inspector->GetContext()->IsContext() || | 25 if (!frame_inspector->GetContext()->IsContext() || |
25 !frame_inspector->GetFunction()->IsJSFunction()) { | 26 !frame_inspector->GetFunction()->IsJSFunction()) { |
26 // Optimized frame, context or function cannot be materialized. Give up. | 27 // Optimized frame, context or function cannot be materialized. Give up. |
27 return; | 28 return; |
28 } | 29 } |
29 | 30 |
30 context_ = Handle<Context>(Context::cast(frame_inspector->GetContext())); | 31 context_ = Handle<Context>(Context::cast(frame_inspector->GetContext())); |
31 | 32 |
32 // Catch the case when the debugger stops in an internal function. | 33 // Catch the case when the debugger stops in an internal function. |
33 Handle<JSFunction> function = GetFunction(); | 34 Handle<JSFunction> function = GetFunction(); |
34 Handle<SharedFunctionInfo> shared_info(function->shared()); | 35 Handle<SharedFunctionInfo> shared_info(function->shared()); |
35 Handle<ScopeInfo> scope_info(shared_info->scope_info()); | 36 Handle<ScopeInfo> scope_info(shared_info->scope_info()); |
36 if (shared_info->script() == isolate->heap()->undefined_value()) { | 37 if (shared_info->script() == isolate->heap()->undefined_value()) { |
37 while (context_->closure() == *function) { | 38 while (context_->closure() == *function) { |
38 context_ = Handle<Context>(context_->previous(), isolate_); | 39 context_ = Handle<Context>(context_->previous(), isolate_); |
39 } | 40 } |
40 return; | 41 return; |
41 } | 42 } |
42 | 43 |
43 // Currently it takes too much time to find nested scopes due to script | 44 // Currently it takes too much time to find nested scopes due to script |
44 // parsing. Sometimes we want to run the ScopeIterator as fast as possible | 45 // parsing. Sometimes we want to run the ScopeIterator as fast as possible |
45 // (for example, while collecting async call stacks on every | 46 // (for example, while collecting async call stacks on every |
46 // addEventListener call), even if we drop some nested scopes. | 47 // addEventListener call), even if we drop some nested scopes. |
47 // Later we may optimize getting the nested scopes (cache the result?) | 48 // Later we may optimize getting the nested scopes (cache the result?) |
48 // and include nested scopes into the "fast" iteration case as well. | 49 // and include nested scopes into the "fast" iteration case as well. |
49 | 50 bool ignore_nested_scopes = (option == IGNORE_NESTED_SCOPES); |
| 51 bool collect_non_locals = (option == COLLECT_NON_LOCALS); |
50 if (!ignore_nested_scopes && shared_info->HasDebugInfo()) { | 52 if (!ignore_nested_scopes && shared_info->HasDebugInfo()) { |
51 // The source position at return is always the end of the function, | 53 // The source position at return is always the end of the function, |
52 // which is not consistent with the current scope chain. Therefore all | 54 // which is not consistent with the current scope chain. Therefore all |
53 // nested with, catch and block contexts are skipped, and we can only | 55 // nested with, catch and block contexts are skipped, and we can only |
54 // inspect the function scope. | 56 // inspect the function scope. |
55 // This can only happen if we set a break point inside right before the | 57 // This can only happen if we set a break point inside right before the |
56 // return, which requires a debug info to be available. | 58 // return, which requires a debug info to be available. |
57 Handle<DebugInfo> debug_info(shared_info->GetDebugInfo()); | 59 Handle<DebugInfo> debug_info(shared_info->GetDebugInfo()); |
58 | 60 |
59 // PC points to the instruction after the current one, possibly a break | 61 // PC points to the instruction after the current one, possibly a break |
(...skipping 11 matching lines...) Expand all Loading... |
71 if (scope_info->HasContext()) { | 73 if (scope_info->HasContext()) { |
72 context_ = Handle<Context>(context_->declaration_context(), isolate_); | 74 context_ = Handle<Context>(context_->declaration_context(), isolate_); |
73 } else { | 75 } else { |
74 while (context_->closure() == *function) { | 76 while (context_->closure() == *function) { |
75 context_ = Handle<Context>(context_->previous(), isolate_); | 77 context_ = Handle<Context>(context_->previous(), isolate_); |
76 } | 78 } |
77 } | 79 } |
78 if (scope_info->scope_type() == FUNCTION_SCOPE) { | 80 if (scope_info->scope_type() == FUNCTION_SCOPE) { |
79 nested_scope_chain_.Add(scope_info); | 81 nested_scope_chain_.Add(scope_info); |
80 } | 82 } |
| 83 if (!collect_non_locals) return; |
| 84 } |
| 85 |
| 86 // Reparse the code and analyze the scopes. |
| 87 Scope* scope = NULL; |
| 88 // Check whether we are in global, eval or function code. |
| 89 Zone zone; |
| 90 if (scope_info->scope_type() != FUNCTION_SCOPE) { |
| 91 // Global or eval code. |
| 92 Handle<Script> script(Script::cast(shared_info->script())); |
| 93 ParseInfo info(&zone, script); |
| 94 if (scope_info->scope_type() == SCRIPT_SCOPE) { |
| 95 info.set_global(); |
| 96 } else { |
| 97 DCHECK(scope_info->scope_type() == EVAL_SCOPE); |
| 98 info.set_eval(); |
| 99 info.set_context(Handle<Context>(function->context())); |
| 100 } |
| 101 if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) { |
| 102 scope = info.literal()->scope(); |
| 103 } |
| 104 if (!ignore_nested_scopes) RetrieveScopeChain(scope); |
| 105 if (collect_non_locals) CollectNonLocals(scope); |
81 } else { | 106 } else { |
82 // Reparse the code and analyze the scopes. | 107 // Function code |
83 Handle<Script> script(Script::cast(shared_info->script())); | 108 ParseInfo info(&zone, function); |
84 Scope* scope = NULL; | 109 if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) { |
85 | 110 scope = info.literal()->scope(); |
86 // Check whether we are in global, eval or function code. | |
87 Zone zone; | |
88 if (scope_info->scope_type() != FUNCTION_SCOPE) { | |
89 // Global or eval code. | |
90 ParseInfo info(&zone, script); | |
91 if (scope_info->scope_type() == SCRIPT_SCOPE) { | |
92 info.set_global(); | |
93 } else { | |
94 DCHECK(scope_info->scope_type() == EVAL_SCOPE); | |
95 info.set_eval(); | |
96 info.set_context(Handle<Context>(function->context())); | |
97 } | |
98 if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) { | |
99 scope = info.literal()->scope(); | |
100 } | |
101 RetrieveScopeChain(scope, shared_info); | |
102 } else { | |
103 // Function code | |
104 ParseInfo info(&zone, function); | |
105 if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) { | |
106 scope = info.literal()->scope(); | |
107 } | |
108 RetrieveScopeChain(scope, shared_info); | |
109 } | 111 } |
| 112 if (!ignore_nested_scopes) RetrieveScopeChain(scope); |
| 113 if (collect_non_locals) CollectNonLocals(scope); |
110 } | 114 } |
111 } | 115 } |
112 | 116 |
113 | 117 |
114 ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function) | 118 ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function) |
115 : isolate_(isolate), | 119 : isolate_(isolate), |
116 frame_inspector_(NULL), | 120 frame_inspector_(NULL), |
117 context_(function->context()), | 121 context_(function->context()), |
| 122 non_locals_(nullptr), |
118 seen_script_scope_(false), | 123 seen_script_scope_(false), |
119 failed_(false) { | 124 failed_(false) { |
120 if (!function->shared()->IsSubjectToDebugging()) context_ = Handle<Context>(); | 125 if (!function->shared()->IsSubjectToDebugging()) context_ = Handle<Context>(); |
121 } | 126 } |
122 | 127 |
123 | 128 |
124 MUST_USE_RESULT MaybeHandle<JSObject> ScopeIterator::MaterializeScopeDetails() { | 129 MUST_USE_RESULT MaybeHandle<JSObject> ScopeIterator::MaterializeScopeDetails() { |
125 // Calculate the size of the result. | 130 // Calculate the size of the result. |
126 Handle<FixedArray> details = | 131 Handle<FixedArray> details = |
127 isolate_->factory()->NewFixedArray(kScopeDetailsSize); | 132 isolate_->factory()->NewFixedArray(kScopeDetailsSize); |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript || | 318 if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript || |
314 nested_scope_chain_.is_empty()) { | 319 nested_scope_chain_.is_empty()) { |
315 return context_; | 320 return context_; |
316 } else if (nested_scope_chain_.last()->HasContext()) { | 321 } else if (nested_scope_chain_.last()->HasContext()) { |
317 return context_; | 322 return context_; |
318 } else { | 323 } else { |
319 return Handle<Context>(); | 324 return Handle<Context>(); |
320 } | 325 } |
321 } | 326 } |
322 | 327 |
| 328 |
| 329 void ScopeIterator::GetNonLocals(List<Handle<String> >* list_out) { |
| 330 Handle<String> this_string = isolate_->factory()->this_string(); |
| 331 for (HashMap::Entry* entry = non_locals_->Start(); entry != nullptr; |
| 332 entry = non_locals_->Next(entry)) { |
| 333 Handle<String> name(reinterpret_cast<String**>(entry->key)); |
| 334 // We need to treat "this" differently. |
| 335 if (name.is_identical_to(this_string)) continue; |
| 336 list_out->Add(Handle<String>(reinterpret_cast<String**>(entry->key))); |
| 337 } |
| 338 } |
| 339 |
| 340 |
| 341 bool ScopeIterator::ThisIsNonLocal() { |
| 342 Handle<String> this_string = isolate_->factory()->this_string(); |
| 343 void* key = reinterpret_cast<void*>(this_string.location()); |
| 344 HashMap::Entry* entry = non_locals_->Lookup(key, this_string->Hash()); |
| 345 return entry != nullptr; |
| 346 } |
| 347 |
| 348 |
323 #ifdef DEBUG | 349 #ifdef DEBUG |
324 // Debug print of the content of the current scope. | 350 // Debug print of the content of the current scope. |
325 void ScopeIterator::DebugPrint() { | 351 void ScopeIterator::DebugPrint() { |
326 OFStream os(stdout); | 352 OFStream os(stdout); |
327 DCHECK(!failed_); | 353 DCHECK(!failed_); |
328 switch (Type()) { | 354 switch (Type()) { |
329 case ScopeIterator::ScopeTypeGlobal: | 355 case ScopeIterator::ScopeTypeGlobal: |
330 os << "Global:\n"; | 356 os << "Global:\n"; |
331 CurrentContext()->Print(os); | 357 CurrentContext()->Print(os); |
332 break; | 358 break; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 break; | 404 break; |
379 | 405 |
380 default: | 406 default: |
381 UNREACHABLE(); | 407 UNREACHABLE(); |
382 } | 408 } |
383 PrintF("\n"); | 409 PrintF("\n"); |
384 } | 410 } |
385 #endif | 411 #endif |
386 | 412 |
387 | 413 |
388 void ScopeIterator::RetrieveScopeChain(Scope* scope, | 414 void ScopeIterator::RetrieveScopeChain(Scope* scope) { |
389 Handle<SharedFunctionInfo> shared_info) { | |
390 if (scope != NULL) { | 415 if (scope != NULL) { |
391 int source_position = frame_inspector_->GetSourcePosition(); | 416 int source_position = frame_inspector_->GetSourcePosition(); |
392 scope->GetNestedScopeChain(isolate_, &nested_scope_chain_, source_position); | 417 scope->GetNestedScopeChain(isolate_, &nested_scope_chain_, source_position); |
393 } else { | 418 } else { |
394 // A failed reparse indicates that the preparser has diverged from the | 419 // A failed reparse indicates that the preparser has diverged from the |
395 // parser or that the preparse data given to the initial parse has been | 420 // parser or that the preparse data given to the initial parse has been |
396 // faulty. We fail in debug mode but in release mode we only provide the | 421 // faulty. We fail in debug mode but in release mode we only provide the |
397 // information we get from the context chain but nothing about | 422 // information we get from the context chain but nothing about |
398 // completely stack allocated scopes or stack allocated locals. | 423 // completely stack allocated scopes or stack allocated locals. |
399 // Or it could be due to stack overflow. | 424 // Or it could be due to stack overflow. |
400 DCHECK(isolate_->has_pending_exception()); | 425 DCHECK(isolate_->has_pending_exception()); |
401 failed_ = true; | 426 failed_ = true; |
402 } | 427 } |
403 } | 428 } |
404 | 429 |
405 | 430 |
| 431 void ScopeIterator::CollectNonLocals(Scope* scope) { |
| 432 if (scope != NULL) { |
| 433 DCHECK_NULL(non_locals_); |
| 434 non_locals_ = new HashMap(InternalizedStringMatch); |
| 435 scope->CollectNonLocals(non_locals_); |
| 436 } |
| 437 } |
| 438 |
| 439 |
406 MaybeHandle<JSObject> ScopeIterator::MaterializeScriptScope() { | 440 MaybeHandle<JSObject> ScopeIterator::MaterializeScriptScope() { |
407 Handle<JSGlobalObject> global(CurrentContext()->global_object()); | 441 Handle<JSGlobalObject> global(CurrentContext()->global_object()); |
408 Handle<ScriptContextTable> script_contexts( | 442 Handle<ScriptContextTable> script_contexts( |
409 global->native_context()->script_context_table()); | 443 global->native_context()->script_context_table()); |
410 | 444 |
411 Handle<JSObject> script_scope = | 445 Handle<JSObject> script_scope = |
412 isolate_->factory()->NewJSObject(isolate_->object_function()); | 446 isolate_->factory()->NewJSObject(isolate_->object_function()); |
413 | 447 |
414 for (int context_index = 0; context_index < script_contexts->used(); | 448 for (int context_index = 0; context_index < script_contexts->used(); |
415 context_index++) { | 449 context_index++) { |
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
783 isolate_, value, Object::GetPropertyOrElement(extension, key), false); | 817 isolate_, value, Object::GetPropertyOrElement(extension, key), false); |
784 RETURN_ON_EXCEPTION_VALUE( | 818 RETURN_ON_EXCEPTION_VALUE( |
785 isolate_, JSObject::SetOwnPropertyIgnoreAttributes( | 819 isolate_, JSObject::SetOwnPropertyIgnoreAttributes( |
786 scope_object, key, value, NONE), false); | 820 scope_object, key, value, NONE), false); |
787 } | 821 } |
788 return true; | 822 return true; |
789 } | 823 } |
790 | 824 |
791 } // namespace internal | 825 } // namespace internal |
792 } // namespace v8 | 826 } // namespace v8 |
OLD | NEW |