LCOV - code coverage report
Current view: top level - src/debug - debug-scopes.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 297 310 95.8 %
Date: 2017-04-26 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/parsing/parse-info.h"
      16             : #include "src/parsing/parsing.h"
      17             : #include "src/parsing/rewriter.h"
      18             : 
      19             : namespace v8 {
      20             : namespace internal {
      21             : 
      22      207565 : ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
      23      324122 :                              ScopeIterator::Option option)
      24             :     : isolate_(isolate),
      25             :       frame_inspector_(frame_inspector),
      26             :       nested_scope_chain_(4),
      27      415130 :       seen_script_scope_(false) {
      28      415130 :   if (!frame_inspector->GetContext()->IsContext()) {
      29             :     // Optimized frame, context or function cannot be materialized. Give up.
      30             :     return;
      31             :   }
      32             : 
      33      207420 :   context_ = Handle<Context>::cast(frame_inspector->GetContext());
      34             : 
      35             :   // We should not instantiate a ScopeIterator for wasm frames.
      36             :   DCHECK(frame_inspector->GetScript()->type() != Script::TYPE_WASM);
      37             : 
      38             :   // Catch the case when the debugger stops in an internal function.
      39             :   Handle<JSFunction> function = GetFunction();
      40             :   Handle<SharedFunctionInfo> shared_info(function->shared());
      41             :   Handle<ScopeInfo> scope_info(shared_info->scope_info());
      42      207420 :   if (shared_info->script()->IsUndefined(isolate)) {
      43           0 :     while (context_->closure() == *function) {
      44           0 :       context_ = Handle<Context>(context_->previous(), isolate_);
      45             :     }
      46             :     return;
      47             :   }
      48             : 
      49             :   // Currently it takes too much time to find nested scopes due to script
      50             :   // parsing. Sometimes we want to run the ScopeIterator as fast as possible
      51             :   // (for example, while collecting async call stacks on every
      52             :   // addEventListener call), even if we drop some nested scopes.
      53             :   // Later we may optimize getting the nested scopes (cache the result?)
      54             :   // and include nested scopes into the "fast" iteration case as well.
      55      207420 :   bool ignore_nested_scopes = (option == IGNORE_NESTED_SCOPES);
      56      207420 :   bool collect_non_locals = (option == COLLECT_NON_LOCALS);
      57      414840 :   if (!ignore_nested_scopes && shared_info->HasDebugInfo()) {
      58             :     // The source position at return is always the end of the function,
      59             :     // which is not consistent with the current scope chain. Therefore all
      60             :     // nested with, catch and block contexts are skipped, and we can only
      61             :     // inspect the function scope.
      62             :     // This can only happen if we set a break point inside right before the
      63             :     // return, which requires a debug info to be available.
      64             :     Handle<DebugInfo> debug_info(shared_info->GetDebugInfo());
      65             : 
      66             :     // Find the break point where execution has stopped.
      67      116702 :     BreakLocation location = BreakLocation::FromFrame(debug_info, GetFrame());
      68             : 
      69      116702 :     ignore_nested_scopes = location.IsReturn();
      70             :   }
      71             : 
      72      207420 :   if (ignore_nested_scopes) {
      73        9364 :     if (scope_info->HasContext()) {
      74         918 :       context_ = Handle<Context>(context_->declaration_context(), isolate_);
      75             :     } else {
      76        9058 :       while (context_->closure() == *function) {
      77           0 :         context_ = Handle<Context>(context_->previous(), isolate_);
      78             :       }
      79             :     }
      80        9364 :     if (scope_info->scope_type() == FUNCTION_SCOPE) {
      81             :       nested_scope_chain_.Add(ExtendedScopeInfo(scope_info,
      82             :                                                 shared_info->start_position(),
      83        6137 :                                                 shared_info->end_position()));
      84             :     }
      85        9364 :     if (!collect_non_locals) return;
      86             :   }
      87             : 
      88             :   // Reparse the code and analyze the scopes.
      89             :   // Check whether we are in global, eval or function code.
      90             :   std::unique_ptr<ParseInfo> info;
      91      198734 :   if (scope_info->scope_type() != FUNCTION_SCOPE) {
      92             :     // Global or eval code.
      93             :     Handle<Script> script(Script::cast(shared_info->script()));
      94       80728 :     info.reset(new ParseInfo(script));
      95       80728 :     if (scope_info->scope_type() == EVAL_SCOPE) {
      96             :       info->set_eval();
      97        5960 :       if (!function->context()->IsNativeContext()) {
      98        2532 :         info->set_outer_scope_info(handle(function->context()->scope_info()));
      99             :       }
     100             :       // Language mode may be inherited from the eval caller.
     101             :       // Retrieve it from shared function info.
     102             :       info->set_language_mode(shared_info->language_mode());
     103       74768 :     } else if (scope_info->scope_type() == MODULE_SCOPE) {
     104             :       info->set_module();
     105             :     } else {
     106             :       DCHECK(scope_info->scope_type() == SCRIPT_SCOPE);
     107             :     }
     108             :   } else {
     109             :     // Inner function.
     110      118006 :     info.reset(new ParseInfo(shared_info));
     111             :   }
     112      394354 :   if (parsing::ParseAny(info.get(), isolate) &&
     113      195620 :       Rewriter::Rewrite(info.get(), isolate)) {
     114      195620 :     DeclarationScope* scope = info->literal()->scope();
     115      195620 :     if (!ignore_nested_scopes || collect_non_locals) {
     116      195620 :       CollectNonLocals(info.get(), scope);
     117             :     }
     118      195620 :     if (!ignore_nested_scopes) {
     119      194942 :       DeclarationScope::Analyze(info.get(), isolate_, AnalyzeMode::kDebugger);
     120      194942 :       RetrieveScopeChain(scope);
     121             :     }
     122             :   } else {
     123             :     // A failed reparse indicates that the preparser has diverged from the
     124             :     // parser or that the preparse data given to the initial parse has been
     125             :     // faulty. We fail in debug mode but in release mode we only provide the
     126             :     // information we get from the context chain but nothing about
     127             :     // completely stack allocated scopes or stack allocated locals.
     128             :     // Or it could be due to stack overflow.
     129             :     // Silently fail by presenting an empty context chain.
     130        3114 :     CHECK(isolate_->has_pending_exception());
     131        3114 :     isolate_->clear_pending_exception();
     132        3114 :     context_ = Handle<Context>();
     133             :   }
     134      198734 :   UnwrapEvaluationContext();
     135             : }
     136             : 
     137          72 : ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
     138             :     : isolate_(isolate),
     139             :       frame_inspector_(NULL),
     140             :       context_(function->context()),
     141         144 :       seen_script_scope_(false) {
     142          72 :   if (!function->shared()->IsSubjectToDebugging()) context_ = Handle<Context>();
     143          72 :   UnwrapEvaluationContext();
     144          72 : }
     145             : 
     146        2272 : ScopeIterator::ScopeIterator(Isolate* isolate,
     147             :                              Handle<JSGeneratorObject> generator)
     148             :     : isolate_(isolate),
     149             :       frame_inspector_(NULL),
     150             :       context_(generator->context()),
     151        4544 :       seen_script_scope_(false) {
     152        2272 :   if (!generator->function()->shared()->IsSubjectToDebugging()) {
     153           0 :     context_ = Handle<Context>();
     154             :   }
     155        2272 :   UnwrapEvaluationContext();
     156        2272 : }
     157             : 
     158      718478 : void ScopeIterator::UnwrapEvaluationContext() {
     159             :   while (true) {
     160      718478 :     if (context_.is_null()) return;
     161      526460 :     if (!context_->IsDebugEvaluateContext()) return;
     162             :     Handle<Object> wrapped(context_->get(Context::WRAPPED_CONTEXT_INDEX),
     163           0 :                            isolate_);
     164           0 :     if (wrapped->IsContext()) {
     165           0 :       context_ = Handle<Context>::cast(wrapped);
     166             :     } else {
     167           0 :       context_ = Handle<Context>(context_->previous(), isolate_);
     168             :     }
     169             :   }
     170             : }
     171             : 
     172             : 
     173      633246 : MUST_USE_RESULT MaybeHandle<JSObject> ScopeIterator::MaterializeScopeDetails() {
     174             :   // Calculate the size of the result.
     175             :   Handle<FixedArray> details =
     176      514336 :       isolate_->factory()->NewFixedArray(kScopeDetailsSize);
     177             :   // Fill in scope details.
     178      514336 :   details->set(kScopeDetailsTypeIndex, Smi::FromInt(Type()));
     179             :   Handle<JSObject> scope_object;
     180     1028672 :   ASSIGN_RETURN_ON_EXCEPTION(isolate_, scope_object, ScopeObject(), JSObject);
     181      514336 :   details->set(kScopeDetailsObjectIndex, *scope_object);
     182      514336 :   Handle<JSFunction> js_function = HasContext()
     183     1352328 :                                        ? handle(CurrentContext()->closure())
     184      609676 :                                        : Handle<JSFunction>::null();
     185      514336 :   if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript) {
     186      377408 :     return isolate_->factory()->NewJSArrayWithElements(details);
     187             :   }
     188             : 
     189             :   int start_position = 0;
     190             :   int end_position = 0;
     191      136928 :   if (!nested_scope_chain_.is_empty()) {
     192             :     js_function = GetFunction();
     193      118910 :     start_position = nested_scope_chain_.last().start_position;
     194      118910 :     end_position = nested_scope_chain_.last().end_position;
     195       18018 :   } else if (!js_function.is_null()) {
     196             :     start_position = js_function->shared()->start_position();
     197             :     end_position = js_function->shared()->end_position();
     198             :   }
     199             : 
     200      136928 :   if (!js_function.is_null()) {
     201      136928 :     Handle<String> closure_name = JSFunction::GetDebugName(js_function);
     202      273856 :     if (!closure_name.is_null() && closure_name->length() != 0) {
     203      117694 :       details->set(kScopeDetailsNameIndex, *closure_name);
     204             :     }
     205             :     details->set(kScopeDetailsStartPositionIndex, Smi::FromInt(start_position));
     206             :     details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position));
     207      136928 :     details->set(kScopeDetailsFunctionIndex, *js_function);
     208             :   }
     209      136928 :   return isolate_->factory()->NewJSArrayWithElements(details);
     210             : }
     211             : 
     212             : 
     213      517400 : void ScopeIterator::Next() {
     214             :   DCHECK(!Done());
     215      517400 :   ScopeType scope_type = Type();
     216      517400 :   if (scope_type == ScopeTypeGlobal) {
     217             :     // The global scope is always the last in the chain.
     218             :     DCHECK(context_->IsNativeContext());
     219      188904 :     context_ = Handle<Context>();
     220      328496 :   } else if (scope_type == ScopeTypeScript) {
     221      189216 :     seen_script_scope_ = true;
     222      189216 :     if (context_->IsScriptContext()) {
     223       25278 :       context_ = Handle<Context>(context_->previous(), isolate_);
     224             :     }
     225      450368 :     if (!nested_scope_chain_.is_empty()) {
     226             :       DCHECK_EQ(nested_scope_chain_.last().scope_info->scope_type(),
     227             :                 SCRIPT_SCOPE);
     228       74061 :       nested_scope_chain_.RemoveLast();
     229             :       DCHECK(nested_scope_chain_.is_empty());
     230             :     }
     231      189216 :     CHECK(context_->IsNativeContext());
     232      139280 :   } else if (nested_scope_chain_.is_empty()) {
     233       38496 :     context_ = Handle<Context>(context_->previous(), isolate_);
     234             :   } else {
     235       10560 :     do {
     236      121872 :       if (nested_scope_chain_.last().scope_info->HasContext()) {
     237             :         DCHECK(context_->previous() != NULL);
     238       48632 :         context_ = Handle<Context>(context_->previous(), isolate_);
     239             :       }
     240      121872 :       nested_scope_chain_.RemoveLast();
     241      121872 :       if (nested_scope_chain_.is_empty()) break;
     242             :       // Repeat to skip hidden scopes.
     243             :     } while (nested_scope_chain_.last().is_hidden());
     244             :   }
     245      517400 :   UnwrapEvaluationContext();
     246      517400 : }
     247             : 
     248             : 
     249             : // Return the type of the current scope.
     250     4216266 : ScopeIterator::ScopeType ScopeIterator::Type() {
     251             :   DCHECK(!Done());
     252     4216266 :   if (!nested_scope_chain_.is_empty()) {
     253     1566116 :     Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info;
     254     1566116 :     switch (scope_info->scope_type()) {
     255             :       case FUNCTION_SCOPE:
     256             :         DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
     257             :         return ScopeTypeLocal;
     258             :       case MODULE_SCOPE:
     259             :         DCHECK(context_->IsModuleContext());
     260        4680 :         return ScopeTypeModule;
     261             :       case SCRIPT_SCOPE:
     262             :         DCHECK(context_->IsScriptContext() || context_->IsNativeContext());
     263      740914 :         return ScopeTypeScript;
     264             :       case WITH_SCOPE:
     265             :         DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext());
     266       30840 :         return ScopeTypeWith;
     267             :       case CATCH_SCOPE:
     268             :         DCHECK(context_->IsCatchContext());
     269       13280 :         return ScopeTypeCatch;
     270             :       case BLOCK_SCOPE:
     271             :         DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
     272       23648 :         return ScopeTypeBlock;
     273             :       case EVAL_SCOPE:
     274             :         DCHECK(!scope_info->HasContext() || context_->IsEvalContext());
     275       35472 :         return ScopeTypeEval;
     276             :     }
     277           0 :     UNREACHABLE();
     278             :   }
     279     2650150 :   if (context_->IsNativeContext()) {
     280             :     DCHECK(context_->global_object()->IsJSGlobalObject());
     281             :     // If we are at the native context and have not yet seen script scope,
     282             :     // fake it.
     283     2365128 :     return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript;
     284             :   }
     285      410094 :   if (context_->IsFunctionContext() || context_->IsEvalContext()) {
     286             :     return ScopeTypeClosure;
     287             :   }
     288      124880 :   if (context_->IsCatchContext()) {
     289             :     return ScopeTypeCatch;
     290             :   }
     291      119348 :   if (context_->IsBlockContext()) {
     292             :     return ScopeTypeBlock;
     293             :   }
     294      117458 :   if (context_->IsModuleContext()) {
     295             :     return ScopeTypeModule;
     296             :   }
     297      112278 :   if (context_->IsScriptContext()) {
     298             :     return ScopeTypeScript;
     299             :   }
     300             :   DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext());
     301        9268 :   return ScopeTypeWith;
     302             : }
     303             : 
     304             : 
     305      514336 : MaybeHandle<JSObject> ScopeIterator::ScopeObject() {
     306             :   DCHECK(!Done());
     307      514336 :   switch (Type()) {
     308             :     case ScopeIterator::ScopeTypeGlobal:
     309      566082 :       return Handle<JSObject>(CurrentContext()->global_proxy());
     310             :     case ScopeIterator::ScopeTypeScript:
     311      188714 :       return MaterializeScriptScope();
     312             :     case ScopeIterator::ScopeTypeLocal:
     313             :       // Materialize the content of the local scope into a JSObject.
     314             :       DCHECK(nested_scope_chain_.length() == 1);
     315      104928 :       return MaterializeLocalScope();
     316             :     case ScopeIterator::ScopeTypeWith:
     317        3842 :       return WithContextExtension();
     318             :     case ScopeIterator::ScopeTypeCatch:
     319        1774 :       return MaterializeCatchScope();
     320             :     case ScopeIterator::ScopeTypeClosure:
     321             :       // Materialize the content of the closure scope into a JSObject.
     322       15916 :       return MaterializeClosure();
     323             :     case ScopeIterator::ScopeTypeBlock:
     324             :     case ScopeIterator::ScopeTypeEval:
     325        9482 :       return MaterializeInnerScope();
     326             :     case ScopeIterator::ScopeTypeModule:
     327         986 :       return MaterializeModuleScope();
     328             :   }
     329           0 :   UNREACHABLE();
     330             :   return Handle<JSObject>();
     331             : }
     332             : 
     333             : 
     334      545518 : bool ScopeIterator::HasContext() {
     335      545518 :   ScopeType type = Type();
     336      545518 :   if (type == ScopeTypeBlock || type == ScopeTypeLocal ||
     337             :       type == ScopeTypeEval) {
     338      145592 :     if (!nested_scope_chain_.is_empty()) {
     339      145410 :       return nested_scope_chain_.last().scope_info->HasContext();
     340             :     }
     341             :   }
     342             :   return true;
     343             : }
     344             : 
     345             : 
     346         376 : bool ScopeIterator::SetVariableValue(Handle<String> variable_name,
     347             :                                      Handle<Object> new_value) {
     348             :   DCHECK(!Done());
     349         376 :   switch (Type()) {
     350             :     case ScopeIterator::ScopeTypeGlobal:
     351             :       break;
     352             :     case ScopeIterator::ScopeTypeLocal:
     353          92 :       return SetLocalVariableValue(variable_name, new_value);
     354             :     case ScopeIterator::ScopeTypeWith:
     355             :       break;
     356             :     case ScopeIterator::ScopeTypeCatch:
     357          20 :       return SetCatchVariableValue(variable_name, new_value);
     358             :     case ScopeIterator::ScopeTypeClosure:
     359         120 :       return SetClosureVariableValue(variable_name, new_value);
     360             :     case ScopeIterator::ScopeTypeScript:
     361          44 :       return SetScriptVariableValue(variable_name, new_value);
     362             :     case ScopeIterator::ScopeTypeBlock:
     363             :     case ScopeIterator::ScopeTypeEval:
     364          44 :       return SetInnerScopeVariableValue(variable_name, new_value);
     365             :     case ScopeIterator::ScopeTypeModule:
     366             :       // TODO(neis): Implement.
     367             :       break;
     368             :   }
     369             :   return false;
     370             : }
     371             : 
     372             : 
     373       17064 : Handle<ScopeInfo> ScopeIterator::CurrentScopeInfo() {
     374             :   DCHECK(!Done());
     375       17064 :   if (!nested_scope_chain_.is_empty()) {
     376       16762 :     return nested_scope_chain_.last().scope_info;
     377         428 :   } else if (context_->IsBlockContext() || context_->IsFunctionContext() ||
     378           6 :              context_->IsEvalContext()) {
     379         604 :     return Handle<ScopeInfo>(context_->scope_info());
     380             :   }
     381             :   return Handle<ScopeInfo>::null();
     382             : }
     383             : 
     384             : 
     385      822508 : Handle<Context> ScopeIterator::CurrentContext() {
     386             :   DCHECK(!Done());
     387      890156 :   if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript ||
     388       67648 :       nested_scope_chain_.is_empty()) {
     389      791050 :     return context_;
     390       31458 :   } else if (nested_scope_chain_.last().scope_info->HasContext()) {
     391       31458 :     return context_;
     392             :   } else {
     393           0 :     return Handle<Context>();
     394             :   }
     395             : }
     396             : 
     397       15266 : Handle<StringSet> ScopeIterator::GetNonLocals() { return non_locals_; }
     398             : 
     399             : #ifdef DEBUG
     400             : // Debug print of the content of the current scope.
     401             : void ScopeIterator::DebugPrint() {
     402             :   OFStream os(stdout);
     403             :   DCHECK(!Done());
     404             :   switch (Type()) {
     405             :     case ScopeIterator::ScopeTypeGlobal:
     406             :       os << "Global:\n";
     407             :       CurrentContext()->Print(os);
     408             :       break;
     409             : 
     410             :     case ScopeIterator::ScopeTypeLocal: {
     411             :       os << "Local:\n";
     412             :       GetFunction()->shared()->scope_info()->Print();
     413             :       if (!CurrentContext().is_null()) {
     414             :         CurrentContext()->Print(os);
     415             :         if (CurrentContext()->has_extension()) {
     416             :           Handle<HeapObject> extension(CurrentContext()->extension(), isolate_);
     417             :           if (extension->IsJSContextExtensionObject()) {
     418             :             extension->Print(os);
     419             :           }
     420             :         }
     421             :       }
     422             :       break;
     423             :     }
     424             : 
     425             :     case ScopeIterator::ScopeTypeWith:
     426             :       os << "With:\n";
     427             :       CurrentContext()->extension()->Print(os);
     428             :       break;
     429             : 
     430             :     case ScopeIterator::ScopeTypeCatch:
     431             :       os << "Catch:\n";
     432             :       CurrentContext()->extension()->Print(os);
     433             :       CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
     434             :       break;
     435             : 
     436             :     case ScopeIterator::ScopeTypeClosure:
     437             :       os << "Closure:\n";
     438             :       CurrentContext()->Print(os);
     439             :       if (CurrentContext()->has_extension()) {
     440             :         Handle<HeapObject> extension(CurrentContext()->extension(), isolate_);
     441             :         if (extension->IsJSContextExtensionObject()) {
     442             :           extension->Print(os);
     443             :         }
     444             :       }
     445             :       break;
     446             : 
     447             :     case ScopeIterator::ScopeTypeScript:
     448             :       os << "Script:\n";
     449             :       CurrentContext()
     450             :           ->global_object()
     451             :           ->native_context()
     452             :           ->script_context_table()
     453             :           ->Print(os);
     454             :       break;
     455             : 
     456             :     default:
     457             :       UNREACHABLE();
     458             :   }
     459             :   PrintF("\n");
     460             : }
     461             : #endif
     462             : 
     463      194942 : void ScopeIterator::RetrieveScopeChain(DeclarationScope* scope) {
     464             :   DCHECK_NOT_NULL(scope);
     465      194942 :   int source_position = frame_inspector_->GetSourcePosition();
     466      194942 :   GetNestedScopeChain(isolate_, scope, source_position);
     467      194942 : }
     468             : 
     469      195620 : void ScopeIterator::CollectNonLocals(ParseInfo* info, DeclarationScope* scope) {
     470             :   DCHECK_NOT_NULL(scope);
     471             :   DCHECK(non_locals_.is_null());
     472      195620 :   non_locals_ = scope->CollectNonLocals(info, StringSet::New(isolate_));
     473      195620 : }
     474             : 
     475             : 
     476      188714 : MaybeHandle<JSObject> ScopeIterator::MaterializeScriptScope() {
     477      566142 :   Handle<JSGlobalObject> global(CurrentContext()->global_object());
     478             :   Handle<ScriptContextTable> script_contexts(
     479             :       global->native_context()->script_context_table());
     480             : 
     481             :   Handle<JSObject> script_scope =
     482      188714 :       isolate_->factory()->NewJSObjectWithNullProto();
     483             : 
     484     1138374 :   for (int context_index = 0; context_index < script_contexts->used();
     485             :        context_index++) {
     486             :     Handle<Context> context =
     487      380473 :         ScriptContextTable::GetContext(script_contexts, context_index);
     488      380473 :     Handle<ScopeInfo> scope_info(context->scope_info());
     489      380473 :     CopyContextLocalsToScopeObject(scope_info, context, script_scope);
     490             :   }
     491      188714 :   return script_scope;
     492             : }
     493             : 
     494             : 
     495      104928 : MaybeHandle<JSObject> ScopeIterator::MaterializeLocalScope() {
     496             :   Handle<JSFunction> function = GetFunction();
     497             : 
     498             :   Handle<JSObject> local_scope =
     499      104928 :       isolate_->factory()->NewJSObjectWithNullProto();
     500      104928 :   frame_inspector_->MaterializeStackLocals(local_scope, function);
     501             : 
     502             :   Handle<Context> frame_context =
     503      104928 :       Handle<Context>::cast(frame_inspector_->GetContext());
     504             : 
     505      104928 :   HandleScope scope(isolate_);
     506             :   Handle<SharedFunctionInfo> shared(function->shared());
     507             :   Handle<ScopeInfo> scope_info(shared->scope_info());
     508             : 
     509      104928 :   if (!scope_info->HasContext()) return local_scope;
     510             : 
     511             :   // Fill all context locals.
     512       18672 :   Handle<Context> function_context(frame_context->closure_context());
     513       18672 :   CopyContextLocalsToScopeObject(scope_info, function_context, local_scope);
     514             : 
     515             :   // Finally copy any properties from the function context extension.
     516             :   // These will be variables introduced by eval.
     517       37344 :   if (function_context->closure() == *function &&
     518       18672 :       !function_context->IsNativeContext()) {
     519             :     CopyContextExtensionToScopeObject(function_context, local_scope,
     520       18672 :                                       KeyCollectionMode::kIncludePrototypes);
     521             :   }
     522             : 
     523             :   return local_scope;
     524             : }
     525             : 
     526             : 
     527             : // Create a plain JSObject which materializes the closure content for the
     528             : // context.
     529       15916 : Handle<JSObject> ScopeIterator::MaterializeClosure() {
     530       15916 :   Handle<Context> context = CurrentContext();
     531             :   DCHECK(context->IsFunctionContext() || context->IsEvalContext());
     532             : 
     533             :   Handle<SharedFunctionInfo> shared(context->closure()->shared());
     534             :   Handle<ScopeInfo> scope_info(shared->scope_info());
     535             : 
     536             :   // Allocate and initialize a JSObject with all the content of this function
     537             :   // closure.
     538             :   Handle<JSObject> closure_scope =
     539       15916 :       isolate_->factory()->NewJSObjectWithNullProto();
     540             : 
     541             :   // Fill all context locals to the context extension.
     542       15916 :   CopyContextLocalsToScopeObject(scope_info, context, closure_scope);
     543             : 
     544             :   // Finally copy any properties from the function context extension. This will
     545             :   // be variables introduced by eval.
     546             :   CopyContextExtensionToScopeObject(context, closure_scope,
     547       15916 :                                     KeyCollectionMode::kOwnOnly);
     548             : 
     549       15916 :   return closure_scope;
     550             : }
     551             : 
     552             : 
     553             : // Create a plain JSObject which materializes the scope for the specified
     554             : // catch context.
     555        1774 : Handle<JSObject> ScopeIterator::MaterializeCatchScope() {
     556        1774 :   Handle<Context> context = CurrentContext();
     557             :   DCHECK(context->IsCatchContext());
     558        1774 :   Handle<String> name(context->catch_name());
     559             :   Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
     560        1774 :                                isolate_);
     561             :   Handle<JSObject> catch_scope =
     562        1774 :       isolate_->factory()->NewJSObjectWithNullProto();
     563             :   JSObject::SetOwnPropertyIgnoreAttributes(catch_scope, name, thrown_object,
     564             :                                            NONE)
     565        3548 :       .Check();
     566        1774 :   return catch_scope;
     567             : }
     568             : 
     569             : // Retrieve the with-context extension object. If the extension object is
     570             : // a proxy, return an empty object.
     571        3842 : Handle<JSObject> ScopeIterator::WithContextExtension() {
     572        3842 :   Handle<Context> context = CurrentContext();
     573             :   DCHECK(context->IsWithContext());
     574        7684 :   if (context->extension_receiver()->IsJSProxy()) {
     575           0 :     return isolate_->factory()->NewJSObjectWithNullProto();
     576             :   }
     577        3842 :   return handle(JSObject::cast(context->extension_receiver()));
     578             : }
     579             : 
     580             : // Create a plain JSObject which materializes the block scope for the specified
     581             : // block context.
     582        9482 : Handle<JSObject> ScopeIterator::MaterializeInnerScope() {
     583             :   Handle<JSObject> inner_scope =
     584        9482 :       isolate_->factory()->NewJSObjectWithNullProto();
     585             : 
     586             :   Handle<Context> context = Handle<Context>::null();
     587        9482 :   if (!nested_scope_chain_.is_empty()) {
     588        9314 :     Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info;
     589        9314 :     frame_inspector_->MaterializeStackLocals(inner_scope, scope_info);
     590        9314 :     if (scope_info->HasContext()) context = CurrentContext();
     591             :   } else {
     592         168 :     context = CurrentContext();
     593             :   }
     594             : 
     595        9482 :   if (!context.is_null()) {
     596             :     // Fill all context locals.
     597         398 :     CopyContextLocalsToScopeObject(CurrentScopeInfo(), context, inner_scope);
     598             :     CopyContextExtensionToScopeObject(context, inner_scope,
     599         398 :                                       KeyCollectionMode::kOwnOnly);
     600             :   }
     601        9482 :   return inner_scope;
     602             : }
     603             : 
     604             : 
     605             : // Create a plain JSObject which materializes the module scope for the specified
     606             : // module context.
     607         986 : MaybeHandle<JSObject> ScopeIterator::MaterializeModuleScope() {
     608         986 :   Handle<Context> context = CurrentContext();
     609             :   DCHECK(context->IsModuleContext());
     610         986 :   Handle<ScopeInfo> scope_info(context->scope_info());
     611             :   Handle<JSObject> module_scope =
     612         986 :       isolate_->factory()->NewJSObjectWithNullProto();
     613         986 :   CopyContextLocalsToScopeObject(scope_info, context, module_scope);
     614         986 :   CopyModuleVarsToScopeObject(scope_info, context, module_scope);
     615         986 :   return module_scope;
     616             : }
     617             : 
     618          92 : bool ScopeIterator::SetParameterValue(Handle<ScopeInfo> scope_info,
     619             :                                       JavaScriptFrame* frame,
     620             :                                       Handle<String> parameter_name,
     621             :                                       Handle<Object> new_value) {
     622             :   // Setting stack locals of optimized frames is not supported.
     623         184 :   if (frame->is_optimized()) return false;
     624          84 :   HandleScope scope(isolate_);
     625         168 :   for (int i = 0; i < scope_info->ParameterCount(); ++i) {
     626          24 :     if (String::Equals(handle(scope_info->ParameterName(i)), parameter_name)) {
     627          12 :       frame->SetParameterValue(i, *new_value);
     628          12 :       return true;
     629             :     }
     630             :   }
     631             :   return false;
     632             : }
     633             : 
     634         136 : bool ScopeIterator::SetStackVariableValue(Handle<ScopeInfo> scope_info,
     635             :                                           Handle<String> variable_name,
     636             :                                           Handle<Object> new_value) {
     637         136 :   if (frame_inspector_ == nullptr) return false;
     638             :   JavaScriptFrame* frame = GetFrame();
     639             :   // Setting stack locals of optimized frames is not supported.
     640         244 :   if (frame->is_optimized()) return false;
     641         114 :   HandleScope scope(isolate_);
     642         288 :   for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
     643         192 :     if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
     644          66 :       frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
     645          66 :       return true;
     646             :     }
     647             :   }
     648             :   return false;
     649             : }
     650             : 
     651         176 : bool ScopeIterator::SetContextVariableValue(Handle<ScopeInfo> scope_info,
     652             :                                             Handle<Context> context,
     653             :                                             Handle<String> variable_name,
     654             :                                             Handle<Object> new_value) {
     655         176 :   HandleScope scope(isolate_);
     656        1088 :   for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
     657         504 :     Handle<String> next_name(scope_info->ContextLocalName(i));
     658         504 :     if (String::Equals(variable_name, next_name)) {
     659             :       VariableMode mode;
     660             :       InitializationFlag init_flag;
     661             :       MaybeAssignedFlag maybe_assigned_flag;
     662             :       int context_index = ScopeInfo::ContextSlotIndex(
     663         136 :           scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag);
     664         136 :       context->set(context_index, *new_value);
     665             :       return true;
     666             :     }
     667             :   }
     668             : 
     669          40 :   if (context->has_extension()) {
     670          12 :     Handle<JSObject> ext(context->extension_object());
     671          12 :     Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
     672             :     DCHECK(maybe.IsJust());
     673          12 :     if (maybe.FromJust()) {
     674             :       // We don't expect this to do anything except replacing property value.
     675             :       JSObject::SetOwnPropertyIgnoreAttributes(ext, variable_name, new_value,
     676             :                                                NONE)
     677          24 :           .Check();
     678          12 :       return true;
     679             :     }
     680             :   }
     681             : 
     682             :   return false;
     683             : }
     684             : 
     685          92 : bool ScopeIterator::SetLocalVariableValue(Handle<String> variable_name,
     686          92 :                                           Handle<Object> new_value) {
     687             :   JavaScriptFrame* frame = GetFrame();
     688          92 :   Handle<ScopeInfo> scope_info(frame->function()->shared()->scope_info());
     689             : 
     690             :   // Parameter might be shadowed in context. Don't stop here.
     691          92 :   bool result = SetParameterValue(scope_info, frame, variable_name, new_value);
     692             : 
     693             :   // Stack locals.
     694          92 :   if (SetStackVariableValue(scope_info, variable_name, new_value)) {
     695             :     return true;
     696             :   }
     697             : 
     698          62 :   if (scope_info->HasContext() &&
     699             :       SetContextVariableValue(scope_info, CurrentContext(), variable_name,
     700          24 :                               new_value)) {
     701             :     return true;
     702             :   }
     703             : 
     704          14 :   return result;
     705             : }
     706             : 
     707          44 : bool ScopeIterator::SetInnerScopeVariableValue(Handle<String> variable_name,
     708             :                                                Handle<Object> new_value) {
     709          44 :   Handle<ScopeInfo> scope_info = CurrentScopeInfo();
     710             :   DCHECK(scope_info->scope_type() == BLOCK_SCOPE ||
     711             :          scope_info->scope_type() == EVAL_SCOPE);
     712             : 
     713             :   // Setting stack locals of optimized frames is not supported.
     714          44 :   if (SetStackVariableValue(scope_info, variable_name, new_value)) {
     715             :     return true;
     716             :   }
     717             : 
     718          64 :   if (HasContext() && SetContextVariableValue(scope_info, CurrentContext(),
     719          32 :                                               variable_name, new_value)) {
     720             :     return true;
     721             :   }
     722             : 
     723           0 :   return false;
     724             : }
     725             : 
     726             : // This method copies structure of MaterializeClosure method above.
     727         120 : bool ScopeIterator::SetClosureVariableValue(Handle<String> variable_name,
     728             :                                             Handle<Object> new_value) {
     729             :   DCHECK(CurrentContext()->IsFunctionContext() ||
     730             :          CurrentContext()->IsEvalContext());
     731             :   return SetContextVariableValue(CurrentScopeInfo(), CurrentContext(),
     732         120 :                                  variable_name, new_value);
     733             : }
     734             : 
     735          44 : bool ScopeIterator::SetScriptVariableValue(Handle<String> variable_name,
     736             :                                            Handle<Object> new_value) {
     737             :   Handle<String> internalized_variable_name =
     738          44 :       isolate_->factory()->InternalizeString(variable_name);
     739          44 :   Handle<Context> context = CurrentContext();
     740             :   Handle<ScriptContextTable> script_contexts(
     741          44 :       context->global_object()->native_context()->script_context_table());
     742             :   ScriptContextTable::LookupResult lookup_result;
     743          44 :   if (ScriptContextTable::Lookup(script_contexts, internalized_variable_name,
     744             :                                  &lookup_result)) {
     745             :     Handle<Context> script_context = ScriptContextTable::GetContext(
     746          44 :         script_contexts, lookup_result.context_index);
     747          88 :     script_context->set(lookup_result.slot_index, *new_value);
     748             :     return true;
     749             :   }
     750             : 
     751             :   return false;
     752             : }
     753             : 
     754          20 : bool ScopeIterator::SetCatchVariableValue(Handle<String> variable_name,
     755             :                                           Handle<Object> new_value) {
     756          20 :   Handle<Context> context = CurrentContext();
     757             :   DCHECK(context->IsCatchContext());
     758          20 :   Handle<String> name(context->catch_name());
     759          20 :   if (!String::Equals(name, variable_name)) {
     760             :     return false;
     761             :   }
     762          20 :   context->set(Context::THROWN_OBJECT_INDEX, *new_value);
     763          20 :   return true;
     764             : }
     765             : 
     766             : 
     767      416445 : void ScopeIterator::CopyContextLocalsToScopeObject(
     768             :     Handle<ScopeInfo> scope_info, Handle<Context> context,
     769             :     Handle<JSObject> scope_object) {
     770             :   Isolate* isolate = scope_info->GetIsolate();
     771      416445 :   int local_count = scope_info->ContextLocalCount();
     772      832890 :   if (local_count == 0) return;
     773             :   // Fill all context locals to the context extension.
     774     1059489 :   for (int i = 0; i < local_count; ++i) {
     775     1059489 :     Handle<String> name(scope_info->ContextLocalName(i));
     776     1059489 :     if (ScopeInfo::VariableIsSynthetic(*name)) continue;
     777      796541 :     int context_index = Context::MIN_CONTEXT_SLOTS + i;
     778             :     Handle<Object> value = Handle<Object>(context->get(context_index), isolate);
     779             :     // Reflect variables under TDZ as undefined in scope object.
     780      796541 :     if (value->IsTheHole(isolate)) continue;
     781             :     // This should always succeed.
     782             :     // TODO(verwaest): Use AddDataProperty instead.
     783             :     JSObject::SetOwnPropertyIgnoreAttributes(scope_object, name, value, NONE)
     784     1586662 :         .Check();
     785             :   }
     786             : }
     787             : 
     788         986 : void ScopeIterator::CopyModuleVarsToScopeObject(Handle<ScopeInfo> scope_info,
     789             :                                                 Handle<Context> context,
     790             :                                                 Handle<JSObject> scope_object) {
     791             :   Isolate* isolate = scope_info->GetIsolate();
     792             : 
     793             :   int module_variable_count =
     794             :       Smi::cast(scope_info->get(scope_info->ModuleVariableCountIndex()))
     795         986 :           ->value();
     796        1178 :   for (int i = 0; i < module_variable_count; ++i) {
     797             :     Handle<String> local_name;
     798             :     Handle<Object> value;
     799             :     {
     800             :       String* name;
     801             :       int index;
     802         192 :       scope_info->ModuleVariable(i, &name, &index);
     803         192 :       CHECK(!ScopeInfo::VariableIsSynthetic(name));
     804         192 :       local_name = handle(name, isolate);
     805         576 :       value = Module::LoadVariable(handle(context->module(), isolate), index);
     806             :     }
     807             : 
     808             :     // Reflect variables under TDZ as undefined in scope object.
     809         192 :     if (value->IsTheHole(isolate)) continue;
     810             :     // This should always succeed.
     811             :     // TODO(verwaest): Use AddDataProperty instead.
     812             :     JSObject::SetOwnPropertyIgnoreAttributes(scope_object, local_name, value,
     813             :                                              NONE)
     814         328 :         .Check();
     815             :   }
     816         986 : }
     817             : 
     818       34986 : void ScopeIterator::CopyContextExtensionToScopeObject(
     819             :     Handle<Context> context, Handle<JSObject> scope_object,
     820             :     KeyCollectionMode mode) {
     821       69972 :   if (context->extension_object() == nullptr) return;
     822         500 :   Handle<JSObject> extension(context->extension_object());
     823             :   Handle<FixedArray> keys =
     824             :       KeyAccumulator::GetKeys(extension, mode, ENUMERABLE_STRINGS)
     825        1000 :           .ToHandleChecked();
     826             : 
     827        2504 :   for (int i = 0; i < keys->length(); i++) {
     828             :     // Names of variables introduced by eval are strings.
     829             :     DCHECK(keys->get(i)->IsString());
     830             :     Handle<String> key(String::cast(keys->get(i)));
     831             :     Handle<Object> value =
     832        1504 :         Object::GetPropertyOrElement(extension, key).ToHandleChecked();
     833             :     JSObject::SetOwnPropertyIgnoreAttributes(scope_object, key, value, NONE)
     834        1504 :         .Check();
     835             :   }
     836             : }
     837             : 
     838      728859 : void ScopeIterator::GetNestedScopeChain(Isolate* isolate, Scope* scope,
     839             :                                         int position) {
     840      205560 :   if (scope->is_function_scope()) {
     841             :     // Do not collect scopes of nested inner functions inside the current one.
     842             :     // Nested arrow functions could have the same end positions.
     843      114291 :     Handle<JSFunction> function = frame_inspector_->GetFunction();
     844      114325 :     if (scope->start_position() > function->shared()->start_position() &&
     845             :         scope->end_position() <= function->shared()->end_position()) {
     846             :       return;
     847             :     }
     848             :   }
     849      205526 :   if (scope->is_hidden()) {
     850             :     // We need to add this chain element in case the scope has a context
     851             :     // associated. We need to keep the scope chain and context chain in sync.
     852        2078 :     nested_scope_chain_.Add(ExtendedScopeInfo(scope->scope_info()));
     853             :   } else {
     854             :     nested_scope_chain_.Add(ExtendedScopeInfo(
     855      203448 :         scope->scope_info(), scope->start_position(), scope->end_position()));
     856             :   }
     857      629572 :   for (Scope* inner_scope = scope->inner_scope(); inner_scope != nullptr;
     858             :        inner_scope = inner_scope->sibling()) {
     859             :     int beg_pos = inner_scope->start_position();
     860             :     int end_pos = inner_scope->end_position();
     861             :     DCHECK((beg_pos >= 0 && end_pos >= 0) || inner_scope->is_hidden());
     862      434664 :     if (beg_pos <= position && position < end_pos) {
     863       10618 :       GetNestedScopeChain(isolate, inner_scope, position);
     864       10618 :       return;
     865             :     }
     866             :   }
     867             : }
     868             : 
     869             : }  // namespace internal
     870             : }  // namespace v8

Generated by: LCOV version 1.10