LCOV - code coverage report
Current view: top level - src/debug - debug-scopes.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 331 352 94.0 %
Date: 2019-01-20 Functions: 35 35 100.0 %

          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/objects/js-generator-inl.h"
      16             : #include "src/objects/module.h"
      17             : #include "src/parsing/parse-info.h"
      18             : #include "src/parsing/parsing.h"
      19             : #include "src/parsing/rewriter.h"
      20             : 
      21             : namespace v8 {
      22             : namespace internal {
      23             : 
      24      158889 : ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
      25             :                              ScopeIterator::Option option)
      26             :     : isolate_(isolate),
      27             :       frame_inspector_(frame_inspector),
      28             :       function_(frame_inspector_->GetFunction()),
      29      635556 :       script_(frame_inspector_->GetScript()) {
      30      476667 :   if (!frame_inspector->GetContext()->IsContext()) {
      31             :     // Optimized frame, context or function cannot be materialized. Give up.
      32      158889 :     return;
      33             :   }
      34      158780 :   context_ = Handle<Context>::cast(frame_inspector->GetContext());
      35             : 
      36             :   // We should not instantiate a ScopeIterator for wasm frames.
      37             :   DCHECK_NE(Script::TYPE_WASM, frame_inspector->GetScript()->type());
      38             : 
      39      158780 :   TryParseAndRetrieveScopes(option);
      40             : }
      41             : 
      42      160339 : ScopeIterator::~ScopeIterator() { delete info_; }
      43             : 
      44      371152 : Handle<Object> ScopeIterator::GetFunctionDebugName() const {
      45      371152 :   if (!function_.is_null()) return JSFunction::GetDebugName(function_);
      46             : 
      47      469072 :   if (!context_->IsNativeContext()) {
      48             :     DisallowHeapAllocation no_gc;
      49       18191 :     ScopeInfo closure_info = context_->closure_context()->scope_info();
      50       18191 :     Handle<String> debug_name(closure_info->FunctionDebugName(), isolate_);
      51       18191 :     if (debug_name->length() > 0) return debug_name;
      52             :   }
      53      451982 :   return isolate_->factory()->undefined_value();
      54             : }
      55             : 
      56          60 : ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
      57         240 :     : isolate_(isolate), context_(function->context(), isolate) {
      58          60 :   if (!function->shared()->IsSubjectToDebugging()) {
      59           5 :     context_ = Handle<Context>();
      60          65 :     return;
      61             :   }
      62         110 :   script_ = handle(Script::cast(function->shared()->script()), isolate);
      63          55 :   UnwrapEvaluationContext();
      64             : }
      65             : 
      66        1390 : ScopeIterator::ScopeIterator(Isolate* isolate,
      67             :                              Handle<JSGeneratorObject> generator)
      68             :     : isolate_(isolate),
      69             :       generator_(generator),
      70             :       function_(generator->function(), isolate),
      71             :       context_(generator->context(), isolate),
      72       11120 :       script_(Script::cast(function_->shared()->script()), isolate) {
      73        1390 :   CHECK(function_->shared()->IsSubjectToDebugging());
      74        1390 :   TryParseAndRetrieveScopes(DEFAULT);
      75        1390 : }
      76             : 
      77       10690 : void ScopeIterator::Restart() {
      78             :   DCHECK_NOT_NULL(frame_inspector_);
      79       10690 :   function_ = frame_inspector_->GetFunction();
      80       10690 :   context_ = Handle<Context>::cast(frame_inspector_->GetContext());
      81       10690 :   current_scope_ = start_scope_;
      82             :   DCHECK_NOT_NULL(current_scope_);
      83       10690 :   UnwrapEvaluationContext();
      84       10690 : }
      85             : 
      86      251068 : void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) {
      87             :   // Catch the case when the debugger stops in an internal function.
      88      480510 :   Handle<SharedFunctionInfo> shared_info(function_->shared(), isolate_);
      89      480510 :   Handle<ScopeInfo> scope_info(shared_info->scope_info(), isolate_);
      90      480510 :   if (shared_info->script()->IsUndefined(isolate_)) {
      91           0 :     current_scope_ = closure_scope_ = nullptr;
      92           0 :     context_ = handle(function_->context(), isolate_);
      93           0 :     function_ = Handle<JSFunction>();
      94           0 :     return;
      95             :   }
      96             : 
      97             :   // Class fields initializer functions don't have any scope
      98             :   // information. We short circuit the parsing of the class literal
      99             :   // and return an empty context here.
     100      160170 :   if (IsClassMembersInitializerFunction(shared_info->kind())) {
     101          20 :     current_scope_ = closure_scope_ = nullptr;
     102          20 :     context_ = Handle<Context>();
     103          20 :     function_ = Handle<JSFunction>();
     104          20 :     return;
     105             :   }
     106             : 
     107             :   DCHECK_NE(IGNORE_NESTED_SCOPES, option);
     108             :   bool ignore_nested_scopes = false;
     109      160150 :   if (shared_info->HasBreakInfo() && frame_inspector_ != nullptr) {
     110             :     // The source position at return is always the end of the function,
     111             :     // which is not consistent with the current scope chain. Therefore all
     112             :     // nested with, catch and block contexts are skipped, and we can only
     113             :     // inspect the function scope.
     114             :     // This can only happen if we set a break point inside right before the
     115             :     // return, which requires a debug info to be available.
     116      272694 :     Handle<DebugInfo> debug_info(shared_info->GetDebugInfo(), isolate_);
     117             : 
     118             :     // Find the break point where execution has stopped.
     119       90898 :     BreakLocation location = BreakLocation::FromFrame(debug_info, GetFrame());
     120             : 
     121       90898 :     ignore_nested_scopes = location.IsReturn();
     122             :   }
     123             : 
     124             :   // Reparse the code and analyze the scopes.
     125             :   // Check whether we are in global, eval or function code.
     126      160150 :   if (scope_info->scope_type() == FUNCTION_SCOPE) {
     127             :     // Inner function.
     128      100927 :     info_ = new ParseInfo(isolate_, shared_info);
     129             :   } else {
     130             :     // Global or eval code.
     131      177669 :     Handle<Script> script(Script::cast(shared_info->script()), isolate_);
     132       59223 :     info_ = new ParseInfo(isolate_, script);
     133       59223 :     if (scope_info->scope_type() == EVAL_SCOPE) {
     134      173841 :       info_->set_eval();
     135       11138 :       if (!context_->IsNativeContext()) {
     136       13004 :         info_->set_outer_scope_info(handle(context_->scope_info(), isolate_));
     137             :       }
     138             :       // Language mode may be inherited from the eval caller.
     139             :       // Retrieve it from shared function info.
     140       11138 :       info_->set_language_mode(shared_info->language_mode());
     141       53654 :     } else if (scope_info->scope_type() == MODULE_SCOPE) {
     142             :       DCHECK(info_->is_module());
     143             :     } else {
     144             :       DCHECK_EQ(SCRIPT_SCOPE, scope_info->scope_type());
     145             :     }
     146             :   }
     147             : 
     148      316089 :   if (parsing::ParseAny(info_, shared_info, isolate_) &&
     149      155939 :       Rewriter::Rewrite(info_)) {
     150      311878 :     info_->ast_value_factory()->Internalize(isolate_);
     151      311878 :     closure_scope_ = info_->literal()->scope();
     152             : 
     153      155939 :     if (option == COLLECT_NON_LOCALS) {
     154             :       DCHECK(non_locals_.is_null());
     155             :       non_locals_ = info_->literal()->scope()->CollectNonLocals(
     156       24666 :           isolate_, info_, StringSet::New(isolate_));
     157             :     }
     158             : 
     159      155939 :     CHECK(DeclarationScope::Analyze(info_));
     160      155939 :     if (ignore_nested_scopes) {
     161        6193 :       current_scope_ = closure_scope_;
     162        6193 :       start_scope_ = current_scope_;
     163        6193 :       if (closure_scope_->NeedsContext()) {
     164         261 :         context_ = handle(context_->closure_context(), isolate_);
     165             :       }
     166             :     } else {
     167      149746 :       RetrieveScopeChain(closure_scope_);
     168             :     }
     169      155939 :     UnwrapEvaluationContext();
     170             :   } else {
     171             :     // A failed reparse indicates that the preparser has diverged from the
     172             :     // parser or that the preparse data given to the initial parse has been
     173             :     // faulty. We fail in debug mode but in release mode we only provide the
     174             :     // information we get from the context chain but nothing about
     175             :     // completely stack allocated scopes or stack allocated locals.
     176             :     // Or it could be due to stack overflow.
     177             :     // Silently fail by presenting an empty context chain.
     178        4211 :     CHECK(isolate_->has_pending_exception());
     179        4211 :     isolate_->clear_pending_exception();
     180        4211 :     context_ = Handle<Context>();
     181             :   }
     182             : }
     183             : 
     184      441531 : void ScopeIterator::UnwrapEvaluationContext() {
     185      883062 :   if (!context_->IsDebugEvaluateContext()) return;
     186           0 :   Context current = *context_;
     187           0 :   do {
     188           0 :     Object wrapped = current->get(Context::WRAPPED_CONTEXT_INDEX);
     189           0 :     if (wrapped->IsContext()) {
     190           0 :       current = Context::cast(wrapped);
     191             :     } else {
     192             :       DCHECK(!current->previous().is_null());
     193           0 :       current = current->previous();
     194             :     }
     195             :   } while (current->IsDebugEvaluateContext());
     196           0 :   context_ = handle(current, isolate_);
     197             : }
     198             : 
     199         945 : Handle<JSObject> ScopeIterator::MaterializeScopeDetails() {
     200             :   // Calculate the size of the result.
     201             :   Handle<FixedArray> details =
     202         945 :       isolate_->factory()->NewFixedArray(kScopeDetailsSize);
     203             :   // Fill in scope details.
     204         945 :   details->set(kScopeDetailsTypeIndex, Smi::FromInt(Type()));
     205         945 :   Handle<JSObject> scope_object = ScopeObject(Mode::ALL);
     206        1890 :   details->set(kScopeDetailsObjectIndex, *scope_object);
     207         945 :   if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript) {
     208         315 :     return isolate_->factory()->NewJSArrayWithElements(details);
     209         630 :   } else if (HasContext()) {
     210         324 :     Handle<Object> closure_name = GetFunctionDebugName();
     211         324 :     details->set(kScopeDetailsNameIndex, *closure_name);
     212             :     details->set(kScopeDetailsStartPositionIndex,
     213         324 :                  Smi::FromInt(start_position()));
     214         324 :     details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position()));
     215         324 :     if (InInnerScope()) {
     216         612 :       details->set(kScopeDetailsFunctionIndex, *function_);
     217             :     }
     218             :   }
     219         630 :   return isolate_->factory()->NewJSArrayWithElements(details);
     220             : }
     221             : 
     222      370678 : bool ScopeIterator::HasPositionInfo() {
     223      839494 :   return InInnerScope() || !context_->IsNativeContext();
     224             : }
     225             : 
     226      154752 : int ScopeIterator::start_position() {
     227      154752 :   if (InInnerScope()) return current_scope_->start_position();
     228       36352 :   if (context_->IsNativeContext()) return 0;
     229       18176 :   return context_->closure_context()->scope_info()->StartPosition();
     230             : }
     231             : 
     232      154752 : int ScopeIterator::end_position() {
     233      154752 :   if (InInnerScope()) return current_scope_->end_position();
     234       36352 :   if (context_->IsNativeContext()) return 0;
     235       18176 :   return context_->closure_context()->scope_info()->EndPosition();
     236             : }
     237             : 
     238      309281 : bool ScopeIterator::DeclaresLocals(Mode mode) const {
     239      309281 :   ScopeType type = Type();
     240             : 
     241      309281 :   if (type == ScopeTypeWith) return mode == Mode::ALL;
     242      306750 :   if (type == ScopeTypeGlobal) return mode == Mode::ALL;
     243             : 
     244      164655 :   bool declares_local = false;
     245             :   auto visitor = [&](Handle<String> name, Handle<Object> value) {
     246      143748 :     declares_local = true;
     247             :     return true;
     248             :   };
     249      329310 :   VisitScope(visitor, mode);
     250      164655 :   return declares_local;
     251             : }
     252             : 
     253       12315 : bool ScopeIterator::HasContext() const {
     254      223468 :   return !InInnerScope() || current_scope_->NeedsContext();
     255             : }
     256             : 
     257      417230 : void ScopeIterator::Next() {
     258             :   DCHECK(!Done());
     259             : 
     260      417230 :   ScopeType scope_type = Type();
     261             : 
     262      417230 :   if (scope_type == ScopeTypeGlobal) {
     263             :     // The global scope is always the last in the chain.
     264             :     DCHECK(context_->IsNativeContext());
     265      142383 :     context_ = Handle<Context>();
     266             :     DCHECK(Done());
     267      559613 :     return;
     268             :   }
     269             : 
     270             :   bool inner = InInnerScope();
     271      395164 :   if (current_scope_ == closure_scope_) function_ = Handle<JSFunction>();
     272             : 
     273      274847 :   if (scope_type == ScopeTypeScript) {
     274             :     DCHECK_IMPLIES(InInnerScope(), current_scope_->is_script_scope());
     275      142545 :     seen_script_scope_ = true;
     276      142545 :     if (context_->IsScriptContext()) {
     277       26739 :       context_ = handle(context_->previous(), isolate_);
     278             :     }
     279      132302 :   } else if (!inner) {
     280             :     DCHECK(!context_->IsNativeContext());
     281       39567 :     context_ = handle(context_->previous(), isolate_);
     282             :   } else {
     283             :     DCHECK_NOT_NULL(current_scope_);
     284      120317 :     do {
     285      240634 :       if (current_scope_->NeedsContext()) {
     286             :         DCHECK(!context_->previous().is_null());
     287       46458 :         context_ = handle(context_->previous(), isolate_);
     288             :       }
     289             :       DCHECK_IMPLIES(InInnerScope(), current_scope_->outer_scope() != nullptr);
     290      240634 :       current_scope_ = current_scope_->outer_scope();
     291             :       // Repeat to skip hidden scopes.
     292             :     } while (current_scope_->is_hidden());
     293             :   }
     294             : 
     295      274847 :   UnwrapEvaluationContext();
     296             : }
     297             : 
     298             : 
     299             : // Return the type of the current scope.
     300     2387633 : ScopeIterator::ScopeType ScopeIterator::Type() const {
     301             :   DCHECK(!Done());
     302     2387633 :   if (InInnerScope()) {
     303      988607 :     switch (current_scope_->scope_type()) {
     304             :       case FUNCTION_SCOPE:
     305             :         DCHECK_IMPLIES(current_scope_->NeedsContext(),
     306             :                        context_->IsFunctionContext());
     307             :         return ScopeTypeLocal;
     308             :       case MODULE_SCOPE:
     309             :         DCHECK_IMPLIES(current_scope_->NeedsContext(),
     310             :                        context_->IsModuleContext());
     311        5562 :         return ScopeTypeModule;
     312             :       case SCRIPT_SCOPE:
     313             :         DCHECK_IMPLIES(
     314             :             current_scope_->NeedsContext(),
     315             :             context_->IsScriptContext() || context_->IsNativeContext());
     316      353852 :         return ScopeTypeScript;
     317             :       case WITH_SCOPE:
     318             :         DCHECK_IMPLIES(
     319             :             current_scope_->NeedsContext(),
     320             :             context_->IsWithContext() || context_->IsDebugEvaluateContext());
     321       11192 :         return ScopeTypeWith;
     322             :       case CATCH_SCOPE:
     323             :         DCHECK(context_->IsCatchContext());
     324        6205 :         return ScopeTypeCatch;
     325             :       case BLOCK_SCOPE:
     326             :         DCHECK_IMPLIES(current_scope_->NeedsContext(),
     327             :                        context_->IsBlockContext());
     328       19331 :         return ScopeTypeBlock;
     329             :       case EVAL_SCOPE:
     330             :         DCHECK_IMPLIES(current_scope_->NeedsContext(),
     331             :                        context_->IsEvalContext());
     332       22717 :         return ScopeTypeEval;
     333             :     }
     334           0 :     UNREACHABLE();
     335             :   }
     336     2798052 :   if (context_->IsNativeContext()) {
     337             :     DCHECK(context_->global_object()->IsJSGlobalObject());
     338             :     // If we are at the native context and have not yet seen script scope,
     339             :     // fake it.
     340     1263809 :     return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript;
     341             :   }
     342      202301 :   if (context_->IsFunctionContext() || context_->IsEvalContext()) {
     343             :     return ScopeTypeClosure;
     344             :   }
     345       61674 :   if (context_->IsCatchContext()) {
     346             :     return ScopeTypeCatch;
     347             :   }
     348       59135 :   if (context_->IsBlockContext()) {
     349             :     return ScopeTypeBlock;
     350             :   }
     351       56712 :   if (context_->IsModuleContext()) {
     352             :     return ScopeTypeModule;
     353             :   }
     354       51396 :   if (context_->IsScriptContext()) {
     355             :     return ScopeTypeScript;
     356             :   }
     357             :   DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext());
     358        2345 :   return ScopeTypeWith;
     359             : }
     360             : 
     361      383768 : Handle<JSObject> ScopeIterator::ScopeObject(Mode mode) {
     362             :   DCHECK(!Done());
     363             : 
     364      383768 :   ScopeType type = Type();
     365      383768 :   if (type == ScopeTypeGlobal) {
     366             :     DCHECK_EQ(Mode::ALL, mode);
     367      426744 :     return handle(context_->global_proxy(), isolate_);
     368             :   }
     369      241520 :   if (type == ScopeTypeWith) {
     370             :     DCHECK_EQ(Mode::ALL, mode);
     371        2513 :     return WithContextExtension();
     372             :   }
     373             : 
     374      239007 :   Handle<JSObject> scope = isolate_->factory()->NewJSObjectWithNullProto();
     375             :   auto visitor = [=](Handle<String> name, Handle<Object> value) {
     376     4603003 :     JSObject::AddProperty(isolate_, scope, name, value, NONE);
     377             :     return false;
     378      239007 :   };
     379             : 
     380      478014 :   VisitScope(visitor, mode);
     381      239007 :   return scope;
     382             : }
     383             : 
     384      403662 : void ScopeIterator::VisitScope(const Visitor& visitor, Mode mode) const {
     385      403662 :   switch (Type()) {
     386             :     case ScopeTypeLocal:
     387             :     case ScopeTypeClosure:
     388             :     case ScopeTypeCatch:
     389             :     case ScopeTypeBlock:
     390             :     case ScopeTypeEval:
     391      129901 :       return VisitLocalScope(visitor, mode);
     392             :     case ScopeTypeModule:
     393        2921 :       if (InInnerScope()) {
     394        1410 :         return VisitLocalScope(visitor, mode);
     395             :       }
     396             :       DCHECK_EQ(Mode::ALL, mode);
     397        1511 :       return VisitModuleScope(visitor);
     398             :     case ScopeTypeScript:
     399             :       DCHECK_EQ(Mode::ALL, mode);
     400      270840 :       return VisitScriptScope(visitor);
     401             :     case ScopeTypeWith:
     402             :     case ScopeTypeGlobal:
     403           0 :       UNREACHABLE();
     404             :   }
     405             : }
     406             : 
     407       83693 : bool ScopeIterator::SetVariableValue(Handle<String> name,
     408             :                                      Handle<Object> value) {
     409             :   DCHECK(!Done());
     410       83693 :   name = isolate_->factory()->InternalizeString(name);
     411       83693 :   switch (Type()) {
     412             :     case ScopeTypeGlobal:
     413             :     case ScopeTypeWith:
     414             :       break;
     415             : 
     416             :     case ScopeTypeEval:
     417             :     case ScopeTypeBlock:
     418             :     case ScopeTypeCatch:
     419             :     case ScopeTypeModule:
     420         777 :       if (InInnerScope()) return SetLocalVariableValue(name, value);
     421          25 :       if (Type() == ScopeTypeModule && SetModuleVariableValue(name, value)) {
     422             :         return true;
     423             :       }
     424          20 :       return SetContextVariableValue(name, value);
     425             : 
     426             :     case ScopeTypeLocal:
     427             :     case ScopeTypeClosure:
     428       82866 :       if (InInnerScope()) {
     429             :         DCHECK_EQ(ScopeTypeLocal, Type());
     430       82816 :         if (SetLocalVariableValue(name, value)) return true;
     431             :         // There may not be an associated context since we're InInnerScope().
     432       73802 :         if (!current_scope_->NeedsContext()) return false;
     433             :       } else {
     434             :         DCHECK_EQ(ScopeTypeClosure, Type());
     435          50 :         if (SetContextVariableValue(name, value)) return true;
     436             :       }
     437             :       // The above functions only set variables statically declared in the
     438             :       // function. There may be eval-introduced variables. Check them in
     439             :       // SetContextExtensionValue.
     440         805 :       return SetContextExtensionValue(name, value);
     441             : 
     442             :     case ScopeTypeScript:
     443          14 :       return SetScriptVariableValue(name, value);
     444             :   }
     445             :   return false;
     446             : }
     447             : 
     448       11967 : Handle<StringSet> ScopeIterator::GetNonLocals() { return non_locals_; }
     449             : 
     450             : #ifdef DEBUG
     451             : // Debug print of the content of the current scope.
     452             : void ScopeIterator::DebugPrint() {
     453             :   StdoutStream os;
     454             :   DCHECK(!Done());
     455             :   switch (Type()) {
     456             :     case ScopeIterator::ScopeTypeGlobal:
     457             :       os << "Global:\n";
     458             :       context_->Print(os);
     459             :       break;
     460             : 
     461             :     case ScopeIterator::ScopeTypeLocal: {
     462             :       os << "Local:\n";
     463             :       if (current_scope_->NeedsContext()) {
     464             :         context_->Print(os);
     465             :         if (context_->has_extension()) {
     466             :           Handle<HeapObject> extension(context_->extension(), isolate_);
     467             :           DCHECK(extension->IsJSContextExtensionObject());
     468             :           extension->Print(os);
     469             :         }
     470             :       }
     471             :       break;
     472             :     }
     473             : 
     474             :     case ScopeIterator::ScopeTypeWith:
     475             :       os << "With:\n";
     476             :       context_->extension()->Print(os);
     477             :       break;
     478             : 
     479             :     case ScopeIterator::ScopeTypeCatch:
     480             :       os << "Catch:\n";
     481             :       context_->extension()->Print(os);
     482             :       context_->get(Context::THROWN_OBJECT_INDEX)->Print(os);
     483             :       break;
     484             : 
     485             :     case ScopeIterator::ScopeTypeClosure:
     486             :       os << "Closure:\n";
     487             :       context_->Print(os);
     488             :       if (context_->has_extension()) {
     489             :         Handle<HeapObject> extension(context_->extension(), isolate_);
     490             :         DCHECK(extension->IsJSContextExtensionObject());
     491             :         extension->Print(os);
     492             :       }
     493             :       break;
     494             : 
     495             :     case ScopeIterator::ScopeTypeScript:
     496             :       os << "Script:\n";
     497             :       context_->global_object()
     498             :           ->native_context()
     499             :           ->script_context_table()
     500             :           ->Print(os);
     501             :       break;
     502             : 
     503             :     default:
     504             :       UNREACHABLE();
     505             :   }
     506             :   PrintF("\n");
     507             : }
     508             : #endif
     509             : 
     510      149746 : int ScopeIterator::GetSourcePosition() {
     511      149746 :   if (frame_inspector_) {
     512      148356 :     return frame_inspector_->GetSourcePosition();
     513             :   } else {
     514             :     DCHECK(!generator_.is_null());
     515        1390 :     return generator_->source_position();
     516             :   }
     517             : }
     518             : 
     519      149746 : void ScopeIterator::RetrieveScopeChain(DeclarationScope* scope) {
     520             :   DCHECK_NOT_NULL(scope);
     521             : 
     522      149746 :   const int position = GetSourcePosition();
     523             : 
     524             :   Scope* parent = nullptr;
     525      157586 :   Scope* current = scope;
     526      457078 :   while (parent != current) {
     527             :     parent = current;
     528      436444 :     for (Scope* inner_scope = current->inner_scope(); inner_scope != nullptr;
     529             :          inner_scope = inner_scope->sibling()) {
     530             :       int beg_pos = inner_scope->start_position();
     531             :       int end_pos = inner_scope->end_position();
     532             :       DCHECK((beg_pos >= 0 && end_pos >= 0) || inner_scope->is_hidden());
     533      278858 :       if (beg_pos <= position && position < end_pos) {
     534             :         // Don't walk into inner functions.
     535        7868 :         if (!inner_scope->is_function_scope()) {
     536             :           current = inner_scope;
     537             :         }
     538             :         break;
     539             :       }
     540             :     }
     541             :   }
     542             : 
     543      149746 :   start_scope_ = current;
     544      149746 :   current_scope_ = current;
     545      149746 : }
     546             : 
     547      270840 : void ScopeIterator::VisitScriptScope(const Visitor& visitor) const {
     548      812520 :   Handle<JSGlobalObject> global(context_->global_object(), isolate_);
     549             :   Handle<ScriptContextTable> script_contexts(
     550      812520 :       global->native_context()->script_context_table(), isolate_);
     551             : 
     552             :   // Skip the first script since that just declares 'this'.
     553      818032 :   for (int context_index = 1; context_index < script_contexts->used();
     554             :        context_index++) {
     555             :     Handle<Context> context = ScriptContextTable::GetContext(
     556      266759 :         isolate_, script_contexts, context_index);
     557      800277 :     Handle<ScopeInfo> scope_info(context->scope_info(), isolate_);
     558      666182 :     if (VisitContextLocals(visitor, scope_info, context)) return;
     559             :   }
     560             : }
     561             : 
     562        1511 : void ScopeIterator::VisitModuleScope(const Visitor& visitor) const {
     563             :   DCHECK(context_->IsModuleContext());
     564             : 
     565        4533 :   Handle<ScopeInfo> scope_info(context_->scope_info(), isolate_);
     566        2269 :   if (VisitContextLocals(visitor, scope_info, context_)) return;
     567             : 
     568         753 :   int count_index = scope_info->ModuleVariableCountIndex();
     569             :   int module_variable_count = Smi::cast(scope_info->get(count_index))->value();
     570             : 
     571        2259 :   Handle<Module> module(context_->module(), isolate_);
     572             : 
     573        2358 :   for (int i = 0; i < module_variable_count; ++i) {
     574             :     int index;
     575             :     Handle<String> name;
     576             :     {
     577        1605 :       String raw_name;
     578        1605 :       scope_info->ModuleVariable(i, &raw_name, &index);
     579        1605 :       CHECK(!ScopeInfo::VariableIsSynthetic(raw_name));
     580        3210 :       name = handle(raw_name, isolate_);
     581             :     }
     582        1605 :     Handle<Object> value = Module::LoadVariable(isolate_, module, index);
     583             : 
     584             :     // Reflect variables under TDZ as undeclared in scope object.
     585        6355 :     if (value->IsTheHole(isolate_)) continue;
     586          65 :     if (visitor(name, value)) return;
     587             :   }
     588             : }
     589             : 
     590      290414 : bool ScopeIterator::VisitContextLocals(const Visitor& visitor,
     591             :                                        Handle<ScopeInfo> scope_info,
     592             :                                        Handle<Context> context) const {
     593             :   // Fill all context locals to the context extension.
     594     1642508 :   for (int i = 0; i < scope_info->ContextLocalCount(); ++i) {
     595     2011203 :     Handle<String> name(scope_info->ContextLocalName(i), isolate_);
     596      670401 :     if (ScopeInfo::VariableIsSynthetic(*name)) continue;
     597             :     int context_index = Context::MIN_CONTEXT_SLOTS + i;
     598     1965078 :     Handle<Object> value(context->get(context_index), isolate_);
     599             :     // Reflect variables under TDZ as undefined in scope object.
     600     1965078 :     if (value->IsTheHole(isolate_)) continue;
     601      652778 :     if (visitor(name, value)) return true;
     602             :   }
     603             :   return false;
     604             : }
     605             : 
     606      109167 : bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode) const {
     607    17221173 :   for (Variable* var : *current_scope_->locals()) {
     608     4368835 :     if (var->is_this()) {
     609             :       // Only collect "this" for DebugEvaluate. The debugger will manually add
     610             :       // "this" in a different way, and if we'd add it here as well, it shows up
     611             :       // twice.
     612       93278 :       if (mode == Mode::ALL) continue;
     613     4275557 :     } else if (ScopeInfo::VariableIsSynthetic(*var->name())) {
     614             :       continue;
     615             :     }
     616             : 
     617             :     int index = var->index();
     618             :     Handle<Object> value;
     619     4170588 :     switch (var->location()) {
     620             :       case VariableLocation::LOOKUP:
     621           0 :         UNREACHABLE();
     622             :         break;
     623             : 
     624             :       case VariableLocation::UNALLOCATED:
     625       97217 :         if (!var->is_this()) continue;
     626             :         // No idea why this diverges...
     627       11216 :         value = frame_inspector_->GetReceiver();
     628       11216 :         break;
     629             : 
     630             :       case VariableLocation::PARAMETER: {
     631       24036 :         if (frame_inspector_ == nullptr) {
     632             :           // Get the variable from the suspended generator.
     633             :           DCHECK(!generator_.is_null());
     634         127 :           if (var->is_this()) {
     635           0 :             value = handle(generator_->receiver(), isolate_);
     636             :           } else {
     637             :             FixedArray parameters_and_registers =
     638         127 :                 generator_->parameters_and_registers();
     639             :             DCHECK_LT(index, parameters_and_registers->length());
     640         127 :             value = handle(parameters_and_registers->get(index), isolate_);
     641             :           }
     642             :         } else {
     643             :           value = var->is_this() ? frame_inspector_->GetReceiver()
     644       23909 :                                  : frame_inspector_->GetParameter(index);
     645             : 
     646       71727 :           if (value->IsOptimizedOut(isolate_)) {
     647           0 :             value = isolate_->factory()->undefined_value();
     648       23965 :           } else if (var->is_this() && value->IsTheHole(isolate_)) {
     649           9 :             value = isolate_->factory()->undefined_value();
     650             :           }
     651             :         }
     652             :         break;
     653             :       }
     654             : 
     655             :       case VariableLocation::LOCAL:
     656     3997166 :         if (frame_inspector_ == nullptr) {
     657             :           // Get the variable from the suspended generator.
     658             :           DCHECK(!generator_.is_null());
     659             :           FixedArray parameters_and_registers =
     660         352 :               generator_->parameters_and_registers();
     661             :           int parameter_count =
     662         352 :               function_->shared()->scope_info()->ParameterCount();
     663         352 :           index += parameter_count;
     664             :           DCHECK_LT(index, parameters_and_registers->length());
     665         352 :           value = handle(parameters_and_registers->get(index), isolate_);
     666        1056 :           if (value->IsTheHole(isolate_)) {
     667           0 :             value = isolate_->factory()->undefined_value();
     668             :           }
     669             :         } else {
     670     3996814 :           value = frame_inspector_->GetExpression(index);
     671    11990442 :           if (value->IsOptimizedOut(isolate_)) {
     672             :             // We'll rematerialize this later.
     673        2937 :             if (current_scope_->is_declaration_scope() &&
     674         947 :                 current_scope_->AsDeclarationScope()->arguments() == var) {
     675             :               continue;
     676             :             }
     677         973 :             value = isolate_->factory()->undefined_value();
     678    11987457 :           } else if (value->IsTheHole(isolate_)) {
     679             :             // Reflect variables under TDZ as undeclared in scope object.
     680             :             continue;
     681             :           }
     682             :         }
     683             :         break;
     684             : 
     685             :       case VariableLocation::CONTEXT:
     686       51007 :         if (mode == Mode::STACK) continue;
     687             :         DCHECK(var->IsContextSlot());
     688      150150 :         value = handle(context_->get(index), isolate_);
     689             :         // Reflect variables under TDZ as undeclared in scope object.
     690      150150 :         if (value->IsTheHole(isolate_)) continue;
     691             :         break;
     692             : 
     693             :       case VariableLocation::MODULE: {
     694        2084 :         if (mode == Mode::STACK) continue;
     695             :         // if (var->IsExport()) continue;
     696        2169 :         Handle<Module> module(context_->module(), isolate_);
     697         723 :         value = Module::LoadVariable(isolate_, module, var->index());
     698             :         // Reflect variables under TDZ as undeclared in scope object.
     699        2169 :         if (value->IsTheHole(isolate_)) continue;
     700         240 :         break;
     701             :       }
     702             :     }
     703             : 
     704     4082156 :     if (visitor(var->name(), value)) return true;
     705             :   }
     706             :   return false;
     707             : }
     708             : 
     709             : // Retrieve the with-context extension object. If the extension object is
     710             : // a proxy, return an empty object.
     711        2513 : Handle<JSObject> ScopeIterator::WithContextExtension() {
     712             :   DCHECK(context_->IsWithContext());
     713        5026 :   if (context_->extension_receiver()->IsJSProxy()) {
     714           0 :     return isolate_->factory()->NewJSObjectWithNullProto();
     715             :   }
     716        7539 :   return handle(JSObject::cast(context_->extension_receiver()), isolate_);
     717             : }
     718             : 
     719             : // Create a plain JSObject which materializes the block scope for the specified
     720             : // block context.
     721      142155 : void ScopeIterator::VisitLocalScope(const Visitor& visitor, Mode mode) const {
     722      131311 :   if (InInnerScope()) {
     723      109167 :     if (VisitLocals(visitor, mode)) return;
     724      104980 :     if (mode == Mode::STACK && Type() == ScopeTypeLocal) {
     725             :       // Hide |this| in arrow functions that may be embedded in other functions
     726             :       // but don't force |this| to be context-allocated. Otherwise we'd find the
     727             :       // wrong |this| value.
     728       57021 :       if (!closure_scope_->has_this_declaration() &&
     729       13385 :           !non_locals_->Has(isolate_, isolate_->factory()->this_string())) {
     730         760 :         if (visitor(isolate_->factory()->this_string(),
     731         760 :                     isolate_->factory()->undefined_value()))
     732             :           return;
     733             :       }
     734             :       // Add |arguments| to the function scope even if it wasn't used.
     735             :       // Currently we don't yet support materializing the arguments object of
     736             :       // suspended generators. We'd need to read the arguments out from the
     737             :       // suspended generator rather than from an activation as
     738             :       // FunctionGetArguments does.
     739       67798 :       if (frame_inspector_ != nullptr && !closure_scope_->is_arrow_scope() &&
     740          67 :           (closure_scope_->arguments() == nullptr ||
     741          67 :            frame_inspector_->GetExpression(closure_scope_->arguments()->index())
     742       11796 :                ->IsOptimizedOut(isolate_))) {
     743             :         JavaScriptFrame* frame = GetFrame();
     744             :         Handle<JSObject> arguments = Accessors::FunctionGetArguments(
     745       21688 :             frame, frame_inspector_->inlined_frame_index());
     746       21688 :         if (visitor(isolate_->factory()->arguments_string(), arguments)) return;
     747             :       }
     748             :     }
     749             :   } else {
     750             :     DCHECK_EQ(Mode::ALL, mode);
     751       66432 :     Handle<ScopeInfo> scope_info(context_->scope_info(), isolate_);
     752       22144 :     if (VisitContextLocals(visitor, scope_info, context_)) return;
     753             :   }
     754             : 
     755      221664 :   if (mode == Mode::ALL && HasContext()) {
     756             :     DCHECK(!context_->IsScriptContext());
     757             :     DCHECK(!context_->IsNativeContext());
     758             :     DCHECK(!context_->IsWithContext());
     759       22938 :     if (!context_->scope_info()->CallsSloppyEval()) return;
     760       15642 :     if (context_->extension_object().is_null()) return;
     761        1014 :     Handle<JSObject> extension(context_->extension_object(), isolate_);
     762             :     Handle<FixedArray> keys =
     763             :         KeyAccumulator::GetKeys(extension, KeyCollectionMode::kOwnOnly,
     764         338 :                                 ENUMERABLE_STRINGS)
     765         676 :             .ToHandleChecked();
     766             : 
     767        1732 :     for (int i = 0; i < keys->length(); i++) {
     768             :       // Names of variables introduced by eval are strings.
     769             :       DCHECK(keys->get(i)->IsString());
     770         528 :       Handle<String> key(String::cast(keys->get(i)), isolate_);
     771         528 :       Handle<Object> value = JSReceiver::GetDataProperty(extension, key);
     772         528 :       if (visitor(key, value)) return;
     773             :     }
     774             :   }
     775             : }
     776             : 
     777       83568 : bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
     778             :                                           Handle<Object> new_value) {
     779             :   // TODO(verwaest): Walk parameters backwards, not forwards.
     780             :   // TODO(verwaest): Use VariableMap rather than locals() list for lookup.
     781     2608788 :   for (Variable* var : *current_scope_->locals()) {
     782     2358079 :     if (String::Equals(isolate_, var->name(), variable_name)) {
     783             :       int index = var->index();
     784       83188 :       switch (var->location()) {
     785             :         case VariableLocation::LOOKUP:
     786             :         case VariableLocation::UNALLOCATED:
     787             :           // Drop assignments to unallocated locals.
     788             :           DCHECK(var->is_this() ||
     789             :                  *variable_name == ReadOnlyRoots(isolate_).arguments_string());
     790             :           return false;
     791             : 
     792             :         case VariableLocation::PARAMETER: {
     793       12474 :           if (var->is_this()) return false;
     794       12455 :           if (frame_inspector_ == nullptr) {
     795             :             // Set the variable in the suspended generator.
     796             :             DCHECK(!generator_.is_null());
     797             :             Handle<FixedArray> parameters_and_registers(
     798           0 :                 generator_->parameters_and_registers(), isolate_);
     799             :             DCHECK_LT(index, parameters_and_registers->length());
     800           0 :             parameters_and_registers->set(index, *new_value);
     801             :           } else {
     802             :             JavaScriptFrame* frame = GetFrame();
     803       24910 :             if (frame->is_optimized()) return false;
     804             : 
     805        2138 :             frame->SetParameterValue(index, *new_value);
     806             :           }
     807             :           return true;
     808             :         }
     809             : 
     810             :         case VariableLocation::LOCAL:
     811       51038 :           if (frame_inspector_ == nullptr) {
     812             :             // Set the variable in the suspended generator.
     813             :             DCHECK(!generator_.is_null());
     814             :             int parameter_count =
     815          27 :                 function_->shared()->scope_info()->ParameterCount();
     816          27 :             index += parameter_count;
     817             :             Handle<FixedArray> parameters_and_registers(
     818          81 :                 generator_->parameters_and_registers(), isolate_);
     819             :             DCHECK_LT(index, parameters_and_registers->length());
     820          27 :             parameters_and_registers->set(index, *new_value);
     821             :           } else {
     822             :             // Set the variable on the stack.
     823             :             JavaScriptFrame* frame = GetFrame();
     824      102022 :             if (frame->is_optimized()) return false;
     825             : 
     826       44174 :             frame->SetExpression(index, *new_value);
     827             :           }
     828             :           return true;
     829             : 
     830             :         case VariableLocation::CONTEXT:
     831             :           DCHECK(var->IsContextSlot());
     832         154 :           context_->set(index, *new_value);
     833          77 :           return true;
     834             : 
     835             :         case VariableLocation::MODULE:
     836          10 :           if (!var->IsExport()) return false;
     837          15 :           Handle<Module> module(context_->module(), isolate_);
     838           5 :           Module::StoreVariable(module, var->index(), new_value);
     839           5 :           return true;
     840             :       }
     841           0 :       UNREACHABLE();
     842             :     }
     843             :   }
     844             : 
     845             :   return false;
     846             : }
     847             : 
     848         805 : bool ScopeIterator::SetContextExtensionValue(Handle<String> variable_name,
     849             :                                              Handle<Object> new_value) {
     850         805 :   if (!context_->has_extension()) return false;
     851             : 
     852             :   DCHECK(context_->extension_object()->IsJSContextExtensionObject());
     853          30 :   Handle<JSObject> ext(context_->extension_object(), isolate_);
     854          10 :   LookupIterator it(isolate_, ext, variable_name, LookupIterator::OWN);
     855          10 :   Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
     856             :   DCHECK(maybe.IsJust());
     857          10 :   if (!maybe.FromJust()) return false;
     858             : 
     859          20 :   CHECK(Object::SetDataProperty(&it, new_value).ToChecked());
     860             :   return true;
     861             : }
     862             : 
     863          70 : bool ScopeIterator::SetContextVariableValue(Handle<String> variable_name,
     864             :                                             Handle<Object> new_value) {
     865         210 :   Handle<ScopeInfo> scope_info(context_->scope_info(), isolate_);
     866             : 
     867             :   VariableMode mode;
     868             :   InitializationFlag flag;
     869             :   MaybeAssignedFlag maybe_assigned_flag;
     870             :   int slot_index = ScopeInfo::ContextSlotIndex(scope_info, variable_name, &mode,
     871          70 :                                                &flag, &maybe_assigned_flag);
     872          70 :   if (slot_index < 0) return false;
     873             : 
     874         120 :   context_->set(slot_index, *new_value);
     875          60 :   return true;
     876             : }
     877             : 
     878          15 : bool ScopeIterator::SetModuleVariableValue(Handle<String> variable_name,
     879             :                                            Handle<Object> new_value) {
     880             :   int cell_index;
     881             :   VariableMode mode;
     882             :   InitializationFlag init_flag;
     883             :   MaybeAssignedFlag maybe_assigned_flag;
     884          30 :   cell_index = context_->scope_info()->ModuleIndex(
     885          15 :       variable_name, &mode, &init_flag, &maybe_assigned_flag);
     886             : 
     887             :   // Setting imports is currently not supported.
     888          15 :   if (ModuleDescriptor::GetCellIndexKind(cell_index) !=
     889             :       ModuleDescriptor::kExport) {
     890             :     return false;
     891             :   }
     892             : 
     893          15 :   Handle<Module> module(context_->module(), isolate_);
     894           5 :   Module::StoreVariable(module, cell_index, new_value);
     895           5 :   return true;
     896             : }
     897             : 
     898          14 : bool ScopeIterator::SetScriptVariableValue(Handle<String> variable_name,
     899             :                                            Handle<Object> new_value) {
     900             :   Handle<ScriptContextTable> script_contexts(
     901          28 :       context_->global_object()->native_context()->script_context_table(),
     902          42 :       isolate_);
     903             :   ScriptContextTable::LookupResult lookup_result;
     904          14 :   if (ScriptContextTable::Lookup(isolate_, script_contexts, variable_name,
     905          14 :                                  &lookup_result)) {
     906             :     Handle<Context> script_context = ScriptContextTable::GetContext(
     907          14 :         isolate_, script_contexts, lookup_result.context_index);
     908          42 :     script_context->set(lookup_result.slot_index, *new_value);
     909             :     return true;
     910             :   }
     911             : 
     912             :   return false;
     913             : }
     914             : 
     915             : }  // namespace internal
     916      183867 : }  // namespace v8

Generated by: LCOV version 1.10