LCOV - code coverage report
Current view: top level - src/debug - debug-scopes.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 325 343 94.8 %
Date: 2019-03-21 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      159517 : 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      638068 :       script_(frame_inspector_->GetScript()) {
      31      319034 :   if (!frame_inspector->GetContext()->IsContext()) {
      32             :     // Optimized frame, context or function cannot be materialized. Give up.
      33             :     return;
      34             :   }
      35      159426 :   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      159426 :   TryParseAndRetrieveScopes(option);
      41             : }
      42             : 
      43      160967 : ScopeIterator::~ScopeIterator() { delete info_; }
      44             : 
      45      372790 : Handle<Object> ScopeIterator::GetFunctionDebugName() const {
      46      372790 :   if (!function_.is_null()) return JSFunction::GetDebugName(function_);
      47             : 
      48      471574 :   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      454512 :   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       10903 : void ScopeIterator::Restart() {
      79             :   DCHECK_NOT_NULL(frame_inspector_);
      80       10903 :   function_ = frame_inspector_->GetFunction();
      81       10903 :   context_ = Handle<Context>::cast(frame_inspector_->GetContext());
      82       10903 :   current_scope_ = start_scope_;
      83             :   DCHECK_NOT_NULL(current_scope_);
      84       10903 :   UnwrapEvaluationContext();
      85       10903 : }
      86             : 
      87      160816 : void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) {
      88             :   // Catch the case when the debugger stops in an internal function.
      89      160816 :   Handle<SharedFunctionInfo> shared_info(function_->shared(), isolate_);
      90      482448 :   Handle<ScopeInfo> scope_info(shared_info->scope_info(), isolate_);
      91      482448 :   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      160816 :   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      160796 :   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       90815 :     Handle<DebugInfo> debug_info(shared_info->GetDebugInfo(), isolate_);
     118             : 
     119             :     // Find the break point where execution has stopped.
     120       90815 :     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      160796 :   if (scope_info->scope_type() == FUNCTION_SCOPE) {
     128             :     // Inner function.
     129      101547 :     info_ = new ParseInfo(isolate_, shared_info);
     130             :   } else {
     131             :     // Global or eval code.
     132      177747 :     Handle<Script> script(Script::cast(shared_info->script()), isolate_);
     133       59249 :     info_ = new ParseInfo(isolate_, script);
     134       59249 :     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       53675 :     } 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      317320 :   if (parsing::ParseAny(info_, shared_info, isolate_) &&
     150      156524 :       Rewriter::Rewrite(info_)) {
     151      313048 :     info_->ast_value_factory()->Internalize(isolate_);
     152      156524 :     closure_scope_ = info_->literal()->scope();
     153             : 
     154      156524 :     if (option == COLLECT_NON_LOCALS) {
     155             :       DCHECK(non_locals_.is_null());
     156       12560 :       non_locals_ = info_->literal()->scope()->CollectNonLocals(
     157       25120 :           isolate_, info_, StringSet::New(isolate_));
     158       26446 :       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      156524 :     CHECK(DeclarationScope::Analyze(info_));
     166      156524 :     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      150322 :       RetrieveScopeChain(closure_scope_);
     174             :     }
     175      156524 :     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        8544 :     CHECK(isolate_->has_pending_exception());
     185             :     isolate_->clear_pending_exception();
     186        4272 :     context_ = Handle<Context>();
     187             :   }
     188             : }
     189             : 
     190      443758 : void ScopeIterator::UnwrapEvaluationContext() {
     191      887516 :   if (!context_->IsDebugEvaluateContext()) return;
     192           0 :   Context current = *context_;
     193           0 :   do {
     194             :     Object wrapped = current->get(Context::WRAPPED_CONTEXT_INDEX);
     195           0 :     if (wrapped->IsContext()) {
     196           0 :       current = Context::cast(wrapped);
     197             :     } else {
     198             :       DCHECK(!current->previous().is_null());
     199           0 :       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         315 :     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         630 :   return isolate_->factory()->NewJSArrayWithElements(details);
     226             : }
     227             : 
     228      372316 : bool ScopeIterator::HasPositionInfo() {
     229      843634 :   return InInnerScope() || !context_->IsNativeContext();
     230             : }
     231             : 
     232      155624 : int ScopeIterator::start_position() {
     233      155624 :   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      155624 : int ScopeIterator::end_position() {
     239      155624 :   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      310405 : bool ScopeIterator::DeclaresLocals(Mode mode) const {
     245      310405 :   ScopeType type = Type();
     246             : 
     247      310405 :   if (type == ScopeTypeWith) return mode == Mode::ALL;
     248      307857 :   if (type == ScopeTypeGlobal) return mode == Mode::ALL;
     249             : 
     250      165439 :   bool declares_local = false;
     251             :   auto visitor = [&](Handle<String> name, Handle<Object> value) {
     252      144641 :     declares_local = true;
     253             :     return true;
     254             :   };
     255      330878 :   VisitScope(visitor, mode);
     256      165439 :   return declares_local;
     257             : }
     258             : 
     259       12424 : bool ScopeIterator::HasContext() const {
     260      118707 :   return !InInnerScope() || current_scope_->NeedsContext();
     261             : }
     262             : 
     263      418982 : void ScopeIterator::Next() {
     264             :   DCHECK(!Done());
     265             : 
     266      418982 :   ScopeType scope_type = Type();
     267             : 
     268      418982 :   if (scope_type == ScopeTypeGlobal) {
     269             :     // The global scope is always the last in the chain.
     270             :     DCHECK(context_->IsNativeContext());
     271      142706 :     context_ = Handle<Context>();
     272             :     DCHECK(Done());
     273      142706 :     return;
     274             :   }
     275             : 
     276             :   bool inner = InInnerScope();
     277      276276 :   if (current_scope_ == closure_scope_) function_ = Handle<JSFunction>();
     278             : 
     279      276276 :   if (scope_type == ScopeTypeScript) {
     280             :     DCHECK_IMPLIES(InInnerScope(), current_scope_->is_script_scope());
     281      142868 :     seen_script_scope_ = true;
     282      142868 :     if (context_->IsScriptContext()) {
     283       26790 :       context_ = handle(context_->previous(), isolate_);
     284             :     }
     285      133408 :   } else if (!inner) {
     286             :     DCHECK(!context_->IsNativeContext());
     287       40974 :     context_ = handle(context_->previous(), isolate_);
     288             :   } else {
     289             :     DCHECK_NOT_NULL(current_scope_);
     290      120954 :     do {
     291      120954 :       if (current_scope_->NeedsContext()) {
     292             :         DCHECK(!context_->previous().is_null());
     293       46485 :         context_ = handle(context_->previous(), isolate_);
     294             :       }
     295             :       DCHECK_IMPLIES(InInnerScope(), current_scope_->outer_scope() != nullptr);
     296      120954 :       current_scope_ = current_scope_->outer_scope();
     297             :       // Repeat to skip hidden scopes.
     298             :     } while (current_scope_->is_hidden());
     299             :   }
     300             : 
     301      276276 :   UnwrapEvaluationContext();
     302             : }
     303             : 
     304             : 
     305             : // Return the type of the current scope.
     306     2398433 : ScopeIterator::ScopeType ScopeIterator::Type() const {
     307             :   DCHECK(!Done());
     308     2398433 :   if (InInnerScope()) {
     309      991399 :     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      353438 :         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             :         DCHECK_IMPLIES(current_scope_->NeedsContext(),
     333             :                        context_->IsBlockContext());
     334       19303 :         return ScopeTypeBlock;
     335             :       case EVAL_SCOPE:
     336             :         DCHECK_IMPLIES(current_scope_->NeedsContext(),
     337             :                        context_->IsEvalContext());
     338       22737 :         return ScopeTypeEval;
     339             :     }
     340           0 :     UNREACHABLE();
     341             :   }
     342     1407034 :   if (context_->IsNativeContext()) {
     343             :     DCHECK(context_->global_object()->IsJSGlobalObject());
     344             :     // If we are at the native context and have not yet seen script scope,
     345             :     // fake it.
     346     1268434 :     return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript;
     347             :   }
     348      406280 :   if (context_->IsFunctionContext() || context_->IsEvalContext() ||
     349      200435 :       context_->IsDebugEvaluateContext()) {
     350             :     return ScopeTypeClosure;
     351             :   }
     352       61835 :   if (context_->IsCatchContext()) {
     353             :     return ScopeTypeCatch;
     354             :   }
     355       59296 :   if (context_->IsBlockContext()) {
     356             :     return ScopeTypeBlock;
     357             :   }
     358       56803 :   if (context_->IsModuleContext()) {
     359             :     return ScopeTypeModule;
     360             :   }
     361       51487 :   if (context_->IsScriptContext()) {
     362             :     return ScopeTypeScript;
     363             :   }
     364             :   DCHECK(context_->IsWithContext());
     365        2345 :   return ScopeTypeWith;
     366             : }
     367             : 
     368      385503 : Handle<JSObject> ScopeIterator::ScopeObject(Mode mode) {
     369             :   DCHECK(!Done());
     370             : 
     371      385503 :   ScopeType type = Type();
     372      385503 :   if (type == ScopeTypeGlobal) {
     373             :     DCHECK_EQ(Mode::ALL, mode);
     374      427698 :     return handle(context_->global_proxy(), isolate_);
     375             :   }
     376      242937 :   if (type == ScopeTypeWith) {
     377             :     DCHECK_EQ(Mode::ALL, mode);
     378        2518 :     return WithContextExtension();
     379             :   }
     380             : 
     381      240419 :   Handle<JSObject> scope = isolate_->factory()->NewJSObjectWithNullProto();
     382             :   auto visitor = [=](Handle<String> name, Handle<Object> value) {
     383     4616350 :     JSObject::AddProperty(isolate_, scope, name, value, NONE);
     384             :     return false;
     385      240419 :   };
     386             : 
     387      480838 :   VisitScope(visitor, mode);
     388      240419 :   return scope;
     389             : }
     390             : 
     391      405858 : void ScopeIterator::VisitScope(const Visitor& visitor, Mode mode) const {
     392      405858 :   switch (Type()) {
     393             :     case ScopeTypeLocal:
     394             :     case ScopeTypeClosure:
     395             :     case ScopeTypeCatch:
     396             :     case ScopeTypeBlock:
     397             :     case ScopeTypeEval:
     398      131349 :       return VisitLocalScope(visitor, mode);
     399             :     case ScopeTypeModule:
     400        2921 :       if (InInnerScope()) {
     401        1410 :         return VisitLocalScope(visitor, mode);
     402             :       }
     403             :       DCHECK_EQ(Mode::ALL, mode);
     404        1511 :       return VisitModuleScope(visitor);
     405             :     case ScopeTypeScript:
     406             :       DCHECK_EQ(Mode::ALL, mode);
     407      271588 :       return VisitScriptScope(visitor);
     408             :     case ScopeTypeWith:
     409             :     case ScopeTypeGlobal:
     410           0 :       UNREACHABLE();
     411             :   }
     412             : }
     413             : 
     414       84138 : bool ScopeIterator::SetVariableValue(Handle<String> name,
     415             :                                      Handle<Object> value) {
     416             :   DCHECK(!Done());
     417       84138 :   name = isolate_->factory()->InternalizeString(name);
     418       84138 :   switch (Type()) {
     419             :     case ScopeTypeGlobal:
     420             :     case ScopeTypeWith:
     421             :       break;
     422             : 
     423             :     case ScopeTypeEval:
     424             :     case ScopeTypeBlock:
     425             :     case ScopeTypeCatch:
     426             :     case ScopeTypeModule:
     427         777 :       if (InInnerScope()) return SetLocalVariableValue(name, value);
     428          25 :       if (Type() == ScopeTypeModule && SetModuleVariableValue(name, value)) {
     429             :         return true;
     430             :       }
     431          20 :       return SetContextVariableValue(name, value);
     432             : 
     433             :     case ScopeTypeLocal:
     434             :     case ScopeTypeClosure:
     435       83311 :       if (InInnerScope()) {
     436             :         DCHECK_EQ(ScopeTypeLocal, Type());
     437       83261 :         if (SetLocalVariableValue(name, value)) return true;
     438             :         // There may not be an associated context since we're InInnerScope().
     439       37183 :         if (!current_scope_->NeedsContext()) return false;
     440             :       } else {
     441             :         DCHECK_EQ(ScopeTypeClosure, Type());
     442          50 :         if (SetContextVariableValue(name, value)) return true;
     443             :       }
     444             :       // The above functions only set variables statically declared in the
     445             :       // function. There may be eval-introduced variables. Check them in
     446             :       // SetContextExtensionValue.
     447         930 :       return SetContextExtensionValue(name, value);
     448             : 
     449             :     case ScopeTypeScript:
     450          14 :       return SetScriptVariableValue(name, value);
     451             :   }
     452             :   return false;
     453             : }
     454             : 
     455       12064 : Handle<StringSet> ScopeIterator::GetNonLocals() { return non_locals_; }
     456             : 
     457             : #ifdef DEBUG
     458             : // Debug print of the content of the current scope.
     459             : void ScopeIterator::DebugPrint() {
     460             :   StdoutStream os;
     461             :   DCHECK(!Done());
     462             :   switch (Type()) {
     463             :     case ScopeIterator::ScopeTypeGlobal:
     464             :       os << "Global:\n";
     465             :       context_->Print(os);
     466             :       break;
     467             : 
     468             :     case ScopeIterator::ScopeTypeLocal: {
     469             :       os << "Local:\n";
     470             :       if (current_scope_->NeedsContext()) {
     471             :         context_->Print(os);
     472             :         if (context_->has_extension()) {
     473             :           Handle<HeapObject> extension(context_->extension(), isolate_);
     474             :           DCHECK(extension->IsJSContextExtensionObject());
     475             :           extension->Print(os);
     476             :         }
     477             :       }
     478             :       break;
     479             :     }
     480             : 
     481             :     case ScopeIterator::ScopeTypeWith:
     482             :       os << "With:\n";
     483             :       context_->extension()->Print(os);
     484             :       break;
     485             : 
     486             :     case ScopeIterator::ScopeTypeCatch:
     487             :       os << "Catch:\n";
     488             :       context_->extension()->Print(os);
     489             :       context_->get(Context::THROWN_OBJECT_INDEX)->Print(os);
     490             :       break;
     491             : 
     492             :     case ScopeIterator::ScopeTypeClosure:
     493             :       os << "Closure:\n";
     494             :       context_->Print(os);
     495             :       if (context_->has_extension()) {
     496             :         Handle<HeapObject> extension(context_->extension(), isolate_);
     497             :         DCHECK(extension->IsJSContextExtensionObject());
     498             :         extension->Print(os);
     499             :       }
     500             :       break;
     501             : 
     502             :     case ScopeIterator::ScopeTypeScript:
     503             :       os << "Script:\n";
     504             :       context_->global_object()
     505             :           ->native_context()
     506             :           ->script_context_table()
     507             :           ->Print(os);
     508             :       break;
     509             : 
     510             :     default:
     511             :       UNREACHABLE();
     512             :   }
     513             :   PrintF("\n");
     514             : }
     515             : #endif
     516             : 
     517      150322 : int ScopeIterator::GetSourcePosition() {
     518      150322 :   if (frame_inspector_) {
     519      148932 :     return frame_inspector_->GetSourcePosition();
     520             :   } else {
     521             :     DCHECK(!generator_.is_null());
     522        2780 :     SharedFunctionInfo::EnsureSourcePositionsAvailable(
     523        1390 :         isolate_, handle(generator_->function()->shared(), isolate_));
     524        1390 :     return generator_->source_position();
     525             :   }
     526             : }
     527             : 
     528      150322 : void ScopeIterator::RetrieveScopeChain(DeclarationScope* scope) {
     529             :   DCHECK_NOT_NULL(scope);
     530             : 
     531      150322 :   const int position = GetSourcePosition();
     532             : 
     533             :   Scope* parent = nullptr;
     534             :   Scope* current = scope;
     535      308488 :   while (parent != current) {
     536             :     parent = current;
     537      699482 :     for (Scope* inner_scope = current->inner_scope(); inner_scope != nullptr;
     538             :          inner_scope = inner_scope->sibling()) {
     539             :       int beg_pos = inner_scope->start_position();
     540             :       int end_pos = inner_scope->end_position();
     541             :       DCHECK((beg_pos >= 0 && end_pos >= 0) || inner_scope->is_hidden());
     542      278530 :       if (beg_pos <= position && position < end_pos) {
     543             :         // Don't walk into inner functions.
     544        7872 :         if (!inner_scope->is_function_scope()) {
     545             :           current = inner_scope;
     546             :         }
     547             :         break;
     548             :       }
     549             :     }
     550             :   }
     551             : 
     552      150322 :   start_scope_ = current;
     553      150322 :   current_scope_ = current;
     554      150322 : }
     555             : 
     556      271588 : void ScopeIterator::VisitScriptScope(const Visitor& visitor) const {
     557      814764 :   Handle<JSGlobalObject> global(context_->global_object(), isolate_);
     558             :   Handle<ScriptContextTable> script_contexts(
     559      814764 :       global->native_context()->script_context_table(), isolate_);
     560             : 
     561             :   // Skip the first script since that just declares 'this'.
     562      548764 :   for (int context_index = 1; context_index < script_contexts->used();
     563             :        context_index++) {
     564             :     Handle<Context> context = ScriptContextTable::GetContext(
     565      267596 :         isolate_, script_contexts, context_index);
     566      802788 :     Handle<ScopeInfo> scope_info(context->scope_info(), isolate_);
     567      396604 :     if (VisitContextLocals(visitor, scope_info, context)) return;
     568             :   }
     569             : }
     570             : 
     571        1511 : void ScopeIterator::VisitModuleScope(const Visitor& visitor) const {
     572             :   DCHECK(context_->IsModuleContext());
     573             : 
     574        4533 :   Handle<ScopeInfo> scope_info(context_->scope_info(), isolate_);
     575        2269 :   if (VisitContextLocals(visitor, scope_info, context_)) return;
     576             : 
     577         753 :   int count_index = scope_info->ModuleVariableCountIndex();
     578             :   int module_variable_count = Smi::cast(scope_info->get(count_index))->value();
     579             : 
     580        2259 :   Handle<Module> module(context_->module(), isolate_);
     581             : 
     582        3983 :   for (int i = 0; i < module_variable_count; ++i) {
     583             :     int index;
     584             :     Handle<String> name;
     585             :     {
     586        1615 :       String raw_name;
     587        1615 :       scope_info->ModuleVariable(i, &raw_name, &index);
     588        1625 :       if (ScopeInfo::VariableIsSynthetic(raw_name)) continue;
     589        1605 :       name = handle(raw_name, isolate_);
     590             :     }
     591        1605 :     Handle<Object> value = Module::LoadVariable(isolate_, module, index);
     592             : 
     593             :     // Reflect variables under TDZ as undeclared in scope object.
     594        3210 :     if (value->IsTheHole(isolate_)) continue;
     595          65 :     if (visitor(name, value)) return;
     596             :   }
     597             : }
     598             : 
     599      292192 : bool ScopeIterator::VisitContextLocals(const Visitor& visitor,
     600             :                                        Handle<ScopeInfo> scope_info,
     601             :                                        Handle<Context> context) const {
     602             :   // Fill all context locals to the context extension.
     603     1383356 :   for (int i = 0; i < scope_info->ContextLocalCount(); ++i) {
     604     2058105 :     Handle<String> name(scope_info->ContextLocalName(i), isolate_);
     605      686035 :     if (ScopeInfo::VariableIsSynthetic(*name)) continue;
     606             :     int context_index = Context::MIN_CONTEXT_SLOTS + i;
     607      668696 :     Handle<Object> value(context->get(context_index), isolate_);
     608             :     // Reflect variables under TDZ as undefined in scope object.
     609     1337392 :     if (value->IsTheHole(isolate_)) continue;
     610      666438 :     if (visitor(name, value)) return true;
     611             :   }
     612             :   return false;
     613             : }
     614             : 
     615      109674 : bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode) const {
     616      134587 :   if (mode == Mode::STACK && current_scope_->is_declaration_scope() &&
     617       12205 :       current_scope_->AsDeclarationScope()->has_this_declaration()) {
     618       11462 :     Handle<Object> receiver = frame_inspector_ == nullptr
     619           0 :                                   ? handle(generator_->receiver(), isolate_)
     620       11462 :                                   : frame_inspector_->GetReceiver();
     621       34386 :     if (receiver->IsOptimizedOut(isolate_) || receiver->IsTheHole(isolate_)) {
     622             :       receiver = isolate_->factory()->undefined_value();
     623             :     }
     624       11462 :     if (visitor(isolate_->factory()->this_string(), receiver)) return true;
     625             :   }
     626             : 
     627     4492079 :   for (Variable* var : *current_scope_->locals()) {
     628             :     DCHECK(!var->is_this());
     629     4277137 :     if (ScopeInfo::VariableIsSynthetic(*var->name())) continue;
     630             : 
     631             :     int index = var->index();
     632             :     Handle<Object> value;
     633     4160346 :     switch (var->location()) {
     634             :       case VariableLocation::LOOKUP:
     635           0 :         UNREACHABLE();
     636             :         break;
     637             : 
     638             :       case VariableLocation::UNALLOCATED:
     639             :         continue;
     640             : 
     641             :       case VariableLocation::PARAMETER: {
     642       25502 :         if (frame_inspector_ == nullptr) {
     643             :           // Get the variable from the suspended generator.
     644             :           DCHECK(!generator_.is_null());
     645             :           FixedArray parameters_and_registers =
     646             :               generator_->parameters_and_registers();
     647             :           DCHECK_LT(index, parameters_and_registers->length());
     648         127 :           value = handle(parameters_and_registers->get(index), isolate_);
     649             :         } else {
     650       25375 :           value = frame_inspector_->GetParameter(index);
     651             : 
     652       50750 :           if (value->IsOptimizedOut(isolate_)) {
     653             :             value = isolate_->factory()->undefined_value();
     654             :           }
     655             :         }
     656             :         break;
     657             :       }
     658             : 
     659             :       case VariableLocation::LOCAL:
     660     3996891 :         if (frame_inspector_ == nullptr) {
     661             :           // Get the variable from the suspended generator.
     662             :           DCHECK(!generator_.is_null());
     663             :           FixedArray parameters_and_registers =
     664             :               generator_->parameters_and_registers();
     665             :           int parameter_count =
     666         352 :               function_->shared()->scope_info()->ParameterCount();
     667         352 :           index += parameter_count;
     668             :           DCHECK_LT(index, parameters_and_registers->length());
     669         352 :           value = handle(parameters_and_registers->get(index), isolate_);
     670         704 :           if (value->IsTheHole(isolate_)) {
     671             :             value = isolate_->factory()->undefined_value();
     672             :           }
     673             :         } else {
     674     3996539 :           value = frame_inspector_->GetExpression(index);
     675     7993078 :           if (value->IsOptimizedOut(isolate_)) {
     676             :             // We'll rematerialize this later.
     677        2979 :             if (current_scope_->is_declaration_scope() &&
     678         961 :                 current_scope_->AsDeclarationScope()->arguments() == var) {
     679             :               continue;
     680             :             }
     681         987 :             value = isolate_->factory()->undefined_value();
     682     3995530 :           } else if (value->IsTheHole(isolate_)) {
     683             :             // Reflect variables under TDZ as undeclared in scope object.
     684             :             continue;
     685             :           }
     686             :         }
     687             :         break;
     688             : 
     689             :       case VariableLocation::CONTEXT:
     690       49951 :         if (mode == Mode::STACK) continue;
     691             :         DCHECK(var->IsContextSlot());
     692       49083 :         value = handle(context_->get(index), isolate_);
     693             :         // Reflect variables under TDZ as undeclared in scope object.
     694       98166 :         if (value->IsTheHole(isolate_)) continue;
     695             :         break;
     696             : 
     697             :       case VariableLocation::MODULE: {
     698        2084 :         if (mode == Mode::STACK) continue;
     699             :         // if (var->IsExport()) continue;
     700        2169 :         Handle<Module> module(context_->module(), isolate_);
     701         723 :         value = Module::LoadVariable(isolate_, module, var->index());
     702             :         // Reflect variables under TDZ as undeclared in scope object.
     703        1446 :         if (value->IsTheHole(isolate_)) continue;
     704         240 :         break;
     705             :       }
     706             :     }
     707             : 
     708     4071168 :     if (visitor(var->name(), value)) return true;
     709             :   }
     710             :   return false;
     711             : }
     712             : 
     713             : // Retrieve the with-context extension object. If the extension object is
     714             : // a proxy, return an empty object.
     715        2518 : Handle<JSObject> ScopeIterator::WithContextExtension() {
     716             :   DCHECK(context_->IsWithContext());
     717        5036 :   if (context_->extension_receiver()->IsJSProxy()) {
     718           0 :     return isolate_->factory()->NewJSObjectWithNullProto();
     719             :   }
     720        7554 :   return handle(JSObject::cast(context_->extension_receiver()), isolate_);
     721             : }
     722             : 
     723             : // Create a plain JSObject which materializes the block scope for the specified
     724             : // block context.
     725      132759 : void ScopeIterator::VisitLocalScope(const Visitor& visitor, Mode mode) const {
     726      132759 :   if (InInnerScope()) {
     727      109674 :     if (VisitLocals(visitor, mode)) return;
     728      105496 :     if (mode == Mode::STACK && Type() == ScopeTypeLocal) {
     729             :       // Hide |this| in arrow functions that may be embedded in other functions
     730             :       // but don't force |this| to be context-allocated. Otherwise we'd find the
     731             :       // wrong |this| value.
     732       23869 :       if (!closure_scope_->has_this_declaration() &&
     733         619 :           !closure_scope_->HasThisReference()) {
     734         380 :         if (visitor(isolate_->factory()->this_string(),
     735         380 :                     isolate_->factory()->undefined_value()))
     736             :           return;
     737             :       }
     738             :       // Add |arguments| to the function scope even if it wasn't used.
     739             :       // Currently we don't yet support materializing the arguments object of
     740             :       // suspended generators. We'd need to read the arguments out from the
     741             :       // suspended generator rather than from an activation as
     742             :       // FunctionGetArguments does.
     743       34875 :       if (frame_inspector_ != nullptr && !closure_scope_->is_arrow_scope() &&
     744          83 :           (closure_scope_->arguments() == nullptr ||
     745          83 :            frame_inspector_->GetExpression(closure_scope_->arguments()->index())
     746          83 :                ->IsOptimizedOut(isolate_))) {
     747             :         JavaScriptFrame* frame = GetFrame();
     748             :         Handle<JSObject> arguments = Accessors::FunctionGetArguments(
     749       10925 :             frame, frame_inspector_->inlined_frame_index());
     750       21850 :         if (visitor(isolate_->factory()->arguments_string(), arguments)) return;
     751             :       }
     752             :     }
     753             :   } else {
     754             :     DCHECK_EQ(Mode::ALL, mode);
     755       69255 :     Handle<ScopeInfo> scope_info(context_->scope_info(), isolate_);
     756       23085 :     if (VisitContextLocals(visitor, scope_info, context_)) return;
     757             :   }
     758             : 
     759      223547 :   if (mode == Mode::ALL && HasContext()) {
     760             :     DCHECK(!context_->IsScriptContext());
     761             :     DCHECK(!context_->IsNativeContext());
     762             :     DCHECK(!context_->IsWithContext());
     763       23365 :     if (!context_->scope_info()->CallsSloppyEval()) return;
     764       15728 :     if (context_->extension_object().is_null()) return;
     765        1089 :     Handle<JSObject> extension(context_->extension_object(), isolate_);
     766             :     Handle<FixedArray> keys =
     767         726 :         KeyAccumulator::GetKeys(extension, KeyCollectionMode::kOwnOnly,
     768         363 :                                 ENUMERABLE_STRINGS)
     769             :             .ToHandleChecked();
     770             : 
     771        1449 :     for (int i = 0; i < keys->length(); i++) {
     772             :       // Names of variables introduced by eval are strings.
     773             :       DCHECK(keys->get(i)->IsString());
     774         553 :       Handle<String> key(String::cast(keys->get(i)), isolate_);
     775         553 :       Handle<Object> value = JSReceiver::GetDataProperty(extension, key);
     776         563 :       if (visitor(key, value)) return;
     777             :     }
     778             :   }
     779             : }
     780             : 
     781       84013 : bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
     782             :                                           Handle<Object> new_value) {
     783             :   // TODO(verwaest): Walk parameters backwards, not forwards.
     784             :   // TODO(verwaest): Use VariableMap rather than locals() list for lookup.
     785     2455045 :   for (Variable* var : *current_scope_->locals()) {
     786     2360553 :     if (String::Equals(isolate_, var->name(), variable_name)) {
     787             :       int index = var->index();
     788       73534 :       switch (var->location()) {
     789             :         case VariableLocation::LOOKUP:
     790             :         case VariableLocation::UNALLOCATED:
     791             :           // Drop assignments to unallocated locals.
     792             :           DCHECK(var->is_this() ||
     793             :                  *variable_name == ReadOnlyRoots(isolate_).arguments_string());
     794             :           return false;
     795             : 
     796             :         case VariableLocation::PARAMETER: {
     797       12455 :           if (var->is_this()) return false;
     798       12455 :           if (frame_inspector_ == nullptr) {
     799             :             // Set the variable in the suspended generator.
     800             :             DCHECK(!generator_.is_null());
     801             :             Handle<FixedArray> parameters_and_registers(
     802           0 :                 generator_->parameters_and_registers(), isolate_);
     803             :             DCHECK_LT(index, parameters_and_registers->length());
     804           0 :             parameters_and_registers->set(index, *new_value);
     805             :           } else {
     806             :             JavaScriptFrame* frame = GetFrame();
     807       24910 :             if (frame->is_optimized()) return false;
     808             : 
     809        2138 :             frame->SetParameterValue(index, *new_value);
     810             :           }
     811             :           return true;
     812             :         }
     813             : 
     814             :         case VariableLocation::LOCAL:
     815       51189 :           if (frame_inspector_ == nullptr) {
     816             :             // Set the variable in the suspended generator.
     817             :             DCHECK(!generator_.is_null());
     818             :             int parameter_count =
     819          27 :                 function_->shared()->scope_info()->ParameterCount();
     820          27 :             index += parameter_count;
     821             :             Handle<FixedArray> parameters_and_registers(
     822          27 :                 generator_->parameters_and_registers(), isolate_);
     823             :             DCHECK_LT(index, parameters_and_registers->length());
     824          27 :             parameters_and_registers->set(index, *new_value);
     825             :           } else {
     826             :             // Set the variable on the stack.
     827             :             JavaScriptFrame* frame = GetFrame();
     828      102324 :             if (frame->is_optimized()) return false;
     829             : 
     830       44337 :             frame->SetExpression(index, *new_value);
     831             :           }
     832             :           return true;
     833             : 
     834             :         case VariableLocation::CONTEXT:
     835             :           DCHECK(var->IsContextSlot());
     836             :           context_->set(index, *new_value);
     837             :           return true;
     838             : 
     839             :         case VariableLocation::MODULE:
     840          10 :           if (!var->IsExport()) return false;
     841          15 :           Handle<Module> module(context_->module(), isolate_);
     842           5 :           Module::StoreVariable(module, var->index(), new_value);
     843           5 :           return true;
     844             :       }
     845           0 :       UNREACHABLE();
     846             :     }
     847             :   }
     848             : 
     849             :   return false;
     850             : }
     851             : 
     852         930 : bool ScopeIterator::SetContextExtensionValue(Handle<String> variable_name,
     853             :                                              Handle<Object> new_value) {
     854        1860 :   if (!context_->has_extension()) return false;
     855             : 
     856             :   DCHECK(context_->extension_object()->IsJSContextExtensionObject());
     857         126 :   Handle<JSObject> ext(context_->extension_object(), isolate_);
     858          42 :   LookupIterator it(isolate_, ext, variable_name, LookupIterator::OWN);
     859          42 :   Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
     860             :   DCHECK(maybe.IsJust());
     861          42 :   if (!maybe.FromJust()) return false;
     862             : 
     863          20 :   CHECK(Object::SetDataProperty(&it, new_value).ToChecked());
     864             :   return true;
     865             : }
     866             : 
     867          70 : bool ScopeIterator::SetContextVariableValue(Handle<String> variable_name,
     868             :                                             Handle<Object> new_value) {
     869             :   DisallowHeapAllocation no_gc;
     870             :   VariableMode mode;
     871             :   InitializationFlag flag;
     872             :   MaybeAssignedFlag maybe_assigned_flag;
     873             :   int slot_index =
     874         140 :       ScopeInfo::ContextSlotIndex(context_->scope_info(), *variable_name, &mode,
     875          70 :                                   &flag, &maybe_assigned_flag);
     876          70 :   if (slot_index < 0) return false;
     877             : 
     878             :   context_->set(slot_index, *new_value);
     879             :   return true;
     880             : }
     881             : 
     882          15 : bool ScopeIterator::SetModuleVariableValue(Handle<String> variable_name,
     883             :                                            Handle<Object> new_value) {
     884             :   DisallowHeapAllocation no_gc;
     885             :   int cell_index;
     886             :   VariableMode mode;
     887             :   InitializationFlag init_flag;
     888             :   MaybeAssignedFlag maybe_assigned_flag;
     889          30 :   cell_index = context_->scope_info()->ModuleIndex(
     890          15 :       *variable_name, &mode, &init_flag, &maybe_assigned_flag);
     891             : 
     892             :   // Setting imports is currently not supported.
     893          15 :   if (ModuleDescriptor::GetCellIndexKind(cell_index) !=
     894             :       ModuleDescriptor::kExport) {
     895             :     return false;
     896             :   }
     897             : 
     898          15 :   Handle<Module> module(context_->module(), isolate_);
     899           5 :   Module::StoreVariable(module, cell_index, new_value);
     900           5 :   return true;
     901             : }
     902             : 
     903          14 : bool ScopeIterator::SetScriptVariableValue(Handle<String> variable_name,
     904             :                                            Handle<Object> new_value) {
     905             :   Handle<ScriptContextTable> script_contexts(
     906          42 :       context_->global_object()->native_context()->script_context_table(),
     907          28 :       isolate_);
     908             :   ScriptContextTable::LookupResult lookup_result;
     909          14 :   if (ScriptContextTable::Lookup(isolate_, *script_contexts, *variable_name,
     910             :                                  &lookup_result)) {
     911             :     Handle<Context> script_context = ScriptContextTable::GetContext(
     912          14 :         isolate_, script_contexts, lookup_result.context_index);
     913          14 :     script_context->set(lookup_result.slot_index, *new_value);
     914             :     return true;
     915             :   }
     916             : 
     917             :   return false;
     918             : }
     919             : 
     920             : }  // namespace internal
     921      120216 : }  // namespace v8

Generated by: LCOV version 1.10