LCOV - code coverage report
Current view: top level - src/debug - debug-scopes.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 352 371 94.9 %
Date: 2017-10-20 Functions: 42 45 93.3 %

          Line data    Source code
       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
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/debug/debug-scopes.h"
       6             : 
       7             : #include <memory>
       8             : 
       9             : #include "src/ast/ast.h"
      10             : #include "src/ast/scopes.h"
      11             : #include "src/debug/debug.h"
      12             : #include "src/frames-inl.h"
      13             : #include "src/globals.h"
      14             : #include "src/isolate-inl.h"
      15             : #include "src/parsing/parse-info.h"
      16             : #include "src/parsing/parsing.h"
      17             : #include "src/parsing/rewriter.h"
      18             : 
      19             : namespace v8 {
      20             : namespace internal {
      21             : 
      22      135623 : ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
      23             :                              ScopeIterator::Option option)
      24             :     : isolate_(isolate),
      25             :       frame_inspector_(frame_inspector),
      26      271246 :       seen_script_scope_(false) {
      27      271246 :   if (!frame_inspector->GetContext()->IsContext()) {
      28             :     // Optimized frame, context or function cannot be materialized. Give up.
      29      135623 :     return;
      30             :   }
      31             : 
      32             :   // We should not instantiate a ScopeIterator for wasm frames.
      33             :   DCHECK(frame_inspector->GetScript()->type() != Script::TYPE_WASM);
      34             : 
      35      135509 :   TryParseAndRetrieveScopes(option);
      36             : }
      37             : 
      38      211693 : void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) {
      39      136894 :   context_ = GetContext();
      40             : 
      41             :   // Catch the case when the debugger stops in an internal function.
      42      136894 :   Handle<JSFunction> function = GetFunction();
      43             :   Handle<SharedFunctionInfo> shared_info(function->shared());
      44             :   Handle<ScopeInfo> scope_info(shared_info->scope_info());
      45      273788 :   if (shared_info->script()->IsUndefined(isolate_)) {
      46           0 :     while (context_->closure() == *function) {
      47           0 :       context_ = Handle<Context>(context_->previous(), isolate_);
      48             :     }
      49        5499 :     return;
      50             :   }
      51             : 
      52             :   // Currently it takes too much time to find nested scopes due to script
      53             :   // parsing. Sometimes we want to run the ScopeIterator as fast as possible
      54             :   // (for example, while collecting async call stacks on every
      55             :   // addEventListener call), even if we drop some nested scopes.
      56             :   // Later we may optimize getting the nested scopes (cache the result?)
      57             :   // and include nested scopes into the "fast" iteration case as well.
      58      136894 :   bool ignore_nested_scopes = (option == IGNORE_NESTED_SCOPES);
      59      136894 :   bool collect_non_locals = (option == COLLECT_NON_LOCALS);
      60      348587 :   if (!ignore_nested_scopes && shared_info->HasBreakInfo() &&
      61       74799 :       frame_inspector_ != nullptr) {
      62             :     // The source position at return is always the end of the function,
      63             :     // which is not consistent with the current scope chain. Therefore all
      64             :     // nested with, catch and block contexts are skipped, and we can only
      65             :     // inspect the function scope.
      66             :     // This can only happen if we set a break point inside right before the
      67             :     // return, which requires a debug info to be available.
      68       74799 :     Handle<DebugInfo> debug_info(shared_info->GetDebugInfo());
      69             : 
      70             :     // Find the break point where execution has stopped.
      71       74799 :     BreakLocation location = BreakLocation::FromFrame(debug_info, GetFrame());
      72             : 
      73       74799 :     ignore_nested_scopes = location.IsReturn();
      74             :   }
      75             : 
      76      136894 :   if (ignore_nested_scopes) {
      77        5940 :     if (scope_info->HasContext()) {
      78         261 :       context_ = Handle<Context>(context_->declaration_context(), isolate_);
      79             :     } else {
      80        5935 :       while (context_->closure() == *function) {
      81         164 :         context_ = Handle<Context>(context_->previous(), isolate_);
      82             :       }
      83             :     }
      84        5940 :     if (scope_info->scope_type() == FUNCTION_SCOPE) {
      85             :       nested_scope_chain_.emplace_back(scope_info,
      86             :                                        shared_info->start_position(),
      87        7552 :                                        shared_info->end_position());
      88             :     }
      89        5940 :     if (!collect_non_locals) return;
      90             :   }
      91             : 
      92             :   // Reparse the code and analyze the scopes.
      93             :   // Check whether we are in global, eval or function code.
      94             :   std::unique_ptr<ParseInfo> info;
      95      131395 :   if (scope_info->scope_type() != FUNCTION_SCOPE) {
      96             :     // Global or eval code.
      97             :     Handle<Script> script(Script::cast(shared_info->script()));
      98       51667 :     info.reset(new ParseInfo(script));
      99       51667 :     if (scope_info->scope_type() == EVAL_SCOPE) {
     100             :       info->set_eval();
     101        3821 :       if (!function->context()->IsNativeContext()) {
     102        1614 :         info->set_outer_scope_info(handle(function->context()->scope_info()));
     103             :       }
     104             :       // Language mode may be inherited from the eval caller.
     105             :       // Retrieve it from shared function info.
     106             :       info->set_language_mode(shared_info->language_mode());
     107       47846 :     } else if (scope_info->scope_type() == MODULE_SCOPE) {
     108             :       info->set_module();
     109             :     } else {
     110             :       DCHECK(scope_info->scope_type() == SCRIPT_SCOPE);
     111             :     }
     112             :   } else {
     113             :     // Inner function.
     114       79728 :     info.reset(new ParseInfo(shared_info));
     115             :   }
     116      262298 :   if (parsing::ParseAny(info.get(), shared_info, isolate_) &&
     117      130903 :       Rewriter::Rewrite(info.get())) {
     118      261806 :     info->ast_value_factory()->Internalize(isolate_);
     119      130903 :     DeclarationScope* scope = info->literal()->scope();
     120      130903 :     if (!ignore_nested_scopes || collect_non_locals) {
     121      130903 :       CollectNonLocals(info.get(), scope);
     122             :     }
     123      130903 :     if (!ignore_nested_scopes) {
     124      130462 :       DeclarationScope::Analyze(info.get());
     125             :       DeclarationScope::AllocateScopeInfos(info.get(), isolate_,
     126      130462 :                                            AnalyzeMode::kDebugger);
     127      130462 :       RetrieveScopeChain(scope);
     128             :     }
     129             :   } else {
     130             :     // A failed reparse indicates that the preparser has diverged from the
     131             :     // parser or that the preparse data given to the initial parse has been
     132             :     // faulty. We fail in debug mode but in release mode we only provide the
     133             :     // information we get from the context chain but nothing about
     134             :     // completely stack allocated scopes or stack allocated locals.
     135             :     // Or it could be due to stack overflow.
     136             :     // Silently fail by presenting an empty context chain.
     137         492 :     CHECK(isolate_->has_pending_exception());
     138         492 :     isolate_->clear_pending_exception();
     139         492 :     context_ = Handle<Context>();
     140             :   }
     141      131395 :   UnwrapEvaluationContext();
     142             : }
     143             : 
     144          25 : ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
     145             :     : isolate_(isolate),
     146             :       context_(function->context()),
     147          50 :       seen_script_scope_(false) {
     148          25 :   if (!function->shared()->IsSubjectToDebugging()) context_ = Handle<Context>();
     149          25 :   UnwrapEvaluationContext();
     150          25 : }
     151             : 
     152        1385 : ScopeIterator::ScopeIterator(Isolate* isolate,
     153             :                              Handle<JSGeneratorObject> generator)
     154             :     : isolate_(isolate),
     155             :       generator_(generator),
     156             :       context_(generator->context()),
     157        2770 :       seen_script_scope_(false) {
     158        1385 :   if (!generator->function()->shared()->IsSubjectToDebugging()) {
     159           0 :     context_ = Handle<Context>();
     160        1385 :     return;
     161             :   }
     162        1385 :   TryParseAndRetrieveScopes(DEFAULT);
     163             : }
     164             : 
     165      474872 : void ScopeIterator::UnwrapEvaluationContext() {
     166             :   while (true) {
     167      474872 :     if (context_.is_null()) return;
     168      349801 :     if (!context_->IsDebugEvaluateContext()) return;
     169             :     Handle<Object> wrapped(context_->get(Context::WRAPPED_CONTEXT_INDEX),
     170           0 :                            isolate_);
     171           0 :     if (wrapped->IsContext()) {
     172           0 :       context_ = Handle<Context>::cast(wrapped);
     173             :     } else {
     174           0 :       context_ = Handle<Context>(context_->previous(), isolate_);
     175             :     }
     176             :   }
     177             : }
     178             : 
     179             : 
     180         965 : MUST_USE_RESULT MaybeHandle<JSObject> ScopeIterator::MaterializeScopeDetails() {
     181             :   // Calculate the size of the result.
     182             :   Handle<FixedArray> details =
     183         965 :       isolate_->factory()->NewFixedArray(kScopeDetailsSize);
     184             :   // Fill in scope details.
     185         965 :   details->set(kScopeDetailsTypeIndex, Smi::FromInt(Type()));
     186             :   Handle<JSObject> scope_object;
     187        1930 :   ASSIGN_RETURN_ON_EXCEPTION(isolate_, scope_object, ScopeObject(), JSObject);
     188         965 :   details->set(kScopeDetailsObjectIndex, *scope_object);
     189         965 :   if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript) {
     190         670 :     return isolate_->factory()->NewJSArrayWithElements(details);
     191             :   }
     192             : 
     193         630 :   Handle<JSFunction> js_function = GetClosure();
     194         630 :   if (!js_function.is_null()) {
     195         630 :     Handle<String> closure_name = JSFunction::GetDebugName(js_function);
     196        1260 :     if (!closure_name.is_null() && closure_name->length() != 0) {
     197         612 :       details->set(kScopeDetailsNameIndex, *closure_name);
     198             :     }
     199             :     details->set(kScopeDetailsStartPositionIndex,
     200         630 :                  Smi::FromInt(start_position()));
     201         630 :     details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position()));
     202         630 :     details->set(kScopeDetailsFunctionIndex, *js_function);
     203             :   }
     204        1260 :   return isolate_->factory()->NewJSArrayWithElements(details);
     205             : }
     206             : 
     207      503032 : Handle<JSFunction> ScopeIterator::GetClosure() {
     208      503032 :   if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript)
     209             :     return Handle<JSFunction>::null();
     210      265319 :   if (HasNestedScopeChain()) return GetFunction();
     211      142668 :   return HasContext() ? handle(CurrentContext()->closure())
     212       35667 :                       : Handle<JSFunction>::null();
     213             : }
     214             : 
     215       88843 : int ScopeIterator::start_position() {
     216       88843 :   if (HasNestedScopeChain()) {
     217       76947 :     return LastNestedScopeChain().start_position;
     218             :   }
     219       11896 :   if (!HasContext()) return 0;
     220       23792 :   Handle<JSFunction> js_function = handle(CurrentContext()->closure());
     221       23792 :   return js_function.is_null() ? 0 : js_function->shared()->start_position();
     222             : }
     223             : 
     224       88843 : int ScopeIterator::end_position() {
     225       88843 :   if (HasNestedScopeChain()) {
     226       76947 :     return LastNestedScopeChain().end_position;
     227             :   }
     228       11896 :   if (!HasContext()) return 0;
     229       23792 :   Handle<JSFunction> js_function = handle(CurrentContext()->closure());
     230       23792 :   return js_function.is_null() ? 0 : js_function->shared()->end_position();
     231             : }
     232             : 
     233      343452 : void ScopeIterator::Next() {
     234             :   DCHECK(!Done());
     235      343452 :   ScopeType scope_type = Type();
     236      343452 :   if (scope_type == ScopeTypeGlobal) {
     237             :     // The global scope is always the last in the chain.
     238             :     DCHECK(context_->IsNativeContext());
     239      124579 :     context_ = Handle<Context>();
     240      218873 :   } else if (scope_type == ScopeTypeScript) {
     241      124741 :     seen_script_scope_ = true;
     242      124741 :     if (context_->IsScriptContext()) {
     243       16456 :       context_ = Handle<Context>(context_->previous(), isolate_);
     244             :     }
     245      124741 :     if (HasNestedScopeChain()) {
     246             :       DCHECK_EQ(LastNestedScopeChain().scope_info->scope_type(), SCRIPT_SCOPE);
     247             :       nested_scope_chain_.pop_back();
     248             :       DCHECK(!HasNestedScopeChain());
     249             :     }
     250      124741 :     CHECK(context_->IsNativeContext());
     251       94132 :   } else if (!HasNestedScopeChain()) {
     252       23928 :     context_ = Handle<Context>(context_->previous(), isolate_);
     253             :   } else {
     254        7376 :     do {
     255       83372 :       if (LastNestedScopeChain().scope_info->HasContext()) {
     256             :         DCHECK(context_->previous() != nullptr);
     257       29202 :         context_ = Handle<Context>(context_->previous(), isolate_);
     258             :       }
     259             :       nested_scope_chain_.pop_back();
     260       83372 :       if (!HasNestedScopeChain()) break;
     261             :       // Repeat to skip hidden scopes.
     262             :     } while (LastNestedScopeChain().is_hidden());
     263             :   }
     264      343452 :   UnwrapEvaluationContext();
     265      343452 : }
     266             : 
     267             : 
     268             : // Return the type of the current scope.
     269     3201388 : ScopeIterator::ScopeType ScopeIterator::Type() {
     270             :   DCHECK(!Done());
     271     3201388 :   if (HasNestedScopeChain()) {
     272     1321040 :     Handle<ScopeInfo> scope_info = LastNestedScopeChain().scope_info;
     273     1321040 :     switch (scope_info->scope_type()) {
     274             :       case FUNCTION_SCOPE:
     275             :         DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
     276             :         return ScopeTypeLocal;
     277             :       case MODULE_SCOPE:
     278             :         DCHECK(context_->IsModuleContext());
     279        7660 :         return ScopeTypeModule;
     280             :       case SCRIPT_SCOPE:
     281             :         DCHECK(context_->IsScriptContext() || context_->IsNativeContext());
     282      494305 :         return ScopeTypeScript;
     283             :       case WITH_SCOPE:
     284             :         DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext());
     285       25041 :         return ScopeTypeWith;
     286             :       case CATCH_SCOPE:
     287             :         DCHECK(context_->IsCatchContext());
     288        9814 :         return ScopeTypeCatch;
     289             :       case BLOCK_SCOPE:
     290             :         DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
     291       27756 :         return ScopeTypeBlock;
     292             :       case EVAL_SCOPE:
     293             :         DCHECK(!scope_info->HasContext() || context_->IsEvalContext());
     294       12369 :         return ScopeTypeEval;
     295             :     }
     296           0 :     UNREACHABLE();
     297             :   }
     298     1880348 :   if (context_->IsNativeContext()) {
     299             :     DCHECK(context_->global_object()->IsJSGlobalObject());
     300             :     // If we are at the native context and have not yet seen script scope,
     301             :     // fake it.
     302     1483964 :     return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript;
     303             :   }
     304      512583 :   if (context_->IsFunctionContext() || context_->IsEvalContext()) {
     305             :     return ScopeTypeClosure;
     306             :   }
     307      115909 :   if (context_->IsCatchContext()) {
     308             :     return ScopeTypeCatch;
     309             :   }
     310      107424 :   if (context_->IsBlockContext()) {
     311             :     return ScopeTypeBlock;
     312             :   }
     313      106089 :   if (context_->IsModuleContext()) {
     314             :     return ScopeTypeModule;
     315             :   }
     316       83544 :   if (context_->IsScriptContext()) {
     317             :     return ScopeTypeScript;
     318             :   }
     319             :   DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext());
     320       11233 :   return ScopeTypeWith;
     321             : }
     322             : 
     323             : 
     324      458741 : MaybeHandle<JSObject> ScopeIterator::ScopeObject() {
     325             :   DCHECK(!Done());
     326      458741 :   switch (Type()) {
     327             :     case ScopeIterator::ScopeTypeGlobal:
     328      373332 :       return Handle<JSObject>(CurrentContext()->global_proxy());
     329             :     case ScopeIterator::ScopeTypeScript:
     330      237896 :       return MaterializeScriptScope();
     331             :     case ScopeIterator::ScopeTypeLocal:
     332             :       // Materialize the content of the local scope into a JSObject.
     333             :       DCHECK_EQ(1, nested_scope_chain_.size());
     334       71247 :       return MaterializeLocalScope();
     335             :     case ScopeIterator::ScopeTypeWith:
     336        2463 :       return WithContextExtension();
     337             :     case ScopeIterator::ScopeTypeCatch:
     338        1106 :       return MaterializeCatchScope();
     339             :     case ScopeIterator::ScopeTypeClosure:
     340             :       // Materialize the content of the closure scope into a JSObject.
     341       10387 :       return MaterializeClosure();
     342             :     case ScopeIterator::ScopeTypeBlock:
     343             :     case ScopeIterator::ScopeTypeEval:
     344        8763 :       return MaterializeInnerScope();
     345             :     case ScopeIterator::ScopeTypeModule:
     346        2435 :       return MaterializeModuleScope();
     347             :   }
     348           0 :   UNREACHABLE();
     349             : }
     350             : 
     351             : 
     352       80064 : bool ScopeIterator::HasContext() {
     353       80064 :   ScopeType type = Type();
     354       80064 :   if (type == ScopeTypeBlock || type == ScopeTypeLocal ||
     355             :       type == ScopeTypeEval) {
     356       20815 :     if (HasNestedScopeChain()) {
     357       20605 :       return LastNestedScopeChain().scope_info->HasContext();
     358             :     }
     359             :   }
     360             :   return true;
     361             : }
     362             : 
     363             : 
     364         353 : bool ScopeIterator::SetVariableValue(Handle<String> variable_name,
     365             :                                      Handle<Object> new_value) {
     366             :   DCHECK(!Done());
     367         353 :   switch (Type()) {
     368             :     case ScopeIterator::ScopeTypeGlobal:
     369             :       break;
     370             :     case ScopeIterator::ScopeTypeLocal:
     371         145 :       return SetLocalVariableValue(variable_name, new_value);
     372             :     case ScopeIterator::ScopeTypeWith:
     373             :       break;
     374             :     case ScopeIterator::ScopeTypeCatch:
     375          19 :       return SetCatchVariableValue(variable_name, new_value);
     376             :     case ScopeIterator::ScopeTypeClosure:
     377          50 :       return SetClosureVariableValue(variable_name, new_value);
     378             :     case ScopeIterator::ScopeTypeScript:
     379          34 :       return SetScriptVariableValue(variable_name, new_value);
     380             :     case ScopeIterator::ScopeTypeBlock:
     381             :     case ScopeIterator::ScopeTypeEval:
     382          34 :       return SetInnerScopeVariableValue(variable_name, new_value);
     383             :     case ScopeIterator::ScopeTypeModule:
     384          35 :       return SetModuleVariableValue(variable_name, new_value);
     385             :       break;
     386             :   }
     387             :   return false;
     388             : }
     389             : 
     390             : 
     391       11187 : Handle<ScopeInfo> ScopeIterator::CurrentScopeInfo() {
     392             :   DCHECK(!Done());
     393       11187 :   if (HasNestedScopeChain()) {
     394       11038 :     return LastNestedScopeChain().scope_info;
     395         204 :   } else if (context_->IsBlockContext() || context_->IsFunctionContext() ||
     396           5 :              context_->IsEvalContext()) {
     397         298 :     return Handle<ScopeInfo>(context_->scope_info());
     398             :   }
     399             :   return Handle<ScopeInfo>::null();
     400             : }
     401             : 
     402             : 
     403      440306 : Handle<Context> ScopeIterator::CurrentContext() {
     404             :   DCHECK(!Done());
     405      518238 :   if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript ||
     406             :       !HasNestedScopeChain()) {
     407      434639 :     return context_;
     408        5667 :   } else if (LastNestedScopeChain().scope_info->HasContext()) {
     409        5667 :     return context_;
     410             :   } else {
     411             :     return Handle<Context>::null();
     412             :   }
     413             : }
     414             : 
     415       10148 : Handle<StringSet> ScopeIterator::GetNonLocals() { return non_locals_; }
     416             : 
     417             : #ifdef DEBUG
     418             : // Debug print of the content of the current scope.
     419             : void ScopeIterator::DebugPrint() {
     420             :   OFStream os(stdout);
     421             :   DCHECK(!Done());
     422             :   switch (Type()) {
     423             :     case ScopeIterator::ScopeTypeGlobal:
     424             :       os << "Global:\n";
     425             :       CurrentContext()->Print(os);
     426             :       break;
     427             : 
     428             :     case ScopeIterator::ScopeTypeLocal: {
     429             :       os << "Local:\n";
     430             :       GetFunction()->shared()->scope_info()->Print();
     431             :       if (!CurrentContext().is_null()) {
     432             :         CurrentContext()->Print(os);
     433             :         if (CurrentContext()->has_extension()) {
     434             :           Handle<HeapObject> extension(CurrentContext()->extension(), isolate_);
     435             :           if (extension->IsJSContextExtensionObject()) {
     436             :             extension->Print(os);
     437             :           }
     438             :         }
     439             :       }
     440             :       break;
     441             :     }
     442             : 
     443             :     case ScopeIterator::ScopeTypeWith:
     444             :       os << "With:\n";
     445             :       CurrentContext()->extension()->Print(os);
     446             :       break;
     447             : 
     448             :     case ScopeIterator::ScopeTypeCatch:
     449             :       os << "Catch:\n";
     450             :       CurrentContext()->extension()->Print(os);
     451             :       CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
     452             :       break;
     453             : 
     454             :     case ScopeIterator::ScopeTypeClosure:
     455             :       os << "Closure:\n";
     456             :       CurrentContext()->Print(os);
     457             :       if (CurrentContext()->has_extension()) {
     458             :         Handle<HeapObject> extension(CurrentContext()->extension(), isolate_);
     459             :         if (extension->IsJSContextExtensionObject()) {
     460             :           extension->Print(os);
     461             :         }
     462             :       }
     463             :       break;
     464             : 
     465             :     case ScopeIterator::ScopeTypeScript:
     466             :       os << "Script:\n";
     467             :       CurrentContext()
     468             :           ->global_object()
     469             :           ->native_context()
     470             :           ->script_context_table()
     471             :           ->Print(os);
     472             :       break;
     473             : 
     474             :     default:
     475             :       UNREACHABLE();
     476             :   }
     477             :   PrintF("\n");
     478             : }
     479             : #endif
     480             : 
     481      208141 : inline Handle<Context> ScopeIterator::GetContext() {
     482      208141 :   if (frame_inspector_) {
     483      206379 :     return Handle<Context>::cast(frame_inspector_->GetContext());
     484             :   } else {
     485             :     DCHECK(!generator_.is_null());
     486             :     return handle(generator_->context());
     487             :   }
     488             : }
     489             : 
     490      516764 : Handle<JSFunction> ScopeIterator::GetFunction() {
     491      516764 :   if (frame_inspector_) {
     492             :     return frame_inspector_->GetFunction();
     493             :   } else {
     494             :     DCHECK(!generator_.is_null());
     495             :     return handle(generator_->function());
     496             :   }
     497             : }
     498             : 
     499           0 : int ScopeIterator::GetSourcePosition() {
     500      130462 :   if (frame_inspector_) {
     501           0 :     return frame_inspector_->GetSourcePosition();
     502             :   } else {
     503             :     DCHECK(!generator_.is_null());
     504        1385 :     return generator_->source_position();
     505             :   }
     506             : }
     507             : 
     508      130462 : void ScopeIterator::RetrieveScopeChain(DeclarationScope* scope) {
     509             :   DCHECK_NOT_NULL(scope);
     510      130462 :   GetNestedScopeChain(isolate_, scope, GetSourcePosition());
     511      130462 : }
     512             : 
     513      130903 : void ScopeIterator::CollectNonLocals(ParseInfo* info, DeclarationScope* scope) {
     514             :   DCHECK_NOT_NULL(scope);
     515             :   DCHECK(non_locals_.is_null());
     516      130903 :   non_locals_ = scope->CollectNonLocals(info, StringSet::New(isolate_));
     517      130903 : }
     518             : 
     519             : 
     520      237896 : MaybeHandle<JSObject> ScopeIterator::MaterializeScriptScope() {
     521      713688 :   Handle<JSGlobalObject> global(CurrentContext()->global_object());
     522             :   Handle<ScriptContextTable> script_contexts(
     523             :       global->native_context()->script_context_table());
     524             : 
     525             :   Handle<JSObject> script_scope =
     526      237896 :       isolate_->factory()->NewJSObjectWithNullProto();
     527             : 
     528     1440388 :   for (int context_index = 0; context_index < script_contexts->used();
     529             :        context_index++) {
     530             :     Handle<Context> context =
     531      482298 :         ScriptContextTable::GetContext(script_contexts, context_index);
     532      482298 :     Handle<ScopeInfo> scope_info(context->scope_info());
     533      482298 :     CopyContextLocalsToScopeObject(scope_info, context, script_scope);
     534             :   }
     535      237896 :   return script_scope;
     536             : }
     537             : 
     538       79911 : void ScopeIterator::MaterializeStackLocals(Handle<JSObject> local_scope,
     539             :                                            Handle<ScopeInfo> scope_info) {
     540       79911 :   if (frame_inspector_) {
     541      159382 :     return frame_inspector_->MaterializeStackLocals(local_scope, scope_info);
     542             :   }
     543             : 
     544             :   DCHECK(!generator_.is_null());
     545             :   // Fill all stack locals.
     546             :   Handle<FixedArray> register_file(generator_->register_file());
     547        2338 :   for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
     548         729 :     Handle<String> name = handle(scope_info->StackLocalName(i));
     549         729 :     if (ScopeInfo::VariableIsSynthetic(*name)) continue;
     550             :     Handle<Object> value(register_file->get(scope_info->StackLocalIndex(i)),
     551         704 :                          isolate_);
     552             :     // TODO(yangguo): We convert optimized out values to {undefined} when they
     553             :     // are passed to the debugger. Eventually we should handle them somehow.
     554        1056 :     if (value->IsTheHole(isolate_) || value->IsOptimizedOut(isolate_)) {
     555             :       DCHECK(!value.is_identical_to(isolate_->factory()->stale_register()));
     556           0 :       value = isolate_->factory()->undefined_value();
     557             :     }
     558         352 :     JSObject::SetOwnPropertyIgnoreAttributes(local_scope, name, value, NONE)
     559         704 :         .Check();
     560             :   }
     561             : }
     562             : 
     563       71247 : MaybeHandle<JSObject> ScopeIterator::MaterializeLocalScope() {
     564       71247 :   Handle<JSFunction> function(GetFunction());
     565             :   Handle<SharedFunctionInfo> shared(function->shared());
     566             :   Handle<ScopeInfo> scope_info(shared->scope_info());
     567             : 
     568             :   Handle<JSObject> local_scope =
     569       71247 :       isolate_->factory()->NewJSObjectWithNullProto();
     570       71247 :   MaterializeStackLocals(local_scope, scope_info);
     571             : 
     572       71247 :   Handle<Context> frame_context = GetContext();
     573             : 
     574       71247 :   if (!scope_info->HasContext()) return local_scope;
     575             : 
     576             :   // Fill all context locals.
     577       10270 :   Handle<Context> function_context(frame_context->closure_context());
     578       10270 :   CopyContextLocalsToScopeObject(scope_info, function_context, local_scope);
     579             : 
     580             :   // Finally copy any properties from the function context extension.
     581             :   // These will be variables introduced by eval.
     582       20540 :   if (function_context->closure() == *function &&
     583       10270 :       !function_context->IsNativeContext()) {
     584             :     CopyContextExtensionToScopeObject(function_context, local_scope,
     585       10270 :                                       KeyCollectionMode::kIncludePrototypes);
     586             :   }
     587             : 
     588       10270 :   return local_scope;
     589             : }
     590             : 
     591             : 
     592             : // Create a plain JSObject which materializes the closure content for the
     593             : // context.
     594       10387 : Handle<JSObject> ScopeIterator::MaterializeClosure() {
     595       10387 :   Handle<Context> context = CurrentContext();
     596             :   DCHECK(context->IsFunctionContext() || context->IsEvalContext());
     597             : 
     598             :   Handle<SharedFunctionInfo> shared(context->closure()->shared());
     599             :   Handle<ScopeInfo> scope_info(shared->scope_info());
     600             : 
     601             :   // Allocate and initialize a JSObject with all the content of this function
     602             :   // closure.
     603             :   Handle<JSObject> closure_scope =
     604       10387 :       isolate_->factory()->NewJSObjectWithNullProto();
     605             : 
     606             :   // Fill all context locals to the context extension.
     607       10387 :   CopyContextLocalsToScopeObject(scope_info, context, closure_scope);
     608             : 
     609             :   // Finally copy any properties from the function context extension. This will
     610             :   // be variables introduced by eval.
     611             :   CopyContextExtensionToScopeObject(context, closure_scope,
     612       10387 :                                     KeyCollectionMode::kOwnOnly);
     613             : 
     614       10387 :   return closure_scope;
     615             : }
     616             : 
     617             : 
     618             : // Create a plain JSObject which materializes the scope for the specified
     619             : // catch context.
     620        1106 : Handle<JSObject> ScopeIterator::MaterializeCatchScope() {
     621        1106 :   Handle<Context> context = CurrentContext();
     622             :   DCHECK(context->IsCatchContext());
     623        1106 :   Handle<String> name(context->catch_name());
     624             :   Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
     625        1106 :                                isolate_);
     626             :   Handle<JSObject> catch_scope =
     627        1106 :       isolate_->factory()->NewJSObjectWithNullProto();
     628             :   JSObject::SetOwnPropertyIgnoreAttributes(catch_scope, name, thrown_object,
     629        1106 :                                            NONE)
     630        2212 :       .Check();
     631        1106 :   return catch_scope;
     632             : }
     633             : 
     634             : // Retrieve the with-context extension object. If the extension object is
     635             : // a proxy, return an empty object.
     636        2463 : Handle<JSObject> ScopeIterator::WithContextExtension() {
     637        2463 :   Handle<Context> context = CurrentContext();
     638             :   DCHECK(context->IsWithContext());
     639        4926 :   if (context->extension_receiver()->IsJSProxy()) {
     640           0 :     return isolate_->factory()->NewJSObjectWithNullProto();
     641             :   }
     642        2463 :   return handle(JSObject::cast(context->extension_receiver()));
     643             : }
     644             : 
     645             : // Create a plain JSObject which materializes the block scope for the specified
     646             : // block context.
     647        8763 : Handle<JSObject> ScopeIterator::MaterializeInnerScope() {
     648             :   Handle<JSObject> inner_scope =
     649        8763 :       isolate_->factory()->NewJSObjectWithNullProto();
     650             : 
     651             :   Handle<Context> context = Handle<Context>::null();
     652        8763 :   if (HasNestedScopeChain()) {
     653        8664 :     Handle<ScopeInfo> scope_info = LastNestedScopeChain().scope_info;
     654        8664 :     MaterializeStackLocals(inner_scope, scope_info);
     655        8664 :     if (scope_info->HasContext()) context = CurrentContext();
     656             :   } else {
     657          99 :     context = CurrentContext();
     658             :   }
     659             : 
     660        8763 :   if (!context.is_null()) {
     661             :     // Fill all context locals.
     662         367 :     CopyContextLocalsToScopeObject(CurrentScopeInfo(), context, inner_scope);
     663             :     CopyContextExtensionToScopeObject(context, inner_scope,
     664         367 :                                       KeyCollectionMode::kOwnOnly);
     665             :   }
     666        8763 :   return inner_scope;
     667             : }
     668             : 
     669             : 
     670             : // Create a plain JSObject which materializes the module scope for the specified
     671             : // module context.
     672        2435 : MaybeHandle<JSObject> ScopeIterator::MaterializeModuleScope() {
     673        2435 :   Handle<Context> context = CurrentContext();
     674             :   DCHECK(context->IsModuleContext());
     675        2435 :   Handle<ScopeInfo> scope_info(context->scope_info());
     676             :   Handle<JSObject> module_scope =
     677        2435 :       isolate_->factory()->NewJSObjectWithNullProto();
     678        2435 :   CopyContextLocalsToScopeObject(scope_info, context, module_scope);
     679        2435 :   CopyModuleVarsToScopeObject(scope_info, context, module_scope);
     680        2435 :   return module_scope;
     681             : }
     682             : 
     683         145 : bool ScopeIterator::SetParameterValue(Handle<ScopeInfo> scope_info,
     684             :                                       Handle<String> parameter_name,
     685          20 :                                       Handle<Object> new_value) {
     686             :   // Setting stack locals of optimized frames is not supported.
     687         145 :   HandleScope scope(isolate_);
     688         290 :   for (int i = 0; i < scope_info->ParameterCount(); ++i) {
     689          40 :     if (String::Equals(handle(scope_info->ParameterName(i)), parameter_name)) {
     690             :       // Suspended generators should not get here because all parameters should
     691             :       // be context-allocated.
     692             :       DCHECK_NOT_NULL(frame_inspector_);
     693             :       JavaScriptFrame* frame = GetFrame();
     694          40 :       if (frame->is_optimized()) {
     695             :         return false;
     696             :       }
     697          20 :       frame->SetParameterValue(i, *new_value);
     698          20 :       return true;
     699             :     }
     700             :   }
     701             :   return false;
     702             : }
     703             : 
     704         179 : bool ScopeIterator::SetStackVariableValue(Handle<ScopeInfo> scope_info,
     705             :                                           Handle<String> variable_name,
     706             :                                           Handle<Object> new_value) {
     707             :   // Setting stack locals of optimized frames is not supported. Suspended
     708             :   // generators are supported.
     709         179 :   HandleScope scope(isolate_);
     710         600 :   for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
     711         408 :     if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
     712          83 :       int stack_local_index = scope_info->StackLocalIndex(i);
     713          83 :       if (frame_inspector_ != nullptr) {
     714             :         // Set the variable on the stack.
     715             :         JavaScriptFrame* frame = GetFrame();
     716         112 :         if (frame->is_optimized()) return false;
     717          52 :         frame->SetExpression(stack_local_index, *new_value);
     718             :       } else {
     719             :         // Set the variable in the suspended generator.
     720             :         DCHECK(!generator_.is_null());
     721             :         Handle<FixedArray> register_file(generator_->register_file());
     722             :         DCHECK_LT(stack_local_index, register_file->length());
     723          27 :         register_file->set(stack_local_index, *new_value);
     724             :       }
     725             :       return true;
     726             :     }
     727             :   }
     728             :   return false;
     729             : }
     730             : 
     731         162 : bool ScopeIterator::SetContextVariableValue(Handle<ScopeInfo> scope_info,
     732             :                                             Handle<Context> context,
     733             :                                             Handle<String> variable_name,
     734             :                                             Handle<Object> new_value) {
     735         162 :   HandleScope scope(isolate_);
     736        1316 :   for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
     737         614 :     Handle<String> next_name(scope_info->ContextLocalName(i));
     738         614 :     if (String::Equals(variable_name, next_name)) {
     739             :       VariableMode mode;
     740             :       InitializationFlag init_flag;
     741             :       MaybeAssignedFlag maybe_assigned_flag;
     742             :       int context_index = ScopeInfo::ContextSlotIndex(
     743         118 :           scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag);
     744         118 :       context->set(context_index, *new_value);
     745             :       return true;
     746             :     }
     747             :   }
     748             : 
     749             :   // TODO(neis): Clean up context "extension" mess.
     750          63 :   if (!context->IsModuleContext() && context->has_extension()) {
     751          10 :     Handle<JSObject> ext(context->extension_object());
     752          10 :     Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
     753             :     DCHECK(maybe.IsJust());
     754          10 :     if (maybe.FromJust()) {
     755             :       // We don't expect this to do anything except replacing property value.
     756             :       JSObject::SetOwnPropertyIgnoreAttributes(ext, variable_name, new_value,
     757          10 :                                                NONE)
     758          20 :           .Check();
     759          10 :       return true;
     760             :     }
     761             :   }
     762             : 
     763             :   return false;
     764             : }
     765             : 
     766         145 : bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
     767             :                                           Handle<Object> new_value) {
     768         290 :   Handle<ScopeInfo> scope_info(GetFunction()->shared()->scope_info());
     769             : 
     770             :   // Parameter might be shadowed in context. Don't stop here.
     771         145 :   bool result = SetParameterValue(scope_info, variable_name, new_value);
     772             : 
     773             :   // Stack locals.
     774         145 :   if (SetStackVariableValue(scope_info, variable_name, new_value)) {
     775             :     return true;
     776             :   }
     777             : 
     778         147 :   if (scope_info->HasContext() &&
     779             :       SetContextVariableValue(scope_info, CurrentContext(), variable_name,
     780          62 :                               new_value)) {
     781             :     return true;
     782             :   }
     783             : 
     784          32 :   return result;
     785             : }
     786             : 
     787          35 : bool ScopeIterator::SetModuleVariableValue(Handle<String> variable_name,
     788             :                                            Handle<Object> new_value) {
     789             :   DCHECK_NOT_NULL(frame_inspector_);
     790             : 
     791             :   // Get module context and its scope info.
     792          35 :   Handle<Context> context = CurrentContext();
     793          70 :   while (!context->IsModuleContext()) {
     794           0 :     context = handle(context->previous(), isolate_);
     795             :   }
     796          70 :   Handle<ScopeInfo> scope_info(context->scope_info(), isolate_);
     797             :   DCHECK_EQ(scope_info->scope_type(), MODULE_SCOPE);
     798             : 
     799          35 :   if (SetContextVariableValue(scope_info, context, variable_name, new_value)) {
     800             :     return true;
     801             :   }
     802             : 
     803             :   int cell_index;
     804             :   {
     805             :     VariableMode mode;
     806             :     InitializationFlag init_flag;
     807             :     MaybeAssignedFlag maybe_assigned_flag;
     808             :     cell_index = scope_info->ModuleIndex(variable_name, &mode, &init_flag,
     809          25 :                                          &maybe_assigned_flag);
     810             :   }
     811             : 
     812             :   // Setting imports is currently not supported.
     813          25 :   bool found = ModuleDescriptor::GetCellIndexKind(cell_index) ==
     814          25 :                ModuleDescriptor::kExport;
     815          25 :   if (found) {
     816             :     Module::StoreVariable(handle(context->module(), isolate_), cell_index,
     817          30 :                           new_value);
     818             :   }
     819          25 :   return found;
     820             : }
     821             : 
     822          34 : bool ScopeIterator::SetInnerScopeVariableValue(Handle<String> variable_name,
     823             :                                                Handle<Object> new_value) {
     824          34 :   Handle<ScopeInfo> scope_info = CurrentScopeInfo();
     825             :   DCHECK(scope_info->scope_type() == BLOCK_SCOPE ||
     826             :          scope_info->scope_type() == EVAL_SCOPE);
     827             : 
     828             :   // Setting stack locals of optimized frames is not supported.
     829          34 :   if (SetStackVariableValue(scope_info, variable_name, new_value)) {
     830             :     return true;
     831             :   }
     832             : 
     833          30 :   if (HasContext() && SetContextVariableValue(scope_info, CurrentContext(),
     834          15 :                                               variable_name, new_value)) {
     835             :     return true;
     836             :   }
     837             : 
     838           0 :   return false;
     839             : }
     840             : 
     841             : // This method copies structure of MaterializeClosure method above.
     842          50 : bool ScopeIterator::SetClosureVariableValue(Handle<String> variable_name,
     843             :                                             Handle<Object> new_value) {
     844             :   DCHECK(CurrentContext()->IsFunctionContext() ||
     845             :          CurrentContext()->IsEvalContext());
     846             :   return SetContextVariableValue(CurrentScopeInfo(), CurrentContext(),
     847          50 :                                  variable_name, new_value);
     848             : }
     849             : 
     850          34 : bool ScopeIterator::SetScriptVariableValue(Handle<String> variable_name,
     851             :                                            Handle<Object> new_value) {
     852             :   Handle<String> internalized_variable_name =
     853          34 :       isolate_->factory()->InternalizeString(variable_name);
     854          34 :   Handle<Context> context = CurrentContext();
     855             :   Handle<ScriptContextTable> script_contexts(
     856          34 :       context->global_object()->native_context()->script_context_table());
     857             :   ScriptContextTable::LookupResult lookup_result;
     858          34 :   if (ScriptContextTable::Lookup(script_contexts, internalized_variable_name,
     859             :                                  &lookup_result)) {
     860             :     Handle<Context> script_context = ScriptContextTable::GetContext(
     861          34 :         script_contexts, lookup_result.context_index);
     862          68 :     script_context->set(lookup_result.slot_index, *new_value);
     863             :     return true;
     864             :   }
     865             : 
     866             :   return false;
     867             : }
     868             : 
     869          19 : bool ScopeIterator::SetCatchVariableValue(Handle<String> variable_name,
     870             :                                           Handle<Object> new_value) {
     871          19 :   Handle<Context> context = CurrentContext();
     872             :   DCHECK(context->IsCatchContext());
     873          19 :   Handle<String> name(context->catch_name());
     874          19 :   if (!String::Equals(name, variable_name)) {
     875             :     return false;
     876             :   }
     877          19 :   context->set(Context::THROWN_OBJECT_INDEX, *new_value);
     878          19 :   return true;
     879             : }
     880             : 
     881             : 
     882      505757 : void ScopeIterator::CopyContextLocalsToScopeObject(
     883             :     Handle<ScopeInfo> scope_info, Handle<Context> context,
     884             :     Handle<JSObject> scope_object) {
     885             :   Isolate* isolate = scope_info->GetIsolate();
     886      505757 :   int local_count = scope_info->ContextLocalCount();
     887     1011514 :   if (local_count == 0) return;
     888             :   // Fill all context locals to the context extension.
     889     1210068 :   for (int i = 0; i < local_count; ++i) {
     890     1210068 :     Handle<String> name(scope_info->ContextLocalName(i));
     891     1210068 :     if (ScopeInfo::VariableIsSynthetic(*name)) continue;
     892      947157 :     int context_index = Context::MIN_CONTEXT_SLOTS + i;
     893             :     Handle<Object> value = Handle<Object>(context->get(context_index), isolate);
     894             :     // Reflect variables under TDZ as undefined in scope object.
     895      947157 :     if (value->IsTheHole(isolate)) continue;
     896             :     // This should always succeed.
     897             :     // TODO(verwaest): Use AddDataProperty instead.
     898      941790 :     JSObject::SetOwnPropertyIgnoreAttributes(scope_object, name, value, NONE)
     899     1883580 :         .Check();
     900             :   }
     901             : }
     902             : 
     903        2435 : void ScopeIterator::CopyModuleVarsToScopeObject(Handle<ScopeInfo> scope_info,
     904             :                                                 Handle<Context> context,
     905             :                                                 Handle<JSObject> scope_object) {
     906             :   Isolate* isolate = scope_info->GetIsolate();
     907             : 
     908             :   int module_variable_count =
     909             :       Smi::cast(scope_info->get(scope_info->ModuleVariableCountIndex()))
     910        2435 :           ->value();
     911        7181 :   for (int i = 0; i < module_variable_count; ++i) {
     912             :     Handle<String> local_name;
     913             :     Handle<Object> value;
     914             :     {
     915             :       String* name;
     916             :       int index;
     917        4746 :       scope_info->ModuleVariable(i, &name, &index);
     918        4746 :       CHECK(!ScopeInfo::VariableIsSynthetic(name));
     919        4746 :       local_name = handle(name, isolate);
     920       14238 :       value = Module::LoadVariable(handle(context->module(), isolate), index);
     921             :     }
     922             : 
     923             :     // Reflect variables under TDZ as undefined in scope object.
     924        4746 :     if (value->IsTheHole(isolate)) continue;
     925             :     // This should always succeed.
     926             :     // TODO(verwaest): Use AddDataProperty instead.
     927             :     JSObject::SetOwnPropertyIgnoreAttributes(scope_object, local_name, value,
     928         635 :                                              NONE)
     929        1270 :         .Check();
     930             :   }
     931        2435 : }
     932             : 
     933       21024 : void ScopeIterator::CopyContextExtensionToScopeObject(
     934             :     Handle<Context> context, Handle<JSObject> scope_object,
     935             :     KeyCollectionMode mode) {
     936       42048 :   if (context->extension_object() == nullptr) return;
     937         347 :   Handle<JSObject> extension(context->extension_object());
     938             :   Handle<FixedArray> keys =
     939         347 :       KeyAccumulator::GetKeys(extension, mode, ENUMERABLE_STRINGS)
     940         694 :           .ToHandleChecked();
     941             : 
     942        1768 :   for (int i = 0; i < keys->length(); i++) {
     943             :     // Names of variables introduced by eval are strings.
     944             :     DCHECK(keys->get(i)->IsString());
     945             :     Handle<String> key(String::cast(keys->get(i)));
     946             :     Handle<Object> value =
     947        1074 :         Object::GetPropertyOrElement(extension, key).ToHandleChecked();
     948         537 :     JSObject::SetOwnPropertyIgnoreAttributes(scope_object, key, value, NONE)
     949        1074 :         .Check();
     950             :   }
     951             : }
     952             : 
     953      628934 : void ScopeIterator::GetNestedScopeChain(Isolate* isolate, Scope* scope,
     954             :                                         int position) {
     955      138267 :   if (scope->is_function_scope()) {
     956             :     // Do not collect scopes of nested inner functions inside the current one.
     957             :     // Nested arrow functions could have the same end positions.
     958       78826 :     Handle<JSFunction> function = GetFunction();
     959       78849 :     if (scope->start_position() > function->shared()->start_position() &&
     960             :         scope->end_position() <= function->shared()->end_position()) {
     961             :       return;
     962             :     }
     963             :   }
     964      138244 :   if (scope->is_hidden()) {
     965             :     // We need to add this chain element in case the scope has a context
     966             :     // associated. We need to keep the scope chain and context chain in sync.
     967        1457 :     nested_scope_chain_.emplace_back(scope->scope_info());
     968             :   } else {
     969             :     nested_scope_chain_.emplace_back(
     970      273574 :         scope->scope_info(), scope->start_position(), scope->end_position());
     971             :   }
     972      405134 :   for (Scope* inner_scope = scope->inner_scope(); inner_scope != nullptr;
     973             :        inner_scope = inner_scope->sibling()) {
     974             :     int beg_pos = inner_scope->start_position();
     975             :     int end_pos = inner_scope->end_position();
     976             :     DCHECK((beg_pos >= 0 && end_pos >= 0) || inner_scope->is_hidden());
     977      274695 :     if (beg_pos <= position && position < end_pos) {
     978        7805 :       GetNestedScopeChain(isolate, inner_scope, position);
     979        7805 :       return;
     980             :     }
     981             :   }
     982             : }
     983             : 
     984           0 : bool ScopeIterator::HasNestedScopeChain() {
     985           0 :   return !nested_scope_chain_.empty();
     986             : }
     987             : 
     988           0 : ScopeIterator::ExtendedScopeInfo& ScopeIterator::LastNestedScopeChain() {
     989             :   DCHECK(HasNestedScopeChain());
     990           0 :   return nested_scope_chain_.back();
     991             : }
     992             : 
     993             : }  // namespace internal
     994             : }  // namespace v8

Generated by: LCOV version 1.10