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