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

Generated by: LCOV version 1.10