// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/debug/debug-scopes.h" #include "src/debug/debug.h" #include "src/frames-inl.h" #include "src/globals.h" #include "src/isolate-inl.h" #include "src/parser.h" #include "src/scopes.h" namespace v8 { namespace internal { ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector, bool ignore_nested_scopes) : isolate_(isolate), frame_inspector_(frame_inspector), nested_scope_chain_(4), seen_script_scope_(false), failed_(false) { if (!frame_inspector->GetContext()->IsContext() || !frame_inspector->GetFunction()->IsJSFunction()) { // Optimized frame, context or function cannot be materialized. Give up. return; } context_ = Handle(Context::cast(frame_inspector->GetContext())); // Catch the case when the debugger stops in an internal function. Handle function = GetFunction(); Handle shared_info(function->shared()); Handle scope_info(shared_info->scope_info()); if (shared_info->script() == isolate->heap()->undefined_value()) { while (context_->closure() == *function) { context_ = Handle(context_->previous(), isolate_); } return; } // 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 && 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 // nested with, catch and block contexts are skipped, and we can only // inspect the function scope. // This can only happen if we set a break point inside right before the // return, which requires a debug info to be available. Handle debug_info(shared_info->GetDebugInfo()); // PC points to the instruction after the current one, possibly a break // location as well. So the "- 1" to exclude it from the search. Address call_pc = GetFrame()->pc() - 1; // Find the break point where execution has stopped. BreakLocation location = BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); ignore_nested_scopes = location.IsReturn(); } if (ignore_nested_scopes) { if (scope_info->HasContext()) { context_ = Handle(context_->declaration_context(), isolate_); } else { while (context_->closure() == *function) { context_ = Handle(context_->previous(), isolate_); } } if (scope_info->scope_type() == FUNCTION_SCOPE) { nested_scope_chain_.Add(scope_info); } } else { // Reparse the code and analyze the scopes. Handle