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