// 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 #include "src/ast/ast.h" #include "src/ast/scopes.h" #include "src/debug/debug.h" #include "src/frames-inl.h" #include "src/globals.h" #include "src/isolate-inl.h" #include "src/objects/js-generator-inl.h" #include "src/objects/module.h" #include "src/parsing/parse-info.h" #include "src/parsing/parsing.h" #include "src/parsing/rewriter.h" namespace v8 { namespace internal { ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector, ScopeIterator::Option option) : isolate_(isolate), frame_inspector_(frame_inspector), function_(frame_inspector_->GetFunction()), script_(frame_inspector_->GetScript()) { if (!frame_inspector->GetContext()->IsContext()) { // Optimized frame, context or function cannot be materialized. Give up. return; } context_ = Handle::cast(frame_inspector->GetContext()); // We should not instantiate a ScopeIterator for wasm frames. DCHECK_NE(Script::TYPE_WASM, frame_inspector->GetScript()->type()); TryParseAndRetrieveScopes(option); } ScopeIterator::~ScopeIterator() { delete info_; } Handle ScopeIterator::GetFunctionDebugName() const { if (!function_.is_null()) return JSFunction::GetDebugName(function_); if (!context_->IsNativeContext()) { DisallowHeapAllocation no_gc; ScopeInfo* closure_info = context_->closure_context()->scope_info(); Handle debug_name(closure_info->FunctionDebugName(), isolate_); if (debug_name->length() > 0) return debug_name; } return isolate_->factory()->undefined_value(); } ScopeIterator::ScopeIterator(Isolate* isolate, Handle function) : isolate_(isolate), context_(function->context(), isolate), script_(Script::cast(function->shared()->script()), isolate) { if (!function->shared()->IsSubjectToDebugging()) { context_ = Handle(); return; } UnwrapEvaluationContext(); } ScopeIterator::ScopeIterator(Isolate* isolate, Handle generator) : isolate_(isolate), generator_(generator), function_(generator->function(), isolate), context_(generator->context(), isolate), script_(Script::cast(function_->shared()->script()), isolate) { if (!function_->shared()->IsSubjectToDebugging()) { context_ = Handle(); return; } TryParseAndRetrieveScopes(DEFAULT); } void ScopeIterator::Restart() { DCHECK_NOT_NULL(frame_inspector_); function_ = frame_inspector_->GetFunction(); context_ = Handle::cast(frame_inspector_->GetContext()); current_scope_ = start_scope_; DCHECK_NOT_NULL(current_scope_); UnwrapEvaluationContext(); } void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) { // Catch the case when the debugger stops in an internal function. Handle shared_info(function_->shared(), isolate_); Handle scope_info(shared_info->scope_info(), isolate_); if (shared_info->script()->IsUndefined(isolate_)) { current_scope_ = closure_scope_ = nullptr; context_ = handle(function_->context(), isolate_); function_ = Handle(); return; } DCHECK_NE(IGNORE_NESTED_SCOPES, option); bool ignore_nested_scopes = false; if (shared_info->HasBreakInfo() && frame_inspector_ != nullptr) { // 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(), isolate_); // Find the break point where execution has stopped. BreakLocation location = BreakLocation::FromFrame(debug_info, GetFrame()); ignore_nested_scopes = location.IsReturn(); } // Reparse the code and analyze the scopes. // Check whether we are in global, eval or function code. if (scope_info->scope_type() == FUNCTION_SCOPE) { // Inner function. info_ = new ParseInfo(isolate_, shared_info); } else { // Global or eval code. Handle