LCOV - code coverage report
Current view: top level - js/src/vm - EnvironmentObject.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 384 1753 21.9 %
Date: 2017-07-14 16:53:18 Functions: 45 176 25.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "vm/EnvironmentObject-inl.h"
       8             : 
       9             : #include "mozilla/PodOperations.h"
      10             : #include "mozilla/ScopeExit.h"
      11             : #include "mozilla/SizePrintfMacros.h"
      12             : 
      13             : #include "jscompartment.h"
      14             : #include "jsiter.h"
      15             : 
      16             : #include "builtin/ModuleObject.h"
      17             : #include "gc/Policy.h"
      18             : #include "vm/ArgumentsObject.h"
      19             : #include "vm/AsyncFunction.h"
      20             : #include "vm/GlobalObject.h"
      21             : #include "vm/ProxyObject.h"
      22             : #include "vm/Shape.h"
      23             : #include "vm/Xdr.h"
      24             : #include "wasm/WasmInstance.h"
      25             : 
      26             : #include "jsatominlines.h"
      27             : #include "jsobjinlines.h"
      28             : #include "jsscriptinlines.h"
      29             : 
      30             : #include "vm/NativeObject-inl.h"
      31             : #include "vm/Stack-inl.h"
      32             : 
      33             : using namespace js;
      34             : using namespace js::gc;
      35             : 
      36             : using mozilla::PodZero;
      37             : using mozilla::Maybe;
      38             : using mozilla::Some;
      39             : using mozilla::Nothing;
      40             : using mozilla::MakeScopeExit;
      41             : 
      42             : typedef Rooted<ArgumentsObject*> RootedArgumentsObject;
      43             : typedef MutableHandle<ArgumentsObject*> MutableHandleArgumentsObject;
      44             : 
      45             : 
      46             : /*****************************************************************************/
      47             : 
      48             : Shape*
      49        1654 : js::EnvironmentCoordinateToEnvironmentShape(JSScript* script, jsbytecode* pc)
      50             : {
      51        1654 :     MOZ_ASSERT(JOF_OPTYPE(JSOp(*pc)) == JOF_ENVCOORD);
      52        1654 :     ScopeIter si(script->innermostScope(pc));
      53        1654 :     uint32_t hops = EnvironmentCoordinate(pc).hops();
      54        2407 :     while (true) {
      55        4061 :         MOZ_ASSERT(!si.done());
      56        4061 :         if (si.hasSyntacticEnvironment()) {
      57        1949 :             if (!hops)
      58        1654 :                 break;
      59         295 :             hops--;
      60             :         }
      61        2407 :         si++;
      62             :     }
      63        1654 :     return si.environmentShape();
      64             : }
      65             : 
      66             : static const uint32_t ENV_COORDINATE_NAME_THRESHOLD = 20;
      67             : 
      68             : void
      69          11 : EnvironmentCoordinateNameCache::purge()
      70             : {
      71          11 :     shape = nullptr;
      72          11 :     if (map.initialized())
      73           0 :         map.finish();
      74          11 : }
      75             : 
      76             : PropertyName*
      77           4 : js::EnvironmentCoordinateName(EnvironmentCoordinateNameCache& cache, JSScript* script,
      78             :                               jsbytecode* pc)
      79             : {
      80           4 :     Shape* shape = EnvironmentCoordinateToEnvironmentShape(script, pc);
      81           4 :     if (shape != cache.shape && shape->slot() >= ENV_COORDINATE_NAME_THRESHOLD) {
      82           0 :         cache.purge();
      83           0 :         if (cache.map.init(shape->slot())) {
      84           0 :             cache.shape = shape;
      85           0 :             Shape::Range<NoGC> r(shape);
      86           0 :             while (!r.empty()) {
      87           0 :                 if (!cache.map.putNew(r.front().slot(), r.front().propid())) {
      88           0 :                     cache.purge();
      89           0 :                     break;
      90             :                 }
      91           0 :                 r.popFront();
      92             :             }
      93             :         }
      94             :     }
      95             : 
      96             :     jsid id;
      97           4 :     EnvironmentCoordinate ec(pc);
      98           4 :     if (shape == cache.shape) {
      99           0 :         EnvironmentCoordinateNameCache::Map::Ptr p = cache.map.lookup(ec.slot());
     100           0 :         id = p->value();
     101             :     } else {
     102           4 :         Shape::Range<NoGC> r(shape);
     103          32 :         while (r.front().slot() != ec.slot())
     104          14 :             r.popFront();
     105           4 :         id = r.front().propidRaw();
     106             :     }
     107             : 
     108             :     /* Beware nameless destructuring formal. */
     109           4 :     if (!JSID_IS_ATOM(id))
     110           0 :         return script->runtimeFromAnyThread()->commonNames->empty;
     111           4 :     return JSID_TO_ATOM(id)->asPropertyName();
     112             : }
     113             : 
     114             : JSScript*
     115         846 : js::EnvironmentCoordinateFunctionScript(JSScript* script, jsbytecode* pc)
     116             : {
     117         846 :     MOZ_ASSERT(JOF_OPTYPE(JSOp(*pc)) == JOF_ENVCOORD);
     118         846 :     ScopeIter si(script->innermostScope(pc));
     119         846 :     uint32_t hops = EnvironmentCoordinate(pc).hops();
     120             :     while (true) {
     121        3166 :         if (si.hasSyntacticEnvironment()) {
     122         856 :             if (!hops)
     123         846 :                 break;
     124          10 :             hops--;
     125             :         }
     126        1160 :         si++;
     127             :     }
     128         846 :     if (si.kind() != ScopeKind::Function)
     129          97 :         return nullptr;
     130         749 :     return si.scope()->as<FunctionScope>().script();
     131             : }
     132             : 
     133             : /*****************************************************************************/
     134             : 
     135             : CallObject*
     136           0 : CallObject::create(JSContext* cx, HandleShape shape, HandleObjectGroup group)
     137             : {
     138           0 :     MOZ_ASSERT(!group->singleton(),
     139             :                "passed a singleton group to create() (use createSingleton() "
     140             :                "instead)");
     141             : 
     142           0 :     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     143           0 :     MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
     144           0 :     kind = gc::GetBackgroundAllocKind(kind);
     145             : 
     146             :     JSObject* obj;
     147           0 :     JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, gc::DefaultHeap, shape, group));
     148             : 
     149           0 :     return &obj->as<CallObject>();
     150             : }
     151             : 
     152             : CallObject*
     153           0 : CallObject::createSingleton(JSContext* cx, HandleShape shape)
     154             : {
     155           0 :     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     156           0 :     MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
     157           0 :     kind = gc::GetBackgroundAllocKind(kind);
     158             : 
     159           0 :     RootedObjectGroup group(cx, ObjectGroup::lazySingletonGroup(cx, &class_, TaggedProto(nullptr)));
     160           0 :     if (!group)
     161           0 :         return nullptr;
     162             : 
     163             :     JSObject* obj;
     164           0 :     JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, gc::TenuredHeap, shape, group));
     165             : 
     166           0 :     MOZ_ASSERT(obj->isSingleton(),
     167             :                "group created inline above must be a singleton");
     168             : 
     169           0 :     return &obj->as<CallObject>();
     170             : }
     171             : 
     172             : /*
     173             :  * Create a CallObject for a JSScript that is not initialized to any particular
     174             :  * callsite. This object can either be initialized (with an enclosing scope and
     175             :  * callee) or used as a template for jit compilation.
     176             :  */
     177             : CallObject*
     178        4318 : CallObject::createTemplateObject(JSContext* cx, HandleScript script, HandleObject enclosing,
     179             :                                  gc::InitialHeap heap)
     180             : {
     181        8636 :     Rooted<FunctionScope*> scope(cx, &script->bodyScope()->as<FunctionScope>());
     182        8636 :     RootedShape shape(cx, scope->environmentShape());
     183        4318 :     MOZ_ASSERT(shape->getObjectClass() == &class_);
     184             : 
     185        8636 :     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
     186        4318 :     if (!group)
     187           0 :         return nullptr;
     188             : 
     189        4318 :     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     190        4318 :     MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_));
     191        4318 :     kind = gc::GetBackgroundAllocKind(kind);
     192             : 
     193             :     JSObject* obj;
     194        4318 :     JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, heap, shape, group));
     195             : 
     196        4318 :     CallObject* callObj = &obj->as<CallObject>();
     197        4318 :     callObj->initEnclosingEnvironment(enclosing);
     198             : 
     199        4318 :     if (scope->hasParameterExprs()) {
     200             :         // If there are parameter expressions, all parameters are lexical and
     201             :         // have TDZ.
     202        1088 :         for (BindingIter bi(script->bodyScope()); bi; bi++) {
     203         873 :             BindingLocation loc = bi.location();
     204         873 :             if (loc.kind() == BindingLocation::Kind::Environment && BindingKindIsLexical(bi.kind()))
     205         347 :                 callObj->initSlot(loc.slot(), MagicValue(JS_UNINITIALIZED_LEXICAL));
     206             :         }
     207             :     }
     208             : 
     209        4318 :     return callObj;
     210             : }
     211             : 
     212             : /*
     213             :  * Construct a call object for the given bindings.  If this is a call object
     214             :  * for a function invocation, callee should be the function being called.
     215             :  * Otherwise it must be a call object for eval of strict mode code, and callee
     216             :  * must be null.
     217             :  */
     218             : CallObject*
     219        4253 : CallObject::create(JSContext* cx, HandleFunction callee, HandleObject enclosing)
     220             : {
     221        8506 :     RootedScript script(cx, callee->nonLazyScript());
     222        4253 :     gc::InitialHeap heap = script->treatAsRunOnce() ? gc::TenuredHeap : gc::DefaultHeap;
     223        4253 :     CallObject* callobj = CallObject::createTemplateObject(cx, script, enclosing, heap);
     224        4253 :     if (!callobj)
     225           0 :         return nullptr;
     226             : 
     227        4253 :     callobj->initFixedSlot(CALLEE_SLOT, ObjectValue(*callee));
     228             : 
     229        4253 :     if (script->treatAsRunOnce()) {
     230           6 :         Rooted<CallObject*> ncallobj(cx, callobj);
     231           3 :         if (!JSObject::setSingleton(cx, ncallobj))
     232           0 :             return nullptr;
     233           3 :         return ncallobj;
     234             :     }
     235             : 
     236        4250 :     return callobj;
     237             : }
     238             : 
     239             : CallObject*
     240        4253 : CallObject::create(JSContext* cx, AbstractFramePtr frame)
     241             : {
     242        4253 :     MOZ_ASSERT(frame.isFunctionFrame());
     243        4253 :     assertSameCompartment(cx, frame);
     244             : 
     245        8506 :     RootedObject envChain(cx, frame.environmentChain());
     246        8506 :     RootedFunction callee(cx, frame.callee());
     247             : 
     248        4253 :     CallObject* callobj = create(cx, callee, envChain);
     249        4253 :     if (!callobj)
     250           0 :         return nullptr;
     251             : 
     252        4253 :     if (!frame.script()->bodyScope()->as<FunctionScope>().hasParameterExprs()) {
     253             :         // If there are no defaults, copy the aliased arguments into the call
     254             :         // object manually. If there are defaults, bytecode is generated to do
     255             :         // the copying.
     256             : 
     257       17378 :         for (PositionalFormalParameterIter fi(frame.script()); fi; fi++) {
     258       13332 :             if (!fi.closedOver())
     259        3806 :                 continue;
     260       19052 :             callobj->setAliasedBinding(cx, fi, frame.unaliasedFormal(fi.argumentSlot(),
     261       19052 :                                                                      DONT_CHECK_ALIASING));
     262             :         }
     263             :     }
     264             : 
     265        4253 :     return callobj;
     266             : }
     267             : 
     268             : CallObject*
     269           0 : CallObject::createHollowForDebug(JSContext* cx, HandleFunction callee)
     270             : {
     271           0 :     MOZ_ASSERT(!callee->needsCallObject());
     272             : 
     273           0 :     RootedScript script(cx, callee->nonLazyScript());
     274           0 :     Rooted<FunctionScope*> scope(cx, &script->bodyScope()->as<FunctionScope>());
     275           0 :     RootedShape shape(cx, FunctionScope::getEmptyEnvironmentShape(cx, scope->hasParameterExprs()));
     276           0 :     if (!shape)
     277           0 :         return nullptr;
     278           0 :     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
     279           0 :     if (!group)
     280           0 :         return nullptr;
     281           0 :     Rooted<CallObject*> callobj(cx, create(cx, shape, group));
     282           0 :     if (!callobj)
     283           0 :         return nullptr;
     284             : 
     285             :     // This environment's enclosing link is never used: the
     286             :     // DebugEnvironmentProxy that refers to this scope carries its own
     287             :     // enclosing link, which is what Debugger uses to construct the tree of
     288             :     // Debugger.Environment objects.
     289           0 :     callobj->initEnclosingEnvironment(&cx->global()->lexicalEnvironment());
     290           0 :     callobj->initFixedSlot(CALLEE_SLOT, ObjectValue(*callee));
     291             : 
     292           0 :     RootedValue optimizedOut(cx, MagicValue(JS_OPTIMIZED_OUT));
     293           0 :     RootedId id(cx);
     294           0 :     for (Rooted<BindingIter> bi(cx, BindingIter(script)); bi; bi++) {
     295           0 :         id = NameToId(bi.name()->asPropertyName());
     296           0 :         if (!SetProperty(cx, callobj, id, optimizedOut))
     297           0 :             return nullptr;
     298             :     }
     299             : 
     300           0 :     return callobj;
     301             : }
     302             : 
     303             : const Class CallObject::class_ = {
     304             :     "Call",
     305             :     JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS)
     306             : };
     307             : 
     308             : /*****************************************************************************/
     309             : 
     310             : /* static */ VarEnvironmentObject*
     311          41 : VarEnvironmentObject::create(JSContext* cx, HandleShape shape, HandleObject enclosing,
     312             :                              gc::InitialHeap heap)
     313             : {
     314          41 :     MOZ_ASSERT(shape->getObjectClass() == &class_);
     315             : 
     316          82 :     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
     317          41 :     if (!group)
     318           0 :         return nullptr;
     319             : 
     320          41 :     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     321          41 :     MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_));
     322          41 :     kind = gc::GetBackgroundAllocKind(kind);
     323             : 
     324             :     JSObject* obj;
     325          41 :     JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, heap, shape, group));
     326             : 
     327          41 :     VarEnvironmentObject* env = &obj->as<VarEnvironmentObject>();
     328          41 :     MOZ_ASSERT(!env->inDictionaryMode());
     329          41 :     MOZ_ASSERT(env->isDelegate());
     330             : 
     331          41 :     env->initEnclosingEnvironment(enclosing);
     332             : 
     333          41 :     return env;
     334             : }
     335             : 
     336             : /* static */ VarEnvironmentObject*
     337          41 : VarEnvironmentObject::create(JSContext* cx, HandleScope scope, AbstractFramePtr frame)
     338             : {
     339             : #ifdef DEBUG
     340          41 :     if (frame.isEvalFrame()) {
     341           2 :         MOZ_ASSERT(scope->is<EvalScope>() && scope == frame.script()->bodyScope());
     342           2 :         MOZ_ASSERT_IF(frame.isInterpreterFrame(),
     343             :                       cx->interpreterFrame() == frame.asInterpreterFrame());
     344           2 :         MOZ_ASSERT_IF(frame.isInterpreterFrame(),
     345             :                       cx->interpreterRegs().pc == frame.script()->code());
     346             :     } else {
     347          39 :         MOZ_ASSERT(frame.environmentChain());
     348          39 :         MOZ_ASSERT_IF(frame.callee()->needsCallObject(),
     349             :                       &frame.environmentChain()->as<CallObject>().callee() == frame.callee());
     350             :     }
     351             : #endif
     352             : 
     353          82 :     RootedScript script(cx, frame.script());
     354          82 :     RootedObject envChain(cx, frame.environmentChain());
     355          41 :     gc::InitialHeap heap = script->treatAsRunOnce() ? gc::TenuredHeap : gc::DefaultHeap;
     356          82 :     RootedShape shape(cx, scope->environmentShape());
     357          41 :     VarEnvironmentObject* env = create(cx, shape, envChain, heap);
     358          41 :     if (!env)
     359           0 :         return nullptr;
     360          41 :     env->initScope(scope);
     361          41 :     return env;
     362             : }
     363             : 
     364             : /* static */ VarEnvironmentObject*
     365           0 : VarEnvironmentObject::createHollowForDebug(JSContext* cx, Handle<VarScope*> scope)
     366             : {
     367           0 :     MOZ_ASSERT(!scope->hasEnvironment());
     368             : 
     369           0 :     RootedShape shape(cx, VarScope::getEmptyEnvironmentShape(cx));
     370           0 :     if (!shape)
     371           0 :         return nullptr;
     372             : 
     373             :     // This environment's enclosing link is never used: the
     374             :     // DebugEnvironmentProxy that refers to this scope carries its own
     375             :     // enclosing link, which is what Debugger uses to construct the tree of
     376             :     // Debugger.Environment objects.
     377           0 :     RootedObject enclosingEnv(cx, &cx->global()->lexicalEnvironment());
     378           0 :     Rooted<VarEnvironmentObject*> env(cx, create(cx, shape, enclosingEnv, gc::TenuredHeap));
     379           0 :     if (!env)
     380           0 :         return nullptr;
     381             : 
     382           0 :     RootedValue optimizedOut(cx, MagicValue(JS_OPTIMIZED_OUT));
     383           0 :     RootedId id(cx);
     384           0 :     for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
     385           0 :         id = NameToId(bi.name()->asPropertyName());
     386           0 :         if (!SetProperty(cx, env, id, optimizedOut))
     387           0 :             return nullptr;
     388             :     }
     389             : 
     390           0 :     env->initScope(scope);
     391           0 :     return env;
     392             : }
     393             : 
     394             : const Class VarEnvironmentObject::class_ = {
     395             :     "Var",
     396             :     JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(VarEnvironmentObject::RESERVED_SLOTS)
     397             : };
     398             : 
     399             : /*****************************************************************************/
     400             : 
     401             : const ObjectOps ModuleEnvironmentObject::objectOps_ = {
     402             :     ModuleEnvironmentObject::lookupProperty,
     403             :     nullptr,                                             /* defineProperty */
     404             :     ModuleEnvironmentObject::hasProperty,
     405             :     ModuleEnvironmentObject::getProperty,
     406             :     ModuleEnvironmentObject::setProperty,
     407             :     ModuleEnvironmentObject::getOwnPropertyDescriptor,
     408             :     ModuleEnvironmentObject::deleteProperty,
     409             :     nullptr, nullptr,                                    /* watch/unwatch */
     410             :     nullptr,                                             /* getElements */
     411             :     nullptr
     412             : };
     413             : 
     414             : const ClassOps ModuleEnvironmentObject::classOps_ = {
     415             :     nullptr,    /* addProperty */
     416             :     nullptr,    /* delProperty */
     417             :     nullptr,    /* getProperty */
     418             :     nullptr,    /* setProperty */
     419             :     nullptr,    /* enumerate */
     420             :     ModuleEnvironmentObject::newEnumerate
     421             : };
     422             : 
     423             : const Class ModuleEnvironmentObject::class_ = {
     424             :     "ModuleEnvironmentObject",
     425             :     JSCLASS_HAS_RESERVED_SLOTS(ModuleEnvironmentObject::RESERVED_SLOTS) |
     426             :     JSCLASS_IS_ANONYMOUS,
     427             :     &ModuleEnvironmentObject::classOps_,
     428             :     JS_NULL_CLASS_SPEC,
     429             :     JS_NULL_CLASS_EXT,
     430             :     &ModuleEnvironmentObject::objectOps_
     431             : };
     432             : 
     433             : /* static */ ModuleEnvironmentObject*
     434           0 : ModuleEnvironmentObject::create(JSContext* cx, HandleModuleObject module)
     435             : {
     436           0 :     RootedScript script(cx, module->script());
     437           0 :     RootedShape shape(cx, script->bodyScope()->as<ModuleScope>().environmentShape());
     438           0 :     MOZ_ASSERT(shape->getObjectClass() == &class_);
     439             : 
     440           0 :     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
     441           0 :     if (!group)
     442           0 :         return nullptr;
     443             : 
     444           0 :     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     445           0 :     MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_));
     446           0 :     kind = gc::GetBackgroundAllocKind(kind);
     447             : 
     448             :     JSObject* obj;
     449           0 :     JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, TenuredHeap, shape, group));
     450             : 
     451           0 :     RootedModuleEnvironmentObject env(cx, &obj->as<ModuleEnvironmentObject>());
     452             : 
     453           0 :     env->initReservedSlot(MODULE_SLOT, ObjectValue(*module));
     454           0 :     if (!JSObject::setSingleton(cx, env))
     455           0 :         return nullptr;
     456             : 
     457             :     // Initialize this early so that we can manipulate the env object without
     458             :     // causing assertions.
     459           0 :     env->initEnclosingEnvironment(&cx->global()->lexicalEnvironment());
     460             : 
     461             :     // Initialize all lexical bindings and imports as uninitialized. Imports
     462             :     // get uninitialized because they have a special TDZ for cyclic imports.
     463           0 :     for (BindingIter bi(script); bi; bi++) {
     464           0 :         BindingLocation loc = bi.location();
     465           0 :         if (loc.kind() == BindingLocation::Kind::Environment && BindingKindIsLexical(bi.kind()))
     466           0 :             env->initSlot(loc.slot(), MagicValue(JS_UNINITIALIZED_LEXICAL));
     467             :     }
     468             : 
     469             :     // It is not be possible to add or remove bindings from a module environment
     470             :     // after this point as module code is always strict.
     471             : #ifdef DEBUG
     472           0 :     for (Shape::Range<NoGC> r(env->lastProperty()); !r.empty(); r.popFront())
     473           0 :         MOZ_ASSERT(!r.front().configurable());
     474           0 :     MOZ_ASSERT(env->lastProperty()->getObjectFlags() & BaseShape::NOT_EXTENSIBLE);
     475           0 :     MOZ_ASSERT(!env->inDictionaryMode());
     476             : #endif
     477             : 
     478           0 :     return env;
     479             : }
     480             : 
     481             : ModuleObject&
     482           0 : ModuleEnvironmentObject::module()
     483             : {
     484           0 :     return getReservedSlot(MODULE_SLOT).toObject().as<ModuleObject>();
     485             : }
     486             : 
     487             : IndirectBindingMap&
     488           0 : ModuleEnvironmentObject::importBindings()
     489             : {
     490           0 :     return module().importBindings();
     491             : }
     492             : 
     493             : bool
     494           0 : ModuleEnvironmentObject::createImportBinding(JSContext* cx, HandleAtom importName,
     495             :                                              HandleModuleObject module, HandleAtom localName)
     496             : {
     497           0 :     RootedId importNameId(cx, AtomToId(importName));
     498           0 :     RootedId localNameId(cx, AtomToId(localName));
     499           0 :     RootedModuleEnvironmentObject env(cx, &module->initialEnvironment());
     500           0 :     if (!importBindings().putNew(cx, importNameId, env, localNameId)) {
     501           0 :         ReportOutOfMemory(cx);
     502           0 :         return false;
     503             :     }
     504             : 
     505           0 :     return true;
     506             : }
     507             : 
     508             : bool
     509           0 : ModuleEnvironmentObject::hasImportBinding(HandlePropertyName name)
     510             : {
     511           0 :     return importBindings().has(NameToId(name));
     512             : }
     513             : 
     514             : bool
     515           0 : ModuleEnvironmentObject::lookupImport(jsid name, ModuleEnvironmentObject** envOut, Shape** shapeOut)
     516             : {
     517           0 :     return importBindings().lookup(name, envOut, shapeOut);
     518             : }
     519             : 
     520             : void
     521           0 : ModuleEnvironmentObject::fixEnclosingEnvironmentAfterCompartmentMerge(GlobalObject& global)
     522             : {
     523           0 :     setEnclosingEnvironment(&global.lexicalEnvironment());
     524           0 : }
     525             : 
     526             : /* static */ bool
     527           0 : ModuleEnvironmentObject::lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
     528             :                                         MutableHandleObject objp, MutableHandle<PropertyResult> propp)
     529             : {
     530           0 :     const IndirectBindingMap& bindings = obj->as<ModuleEnvironmentObject>().importBindings();
     531             :     Shape* shape;
     532             :     ModuleEnvironmentObject* env;
     533           0 :     if (bindings.lookup(id, &env, &shape)) {
     534           0 :         objp.set(env);
     535           0 :         propp.setNativeProperty(shape);
     536           0 :         return true;
     537             :     }
     538             : 
     539           0 :     RootedNativeObject target(cx, &obj->as<NativeObject>());
     540           0 :     if (!NativeLookupOwnProperty<CanGC>(cx, target, id, propp))
     541           0 :         return false;
     542             : 
     543           0 :     objp.set(obj);
     544           0 :     return true;
     545             : }
     546             : 
     547             : /* static */ bool
     548           0 : ModuleEnvironmentObject::hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
     549             : {
     550           0 :     if (obj->as<ModuleEnvironmentObject>().importBindings().has(id)) {
     551           0 :         *foundp = true;
     552           0 :         return true;
     553             :     }
     554             : 
     555           0 :     RootedNativeObject self(cx, &obj->as<NativeObject>());
     556           0 :     return NativeHasProperty(cx, self, id, foundp);
     557             : }
     558             : 
     559             : /* static */ bool
     560           0 : ModuleEnvironmentObject::getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
     561             :                                      HandleId id, MutableHandleValue vp)
     562             : {
     563           0 :     const IndirectBindingMap& bindings = obj->as<ModuleEnvironmentObject>().importBindings();
     564             :     Shape* shape;
     565             :     ModuleEnvironmentObject* env;
     566           0 :     if (bindings.lookup(id, &env, &shape)) {
     567           0 :         vp.set(env->getSlot(shape->slot()));
     568           0 :         return true;
     569             :     }
     570             : 
     571           0 :     RootedNativeObject self(cx, &obj->as<NativeObject>());
     572           0 :     return NativeGetProperty(cx, self, receiver, id, vp);
     573             : }
     574             : 
     575             : /* static */ bool
     576           0 : ModuleEnvironmentObject::setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
     577             :                                      HandleValue receiver, JS::ObjectOpResult& result)
     578             : {
     579           0 :     RootedModuleEnvironmentObject self(cx, &obj->as<ModuleEnvironmentObject>());
     580           0 :     if (self->importBindings().has(id))
     581           0 :         return result.failReadOnly();
     582             : 
     583           0 :     return NativeSetProperty(cx, self, id, v, receiver, Qualified, result);
     584             : }
     585             : 
     586             : /* static */ bool
     587           0 : ModuleEnvironmentObject::getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
     588             :                                                   MutableHandle<PropertyDescriptor> desc)
     589             : {
     590           0 :     const IndirectBindingMap& bindings = obj->as<ModuleEnvironmentObject>().importBindings();
     591             :     Shape* shape;
     592             :     ModuleEnvironmentObject* env;
     593           0 :     if (bindings.lookup(id, &env, &shape)) {
     594           0 :         desc.setAttributes(JSPROP_ENUMERATE | JSPROP_PERMANENT);
     595           0 :         desc.object().set(obj);
     596           0 :         RootedValue value(cx, env->getSlot(shape->slot()));
     597           0 :         desc.setValue(value);
     598           0 :         desc.assertComplete();
     599           0 :         return true;
     600             :     }
     601             : 
     602           0 :     RootedNativeObject self(cx, &obj->as<NativeObject>());
     603           0 :     return NativeGetOwnPropertyDescriptor(cx, self, id, desc);
     604             : }
     605             : 
     606             : /* static */ bool
     607           0 : ModuleEnvironmentObject::deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
     608             :                                         ObjectOpResult& result)
     609             : {
     610           0 :     return result.failCantDelete();
     611             : }
     612             : 
     613             : /* static */ bool
     614           0 : ModuleEnvironmentObject::newEnumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
     615             :                                       bool enumerableOnly)
     616             : {
     617           0 :     RootedModuleEnvironmentObject self(cx, &obj->as<ModuleEnvironmentObject>());
     618           0 :     const IndirectBindingMap& bs(self->importBindings());
     619             : 
     620           0 :     MOZ_ASSERT(properties.length() == 0);
     621           0 :     size_t count = bs.count() + self->slotSpan() - RESERVED_SLOTS;
     622           0 :     if (!properties.reserve(count)) {
     623           0 :         ReportOutOfMemory(cx);
     624           0 :         return false;
     625             :     }
     626             : 
     627           0 :     bs.forEachExportedName([&] (jsid name) {
     628           0 :         properties.infallibleAppend(name);
     629           0 :     });
     630             : 
     631           0 :     for (Shape::Range<NoGC> r(self->lastProperty()); !r.empty(); r.popFront())
     632           0 :         properties.infallibleAppend(r.front().propid());
     633             : 
     634           0 :     MOZ_ASSERT(properties.length() == count);
     635           0 :     return true;
     636             : }
     637             : 
     638             : /*****************************************************************************/
     639             : 
     640             : const Class WasmFunctionCallObject::class_ = {
     641             :     "WasmCall",
     642             :     JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(WasmFunctionCallObject::RESERVED_SLOTS)
     643             : };
     644             : 
     645             : /* static */ WasmFunctionCallObject*
     646           0 : WasmFunctionCallObject::createHollowForDebug(JSContext* cx, Handle<WasmFunctionScope*> scope)
     647             : {
     648           0 :     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
     649           0 :     if (!group)
     650           0 :         return nullptr;
     651             : 
     652           0 :     RootedShape shape(cx, scope->getEmptyEnvironmentShape(cx));
     653           0 :     if (!shape)
     654           0 :         return nullptr;
     655             : 
     656           0 :     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     657           0 :     MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_));
     658           0 :     kind = gc::GetBackgroundAllocKind(kind);
     659             : 
     660             :     JSObject* obj;
     661           0 :     JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, gc::DefaultHeap, shape, group));
     662             : 
     663           0 :     Rooted<WasmFunctionCallObject*> callobj(cx, &obj->as<WasmFunctionCallObject>());
     664           0 :     callobj->initEnclosingEnvironment(&cx->global()->lexicalEnvironment());
     665           0 :     callobj->initReservedSlot(SCOPE_SLOT, PrivateGCThingValue(scope));
     666             : 
     667           0 :     return callobj;
     668             : }
     669             : 
     670             : /*****************************************************************************/
     671             : 
     672             : WithEnvironmentObject*
     673        1591 : WithEnvironmentObject::create(JSContext* cx, HandleObject object, HandleObject enclosing,
     674             :                               Handle<WithScope*> scope)
     675             : {
     676        3182 :     Rooted<WithEnvironmentObject*> obj(cx);
     677        3182 :     obj = NewObjectWithNullTaggedProto<WithEnvironmentObject>(cx, GenericObject,
     678        1591 :                                                               BaseShape::DELEGATE);
     679        1591 :     if (!obj)
     680           0 :         return nullptr;
     681             : 
     682        1591 :     Value thisv = GetThisValue(object);
     683             : 
     684        1591 :     obj->initEnclosingEnvironment(enclosing);
     685        1591 :     obj->initReservedSlot(OBJECT_SLOT, ObjectValue(*object));
     686        1591 :     obj->initReservedSlot(THIS_SLOT, thisv);
     687        1591 :     if (scope)
     688           0 :         obj->initReservedSlot(SCOPE_SLOT, PrivateGCThingValue(scope));
     689             :     else
     690        1591 :         obj->initReservedSlot(SCOPE_SLOT, NullValue());
     691             : 
     692        1591 :     return obj;
     693             : }
     694             : 
     695             : WithEnvironmentObject*
     696        1591 : WithEnvironmentObject::createNonSyntactic(JSContext* cx, HandleObject object,
     697             :                                           HandleObject enclosing)
     698             : {
     699        1591 :     return create(cx, object, enclosing, nullptr);
     700             : }
     701             : 
     702             : static inline bool
     703        2987 : IsUnscopableDotName(JSContext* cx, HandleId id)
     704             : {
     705        2987 :     return JSID_IS_ATOM(id, cx->names().dotThis) || JSID_IS_ATOM(id, cx->names().dotGenerator);
     706             : }
     707             : 
     708             : /* Implements ES6 8.1.1.2.1 HasBinding steps 7-9. */
     709             : static bool
     710        1029 : CheckUnscopables(JSContext *cx, HandleObject obj, HandleId id, bool *scopable)
     711             : {
     712        3087 :     RootedId unscopablesId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols()
     713        3087 :                                                 .get(JS::SymbolCode::unscopables)));
     714        2058 :     RootedValue v(cx);
     715        1029 :     if (!GetProperty(cx, obj, obj, unscopablesId, &v))
     716           0 :         return false;
     717        1029 :     if (v.isObject()) {
     718           0 :         RootedObject unscopablesObj(cx, &v.toObject());
     719           0 :         if (!GetProperty(cx, unscopablesObj, unscopablesObj, id, &v))
     720           0 :             return false;
     721           0 :         *scopable = !ToBoolean(v);
     722             :     } else {
     723        1029 :         *scopable = true;
     724             :     }
     725        1029 :     return true;
     726             : }
     727             : 
     728             : static bool
     729        2733 : with_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
     730             :                     MutableHandleObject objp, MutableHandle<PropertyResult> propp)
     731             : {
     732             :     // SpiderMonkey-specific: consider internal '.generator' and '.this' names
     733             :     // to be unscopable.
     734        2733 :     if (IsUnscopableDotName(cx, id)) {
     735           0 :         objp.set(nullptr);
     736           0 :         propp.setNotFound();
     737           0 :         return true;
     738             :     }
     739             : 
     740        5466 :     RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
     741        2733 :     if (!LookupProperty(cx, actual, id, objp, propp))
     742           0 :         return false;
     743             : 
     744        2733 :     if (propp) {
     745             :         bool scopable;
     746        1029 :         if (!CheckUnscopables(cx, actual, id, &scopable))
     747           0 :             return false;
     748        1029 :         if (!scopable) {
     749           0 :             objp.set(nullptr);
     750           0 :             propp.setNotFound();
     751             :         }
     752             :     }
     753        2733 :     return true;
     754             : }
     755             : 
     756             : static bool
     757          52 : with_DefineProperty(JSContext* cx, HandleObject obj, HandleId id, Handle<PropertyDescriptor> desc,
     758             :                     ObjectOpResult& result)
     759             : {
     760          52 :     MOZ_ASSERT(!IsUnscopableDotName(cx, id));
     761         104 :     RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
     762         104 :     return DefineProperty(cx, actual, id, desc, result);
     763             : }
     764             : 
     765             : static bool
     766           0 : with_HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
     767             : {
     768           0 :     MOZ_ASSERT(!IsUnscopableDotName(cx, id));
     769           0 :     RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
     770             : 
     771             :     // ES 8.1.1.2.1 step 3-5.
     772           0 :     if (!HasProperty(cx, actual, id, foundp))
     773           0 :         return false;
     774           0 :     if (!*foundp)
     775           0 :         return true;
     776             : 
     777             :     // Steps 7-10. (Step 6 is a no-op.)
     778           0 :     return CheckUnscopables(cx, actual, id, foundp);
     779             : }
     780             : 
     781             : static bool
     782           0 : with_GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
     783             :                  MutableHandleValue vp)
     784             : {
     785           0 :     MOZ_ASSERT(!IsUnscopableDotName(cx, id));
     786           0 :     RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
     787           0 :     RootedValue actualReceiver(cx, receiver);
     788           0 :     if (receiver.isObject() && &receiver.toObject() == obj)
     789           0 :         actualReceiver.setObject(*actual);
     790           0 :     return GetProperty(cx, actual, actualReceiver, id, vp);
     791             : }
     792             : 
     793             : static bool
     794          20 : with_SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
     795             :                  HandleValue receiver, ObjectOpResult& result)
     796             : {
     797          20 :     MOZ_ASSERT(!IsUnscopableDotName(cx, id));
     798          40 :     RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
     799          40 :     RootedValue actualReceiver(cx, receiver);
     800          20 :     if (receiver.isObject() && &receiver.toObject() == obj)
     801          20 :         actualReceiver.setObject(*actual);
     802          40 :     return SetProperty(cx, actual, id, v, actualReceiver, result);
     803             : }
     804             : 
     805             : static bool
     806         182 : with_GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
     807             :                               MutableHandle<PropertyDescriptor> desc)
     808             : {
     809         182 :     MOZ_ASSERT(!IsUnscopableDotName(cx, id));
     810         364 :     RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
     811         364 :     return GetOwnPropertyDescriptor(cx, actual, id, desc);
     812             : }
     813             : 
     814             : static bool
     815           0 : with_DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
     816             : {
     817           0 :     MOZ_ASSERT(!IsUnscopableDotName(cx, id));
     818           0 :     RootedObject actual(cx, &obj->as<WithEnvironmentObject>().object());
     819           0 :     return DeleteProperty(cx, actual, id, result);
     820             : }
     821             : 
     822             : static const ObjectOps WithEnvironmentObjectOps = {
     823             :     with_LookupProperty,
     824             :     with_DefineProperty,
     825             :     with_HasProperty,
     826             :     with_GetProperty,
     827             :     with_SetProperty,
     828             :     with_GetOwnPropertyDescriptor,
     829             :     with_DeleteProperty,
     830             :     nullptr, nullptr,    /* watch/unwatch */
     831             :     nullptr,             /* getElements */
     832             :     nullptr,
     833             : };
     834             : 
     835             : const Class WithEnvironmentObject::class_ = {
     836             :     "With",
     837             :     JSCLASS_HAS_RESERVED_SLOTS(WithEnvironmentObject::RESERVED_SLOTS) |
     838             :     JSCLASS_IS_ANONYMOUS,
     839             :     JS_NULL_CLASS_OPS,
     840             :     JS_NULL_CLASS_SPEC,
     841             :     JS_NULL_CLASS_EXT,
     842             :     &WithEnvironmentObjectOps
     843             : };
     844             : 
     845             : /* static */ NonSyntacticVariablesObject*
     846          43 : NonSyntacticVariablesObject::create(JSContext* cx)
     847             : {
     848             :     Rooted<NonSyntacticVariablesObject*> obj(cx,
     849          86 :         NewObjectWithNullTaggedProto<NonSyntacticVariablesObject>(cx, TenuredObject,
     850          86 :                                                                   BaseShape::DELEGATE));
     851          43 :     if (!obj)
     852           0 :         return nullptr;
     853             : 
     854          43 :     MOZ_ASSERT(obj->isUnqualifiedVarObj());
     855          43 :     if (!JSObject::setQualifiedVarObj(cx, obj))
     856           0 :         return nullptr;
     857             : 
     858          43 :     obj->initEnclosingEnvironment(&cx->global()->lexicalEnvironment());
     859          43 :     return obj;
     860             : }
     861             : 
     862             : const Class NonSyntacticVariablesObject::class_ = {
     863             :     "NonSyntacticVariablesObject",
     864             :     JSCLASS_HAS_RESERVED_SLOTS(NonSyntacticVariablesObject::RESERVED_SLOTS) |
     865             :     JSCLASS_IS_ANONYMOUS
     866             : };
     867             : 
     868             : /*****************************************************************************/
     869             : 
     870             : /* static */ LexicalEnvironmentObject*
     871        2508 : LexicalEnvironmentObject::createTemplateObject(JSContext* cx, HandleShape shape,
     872             :                                                HandleObject enclosing, gc::InitialHeap heap)
     873             : {
     874        2508 :     MOZ_ASSERT(shape->getObjectClass() == &LexicalEnvironmentObject::class_);
     875             : 
     876             :     RootedObjectGroup group(cx,
     877        5016 :         ObjectGroup::defaultNewGroup(cx, &LexicalEnvironmentObject::class_, TaggedProto(nullptr)));
     878        2508 :     if (!group)
     879           0 :         return nullptr;
     880             : 
     881        2508 :     gc::AllocKind allocKind = gc::GetGCObjectKind(shape->numFixedSlots());
     882        2508 :     MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, &LexicalEnvironmentObject::class_));
     883        2508 :     allocKind = GetBackgroundAllocKind(allocKind);
     884             : 
     885             :     JSObject* obj;
     886        2508 :     JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, allocKind, heap, shape, group));
     887             : 
     888        2508 :     LexicalEnvironmentObject* env = &obj->as<LexicalEnvironmentObject>();
     889        2508 :     MOZ_ASSERT(!env->inDictionaryMode());
     890        2508 :     MOZ_ASSERT(env->isDelegate());
     891             : 
     892        2508 :     if (enclosing)
     893        2508 :         env->initEnclosingEnvironment(enclosing);
     894             : 
     895        2508 :     return env;
     896             : }
     897             : 
     898             : /* static */ LexicalEnvironmentObject*
     899        2089 : LexicalEnvironmentObject::create(JSContext* cx, Handle<LexicalScope*> scope,
     900             :                                  HandleObject enclosing, gc::InitialHeap heap)
     901             : {
     902        2089 :     assertSameCompartment(cx, enclosing);
     903        2089 :     MOZ_ASSERT(scope->hasEnvironment());
     904             : 
     905        4178 :     RootedShape shape(cx, scope->environmentShape());
     906        2089 :     LexicalEnvironmentObject* env = createTemplateObject(cx, shape, enclosing, heap);
     907        2089 :     if (!env)
     908           0 :         return nullptr;
     909             : 
     910             :     // All lexical bindings start off uninitialized for TDZ.
     911        2089 :     uint32_t lastSlot = shape->slot();
     912        2089 :     MOZ_ASSERT(lastSlot == env->lastProperty()->slot());
     913        4721 :     for (uint32_t slot = JSSLOT_FREE(&class_); slot <= lastSlot; slot++)
     914        2632 :         env->initSlot(slot, MagicValue(JS_UNINITIALIZED_LEXICAL));
     915             : 
     916        2089 :     env->initScopeUnchecked(scope);
     917        2089 :     return env;
     918             : }
     919             : 
     920             : /* static */ LexicalEnvironmentObject*
     921        1468 : LexicalEnvironmentObject::create(JSContext* cx, Handle<LexicalScope*> scope,
     922             :                                  AbstractFramePtr frame)
     923             : {
     924        2936 :     RootedObject enclosing(cx, frame.environmentChain());
     925        2936 :     return create(cx, scope, enclosing, gc::DefaultHeap);
     926             : }
     927             : 
     928             : /* static */ LexicalEnvironmentObject*
     929         311 : LexicalEnvironmentObject::createGlobal(JSContext* cx, Handle<GlobalObject*> global)
     930             : {
     931         311 :     MOZ_ASSERT(global);
     932             : 
     933         622 :     RootedShape shape(cx, LexicalScope::getEmptyExtensibleEnvironmentShape(cx));
     934         311 :     if (!shape)
     935           0 :         return nullptr;
     936             : 
     937             :     Rooted<LexicalEnvironmentObject*> env(cx,
     938         622 :         LexicalEnvironmentObject::createTemplateObject(cx, shape, global, gc::TenuredHeap));
     939         311 :     if (!env)
     940           0 :         return nullptr;
     941             : 
     942         311 :     if (!JSObject::setSingleton(cx, env))
     943           0 :         return nullptr;
     944             : 
     945         311 :     env->initThisValue(global);
     946         311 :     return env;
     947             : }
     948             : 
     949             : /* static */ LexicalEnvironmentObject*
     950         108 : LexicalEnvironmentObject::createNonSyntactic(JSContext* cx, HandleObject enclosing)
     951             : {
     952         108 :     MOZ_ASSERT(enclosing);
     953         108 :     MOZ_ASSERT(!IsSyntacticEnvironment(enclosing));
     954             : 
     955         216 :     RootedShape shape(cx, LexicalScope::getEmptyExtensibleEnvironmentShape(cx));
     956         108 :     if (!shape)
     957           0 :         return nullptr;
     958             : 
     959             :     LexicalEnvironmentObject* env =
     960         108 :         LexicalEnvironmentObject::createTemplateObject(cx, shape, enclosing, gc::TenuredHeap);
     961         108 :     if (!env)
     962           0 :         return nullptr;
     963             : 
     964         108 :     env->initThisValue(enclosing);
     965         108 :     return env;
     966             : }
     967             : 
     968             : /* static */ LexicalEnvironmentObject*
     969           0 : LexicalEnvironmentObject::createHollowForDebug(JSContext* cx, Handle<LexicalScope*> scope)
     970             : {
     971           0 :     MOZ_ASSERT(!scope->hasEnvironment());
     972             : 
     973           0 :     RootedShape shape(cx, LexicalScope::getEmptyExtensibleEnvironmentShape(cx));
     974           0 :     if (!shape)
     975           0 :         return nullptr;
     976             : 
     977             :     // This environment's enclosing link is never used: the
     978             :     // DebugEnvironmentProxy that refers to this scope carries its own
     979             :     // enclosing link, which is what Debugger uses to construct the tree of
     980             :     // Debugger.Environment objects.
     981           0 :     RootedObject enclosingEnv(cx, &cx->global()->lexicalEnvironment());
     982           0 :     Rooted<LexicalEnvironmentObject*> env(cx, createTemplateObject(cx, shape, enclosingEnv,
     983           0 :                                                                    gc::TenuredHeap));
     984           0 :     if (!env)
     985           0 :         return nullptr;
     986             : 
     987           0 :     RootedValue optimizedOut(cx, MagicValue(JS_OPTIMIZED_OUT));
     988           0 :     RootedId id(cx);
     989           0 :     for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
     990           0 :         id = NameToId(bi.name()->asPropertyName());
     991           0 :         if (!SetProperty(cx, env, id, optimizedOut))
     992           0 :             return nullptr;
     993             :     }
     994             : 
     995           0 :     if (!JSObject::setFlags(cx, env, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE))
     996           0 :         return nullptr;
     997             : 
     998           0 :     env->initScopeUnchecked(scope);
     999           0 :     return env;
    1000             : }
    1001             : 
    1002             : /* static */ LexicalEnvironmentObject*
    1003           0 : LexicalEnvironmentObject::clone(JSContext* cx, Handle<LexicalEnvironmentObject*> env)
    1004             : {
    1005           0 :     Rooted<LexicalScope*> scope(cx, &env->scope());
    1006           0 :     RootedObject enclosing(cx, &env->enclosingEnvironment());
    1007           0 :     Rooted<LexicalEnvironmentObject*> copy(cx, create(cx, scope, enclosing, gc::TenuredHeap));
    1008           0 :     if (!copy)
    1009           0 :         return nullptr;
    1010             : 
    1011             :     // We can't assert that the clone has the same shape, because it could
    1012             :     // have been reshaped by PurgeEnvironmentChain.
    1013           0 :     MOZ_ASSERT(env->slotSpan() == copy->slotSpan());
    1014           0 :     for (uint32_t i = JSSLOT_FREE(&class_); i < copy->slotSpan(); i++)
    1015           0 :         copy->setSlot(i, env->getSlot(i));
    1016             : 
    1017           0 :     return copy;
    1018             : }
    1019             : 
    1020             : /* static */ LexicalEnvironmentObject*
    1021         619 : LexicalEnvironmentObject::recreate(JSContext* cx, Handle<LexicalEnvironmentObject*> env)
    1022             : {
    1023        1238 :     Rooted<LexicalScope*> scope(cx, &env->scope());
    1024        1238 :     RootedObject enclosing(cx, &env->enclosingEnvironment());
    1025        1238 :     return create(cx, scope, enclosing, gc::TenuredHeap);
    1026             : }
    1027             : 
    1028             : bool
    1029       34097 : LexicalEnvironmentObject::isExtensible() const
    1030             : {
    1031       34097 :     return nonProxyIsExtensible();
    1032             : }
    1033             : 
    1034             : Value
    1035        1787 : LexicalEnvironmentObject::thisValue() const
    1036             : {
    1037        1787 :     MOZ_ASSERT(isExtensible());
    1038        1787 :     Value v = getReservedSlot(THIS_VALUE_OR_SCOPE_SLOT);
    1039        1787 :     if (v.isObject()) {
    1040             :         // If `v` is a Window, return the WindowProxy instead. We called
    1041             :         // GetThisValue (which also does ToWindowProxyIfWindow) when storing
    1042             :         // the value in THIS_VALUE_OR_SCOPE_SLOT, but it's possible the
    1043             :         // WindowProxy was attached to the global *after* we set
    1044             :         // THIS_VALUE_OR_SCOPE_SLOT.
    1045        1787 :         return ObjectValue(*ToWindowProxyIfWindow(&v.toObject()));
    1046             :     }
    1047           0 :     return v;
    1048             : }
    1049             : 
    1050             : const Class LexicalEnvironmentObject::class_ = {
    1051             :     "LexicalEnvironment",
    1052             :     JSCLASS_HAS_RESERVED_SLOTS(LexicalEnvironmentObject::RESERVED_SLOTS) |
    1053             :     JSCLASS_IS_ANONYMOUS,
    1054             :     JS_NULL_CLASS_OPS,
    1055             :     JS_NULL_CLASS_SPEC,
    1056             :     JS_NULL_CLASS_EXT,
    1057             :     JS_NULL_OBJECT_OPS
    1058             : };
    1059             : 
    1060             : /* static */ NamedLambdaObject*
    1061           2 : NamedLambdaObject::create(JSContext* cx, HandleFunction callee,
    1062             :                           HandleFunction func,
    1063             :                           HandleObject enclosing,
    1064             :                           gc::InitialHeap heap)
    1065             : {
    1066           2 :     MOZ_ASSERT(callee->isNamedLambda());
    1067           4 :     RootedScope scope(cx, callee->nonLazyScript()->maybeNamedLambdaScope());
    1068           2 :     MOZ_ASSERT(scope && scope->environmentShape());
    1069           2 :     MOZ_ASSERT(scope->environmentShape()->slot() == lambdaSlot());
    1070           2 :     MOZ_ASSERT(!scope->environmentShape()->writable());
    1071             : 
    1072             : #ifdef DEBUG
    1073             :     // There should be exactly one binding in the named lambda scope.
    1074           2 :     BindingIter bi(scope);
    1075           2 :     bi++;
    1076           2 :     MOZ_ASSERT(bi.done());
    1077             : #endif
    1078             : 
    1079             :     LexicalEnvironmentObject* obj =
    1080           2 :         LexicalEnvironmentObject::create(cx, scope.as<LexicalScope>(), enclosing, heap);
    1081           2 :     if (!obj)
    1082           0 :         return nullptr;
    1083             : 
    1084           2 :     obj->initFixedSlot(lambdaSlot(), ObjectValue(*func));
    1085           2 :     return static_cast<NamedLambdaObject*>(obj);
    1086             : }
    1087             : 
    1088             : /* static */ NamedLambdaObject*
    1089           0 : NamedLambdaObject::createTemplateObject(JSContext* cx, HandleFunction callee, gc::InitialHeap heap)
    1090             : {
    1091           0 :     return create(cx, callee, callee, nullptr, heap);
    1092             : }
    1093             : 
    1094             : /* static */ NamedLambdaObject*
    1095           0 : NamedLambdaObject::create(JSContext* cx, AbstractFramePtr frame)
    1096             : {
    1097           0 :     RootedFunction fun(cx, frame.callee());
    1098           0 :     RootedObject enclosing(cx, frame.environmentChain());
    1099           0 :     return create(cx, fun, fun, enclosing, gc::DefaultHeap);
    1100             : }
    1101             : 
    1102             : /* static */ NamedLambdaObject*
    1103           2 : NamedLambdaObject::create(JSContext* cx, AbstractFramePtr frame, HandleFunction replacement)
    1104             : {
    1105           4 :     RootedFunction fun(cx, frame.callee());
    1106           4 :     RootedObject enclosing(cx, frame.environmentChain());
    1107           4 :     return create(cx, fun, replacement, enclosing, gc::DefaultHeap);
    1108             : }
    1109             : 
    1110             : /* static */ size_t
    1111           4 : NamedLambdaObject::lambdaSlot()
    1112             : {
    1113             :     // Named lambda environments have exactly one name.
    1114           4 :     return JSSLOT_FREE(&LexicalEnvironmentObject::class_);
    1115             : }
    1116             : 
    1117             : /* static */ RuntimeLexicalErrorObject*
    1118           0 : RuntimeLexicalErrorObject::create(JSContext* cx, HandleObject enclosing, unsigned errorNumber)
    1119             : {
    1120             :     RuntimeLexicalErrorObject* obj =
    1121             :         NewObjectWithNullTaggedProto<RuntimeLexicalErrorObject>(cx, GenericObject,
    1122           0 :                                                                 BaseShape::DELEGATE);
    1123           0 :     if (!obj)
    1124           0 :         return nullptr;
    1125           0 :     obj->initEnclosingEnvironment(enclosing);
    1126           0 :     obj->initReservedSlot(ERROR_SLOT, Int32Value(int32_t(errorNumber)));
    1127           0 :     return obj;
    1128             : }
    1129             : 
    1130             : static void
    1131           0 : ReportRuntimeLexicalErrorId(JSContext* cx, unsigned errorNumber, HandleId id)
    1132             : {
    1133           0 :     if (JSID_IS_ATOM(id)) {
    1134           0 :         RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
    1135           0 :         ReportRuntimeLexicalError(cx, errorNumber, name);
    1136           0 :         return;
    1137             :     }
    1138           0 :     MOZ_CRASH("RuntimeLexicalErrorObject should only be used with property names");
    1139             : }
    1140             : 
    1141             : static bool
    1142           0 : lexicalError_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
    1143             :                             MutableHandleObject objp, MutableHandle<PropertyResult> propp)
    1144             : {
    1145           0 :     ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
    1146           0 :     return false;
    1147             : }
    1148             : 
    1149             : static bool
    1150           0 : lexicalError_HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
    1151             : {
    1152           0 :     ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
    1153           0 :     return false;
    1154             : }
    1155             : 
    1156             : static bool
    1157           0 : lexicalError_GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
    1158             :                          MutableHandleValue vp)
    1159             : {
    1160           0 :     ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
    1161           0 :     return false;
    1162             : }
    1163             : 
    1164             : static bool
    1165           0 : lexicalError_SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
    1166             :                          HandleValue receiver, ObjectOpResult& result)
    1167             : {
    1168           0 :     ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
    1169           0 :     return false;
    1170             : }
    1171             : 
    1172             : static bool
    1173           0 : lexicalError_GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
    1174             :                                       MutableHandle<PropertyDescriptor> desc)
    1175             : {
    1176           0 :     ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
    1177           0 :     return false;
    1178             : }
    1179             : 
    1180             : static bool
    1181           0 : lexicalError_DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
    1182             : {
    1183           0 :     ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
    1184           0 :     return false;
    1185             : }
    1186             : 
    1187             : static const ObjectOps RuntimeLexicalErrorObjectObjectOps = {
    1188             :     lexicalError_LookupProperty,
    1189             :     nullptr,             /* defineProperty */
    1190             :     lexicalError_HasProperty,
    1191             :     lexicalError_GetProperty,
    1192             :     lexicalError_SetProperty,
    1193             :     lexicalError_GetOwnPropertyDescriptor,
    1194             :     lexicalError_DeleteProperty,
    1195             :     nullptr, nullptr,    /* watch/unwatch */
    1196             :     nullptr,             /* getElements */
    1197             :     nullptr,             /* this */
    1198             : };
    1199             : 
    1200             : const Class RuntimeLexicalErrorObject::class_ = {
    1201             :     "RuntimeLexicalError",
    1202             :     JSCLASS_HAS_RESERVED_SLOTS(RuntimeLexicalErrorObject::RESERVED_SLOTS) |
    1203             :     JSCLASS_IS_ANONYMOUS,
    1204             :     JS_NULL_CLASS_OPS,
    1205             :     JS_NULL_CLASS_SPEC,
    1206             :     JS_NULL_CLASS_EXT,
    1207             :     &RuntimeLexicalErrorObjectObjectOps
    1208             : };
    1209             : 
    1210             : /*****************************************************************************/
    1211             : 
    1212           0 : EnvironmentIter::EnvironmentIter(JSContext* cx, const EnvironmentIter& ei
    1213           0 :                                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
    1214             :   : si_(cx, ei.si_.get()),
    1215             :     env_(cx, ei.env_),
    1216           0 :     frame_(ei.frame_)
    1217             : {
    1218           0 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    1219           0 : }
    1220             : 
    1221          34 : EnvironmentIter::EnvironmentIter(JSContext* cx, JSObject* env, Scope* scope
    1222          34 :                                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
    1223          68 :   : si_(cx, ScopeIter(scope)),
    1224             :     env_(cx, env),
    1225          68 :     frame_(NullFramePtr())
    1226             : {
    1227          34 :     settle();
    1228          34 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    1229          34 : }
    1230             : 
    1231       14296 : EnvironmentIter::EnvironmentIter(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc
    1232       14296 :                                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
    1233       28592 :   : si_(cx, frame.script()->innermostScope(pc)),
    1234       28592 :     env_(cx, frame.environmentChain()),
    1235       42888 :     frame_(frame)
    1236             : {
    1237       14296 :     assertSameCompartment(cx, frame);
    1238       14296 :     settle();
    1239       14296 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    1240       14296 : }
    1241             : 
    1242           0 : EnvironmentIter::EnvironmentIter(JSContext* cx, JSObject* env, Scope* scope, AbstractFramePtr frame
    1243           0 :                                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
    1244           0 :   : si_(cx, ScopeIter(scope)),
    1245             :     env_(cx, env),
    1246           0 :     frame_(frame)
    1247             : {
    1248           0 :     assertSameCompartment(cx, frame);
    1249           0 :     settle();
    1250           0 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    1251           0 : }
    1252             : 
    1253             : void
    1254       14899 : EnvironmentIter::incrementScopeIter()
    1255             : {
    1256       14899 :     if (si_.scope()->is<GlobalScope>()) {
    1257             :         // GlobalScopes may be syntactic or non-syntactic. Non-syntactic
    1258             :         // GlobalScopes correspond to zero or more non-syntactic
    1259             :         // EnvironmentsObjects followed by the global lexical scope, then the
    1260             :         // GlobalObject or another non-EnvironmentObject object.
    1261        1891 :         if (!env_->is<EnvironmentObject>())
    1262         487 :             si_++;
    1263             :     } else {
    1264       13008 :         si_++;
    1265             :     }
    1266       14899 : }
    1267             : 
    1268             : void
    1269       29229 : EnvironmentIter::settle()
    1270             : {
    1271             :     // Check for trying to iterate a function or eval frame before the prologue has
    1272             :     // created the CallObject, in which case we have to skip.
    1273      116836 :     if (frame_ && frame_.hasScript() &&
    1274       61429 :         frame_.script()->initialEnvironmentShape() && !frame_.hasInitialEnvironment())
    1275             :     {
    1276             :         // Skip until we're at the enclosing scope of the script.
    1277           0 :         while (si_.scope() != frame_.script()->enclosingScope()) {
    1278           0 :             if (env_->is<LexicalEnvironmentObject>() &&
    1279           0 :                 !env_->as<LexicalEnvironmentObject>().isExtensible() &&
    1280           0 :                 &env_->as<LexicalEnvironmentObject>().scope() == si_.scope())
    1281             :             {
    1282           0 :                 MOZ_ASSERT(si_.kind() == ScopeKind::NamedLambda ||
    1283             :                            si_.kind() == ScopeKind::StrictNamedLambda);
    1284           0 :                 env_ = &env_->as<EnvironmentObject>().enclosingEnvironment();
    1285             :             }
    1286           0 :             incrementScopeIter();
    1287             :         }
    1288             :     }
    1289             : 
    1290             :     // Check if we have left the extent of the initial frame after we've
    1291             :     // settled on a static scope.
    1292       70643 :     if (frame_ &&
    1293       57891 :         (!si_ ||
    1294       74368 :          (frame_.hasScript() && si_.scope() == frame_.script()->enclosingScope()) ||
    1295       46193 :          (frame_.isWasmDebugFrame() && !si_.scope()->is<WasmFunctionScope>())))
    1296             :     {
    1297       12225 :         frame_ = NullFramePtr();
    1298             :     }
    1299             : 
    1300             : #ifdef DEBUG
    1301       29229 :     if (si_) {
    1302       28742 :         if (hasSyntacticEnvironment()) {
    1303       12517 :             Scope* scope = si_.scope();
    1304       12517 :             if (scope->is<LexicalScope>()) {
    1305         864 :                 MOZ_ASSERT(scope == &env_->as<LexicalEnvironmentObject>().scope());
    1306       11653 :             } else if (scope->is<FunctionScope>()) {
    1307        1900 :                 MOZ_ASSERT(scope->as<FunctionScope>().script() ==
    1308             :                            env_->as<CallObject>().callee().existingScriptNonDelazifying());
    1309        9753 :             } else if (scope->is<VarScope>()) {
    1310          30 :                 MOZ_ASSERT(scope == &env_->as<VarEnvironmentObject>().scope());
    1311        9723 :             } else if (scope->is<WithScope>()) {
    1312           0 :                 MOZ_ASSERT(scope == &env_->as<WithEnvironmentObject>().scope());
    1313        9723 :             } else if (scope->is<EvalScope>()) {
    1314           2 :                 MOZ_ASSERT(scope == &env_->as<VarEnvironmentObject>().scope());
    1315        9721 :             } else if (scope->is<GlobalScope>()) {
    1316        9721 :                 MOZ_ASSERT(env_->is<GlobalObject>() || IsGlobalLexicalEnvironment(env_));
    1317             :             }
    1318       16225 :         } else if (hasNonSyntacticEnvironmentObject()) {
    1319        2111 :             if (env_->is<LexicalEnvironmentObject>()) {
    1320             :                 // The global lexical environment still encloses non-syntactic
    1321             :                 // environment objects.
    1322         880 :                 MOZ_ASSERT(!env_->as<LexicalEnvironmentObject>().isSyntactic() ||
    1323             :                            env_->as<LexicalEnvironmentObject>().isGlobal());
    1324        1231 :             } else if (env_->is<WithEnvironmentObject>()) {
    1325        1188 :                 MOZ_ASSERT(!env_->as<WithEnvironmentObject>().isSyntactic());
    1326             :             } else {
    1327          43 :                 MOZ_ASSERT(env_->is<NonSyntacticVariablesObject>());
    1328             :             }
    1329             :         }
    1330             :     }
    1331             : #endif
    1332       29229 : }
    1333             : 
    1334             : JSObject&
    1335           0 : EnvironmentIter::enclosingEnvironment() const
    1336             : {
    1337             :     // As an engine invariant (maintained internally and asserted by Execute),
    1338             :     // EnvironmentObjects and non-EnvironmentObjects cannot be interleaved on
    1339             :     // the scope chain; every scope chain must start with zero or more
    1340             :     // EnvironmentObjects and terminate with one or more
    1341             :     // non-EnvironmentObjects (viz., GlobalObject).
    1342           0 :     MOZ_ASSERT(done());
    1343           0 :     MOZ_ASSERT(!env_->is<EnvironmentObject>());
    1344           0 :     return *env_;
    1345             : }
    1346             : 
    1347             : bool
    1348       31158 : EnvironmentIter::hasNonSyntacticEnvironmentObject() const
    1349             : {
    1350             :     // The case we're worrying about here is a NonSyntactic static scope
    1351             :     // which has 0+ corresponding non-syntactic WithEnvironmentObject
    1352             :     // scopes, a NonSyntacticVariablesObject, or a non-syntactic
    1353             :     // LexicalEnvironmentObject.
    1354       31158 :     if (si_.kind() == ScopeKind::NonSyntactic) {
    1355        3688 :         MOZ_ASSERT_IF(env_->is<WithEnvironmentObject>(),
    1356             :                       !env_->as<WithEnvironmentObject>().isSyntactic());
    1357        3688 :         return env_->is<EnvironmentObject>();
    1358             :     }
    1359       27470 :     return false;
    1360             : }
    1361             : 
    1362             : /* static */ HashNumber
    1363           0 : MissingEnvironmentKey::hash(MissingEnvironmentKey ek)
    1364             : {
    1365           0 :     return size_t(ek.frame_.raw()) ^ size_t(ek.scope_);
    1366             : }
    1367             : 
    1368             : /* static */ bool
    1369           0 : MissingEnvironmentKey::match(MissingEnvironmentKey ek1, MissingEnvironmentKey ek2)
    1370             : {
    1371           0 :     return ek1.frame_ == ek2.frame_ && ek1.scope_ == ek2.scope_;
    1372             : }
    1373             : 
    1374             : bool
    1375           0 : LiveEnvironmentVal::needsSweep()
    1376             : {
    1377           0 :     if (scope_)
    1378           0 :         MOZ_ALWAYS_FALSE(IsAboutToBeFinalized(&scope_));
    1379           0 :     return false;
    1380             : }
    1381             : 
    1382             : // Live EnvironmentIter values may be added to DebugEnvironments::liveEnvs, as
    1383             : // LiveEnvironmentVal instances.  They need to have write barriers when they are added
    1384             : // to the hash table, but no barriers when rehashing inside GC.  It's a nasty
    1385             : // hack, but the important thing is that LiveEnvironmentVal and MissingEnvironmentKey need to
    1386             : // alias each other.
    1387             : void
    1388           0 : LiveEnvironmentVal::staticAsserts()
    1389             : {
    1390             :     static_assert(sizeof(LiveEnvironmentVal) == sizeof(MissingEnvironmentKey),
    1391             :                   "LiveEnvironmentVal must be same size of MissingEnvironmentKey");
    1392             :     static_assert(offsetof(LiveEnvironmentVal, scope_) == offsetof(MissingEnvironmentKey, scope_),
    1393             :                   "LiveEnvironmentVal.scope_ must alias MissingEnvironmentKey.scope_");
    1394           0 : }
    1395             : 
    1396             : /*****************************************************************************/
    1397             : 
    1398             : namespace {
    1399             : 
    1400             : static void
    1401           0 : ReportOptimizedOut(JSContext* cx, HandleId id)
    1402             : {
    1403           0 :     JSAutoByteString printable;
    1404           0 :     if (ValueToPrintable(cx, IdToValue(id), &printable)) {
    1405           0 :         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_OPTIMIZED_OUT,
    1406           0 :                                    printable.ptr());
    1407             :     }
    1408           0 : }
    1409             : 
    1410             : /*
    1411             :  * DebugEnvironmentProxy is the handler for DebugEnvironmentProxy proxy
    1412             :  * objects. Having a custom handler (rather than trying to reuse js::Wrapper)
    1413             :  * gives us several important abilities:
    1414             :  *  - We want to pass the EnvironmentObject as the receiver to forwarded scope
    1415             :  *    property ops on aliased variables so that Call/Block/With ops do not all
    1416             :  *    require a 'normalization' step.
    1417             :  *  - The debug scope proxy can directly manipulate the stack frame to allow
    1418             :  *    the debugger to read/write args/locals that were otherwise unaliased.
    1419             :  *  - The debug scope proxy can store unaliased variables after the stack frame
    1420             :  *    is popped so that they may still be read/written by the debugger.
    1421             :  *  - The engine has made certain assumptions about the possible reads/writes
    1422             :  *    in a scope. DebugEnvironmentProxy allows us to prevent the debugger from
    1423             :  *    breaking those assumptions.
    1424             :  *  - The engine makes optimizations that are observable to the debugger. The
    1425             :  *    proxy can either hide these optimizations or make the situation more
    1426             :  *    clear to the debugger. An example is 'arguments'.
    1427             :  */
    1428             : class DebugEnvironmentProxyHandler : public BaseProxyHandler
    1429             : {
    1430             :     enum Action { SET, GET };
    1431             : 
    1432             :     enum AccessResult {
    1433             :         ACCESS_UNALIASED,
    1434             :         ACCESS_GENERIC,
    1435             :         ACCESS_LOST
    1436             :     };
    1437             : 
    1438             :     /*
    1439             :      * This function handles access to unaliased locals/formals. Since they
    1440             :      * are unaliased, the values of these variables are not stored in the
    1441             :      * slots of the normal CallObject and LexicalEnvironmentObject
    1442             :      * environments and thus must be recovered from somewhere else:
    1443             :      *  + if the invocation for which the env was created is still executing,
    1444             :      *    there is a JS frame live on the stack holding the values;
    1445             :      *  + if the invocation for which the env was created finished executing:
    1446             :      *     - and there was a DebugEnvironmentProxy associated with env, then
    1447             :      *       the DebugEnvironments::onPop(Call|Lexical) handler copied out the
    1448             :      *       unaliased variables. In both cases, a dense array is created in
    1449             :      *       onPop(Call|Lexical) to hold the unaliased values and attached to
    1450             :      *       the DebugEnvironmentProxy;
    1451             :      *     - and there was not a DebugEnvironmentProxy yet associated with the
    1452             :      *       scope, then the unaliased values are lost and not recoverable.
    1453             :      *
    1454             :      * Callers should check accessResult for non-failure results:
    1455             :      *  - ACCESS_UNALIASED if the access was unaliased and completed
    1456             :      *  - ACCESS_GENERIC   if the access was aliased or the property not found
    1457             :      *  - ACCESS_LOST      if the value has been lost to the debugger and the
    1458             :      *                     action is GET; if the action is SET, we assign to the
    1459             :      *                     name of the variable on the environment object
    1460             :      */
    1461           0 :     bool handleUnaliasedAccess(JSContext* cx, Handle<DebugEnvironmentProxy*> debugEnv,
    1462             :                                Handle<EnvironmentObject*> env, HandleId id, Action action,
    1463             :                                MutableHandleValue vp, AccessResult* accessResult) const
    1464             :     {
    1465           0 :         MOZ_ASSERT(&debugEnv->environment() == env);
    1466           0 :         MOZ_ASSERT_IF(action == SET, !debugEnv->isOptimizedOut());
    1467           0 :         *accessResult = ACCESS_GENERIC;
    1468           0 :         LiveEnvironmentVal* maybeLiveEnv = DebugEnvironments::hasLiveEnvironment(*env);
    1469             : 
    1470           0 :         if (env->is<ModuleEnvironmentObject>()) {
    1471             :             /* Everything is aliased and stored in the environment object. */
    1472           0 :             return true;
    1473             :         }
    1474             : 
    1475             :         /* Handle unaliased formals, vars, lets, and consts at function scope. */
    1476           0 :         if (env->is<CallObject>()) {
    1477           0 :             CallObject& callobj = env->as<CallObject>();
    1478           0 :             RootedFunction fun(cx, &callobj.callee());
    1479           0 :             RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
    1480           0 :             if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
    1481           0 :                 return false;
    1482             : 
    1483           0 :             BindingIter bi(script);
    1484           0 :             while (bi && NameToId(bi.name()->asPropertyName()) != id)
    1485           0 :                 bi++;
    1486           0 :             if (!bi)
    1487           0 :                 return true;
    1488             : 
    1489           0 :             if (!bi.hasArgumentSlot()) {
    1490           0 :                 if (bi.closedOver())
    1491           0 :                     return true;
    1492             : 
    1493           0 :                 uint32_t i = bi.location().slot();
    1494           0 :                 if (maybeLiveEnv) {
    1495           0 :                     AbstractFramePtr frame = maybeLiveEnv->frame();
    1496           0 :                     if (action == GET)
    1497           0 :                         vp.set(frame.unaliasedLocal(i));
    1498             :                     else
    1499           0 :                         frame.unaliasedLocal(i) = vp;
    1500           0 :                 } else if (NativeObject* snapshot = debugEnv->maybeSnapshot()) {
    1501           0 :                     if (action == GET)
    1502           0 :                         vp.set(snapshot->getDenseElement(script->numArgs() + i));
    1503             :                     else
    1504           0 :                         snapshot->setDenseElement(script->numArgs() + i, vp);
    1505             :                 } else {
    1506             :                     /* The unaliased value has been lost to the debugger. */
    1507           0 :                     if (action == GET) {
    1508           0 :                         *accessResult = ACCESS_LOST;
    1509           0 :                         return true;
    1510             :                     }
    1511             :                 }
    1512             :             } else {
    1513           0 :                 unsigned i = bi.argumentSlot();
    1514           0 :                 if (bi.closedOver())
    1515           0 :                     return true;
    1516             : 
    1517           0 :                 if (maybeLiveEnv) {
    1518           0 :                     AbstractFramePtr frame = maybeLiveEnv->frame();
    1519           0 :                     if (script->argsObjAliasesFormals() && frame.hasArgsObj()) {
    1520           0 :                         if (action == GET)
    1521           0 :                             vp.set(frame.argsObj().arg(i));
    1522             :                         else
    1523           0 :                             frame.argsObj().setArg(i, vp);
    1524             :                     } else {
    1525           0 :                         if (action == GET)
    1526           0 :                             vp.set(frame.unaliasedFormal(i, DONT_CHECK_ALIASING));
    1527             :                         else
    1528           0 :                             frame.unaliasedFormal(i, DONT_CHECK_ALIASING) = vp;
    1529             :                     }
    1530           0 :                 } else if (NativeObject* snapshot = debugEnv->maybeSnapshot()) {
    1531           0 :                     if (action == GET)
    1532           0 :                         vp.set(snapshot->getDenseElement(i));
    1533             :                     else
    1534           0 :                         snapshot->setDenseElement(i, vp);
    1535             :                 } else {
    1536             :                     /* The unaliased value has been lost to the debugger. */
    1537           0 :                     if (action == GET) {
    1538           0 :                         *accessResult = ACCESS_LOST;
    1539           0 :                         return true;
    1540             :                     }
    1541             :                 }
    1542             : 
    1543           0 :                 if (action == SET)
    1544           0 :                     TypeScript::SetArgument(cx, script, i, vp);
    1545             :             }
    1546             : 
    1547             :             // It is possible that an optimized out value flows to this
    1548             :             // location due to Debugger.Frame.prototype.eval operating on a
    1549             :             // live bailed-out Baseline frame. In that case, treat the access
    1550             :             // as lost.
    1551           0 :             if (vp.isMagic() && vp.whyMagic() == JS_OPTIMIZED_OUT)
    1552           0 :                 *accessResult = ACCESS_LOST;
    1553             :             else
    1554           0 :                 *accessResult = ACCESS_UNALIASED;
    1555             : 
    1556           0 :             return true;
    1557             :         }
    1558             : 
    1559             :         /*
    1560             :          * Handle unaliased vars in functions with parameter expressions and
    1561             :          * lexical bindings at block scope.
    1562             :          */
    1563           0 :         if (env->is<LexicalEnvironmentObject>() || env->is<VarEnvironmentObject>()) {
    1564             :             // Currently consider all global and non-syntactic top-level lexical
    1565             :             // bindings to be aliased.
    1566           0 :             if (env->is<LexicalEnvironmentObject>() &&
    1567           0 :                 env->as<LexicalEnvironmentObject>().isExtensible())
    1568             :             {
    1569           0 :                 MOZ_ASSERT(IsGlobalLexicalEnvironment(env) || !IsSyntacticEnvironment(env));
    1570           0 :                 return true;
    1571             :             }
    1572             : 
    1573             :             // Currently all vars inside eval var environments are aliased.
    1574           0 :             if (env->is<VarEnvironmentObject>() && env->as<VarEnvironmentObject>().isForEval())
    1575           0 :                 return true;
    1576             : 
    1577           0 :             RootedScope scope(cx, getEnvironmentScope(*env));
    1578             :             uint32_t firstFrameSlot;
    1579           0 :             if (env->is<LexicalEnvironmentObject>())
    1580           0 :                 firstFrameSlot = scope->as<LexicalScope>().firstFrameSlot();
    1581             :             else
    1582           0 :                 firstFrameSlot = scope->as<VarScope>().firstFrameSlot();
    1583             : 
    1584           0 :             BindingIter bi(scope);
    1585           0 :             while (bi && NameToId(bi.name()->asPropertyName()) != id)
    1586           0 :                 bi++;
    1587           0 :             if (!bi)
    1588           0 :                 return true;
    1589             : 
    1590           0 :             BindingLocation loc = bi.location();
    1591           0 :             if (loc.kind() == BindingLocation::Kind::Environment)
    1592           0 :                 return true;
    1593             : 
    1594             :             // Named lambdas that are not closed over are lost.
    1595           0 :             if (loc.kind() == BindingLocation::Kind::NamedLambdaCallee) {
    1596           0 :                 if (action == GET)
    1597           0 :                     *accessResult = ACCESS_LOST;
    1598           0 :                 return true;
    1599             :             }
    1600             : 
    1601           0 :             MOZ_ASSERT(loc.kind() == BindingLocation::Kind::Frame);
    1602             : 
    1603           0 :             if (maybeLiveEnv) {
    1604           0 :                 AbstractFramePtr frame = maybeLiveEnv->frame();
    1605           0 :                 uint32_t local = loc.slot();
    1606           0 :                 MOZ_ASSERT(local < frame.script()->nfixed());
    1607           0 :                 if (action == GET)
    1608           0 :                     vp.set(frame.unaliasedLocal(local));
    1609             :                 else
    1610           0 :                     frame.unaliasedLocal(local) = vp;
    1611           0 :             } else if (NativeObject* snapshot = debugEnv->maybeSnapshot()) {
    1612             :                 // Indices in the frame snapshot are offset by the first frame
    1613             :                 // slot. See DebugEnvironments::takeFrameSnapshot.
    1614           0 :                 MOZ_ASSERT(loc.slot() >= firstFrameSlot);
    1615           0 :                 uint32_t snapshotIndex = loc.slot() - firstFrameSlot;
    1616           0 :                 if (action == GET)
    1617           0 :                     vp.set(snapshot->getDenseElement(snapshotIndex));
    1618             :                 else
    1619           0 :                     snapshot->setDenseElement(snapshotIndex, vp);
    1620             :             } else {
    1621           0 :                 if (action == GET) {
    1622             :                     // A {Lexical,Var}EnvironmentObject whose static scope
    1623             :                     // does not have an environment shape at all is a "hollow"
    1624             :                     // block object reflected for missing block scopes. Their
    1625             :                     // slot values are lost.
    1626           0 :                     if (!scope->hasEnvironment()) {
    1627           0 :                         *accessResult = ACCESS_LOST;
    1628           0 :                         return true;
    1629             :                     }
    1630             : 
    1631           0 :                     if (!GetProperty(cx, env, env, id, vp))
    1632           0 :                         return false;
    1633             :                 } else {
    1634           0 :                     if (!SetProperty(cx, env, id, vp))
    1635           0 :                         return false;
    1636             :                 }
    1637             :             }
    1638             : 
    1639             :             // See comment above in analogous CallObject case.
    1640           0 :             if (vp.isMagic() && vp.whyMagic() == JS_OPTIMIZED_OUT)
    1641           0 :                 *accessResult = ACCESS_LOST;
    1642             :             else
    1643           0 :                 *accessResult = ACCESS_UNALIASED;
    1644             : 
    1645           0 :             return true;
    1646             :         }
    1647             : 
    1648           0 :         if (env->is<WasmFunctionCallObject>()) {
    1649           0 :             if (maybeLiveEnv) {
    1650           0 :                 RootedScope scope(cx, getEnvironmentScope(*env));
    1651           0 :                 uint32_t index = 0;
    1652           0 :                 for (BindingIter bi(scope); bi; bi++) {
    1653           0 :                     if (JSID_IS_ATOM(id, bi.name()))
    1654           0 :                         break;
    1655           0 :                     MOZ_ASSERT(!bi.isLast());
    1656           0 :                     index++;
    1657             :                 }
    1658             : 
    1659           0 :                 AbstractFramePtr frame = maybeLiveEnv->frame();
    1660           0 :                 MOZ_ASSERT(frame.isWasmDebugFrame());
    1661           0 :                 wasm::DebugFrame* wasmFrame = frame.asWasmDebugFrame();
    1662           0 :                 if (action == GET) {
    1663           0 :                     if (!wasmFrame->getLocal(index, vp)) {
    1664           0 :                         ReportOutOfMemory(cx);
    1665           0 :                         return false;
    1666             :                     }
    1667           0 :                     *accessResult = ACCESS_UNALIASED;
    1668             :                 } else { // if (action == SET)
    1669             :                     // TODO
    1670             :                 }
    1671             :             } else {
    1672           0 :                 *accessResult = ACCESS_LOST;
    1673             :             }
    1674           0 :             return true;
    1675             :         }
    1676             : 
    1677             :         /* The rest of the internal scopes do not have unaliased vars. */
    1678           0 :         MOZ_ASSERT(!IsSyntacticEnvironment(env) ||
    1679             :                    env->is<WithEnvironmentObject>());
    1680           0 :         return true;
    1681             :     }
    1682             : 
    1683           0 :     static bool isArguments(JSContext* cx, jsid id)
    1684             :     {
    1685           0 :         return id == NameToId(cx->names().arguments);
    1686             :     }
    1687           0 :     static bool isThis(JSContext* cx, jsid id)
    1688             :     {
    1689           0 :         return id == NameToId(cx->names().dotThis);
    1690             :     }
    1691             : 
    1692           0 :     static bool isFunctionEnvironment(const JSObject& env)
    1693             :     {
    1694           0 :         return env.is<CallObject>();
    1695             :     }
    1696             : 
    1697           0 :     static bool isNonExtensibleLexicalEnvironment(const JSObject& env)
    1698             :     {
    1699           0 :         return env.is<LexicalEnvironmentObject>() &&
    1700           0 :                !env.as<LexicalEnvironmentObject>().isExtensible();
    1701             :     }
    1702             : 
    1703           0 :     static Scope* getEnvironmentScope(const JSObject& env)
    1704             :     {
    1705           0 :         if (isFunctionEnvironment(env))
    1706           0 :             return env.as<CallObject>().callee().nonLazyScript()->bodyScope();
    1707           0 :         if (isNonExtensibleLexicalEnvironment(env))
    1708           0 :             return &env.as<LexicalEnvironmentObject>().scope();
    1709           0 :         if (env.is<VarEnvironmentObject>())
    1710           0 :             return &env.as<VarEnvironmentObject>().scope();
    1711           0 :         if (env.is<WasmFunctionCallObject>())
    1712           0 :             return &env.as<WasmFunctionCallObject>().scope();
    1713           0 :         return nullptr;
    1714             :     }
    1715             : 
    1716             :     /*
    1717             :      * In theory, every non-arrow function scope contains an 'arguments'
    1718             :      * bindings.  However, the engine only adds a binding if 'arguments' is
    1719             :      * used in the function body. Thus, from the debugger's perspective,
    1720             :      * 'arguments' may be missing from the list of bindings.
    1721             :      */
    1722           0 :     static bool isMissingArgumentsBinding(EnvironmentObject& env)
    1723             :     {
    1724           0 :         return isFunctionEnvironment(env) &&
    1725           0 :                !env.as<CallObject>().callee().nonLazyScript()->argumentsHasVarBinding();
    1726             :     }
    1727             : 
    1728             :     /*
    1729             :      * Similar to 'arguments' above, we don't add a 'this' binding to
    1730             :      * non-arrow functions if it's not used.
    1731             :      */
    1732           0 :     static bool isMissingThisBinding(EnvironmentObject& env)
    1733             :     {
    1734           0 :         return isFunctionEnvironmentWithThis(env) &&
    1735           0 :                !env.as<CallObject>().callee().nonLazyScript()->functionHasThisBinding();
    1736             :     }
    1737             : 
    1738             :     /*
    1739             :      * This function checks if an arguments object needs to be created when
    1740             :      * the debugger requests 'arguments' for a function scope where the
    1741             :      * arguments object has been optimized away (either because the binding is
    1742             :      * missing altogether or because !ScriptAnalysis::needsArgsObj).
    1743             :      */
    1744           0 :     static bool isMissingArguments(JSContext* cx, jsid id, EnvironmentObject& env)
    1745             :     {
    1746           0 :         return isArguments(cx, id) && isFunctionEnvironment(env) &&
    1747           0 :                !env.as<CallObject>().callee().nonLazyScript()->needsArgsObj();
    1748             :     }
    1749           0 :     static bool isMissingThis(JSContext* cx, jsid id, EnvironmentObject& env)
    1750             :     {
    1751           0 :         return isThis(cx, id) && isMissingThisBinding(env);
    1752             :     }
    1753             : 
    1754             :     /*
    1755             :      * Check if the value is the magic value JS_OPTIMIZED_ARGUMENTS. The
    1756             :      * arguments analysis may have optimized out the 'arguments', and this
    1757             :      * magic value could have propagated to other local slots. e.g.,
    1758             :      *
    1759             :      *   function f() { var a = arguments; h(); }
    1760             :      *   function h() { evalInFrame(1, "a.push(0)"); }
    1761             :      *
    1762             :      * where evalInFrame(N, str) means to evaluate str N frames up.
    1763             :      *
    1764             :      * In this case we don't know we need to recover a missing arguments
    1765             :      * object until after we've performed the property get.
    1766             :      */
    1767           0 :     static bool isMagicMissingArgumentsValue(JSContext* cx, EnvironmentObject& env, HandleValue v)
    1768             :     {
    1769           0 :         bool isMagic = v.isMagic() && v.whyMagic() == JS_OPTIMIZED_ARGUMENTS;
    1770             : 
    1771             : #ifdef DEBUG
    1772             :         // The |env| object here is not limited to CallObjects but may also
    1773             :         // be lexical envs in case of the following:
    1774             :         //
    1775             :         //   function f() { { let a = arguments; } }
    1776             :         //
    1777             :         // We need to check that |env|'s scope's nearest function scope has an
    1778             :         // 'arguments' var binding. The environment chain is not sufficient:
    1779             :         // |f| above will not have a CallObject because there are no aliased
    1780             :         // body-level bindings.
    1781           0 :         if (isMagic) {
    1782           0 :             JSFunction* callee = nullptr;
    1783           0 :             if (isFunctionEnvironment(env)) {
    1784           0 :                 callee = &env.as<CallObject>().callee();
    1785             :             } else {
    1786             :                 // We will never have a WithEnvironmentObject here because no
    1787             :                 // binding accesses on with scopes are unaliased.
    1788           0 :                 for (ScopeIter si(getEnvironmentScope(env)); si; si++) {
    1789           0 :                     if (si.kind() == ScopeKind::Function) {
    1790           0 :                         callee = si.scope()->as<FunctionScope>().canonicalFunction();
    1791           0 :                         break;
    1792             :                     }
    1793             :                 }
    1794             :             }
    1795           0 :             MOZ_ASSERT(callee && callee->nonLazyScript()->argumentsHasVarBinding());
    1796             :         }
    1797             : #endif
    1798             : 
    1799           0 :         return isMagic;
    1800             :     }
    1801             : 
    1802             :     /*
    1803             :      * If the value of |this| is requested before the this-binding has been
    1804             :      * initialized by JSOP_FUNCTIONTHIS, the this-binding will be |undefined|.
    1805             :      * In that case, we have to call createMissingThis to initialize the
    1806             :      * this-binding.
    1807             :      *
    1808             :      * Note that an |undefined| this-binding is perfectly valid in strict-mode
    1809             :      * code, but that's fine: createMissingThis will do the right thing in that
    1810             :      * case.
    1811             :      */
    1812           0 :     static bool isMaybeUninitializedThisValue(JSContext* cx, jsid id, const Value& v)
    1813             :     {
    1814           0 :         return isThis(cx, id) && v.isUndefined();
    1815             :     }
    1816             : 
    1817             :     /*
    1818             :      * Create a missing arguments object. If the function returns true but
    1819             :      * argsObj is null, it means the env is dead.
    1820             :      */
    1821           0 :     static bool createMissingArguments(JSContext* cx, EnvironmentObject& env,
    1822             :                                        MutableHandleArgumentsObject argsObj)
    1823             :     {
    1824           0 :         argsObj.set(nullptr);
    1825             : 
    1826           0 :         LiveEnvironmentVal* maybeEnv = DebugEnvironments::hasLiveEnvironment(env);
    1827           0 :         if (!maybeEnv)
    1828           0 :             return true;
    1829             : 
    1830           0 :         argsObj.set(ArgumentsObject::createUnexpected(cx, maybeEnv->frame()));
    1831           0 :         return !!argsObj;
    1832             :     }
    1833             : 
    1834             :     /*
    1835             :      * Create a missing this Value. If the function returns true but
    1836             :      * *success is false, it means the scope is dead.
    1837             :      */
    1838           0 :     static bool createMissingThis(JSContext* cx, EnvironmentObject& env,
    1839             :                                   MutableHandleValue thisv, bool* success)
    1840             :     {
    1841           0 :         *success = false;
    1842             : 
    1843           0 :         LiveEnvironmentVal* maybeEnv = DebugEnvironments::hasLiveEnvironment(env);
    1844           0 :         if (!maybeEnv)
    1845           0 :             return true;
    1846             : 
    1847           0 :         if (!GetFunctionThis(cx, maybeEnv->frame(), thisv))
    1848           0 :             return false;
    1849             : 
    1850             :         // Update the this-argument to avoid boxing primitive |this| more
    1851             :         // than once.
    1852           0 :         maybeEnv->frame().thisArgument() = thisv;
    1853           0 :         *success = true;
    1854           0 :         return true;
    1855             :     }
    1856             : 
    1857             :   public:
    1858             :     static const char family;
    1859             :     static const DebugEnvironmentProxyHandler singleton;
    1860             : 
    1861             :     constexpr DebugEnvironmentProxyHandler() : BaseProxyHandler(&family) {}
    1862             : 
    1863           0 :     static bool isFunctionEnvironmentWithThis(const JSObject& env)
    1864             :     {
    1865             :         // All functions except arrows and generator expression lambdas should
    1866             :         // have their own this binding.
    1867           0 :         return isFunctionEnvironment(env) && !env.as<CallObject>().callee().hasLexicalThis();
    1868             :     }
    1869             : 
    1870           0 :     bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
    1871             :                                 MutableHandleObject protop) const override
    1872             :     {
    1873           0 :         MOZ_CRASH("shouldn't be possible to access the prototype chain of a DebugEnvironmentProxyHandler");
    1874             :     }
    1875             : 
    1876           0 :     bool preventExtensions(JSContext* cx, HandleObject proxy,
    1877             :                            ObjectOpResult& result) const override
    1878             :     {
    1879             :         // always [[Extensible]], can't be made non-[[Extensible]], like most
    1880             :         // proxies
    1881           0 :         return result.fail(JSMSG_CANT_CHANGE_EXTENSIBILITY);
    1882             :     }
    1883             : 
    1884           0 :     bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override
    1885             :     {
    1886             :         // See above.
    1887           0 :         *extensible = true;
    1888           0 :         return true;
    1889             :     }
    1890             : 
    1891           0 :     bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
    1892             :                                MutableHandle<PropertyDescriptor> desc) const override
    1893             :     {
    1894           0 :         return getOwnPropertyDescriptor(cx, proxy, id, desc);
    1895             :     }
    1896             : 
    1897           0 :     bool getMissingArgumentsPropertyDescriptor(JSContext* cx,
    1898             :                                                Handle<DebugEnvironmentProxy*> debugEnv,
    1899             :                                                EnvironmentObject& env,
    1900             :                                                MutableHandle<PropertyDescriptor> desc) const
    1901             :     {
    1902           0 :         RootedArgumentsObject argsObj(cx);
    1903           0 :         if (!createMissingArguments(cx, env, &argsObj))
    1904           0 :             return false;
    1905             : 
    1906           0 :         if (!argsObj) {
    1907             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
    1908           0 :                                       "Debugger scope");
    1909           0 :             return false;
    1910             :         }
    1911             : 
    1912           0 :         desc.object().set(debugEnv);
    1913           0 :         desc.setAttributes(JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);
    1914           0 :         desc.value().setObject(*argsObj);
    1915           0 :         desc.setGetter(nullptr);
    1916           0 :         desc.setSetter(nullptr);
    1917           0 :         return true;
    1918             :     }
    1919           0 :     bool getMissingThisPropertyDescriptor(JSContext* cx,
    1920             :                                           Handle<DebugEnvironmentProxy*> debugEnv,
    1921             :                                           EnvironmentObject& env,
    1922             :                                           MutableHandle<PropertyDescriptor> desc) const
    1923             :     {
    1924           0 :         RootedValue thisv(cx);
    1925             :         bool success;
    1926           0 :         if (!createMissingThis(cx, env, &thisv, &success))
    1927           0 :             return false;
    1928             : 
    1929           0 :         if (!success) {
    1930             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
    1931           0 :                                       "Debugger scope");
    1932           0 :             return false;
    1933             :         }
    1934             : 
    1935           0 :         desc.object().set(debugEnv);
    1936           0 :         desc.setAttributes(JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);
    1937           0 :         desc.value().set(thisv);
    1938           0 :         desc.setGetter(nullptr);
    1939           0 :         desc.setSetter(nullptr);
    1940           0 :         return true;
    1941             :     }
    1942             : 
    1943           0 :     bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
    1944             :                                   MutableHandle<PropertyDescriptor> desc) const override
    1945             :     {
    1946           0 :         Rooted<DebugEnvironmentProxy*> debugEnv(cx, &proxy->as<DebugEnvironmentProxy>());
    1947           0 :         Rooted<EnvironmentObject*> env(cx, &debugEnv->environment());
    1948             : 
    1949           0 :         if (isMissingArguments(cx, id, *env))
    1950           0 :             return getMissingArgumentsPropertyDescriptor(cx, debugEnv, *env, desc);
    1951             : 
    1952           0 :         if (isMissingThis(cx, id, *env))
    1953           0 :             return getMissingThisPropertyDescriptor(cx, debugEnv, *env, desc);
    1954             : 
    1955           0 :         RootedValue v(cx);
    1956             :         AccessResult access;
    1957           0 :         if (!handleUnaliasedAccess(cx, debugEnv, env, id, GET, &v, &access))
    1958           0 :             return false;
    1959             : 
    1960           0 :         switch (access) {
    1961             :           case ACCESS_UNALIASED:
    1962           0 :             if (isMagicMissingArgumentsValue(cx, *env, v))
    1963           0 :                 return getMissingArgumentsPropertyDescriptor(cx, debugEnv, *env, desc);
    1964           0 :             desc.object().set(debugEnv);
    1965           0 :             desc.setAttributes(JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);
    1966           0 :             desc.value().set(v);
    1967           0 :             desc.setGetter(nullptr);
    1968           0 :             desc.setSetter(nullptr);
    1969           0 :             return true;
    1970             :           case ACCESS_GENERIC:
    1971           0 :             return JS_GetOwnPropertyDescriptorById(cx, env, id, desc);
    1972             :           case ACCESS_LOST:
    1973           0 :             ReportOptimizedOut(cx, id);
    1974           0 :             return false;
    1975             :           default:
    1976           0 :             MOZ_CRASH("bad AccessResult");
    1977             :         }
    1978             :     }
    1979             : 
    1980           0 :     bool getMissingArguments(JSContext* cx, EnvironmentObject& env, MutableHandleValue vp) const
    1981             :     {
    1982           0 :         RootedArgumentsObject argsObj(cx);
    1983           0 :         if (!createMissingArguments(cx, env, &argsObj))
    1984           0 :             return false;
    1985             : 
    1986           0 :         if (!argsObj) {
    1987             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
    1988           0 :                                       "Debugger env");
    1989           0 :             return false;
    1990             :         }
    1991             : 
    1992           0 :         vp.setObject(*argsObj);
    1993           0 :         return true;
    1994             :     }
    1995             : 
    1996           0 :     bool getMissingThis(JSContext* cx, EnvironmentObject& env, MutableHandleValue vp) const
    1997             :     {
    1998           0 :         RootedValue thisv(cx);
    1999             :         bool success;
    2000           0 :         if (!createMissingThis(cx, env, &thisv, &success))
    2001           0 :             return false;
    2002             : 
    2003           0 :         if (!success) {
    2004             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
    2005           0 :                                       "Debugger env");
    2006           0 :             return false;
    2007             :         }
    2008             : 
    2009           0 :         vp.set(thisv);
    2010           0 :         return true;
    2011             :     }
    2012             : 
    2013           0 :     bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
    2014             :              MutableHandleValue vp) const override
    2015             :     {
    2016           0 :         Rooted<DebugEnvironmentProxy*> debugEnv(cx, &proxy->as<DebugEnvironmentProxy>());
    2017           0 :         Rooted<EnvironmentObject*> env(cx, &proxy->as<DebugEnvironmentProxy>().environment());
    2018             : 
    2019           0 :         if (isMissingArguments(cx, id, *env))
    2020           0 :             return getMissingArguments(cx, *env, vp);
    2021             : 
    2022           0 :         if (isMissingThis(cx, id, *env))
    2023           0 :             return getMissingThis(cx, *env, vp);
    2024             : 
    2025             :         AccessResult access;
    2026           0 :         if (!handleUnaliasedAccess(cx, debugEnv, env, id, GET, vp, &access))
    2027           0 :             return false;
    2028             : 
    2029           0 :         switch (access) {
    2030             :           case ACCESS_UNALIASED:
    2031           0 :             if (isMagicMissingArgumentsValue(cx, *env, vp))
    2032           0 :                 return getMissingArguments(cx, *env, vp);
    2033           0 :             if (isMaybeUninitializedThisValue(cx, id, vp))
    2034           0 :                 return getMissingThis(cx, *env, vp);
    2035           0 :             return true;
    2036             :           case ACCESS_GENERIC:
    2037           0 :             if (!GetProperty(cx, env, env, id, vp))
    2038           0 :                 return false;
    2039           0 :             if (isMaybeUninitializedThisValue(cx, id, vp))
    2040           0 :                 return getMissingThis(cx, *env, vp);
    2041           0 :             return true;
    2042             :           case ACCESS_LOST:
    2043           0 :             ReportOptimizedOut(cx, id);
    2044           0 :             return false;
    2045             :           default:
    2046           0 :             MOZ_CRASH("bad AccessResult");
    2047             :         }
    2048             :     }
    2049             : 
    2050           0 :     bool getMissingArgumentsMaybeSentinelValue(JSContext* cx, EnvironmentObject& env,
    2051             :                                                MutableHandleValue vp) const
    2052             :     {
    2053           0 :         RootedArgumentsObject argsObj(cx);
    2054           0 :         if (!createMissingArguments(cx, env, &argsObj))
    2055           0 :             return false;
    2056           0 :         vp.set(argsObj ? ObjectValue(*argsObj) : MagicValue(JS_OPTIMIZED_ARGUMENTS));
    2057           0 :         return true;
    2058             :     }
    2059             : 
    2060           0 :     bool getMissingThisMaybeSentinelValue(JSContext* cx, EnvironmentObject& env,
    2061             :                                           MutableHandleValue vp) const
    2062             :     {
    2063           0 :         RootedValue thisv(cx);
    2064             :         bool success;
    2065           0 :         if (!createMissingThis(cx, env, &thisv, &success))
    2066           0 :             return false;
    2067           0 :         vp.set(success ? thisv : MagicValue(JS_OPTIMIZED_OUT));
    2068           0 :         return true;
    2069             :     }
    2070             : 
    2071             :     /*
    2072             :      * Like 'get', but returns sentinel values instead of throwing on
    2073             :      * exceptional cases.
    2074             :      */
    2075           0 :     bool getMaybeSentinelValue(JSContext* cx, Handle<DebugEnvironmentProxy*> debugEnv,
    2076             :                                HandleId id, MutableHandleValue vp) const
    2077             :     {
    2078           0 :         Rooted<EnvironmentObject*> env(cx, &debugEnv->environment());
    2079             : 
    2080           0 :         if (isMissingArguments(cx, id, *env))
    2081           0 :             return getMissingArgumentsMaybeSentinelValue(cx, *env, vp);
    2082           0 :         if (isMissingThis(cx, id, *env))
    2083           0 :             return getMissingThisMaybeSentinelValue(cx, *env, vp);
    2084             : 
    2085             :         AccessResult access;
    2086           0 :         if (!handleUnaliasedAccess(cx, debugEnv, env, id, GET, vp, &access))
    2087           0 :             return false;
    2088             : 
    2089           0 :         switch (access) {
    2090             :           case ACCESS_UNALIASED:
    2091           0 :             if (isMagicMissingArgumentsValue(cx, *env, vp))
    2092           0 :                 return getMissingArgumentsMaybeSentinelValue(cx, *env, vp);
    2093           0 :             if (isMaybeUninitializedThisValue(cx, id, vp))
    2094           0 :                 return getMissingThisMaybeSentinelValue(cx, *env, vp);
    2095           0 :             return true;
    2096             :           case ACCESS_GENERIC:
    2097           0 :             if (!GetProperty(cx, env, env, id, vp))
    2098           0 :                 return false;
    2099           0 :             if (isMaybeUninitializedThisValue(cx, id, vp))
    2100           0 :                 return getMissingThisMaybeSentinelValue(cx, *env, vp);
    2101           0 :             return true;
    2102             :           case ACCESS_LOST:
    2103           0 :             vp.setMagic(JS_OPTIMIZED_OUT);
    2104           0 :             return true;
    2105             :           default:
    2106           0 :             MOZ_CRASH("bad AccessResult");
    2107             :         }
    2108             :     }
    2109             : 
    2110           0 :     bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver,
    2111             :              ObjectOpResult& result) const override
    2112             :     {
    2113           0 :         Rooted<DebugEnvironmentProxy*> debugEnv(cx, &proxy->as<DebugEnvironmentProxy>());
    2114           0 :         Rooted<EnvironmentObject*> env(cx, &proxy->as<DebugEnvironmentProxy>().environment());
    2115             : 
    2116           0 :         if (debugEnv->isOptimizedOut())
    2117           0 :             return Throw(cx, id, JSMSG_DEBUG_CANT_SET_OPT_ENV);
    2118             : 
    2119             :         AccessResult access;
    2120           0 :         RootedValue valCopy(cx, v);
    2121           0 :         if (!handleUnaliasedAccess(cx, debugEnv, env, id, SET, &valCopy, &access))
    2122           0 :             return false;
    2123             : 
    2124           0 :         switch (access) {
    2125             :           case ACCESS_UNALIASED:
    2126           0 :             return result.succeed();
    2127             :           case ACCESS_GENERIC: {
    2128           0 :             RootedValue envVal(cx, ObjectValue(*env));
    2129           0 :             return SetProperty(cx, env, id, v, envVal, result);
    2130             :           }
    2131             :           default:
    2132           0 :             MOZ_CRASH("bad AccessResult");
    2133             :         }
    2134             :     }
    2135             : 
    2136           0 :     bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
    2137             :                         Handle<PropertyDescriptor> desc,
    2138             :                         ObjectOpResult& result) const override
    2139             :     {
    2140           0 :         Rooted<EnvironmentObject*> env(cx, &proxy->as<DebugEnvironmentProxy>().environment());
    2141             : 
    2142             :         bool found;
    2143           0 :         if (!has(cx, proxy, id, &found))
    2144           0 :             return false;
    2145           0 :         if (found)
    2146           0 :             return Throw(cx, id, JSMSG_CANT_REDEFINE_PROP);
    2147             : 
    2148           0 :         return JS_DefinePropertyById(cx, env, id, desc, result);
    2149             :     }
    2150             : 
    2151           0 :     bool ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const override
    2152             :     {
    2153           0 :         Rooted<EnvironmentObject*> env(cx, &proxy->as<DebugEnvironmentProxy>().environment());
    2154             : 
    2155           0 :         if (isMissingArgumentsBinding(*env)) {
    2156           0 :             if (!props.append(NameToId(cx->names().arguments)))
    2157           0 :                 return false;
    2158             :         }
    2159           0 :         if (isMissingThisBinding(*env)) {
    2160           0 :             if (!props.append(NameToId(cx->names().dotThis)))
    2161           0 :                 return false;
    2162             :         }
    2163             : 
    2164             :         // WithEnvironmentObject isn't a very good proxy.  It doesn't have a
    2165             :         // JSNewEnumerateOp implementation, because if it just delegated to the
    2166             :         // target object, the object would indicate that native enumeration is
    2167             :         // the thing to do, but native enumeration over the WithEnvironmentObject
    2168             :         // wrapper yields no properties.  So instead here we hack around the
    2169             :         // issue: punch a hole through to the with object target, then manually
    2170             :         // examine @@unscopables.
    2171           0 :         RootedObject target(cx);
    2172           0 :         bool isWith = env->is<WithEnvironmentObject>();
    2173           0 :         if (isWith)
    2174           0 :             target = &env->as<WithEnvironmentObject>().object();
    2175             :         else
    2176           0 :             target = env;
    2177           0 :         if (!GetPropertyKeys(cx, target, JSITER_OWNONLY, &props))
    2178           0 :             return false;
    2179             : 
    2180           0 :         if (isWith) {
    2181           0 :             size_t j = 0;
    2182           0 :             for (size_t i = 0; i < props.length(); i++) {
    2183             :                 bool inScope;
    2184           0 :                 if (!CheckUnscopables(cx, env, props[i], &inScope))
    2185           0 :                     return false;
    2186           0 :                 if (inScope)
    2187           0 :                     props[j++].set(props[i]);
    2188             :             }
    2189           0 :             if (!props.resize(j))
    2190           0 :                 return false;
    2191             :         }
    2192             : 
    2193             :         /*
    2194             :          * Environments with Scopes are optimized to not contain unaliased
    2195             :          * variables so they must be manually appended here.
    2196             :          */
    2197           0 :         if (Scope* scope = getEnvironmentScope(*env)) {
    2198           0 :             for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
    2199           0 :                 if (!bi.closedOver() && !props.append(NameToId(bi.name()->asPropertyName())))
    2200           0 :                     return false;
    2201             :             }
    2202             :         }
    2203             : 
    2204           0 :         return true;
    2205             :     }
    2206             : 
    2207           0 :     bool has(JSContext* cx, HandleObject proxy, HandleId id_, bool* bp) const override
    2208             :     {
    2209           0 :         RootedId id(cx, id_);
    2210           0 :         EnvironmentObject& envObj = proxy->as<DebugEnvironmentProxy>().environment();
    2211             : 
    2212           0 :         if (isArguments(cx, id) && isFunctionEnvironment(envObj)) {
    2213           0 :             *bp = true;
    2214           0 :             return true;
    2215             :         }
    2216             : 
    2217             :         // Be careful not to look up '.this' as a normal binding below, it will
    2218             :         // assert in with_HasProperty.
    2219           0 :         if (isThis(cx, id)) {
    2220           0 :             *bp = isFunctionEnvironmentWithThis(envObj);
    2221           0 :             return true;
    2222             :         }
    2223             : 
    2224             :         bool found;
    2225           0 :         RootedObject env(cx, &envObj);
    2226           0 :         if (!JS_HasPropertyById(cx, env, id, &found))
    2227           0 :             return false;
    2228             : 
    2229           0 :         if (!found) {
    2230           0 :             if (Scope* scope = getEnvironmentScope(*env)) {
    2231           0 :                 for (BindingIter bi(scope); bi; bi++) {
    2232           0 :                     if (!bi.closedOver() && NameToId(bi.name()->asPropertyName()) == id) {
    2233           0 :                         found = true;
    2234           0 :                         break;
    2235             :                     }
    2236             :                 }
    2237             :             }
    2238             :         }
    2239             : 
    2240           0 :         *bp = found;
    2241           0 :         return true;
    2242             :     }
    2243             : 
    2244           0 :     bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
    2245             :                  ObjectOpResult& result) const override
    2246             :     {
    2247           0 :         return result.fail(JSMSG_CANT_DELETE);
    2248             :     }
    2249             : };
    2250             : 
    2251             : } /* anonymous namespace */
    2252             : 
    2253             : template<>
    2254             : bool
    2255       12456 : JSObject::is<js::DebugEnvironmentProxy>() const
    2256             : {
    2257       12456 :     return IsDerivedProxyObject(this, &DebugEnvironmentProxyHandler::singleton);
    2258             : }
    2259             : 
    2260             : const char DebugEnvironmentProxyHandler::family = 0;
    2261             : const DebugEnvironmentProxyHandler DebugEnvironmentProxyHandler::singleton;
    2262             : 
    2263             : /* static */ DebugEnvironmentProxy*
    2264           0 : DebugEnvironmentProxy::create(JSContext* cx, EnvironmentObject& env, HandleObject enclosing)
    2265             : {
    2266           0 :     MOZ_ASSERT(env.compartment() == cx->compartment());
    2267           0 :     MOZ_ASSERT(!enclosing->is<EnvironmentObject>());
    2268             : 
    2269           0 :     RootedValue priv(cx, ObjectValue(env));
    2270           0 :     JSObject* obj = NewProxyObject(cx, &DebugEnvironmentProxyHandler::singleton, priv,
    2271           0 :                                    nullptr /* proto */);
    2272           0 :     if (!obj)
    2273           0 :         return nullptr;
    2274             : 
    2275           0 :     DebugEnvironmentProxy* debugEnv = &obj->as<DebugEnvironmentProxy>();
    2276           0 :     debugEnv->setReservedSlot(ENCLOSING_SLOT, ObjectValue(*enclosing));
    2277           0 :     debugEnv->setReservedSlot(SNAPSHOT_SLOT, NullValue());
    2278             : 
    2279           0 :     return debugEnv;
    2280             : }
    2281             : 
    2282             : EnvironmentObject&
    2283           0 : DebugEnvironmentProxy::environment() const
    2284             : {
    2285           0 :     return target()->as<EnvironmentObject>();
    2286             : }
    2287             : 
    2288             : JSObject&
    2289           0 : DebugEnvironmentProxy::enclosingEnvironment() const
    2290             : {
    2291           0 :     return reservedSlot(ENCLOSING_SLOT).toObject();
    2292             : }
    2293             : 
    2294             : ArrayObject*
    2295           0 : DebugEnvironmentProxy::maybeSnapshot() const
    2296             : {
    2297           0 :     JSObject* obj = reservedSlot(SNAPSHOT_SLOT).toObjectOrNull();
    2298           0 :     return obj ? &obj->as<ArrayObject>() : nullptr;
    2299             : }
    2300             : 
    2301             : void
    2302           0 : DebugEnvironmentProxy::initSnapshot(ArrayObject& o)
    2303             : {
    2304           0 :     MOZ_ASSERT(maybeSnapshot() == nullptr);
    2305           0 :     setReservedSlot(SNAPSHOT_SLOT, ObjectValue(o));
    2306           0 : }
    2307             : 
    2308             : bool
    2309           0 : DebugEnvironmentProxy::isForDeclarative() const
    2310             : {
    2311           0 :     EnvironmentObject& e = environment();
    2312           0 :     return e.is<CallObject>() ||
    2313           0 :            e.is<VarEnvironmentObject>() ||
    2314           0 :            e.is<ModuleEnvironmentObject>() ||
    2315           0 :            e.is<WasmFunctionCallObject>() ||
    2316           0 :            e.is<LexicalEnvironmentObject>();
    2317             : }
    2318             : 
    2319             : /* static */ bool
    2320           0 : DebugEnvironmentProxy::getMaybeSentinelValue(JSContext* cx, Handle<DebugEnvironmentProxy*> env,
    2321             :                                              HandleId id, MutableHandleValue vp)
    2322             : {
    2323           0 :     return DebugEnvironmentProxyHandler::singleton.getMaybeSentinelValue(cx, env, id, vp);
    2324             : }
    2325             : 
    2326             : bool
    2327           0 : DebugEnvironmentProxy::isFunctionEnvironmentWithThis()
    2328             : {
    2329           0 :     return DebugEnvironmentProxyHandler::isFunctionEnvironmentWithThis(environment());
    2330             : }
    2331             : 
    2332             : bool
    2333           0 : DebugEnvironmentProxy::isOptimizedOut() const
    2334             : {
    2335           0 :     EnvironmentObject& e = environment();
    2336             : 
    2337           0 :     if (DebugEnvironments::hasLiveEnvironment(e))
    2338           0 :         return false;
    2339             : 
    2340           0 :     if (e.is<LexicalEnvironmentObject>()) {
    2341           0 :         return !e.as<LexicalEnvironmentObject>().isExtensible() &&
    2342           0 :                !e.as<LexicalEnvironmentObject>().scope().hasEnvironment();
    2343             :     }
    2344             : 
    2345           0 :     if (e.is<CallObject>()) {
    2346           0 :         return !e.as<CallObject>().callee().needsCallObject() &&
    2347           0 :                !maybeSnapshot();
    2348             :     }
    2349             : 
    2350           0 :     return false;
    2351             : }
    2352             : 
    2353             : /*****************************************************************************/
    2354             : 
    2355           0 : DebugEnvironments::DebugEnvironments(JSContext* cx, Zone* zone)
    2356             :  : zone_(zone),
    2357             :    proxiedEnvs(cx),
    2358             :    missingEnvs(cx->runtime()),
    2359           0 :    liveEnvs(cx->runtime())
    2360           0 : {}
    2361             : 
    2362           0 : DebugEnvironments::~DebugEnvironments()
    2363             : {
    2364           0 :     MOZ_ASSERT_IF(missingEnvs.initialized(), missingEnvs.empty());
    2365           0 : }
    2366             : 
    2367             : bool
    2368           0 : DebugEnvironments::init()
    2369             : {
    2370           0 :     return proxiedEnvs.init() && missingEnvs.init() && liveEnvs.init();
    2371             : }
    2372             : 
    2373             : void
    2374           0 : DebugEnvironments::trace(JSTracer* trc)
    2375             : {
    2376           0 :     proxiedEnvs.trace(trc);
    2377           0 : }
    2378             : 
    2379             : void
    2380           0 : DebugEnvironments::sweep(JSRuntime* rt)
    2381             : {
    2382             :     /*
    2383             :      * missingEnvs points to debug envs weakly so that debug envs can be
    2384             :      * released more eagerly.
    2385             :      */
    2386           0 :     for (MissingEnvironmentMap::Enum e(missingEnvs); !e.empty(); e.popFront()) {
    2387           0 :         if (IsAboutToBeFinalized(&e.front().value())) {
    2388             :             /*
    2389             :              * Note that onPopCall, onPopVar, and onPopLexical rely on
    2390             :              * missingEnvs to find environment objects that we synthesized for
    2391             :              * the debugger's sake, and clean up the synthetic environment
    2392             :              * objects' entries in liveEnvs. So if we remove an entry from
    2393             :              * missingEnvs here, we must also remove the corresponding
    2394             :              * liveEnvs entry.
    2395             :              *
    2396             :              * Since the DebugEnvironmentProxy is the only thing using its environment
    2397             :              * object, and the DSO is about to be finalized, you might assume
    2398             :              * that the synthetic SO is also about to be finalized too, and thus
    2399             :              * the loop below will take care of things. But complex GC behavior
    2400             :              * means that marks are only conservative approximations of
    2401             :              * liveness; we should assume that anything could be marked.
    2402             :              *
    2403             :              * Thus, we must explicitly remove the entries from both liveEnvs
    2404             :              * and missingEnvs here.
    2405             :              */
    2406           0 :             liveEnvs.remove(&e.front().value().unbarrieredGet()->environment());
    2407           0 :             e.removeFront();
    2408             :         } else {
    2409           0 :             MissingEnvironmentKey key = e.front().key();
    2410           0 :             if (IsForwarded(key.scope())) {
    2411           0 :                 key.updateScope(Forwarded(key.scope()));
    2412           0 :                 e.rekeyFront(key);
    2413             :             }
    2414             :         }
    2415             :     }
    2416             : 
    2417             :     /*
    2418             :      * Scopes can be finalized when a debugger-synthesized EnvironmentObject is
    2419             :      * no longer reachable via its DebugEnvironmentProxy.
    2420             :      */
    2421           0 :     liveEnvs.sweep();
    2422           0 : }
    2423             : 
    2424             : void
    2425           0 : DebugEnvironments::finish()
    2426             : {
    2427           0 :     proxiedEnvs.clear();
    2428           0 : }
    2429             : 
    2430             : #ifdef JSGC_HASH_TABLE_CHECKS
    2431             : void
    2432           0 : DebugEnvironments::checkHashTablesAfterMovingGC(JSRuntime* runtime)
    2433             : {
    2434             :     /*
    2435             :      * This is called at the end of StoreBuffer::mark() to check that our
    2436             :      * postbarriers have worked and that no hashtable keys (or values) are left
    2437             :      * pointing into the nursery.
    2438             :      */
    2439           0 :     proxiedEnvs.checkAfterMovingGC();
    2440           0 :     for (MissingEnvironmentMap::Range r = missingEnvs.all(); !r.empty(); r.popFront()) {
    2441           0 :         CheckGCThingAfterMovingGC(r.front().key().scope());
    2442           0 :         CheckGCThingAfterMovingGC(r.front().value().get());
    2443             :     }
    2444           0 :     for (LiveEnvironmentMap::Range r = liveEnvs.all(); !r.empty(); r.popFront()) {
    2445           0 :         CheckGCThingAfterMovingGC(r.front().key());
    2446           0 :         CheckGCThingAfterMovingGC(r.front().value().scope_.get());
    2447             :     }
    2448           0 : }
    2449             : #endif
    2450             : 
    2451             : /*
    2452             :  * Unfortunately, GetDebugEnvironmentForFrame needs to work even outside debug mode
    2453             :  * (in particular, JS_GetFrameScopeChain does not require debug mode). Since
    2454             :  * DebugEnvironments::onPop* are only called in debuggee frames, this means we
    2455             :  * cannot use any of the maps in DebugEnvironments. This will produce debug scope
    2456             :  * chains that do not obey the debugger invariants but that is just fine.
    2457             :  */
    2458             : static bool
    2459           0 : CanUseDebugEnvironmentMaps(JSContext* cx)
    2460             : {
    2461           0 :     return cx->compartment()->isDebuggee();
    2462             : }
    2463             : 
    2464             : DebugEnvironments*
    2465           0 : DebugEnvironments::ensureCompartmentData(JSContext* cx)
    2466             : {
    2467           0 :     JSCompartment* c = cx->compartment();
    2468           0 :     if (c->debugEnvs)
    2469           0 :         return c->debugEnvs;
    2470             : 
    2471           0 :     auto debugEnvs = cx->make_unique<DebugEnvironments>(cx, cx->zone());
    2472           0 :     if (!debugEnvs || !debugEnvs->init()) {
    2473           0 :         ReportOutOfMemory(cx);
    2474           0 :         return nullptr;
    2475             :     }
    2476             : 
    2477           0 :     c->debugEnvs = debugEnvs.release();
    2478           0 :     return c->debugEnvs;
    2479             : }
    2480             : 
    2481             : /* static */ DebugEnvironmentProxy*
    2482           0 : DebugEnvironments::hasDebugEnvironment(JSContext* cx, EnvironmentObject& env)
    2483             : {
    2484           0 :     DebugEnvironments* envs = env.compartment()->debugEnvs;
    2485           0 :     if (!envs)
    2486           0 :         return nullptr;
    2487             : 
    2488           0 :     if (JSObject* obj = envs->proxiedEnvs.lookup(&env)) {
    2489           0 :         MOZ_ASSERT(CanUseDebugEnvironmentMaps(cx));
    2490           0 :         return &obj->as<DebugEnvironmentProxy>();
    2491             :     }
    2492             : 
    2493           0 :     return nullptr;
    2494             : }
    2495             : 
    2496             : /* static */ bool
    2497           0 : DebugEnvironments::addDebugEnvironment(JSContext* cx, Handle<EnvironmentObject*> env,
    2498             :                                        Handle<DebugEnvironmentProxy*> debugEnv)
    2499             : {
    2500           0 :     MOZ_ASSERT(cx->compartment() == env->compartment());
    2501           0 :     MOZ_ASSERT(cx->compartment() == debugEnv->compartment());
    2502             : 
    2503           0 :     if (!CanUseDebugEnvironmentMaps(cx))
    2504           0 :         return true;
    2505             : 
    2506           0 :     DebugEnvironments* envs = ensureCompartmentData(cx);
    2507           0 :     if (!envs)
    2508           0 :         return false;
    2509             : 
    2510           0 :     return envs->proxiedEnvs.add(cx, env, debugEnv);
    2511             : }
    2512             : 
    2513             : /* static */ DebugEnvironmentProxy*
    2514           0 : DebugEnvironments::hasDebugEnvironment(JSContext* cx, const EnvironmentIter& ei)
    2515             : {
    2516           0 :     MOZ_ASSERT(!ei.hasSyntacticEnvironment());
    2517             : 
    2518           0 :     DebugEnvironments* envs = cx->compartment()->debugEnvs;
    2519           0 :     if (!envs)
    2520           0 :         return nullptr;
    2521             : 
    2522           0 :     if (MissingEnvironmentMap::Ptr p = envs->missingEnvs.lookup(MissingEnvironmentKey(ei))) {
    2523           0 :         MOZ_ASSERT(CanUseDebugEnvironmentMaps(cx));
    2524           0 :         return p->value();
    2525             :     }
    2526           0 :     return nullptr;
    2527             : }
    2528             : 
    2529             : /* static */ bool
    2530           0 : DebugEnvironments::addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei,
    2531             :                                        Handle<DebugEnvironmentProxy*> debugEnv)
    2532             : {
    2533           0 :     MOZ_ASSERT(!ei.hasSyntacticEnvironment());
    2534           0 :     MOZ_ASSERT(cx->compartment() == debugEnv->compartment());
    2535             :     // Generators should always have environments.
    2536           0 :     MOZ_ASSERT_IF(ei.scope().is<FunctionScope>(),
    2537             :                   !ei.scope().as<FunctionScope>().canonicalFunction()->isStarGenerator() &&
    2538             :                   !ei.scope().as<FunctionScope>().canonicalFunction()->isLegacyGenerator() &&
    2539             :                   !ei.scope().as<FunctionScope>().canonicalFunction()->isAsync());
    2540             : 
    2541           0 :     if (!CanUseDebugEnvironmentMaps(cx))
    2542           0 :         return true;
    2543             : 
    2544           0 :     DebugEnvironments* envs = ensureCompartmentData(cx);
    2545           0 :     if (!envs)
    2546           0 :         return false;
    2547             : 
    2548           0 :     MissingEnvironmentKey key(ei);
    2549           0 :     MOZ_ASSERT(!envs->missingEnvs.has(key));
    2550           0 :     if (!envs->missingEnvs.put(key, ReadBarriered<DebugEnvironmentProxy*>(debugEnv))) {
    2551           0 :         ReportOutOfMemory(cx);
    2552           0 :         return false;
    2553             :     }
    2554             : 
    2555             :     // Only add to liveEnvs if we synthesized the debug env on a live
    2556             :     // frame.
    2557           0 :     if (ei.withinInitialFrame()) {
    2558           0 :         MOZ_ASSERT(!envs->liveEnvs.has(&debugEnv->environment()));
    2559           0 :         if (!envs->liveEnvs.put(&debugEnv->environment(), LiveEnvironmentVal(ei))) {
    2560           0 :             ReportOutOfMemory(cx);
    2561           0 :             return false;
    2562             :         }
    2563             :     }
    2564             : 
    2565           0 :     return true;
    2566             : }
    2567             : 
    2568             : /* static */ void
    2569           0 : DebugEnvironments::takeFrameSnapshot(JSContext* cx, Handle<DebugEnvironmentProxy*> debugEnv,
    2570             :                                      AbstractFramePtr frame)
    2571             : {
    2572             :     /*
    2573             :      * When the JS stack frame is popped, the values of unaliased variables
    2574             :      * are lost. If there is any debug env referring to this environment, save a
    2575             :      * copy of the unaliased variables' values in an array for later debugger
    2576             :      * access via DebugEnvironmentProxy::handleUnaliasedAccess.
    2577             :      *
    2578             :      * Note: since it is simplest for this function to be infallible, failure
    2579             :      * in this code will be silently ignored. This does not break any
    2580             :      * invariants since DebugEnvironmentProxy::maybeSnapshot can already be nullptr.
    2581             :      */
    2582             : 
    2583             :     // Act like no snapshot was taken if we run OOM while taking the snapshot.
    2584           0 :     Rooted<GCVector<Value>> vec(cx, GCVector<Value>(cx));
    2585           0 :     if (debugEnv->environment().is<CallObject>()) {
    2586           0 :         JSScript* script = frame.script();
    2587             : 
    2588           0 :         FunctionScope* scope = &script->bodyScope()->as<FunctionScope>();
    2589           0 :         uint32_t frameSlotCount = scope->nextFrameSlot();
    2590           0 :         MOZ_ASSERT(frameSlotCount <= script->nfixed());
    2591             : 
    2592             :         // For simplicity, copy all frame slots from 0 to the frameSlotCount,
    2593             :         // even if we don't need all of them (like in the case of a defaults
    2594             :         // parameter scope having frame slots).
    2595           0 :         uint32_t numFormals = frame.numFormalArgs();
    2596           0 :         if (!vec.resize(numFormals + frameSlotCount)) {
    2597           0 :             cx->recoverFromOutOfMemory();
    2598           0 :             return;
    2599             :         }
    2600           0 :         mozilla::PodCopy(vec.begin(), frame.argv(), numFormals);
    2601           0 :         for (uint32_t slot = 0; slot < frameSlotCount; slot++)
    2602           0 :             vec[slot + frame.numFormalArgs()].set(frame.unaliasedLocal(slot));
    2603             : 
    2604             :         /*
    2605             :          * Copy in formals that are not aliased via the scope chain
    2606             :          * but are aliased via the arguments object.
    2607             :          */
    2608           0 :         if (script->analyzedArgsUsage() && script->needsArgsObj() && frame.hasArgsObj()) {
    2609           0 :             for (unsigned i = 0; i < frame.numFormalArgs(); ++i) {
    2610           0 :                 if (script->formalLivesInArgumentsObject(i))
    2611           0 :                     vec[i].set(frame.argsObj().arg(i));
    2612             :             }
    2613             :         }
    2614             :     } else {
    2615             :         uint32_t frameSlotStart;
    2616             :         uint32_t frameSlotEnd;
    2617             : 
    2618           0 :         if (debugEnv->environment().is<LexicalEnvironmentObject>()) {
    2619           0 :             LexicalScope* scope = &debugEnv->environment().as<LexicalEnvironmentObject>().scope();
    2620           0 :             frameSlotStart = scope->firstFrameSlot();
    2621           0 :             frameSlotEnd = scope->nextFrameSlot();
    2622             :         } else {
    2623           0 :             VarEnvironmentObject* env = &debugEnv->environment().as<VarEnvironmentObject>();
    2624           0 :             if (frame.isFunctionFrame()) {
    2625           0 :                 VarScope* scope = &env->scope().as<VarScope>();
    2626           0 :                 frameSlotStart = scope->firstFrameSlot();
    2627           0 :                 frameSlotEnd = scope->nextFrameSlot();
    2628             :             } else {
    2629           0 :                 EvalScope* scope = &env->scope().as<EvalScope>();
    2630           0 :                 MOZ_ASSERT(scope == frame.script()->bodyScope());
    2631           0 :                 frameSlotStart = 0;
    2632           0 :                 frameSlotEnd = scope->nextFrameSlot();
    2633             :             }
    2634             :         }
    2635             : 
    2636           0 :         uint32_t frameSlotCount = frameSlotEnd - frameSlotStart;
    2637           0 :         MOZ_ASSERT(frameSlotCount <= frame.script()->nfixed());
    2638             : 
    2639           0 :         if (!vec.resize(frameSlotCount)) {
    2640           0 :             cx->recoverFromOutOfMemory();
    2641           0 :             return;
    2642             :         }
    2643           0 :         for (uint32_t slot = frameSlotStart; slot < frameSlotCount; slot++)
    2644           0 :             vec[slot - frameSlotStart].set(frame.unaliasedLocal(slot));
    2645             :     }
    2646             : 
    2647           0 :     if (vec.length() == 0)
    2648           0 :         return;
    2649             : 
    2650             :     /*
    2651             :      * Use a dense array as storage (since proxies do not have trace
    2652             :      * hooks). This array must not escape into the wild.
    2653             :      */
    2654           0 :     RootedArrayObject snapshot(cx, NewDenseCopiedArray(cx, vec.length(), vec.begin()));
    2655           0 :     if (!snapshot) {
    2656           0 :         cx->recoverFromOutOfMemory();
    2657           0 :         return;
    2658             :     }
    2659             : 
    2660           0 :     debugEnv->initSnapshot(*snapshot);
    2661             : }
    2662             : 
    2663             : /* static */ void
    2664           0 : DebugEnvironments::onPopCall(JSContext* cx, AbstractFramePtr frame)
    2665             : {
    2666           0 :     assertSameCompartment(cx, frame);
    2667             : 
    2668           0 :     DebugEnvironments* envs = cx->compartment()->debugEnvs;
    2669           0 :     if (!envs)
    2670           0 :         return;
    2671             : 
    2672           0 :     Rooted<DebugEnvironmentProxy*> debugEnv(cx, nullptr);
    2673             : 
    2674           0 :     FunctionScope* funScope = &frame.script()->bodyScope()->as<FunctionScope>();
    2675           0 :     if (funScope->hasEnvironment()) {
    2676           0 :         MOZ_ASSERT(frame.callee()->needsCallObject());
    2677             : 
    2678             :         /*
    2679             :          * The frame may be observed before the prologue has created the
    2680             :          * CallObject. See EnvironmentIter::settle.
    2681             :          */
    2682           0 :         if (!frame.environmentChain()->is<CallObject>())
    2683           0 :             return;
    2684             : 
    2685           0 :         if (frame.callee()->isStarGenerator() || frame.callee()->isLegacyGenerator() ||
    2686           0 :             frame.callee()->isAsync())
    2687             :         {
    2688           0 :             return;
    2689             :         }
    2690             : 
    2691           0 :         CallObject& callobj = frame.environmentChain()->as<CallObject>();
    2692           0 :         envs->liveEnvs.remove(&callobj);
    2693           0 :         if (JSObject* obj = envs->proxiedEnvs.lookup(&callobj))
    2694           0 :             debugEnv = &obj->as<DebugEnvironmentProxy>();
    2695             :     } else {
    2696           0 :         MissingEnvironmentKey key(frame, funScope);
    2697           0 :         if (MissingEnvironmentMap::Ptr p = envs->missingEnvs.lookup(key)) {
    2698           0 :             debugEnv = p->value();
    2699           0 :             envs->liveEnvs.remove(&debugEnv->environment().as<CallObject>());
    2700           0 :             envs->missingEnvs.remove(p);
    2701             :         }
    2702             :     }
    2703             : 
    2704           0 :     if (debugEnv)
    2705           0 :         DebugEnvironments::takeFrameSnapshot(cx, debugEnv, frame);
    2706             : }
    2707             : 
    2708             : void
    2709           0 : DebugEnvironments::onPopLexical(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc)
    2710             : {
    2711           0 :     assertSameCompartment(cx, frame);
    2712             : 
    2713           0 :     DebugEnvironments* envs = cx->compartment()->debugEnvs;
    2714           0 :     if (!envs)
    2715           0 :         return;
    2716             : 
    2717           0 :     EnvironmentIter ei(cx, frame, pc);
    2718           0 :     onPopLexical(cx, ei);
    2719             : }
    2720             : 
    2721             : template <typename Environment, typename Scope>
    2722             : void
    2723           0 : DebugEnvironments::onPopGeneric(JSContext* cx, const EnvironmentIter& ei)
    2724             : {
    2725           0 :     DebugEnvironments* envs = cx->compartment()->debugEnvs;
    2726           0 :     if (!envs)
    2727           0 :         return;
    2728             : 
    2729           0 :     MOZ_ASSERT(ei.withinInitialFrame());
    2730           0 :     MOZ_ASSERT(ei.scope().is<Scope>());
    2731             : 
    2732           0 :     Rooted<Environment*> env(cx);
    2733           0 :     if (MissingEnvironmentMap::Ptr p = envs->missingEnvs.lookup(MissingEnvironmentKey(ei))) {
    2734           0 :         env = &p->value()->environment().as<Environment>();
    2735           0 :         envs->missingEnvs.remove(p);
    2736           0 :     } else if (ei.hasSyntacticEnvironment()) {
    2737           0 :         env = &ei.environment().as<Environment>();
    2738             :     }
    2739             : 
    2740           0 :     if (env) {
    2741           0 :         envs->liveEnvs.remove(env);
    2742             : 
    2743           0 :         if (JSObject* obj = envs->proxiedEnvs.lookup(env)) {
    2744           0 :             Rooted<DebugEnvironmentProxy*> debugEnv(cx, &obj->as<DebugEnvironmentProxy>());
    2745           0 :             DebugEnvironments::takeFrameSnapshot(cx, debugEnv, ei.initialFrame());
    2746             :         }
    2747             :     }
    2748             : }
    2749             : 
    2750             : void
    2751           0 : DebugEnvironments::onPopLexical(JSContext* cx, const EnvironmentIter& ei)
    2752             : {
    2753           0 :     onPopGeneric<LexicalEnvironmentObject, LexicalScope>(cx, ei);
    2754           0 : }
    2755             : 
    2756             : void
    2757           0 : DebugEnvironments::onPopVar(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc)
    2758             : {
    2759           0 :     assertSameCompartment(cx, frame);
    2760             : 
    2761           0 :     DebugEnvironments* envs = cx->compartment()->debugEnvs;
    2762           0 :     if (!envs)
    2763           0 :         return;
    2764             : 
    2765           0 :     EnvironmentIter ei(cx, frame, pc);
    2766           0 :     onPopVar(cx, ei);
    2767             : }
    2768             : 
    2769             : void
    2770           0 : DebugEnvironments::onPopVar(JSContext* cx, const EnvironmentIter& ei)
    2771             : {
    2772           0 :     if (ei.scope().is<EvalScope>())
    2773           0 :         onPopGeneric<VarEnvironmentObject, EvalScope>(cx, ei);
    2774             :     else
    2775           0 :         onPopGeneric<VarEnvironmentObject, VarScope>(cx, ei);
    2776           0 : }
    2777             : 
    2778             : void
    2779           0 : DebugEnvironments::onPopWith(AbstractFramePtr frame)
    2780             : {
    2781           0 :     if (DebugEnvironments* envs = frame.compartment()->debugEnvs)
    2782           0 :         envs->liveEnvs.remove(&frame.environmentChain()->as<WithEnvironmentObject>());
    2783           0 : }
    2784             : 
    2785             : void
    2786           0 : DebugEnvironments::onCompartmentUnsetIsDebuggee(JSCompartment* c)
    2787             : {
    2788           0 :     if (DebugEnvironments* envs = c->debugEnvs) {
    2789           0 :         envs->proxiedEnvs.clear();
    2790           0 :         envs->missingEnvs.clear();
    2791           0 :         envs->liveEnvs.clear();
    2792             :     }
    2793           0 : }
    2794             : 
    2795             : bool
    2796           0 : DebugEnvironments::updateLiveEnvironments(JSContext* cx)
    2797             : {
    2798           0 :     if (!CheckRecursionLimit(cx))
    2799           0 :         return false;
    2800             : 
    2801             :     /*
    2802             :      * Note that we must always update the top frame's environment objects'
    2803             :      * entries in liveEnvs because we can't be sure code hasn't run in that
    2804             :      * frame to change the environment chain since we were last called. The
    2805             :      * fp->prevUpToDate() flag indicates whether the environments of frames
    2806             :      * older than fp are already included in liveEnvs. It might seem simpler
    2807             :      * to have fp instead carry a flag indicating whether fp itself is
    2808             :      * accurately described, but then we would need to clear that flag
    2809             :      * whenever fp ran code. By storing the 'up to date' bit for fp->prev() in
    2810             :      * fp, simply popping fp effectively clears the flag for us, at exactly
    2811             :      * the time when execution resumes fp->prev().
    2812             :      */
    2813           0 :     for (AllFramesIter i(cx); !i.done(); ++i) {
    2814           0 :         if (!i.hasUsableAbstractFramePtr())
    2815           0 :             continue;
    2816             : 
    2817           0 :         AbstractFramePtr frame = i.abstractFramePtr();
    2818           0 :         if (frame.environmentChain()->compartment() != cx->compartment())
    2819           0 :             continue;
    2820             : 
    2821           0 :         if (frame.isFunctionFrame()) {
    2822           0 :             if (frame.callee()->isStarGenerator() || frame.callee()->isLegacyGenerator() ||
    2823           0 :                 frame.callee()->isAsync())
    2824             :             {
    2825           0 :                 continue;
    2826             :             }
    2827             :         }
    2828             : 
    2829           0 :         if (!frame.isDebuggee())
    2830           0 :             continue;
    2831             : 
    2832           0 :         RootedObject env(cx);
    2833           0 :         RootedScope scope(cx);
    2834           0 :         if (!GetFrameEnvironmentAndScope(cx, frame, i.pc(), &env, &scope))
    2835           0 :             return false;
    2836             : 
    2837           0 :         for (EnvironmentIter ei(cx, env, scope, frame); ei.withinInitialFrame(); ei++) {
    2838           0 :             if (ei.hasSyntacticEnvironment() && !ei.scope().is<GlobalScope>()) {
    2839           0 :                 MOZ_ASSERT(ei.environment().compartment() == cx->compartment());
    2840           0 :                 DebugEnvironments* envs = ensureCompartmentData(cx);
    2841           0 :                 if (!envs)
    2842           0 :                     return false;
    2843           0 :                 if (!envs->liveEnvs.put(&ei.environment(), LiveEnvironmentVal(ei)))
    2844           0 :                     return false;
    2845             :             }
    2846             :         }
    2847             : 
    2848           0 :         if (frame.prevUpToDate())
    2849           0 :             return true;
    2850           0 :         MOZ_ASSERT(frame.environmentChain()->compartment()->isDebuggee());
    2851           0 :         frame.setPrevUpToDate();
    2852             :     }
    2853             : 
    2854           0 :     return true;
    2855             : }
    2856             : 
    2857             : LiveEnvironmentVal*
    2858           0 : DebugEnvironments::hasLiveEnvironment(EnvironmentObject& env)
    2859             : {
    2860           0 :     DebugEnvironments* envs = env.compartment()->debugEnvs;
    2861           0 :     if (!envs)
    2862           0 :         return nullptr;
    2863             : 
    2864           0 :     if (LiveEnvironmentMap::Ptr p = envs->liveEnvs.lookup(&env))
    2865           0 :         return &p->value();
    2866             : 
    2867           0 :     return nullptr;
    2868             : }
    2869             : 
    2870             : /* static */ void
    2871           0 : DebugEnvironments::unsetPrevUpToDateUntil(JSContext* cx, AbstractFramePtr until)
    2872             : {
    2873             :     // This are two exceptions where fp->prevUpToDate() is cleared without
    2874             :     // popping the frame. When a frame is rematerialized or has its
    2875             :     // debuggeeness toggled off->on, all frames younger than the frame must
    2876             :     // have their prevUpToDate set to false. This is because unrematerialized
    2877             :     // Ion frames and non-debuggee frames are skipped by updateLiveEnvironments. If
    2878             :     // in the future a frame suddenly gains a usable AbstractFramePtr via
    2879             :     // rematerialization or becomes a debuggee, the prevUpToDate invariant
    2880             :     // will no longer hold for older frames on its stack.
    2881           0 :     for (AllFramesIter i(cx); !i.done(); ++i) {
    2882           0 :         if (!i.hasUsableAbstractFramePtr())
    2883           0 :             continue;
    2884             : 
    2885           0 :         AbstractFramePtr frame = i.abstractFramePtr();
    2886           0 :         if (frame == until)
    2887           0 :             return;
    2888             : 
    2889           0 :         if (frame.environmentChain()->compartment() != cx->compartment())
    2890           0 :             continue;
    2891             : 
    2892           0 :         frame.unsetPrevUpToDate();
    2893             :     }
    2894             : }
    2895             : 
    2896             : /* static */ void
    2897           0 : DebugEnvironments::forwardLiveFrame(JSContext* cx, AbstractFramePtr from, AbstractFramePtr to)
    2898             : {
    2899           0 :     DebugEnvironments* envs = cx->compartment()->debugEnvs;
    2900           0 :     if (!envs)
    2901           0 :         return;
    2902             : 
    2903           0 :     for (MissingEnvironmentMap::Enum e(envs->missingEnvs); !e.empty(); e.popFront()) {
    2904           0 :         MissingEnvironmentKey key = e.front().key();
    2905           0 :         if (key.frame() == from) {
    2906           0 :             key.updateFrame(to);
    2907           0 :             e.rekeyFront(key);
    2908             :         }
    2909             :     }
    2910             : 
    2911           0 :     for (LiveEnvironmentMap::Enum e(envs->liveEnvs); !e.empty(); e.popFront()) {
    2912           0 :         LiveEnvironmentVal& val = e.front().value();
    2913           0 :         if (val.frame() == from)
    2914           0 :             val.updateFrame(to);
    2915             :     }
    2916             : }
    2917             : 
    2918             : /* static */ void
    2919           0 : DebugEnvironments::traceLiveFrame(JSTracer* trc, AbstractFramePtr frame)
    2920             : {
    2921           0 :     for (MissingEnvironmentMap::Enum e(missingEnvs); !e.empty(); e.popFront()) {
    2922           0 :         if (e.front().key().frame() == frame)
    2923           0 :             TraceEdge(trc, &e.front().value(), "debug-env-live-frame-missing-env");
    2924             :     }
    2925           0 : }
    2926             : 
    2927             : /*****************************************************************************/
    2928             : 
    2929             : static JSObject*
    2930             : GetDebugEnvironment(JSContext* cx, const EnvironmentIter& ei);
    2931             : 
    2932             : static DebugEnvironmentProxy*
    2933           0 : GetDebugEnvironmentForEnvironmentObject(JSContext* cx, const EnvironmentIter& ei)
    2934             : {
    2935           0 :     Rooted<EnvironmentObject*> env(cx, &ei.environment());
    2936           0 :     if (DebugEnvironmentProxy* debugEnv = DebugEnvironments::hasDebugEnvironment(cx, *env))
    2937           0 :         return debugEnv;
    2938             : 
    2939           0 :     EnvironmentIter copy(cx, ei);
    2940           0 :     RootedObject enclosingDebug(cx, GetDebugEnvironment(cx, ++copy));
    2941           0 :     if (!enclosingDebug)
    2942           0 :         return nullptr;
    2943             : 
    2944             :     Rooted<DebugEnvironmentProxy*> debugEnv(cx,
    2945           0 :         DebugEnvironmentProxy::create(cx, *env, enclosingDebug));
    2946           0 :     if (!debugEnv)
    2947           0 :         return nullptr;
    2948             : 
    2949           0 :     if (!DebugEnvironments::addDebugEnvironment(cx, env, debugEnv))
    2950           0 :         return nullptr;
    2951             : 
    2952           0 :     return debugEnv;
    2953             : }
    2954             : 
    2955             : static DebugEnvironmentProxy*
    2956           0 : GetDebugEnvironmentForMissing(JSContext* cx, const EnvironmentIter& ei)
    2957             : {
    2958           0 :     MOZ_ASSERT(!ei.hasSyntacticEnvironment() &&
    2959             :                (ei.scope().is<FunctionScope>() ||
    2960             :                 ei.scope().is<LexicalScope>() ||
    2961             :                 ei.scope().is<WasmFunctionScope>() ||
    2962             :                 ei.scope().is<VarScope>()));
    2963             : 
    2964           0 :     if (DebugEnvironmentProxy* debugEnv = DebugEnvironments::hasDebugEnvironment(cx, ei))
    2965           0 :         return debugEnv;
    2966             : 
    2967           0 :     EnvironmentIter copy(cx, ei);
    2968           0 :     RootedObject enclosingDebug(cx, GetDebugEnvironment(cx, ++copy));
    2969           0 :     if (!enclosingDebug)
    2970           0 :         return nullptr;
    2971             : 
    2972             :     /*
    2973             :      * Create the missing environment object. For lexical environment objects,
    2974             :      * this takes care of storing variable values after the stack frame has
    2975             :      * been popped. For call objects, we only use the pretend call object to
    2976             :      * access callee, bindings and to receive dynamically added
    2977             :      * properties. Together, this provides the nice invariant that every
    2978             :      * DebugEnvironmentProxy has a EnvironmentObject.
    2979             :      *
    2980             :      * Note: to preserve envChain depth invariants, these lazily-reified
    2981             :      * envs must not be put on the frame's environment chain; instead, they are
    2982             :      * maintained via DebugEnvironments hooks.
    2983             :      */
    2984           0 :     Rooted<DebugEnvironmentProxy*> debugEnv(cx);
    2985           0 :     if (ei.scope().is<FunctionScope>()) {
    2986           0 :         RootedFunction callee(cx, ei.scope().as<FunctionScope>().canonicalFunction());
    2987             :         // Generators should always reify their scopes.
    2988           0 :         MOZ_ASSERT(!callee->isStarGenerator() && !callee->isLegacyGenerator() &&
    2989             :                    !callee->isAsync());
    2990             : 
    2991           0 :         JS::ExposeObjectToActiveJS(callee);
    2992           0 :         Rooted<CallObject*> callobj(cx, CallObject::createHollowForDebug(cx, callee));
    2993           0 :         if (!callobj)
    2994           0 :             return nullptr;
    2995             : 
    2996           0 :         debugEnv = DebugEnvironmentProxy::create(cx, *callobj, enclosingDebug);
    2997           0 :     } else if (ei.scope().is<LexicalScope>()) {
    2998           0 :         Rooted<LexicalScope*> lexicalScope(cx, &ei.scope().as<LexicalScope>());
    2999             :         Rooted<LexicalEnvironmentObject*> env(cx,
    3000           0 :             LexicalEnvironmentObject::createHollowForDebug(cx, lexicalScope));
    3001           0 :         if (!env)
    3002           0 :             return nullptr;
    3003             : 
    3004           0 :         debugEnv = DebugEnvironmentProxy::create(cx, *env, enclosingDebug);
    3005           0 :     } else if (ei.scope().is<WasmFunctionScope>()) {
    3006           0 :         Rooted<WasmFunctionScope*> wasmFunctionScope(cx, &ei.scope().as<WasmFunctionScope>());
    3007           0 :         Rooted<WasmFunctionCallObject*> callobj(cx, WasmFunctionCallObject::createHollowForDebug(cx, wasmFunctionScope));
    3008           0 :         if (!callobj)
    3009           0 :             return nullptr;
    3010             : 
    3011           0 :         debugEnv = DebugEnvironmentProxy::create(cx, *callobj, enclosingDebug);
    3012             :     } else {
    3013           0 :         Rooted<VarScope*> varScope(cx, &ei.scope().as<VarScope>());
    3014             :         Rooted<VarEnvironmentObject*> env(cx,
    3015           0 :             VarEnvironmentObject::createHollowForDebug(cx, varScope));
    3016           0 :         if (!env)
    3017           0 :             return nullptr;
    3018             : 
    3019           0 :         debugEnv = DebugEnvironmentProxy::create(cx, *env, enclosingDebug);
    3020             :     }
    3021             : 
    3022           0 :     if (!debugEnv)
    3023           0 :         return nullptr;
    3024             : 
    3025           0 :     if (!DebugEnvironments::addDebugEnvironment(cx, ei, debugEnv))
    3026           0 :         return nullptr;
    3027             : 
    3028           0 :     return debugEnv;
    3029             : }
    3030             : 
    3031             : static JSObject*
    3032           0 : GetDebugEnvironmentForNonEnvironmentObject(const EnvironmentIter& ei)
    3033             : {
    3034           0 :     JSObject& enclosing = ei.enclosingEnvironment();
    3035             : #ifdef DEBUG
    3036           0 :     JSObject* o = &enclosing;
    3037           0 :     while ((o = o->enclosingEnvironment()))
    3038           0 :         MOZ_ASSERT(!o->is<EnvironmentObject>());
    3039             : #endif
    3040           0 :     return &enclosing;
    3041             : }
    3042             : 
    3043             : static JSObject*
    3044           0 : GetDebugEnvironment(JSContext* cx, const EnvironmentIter& ei)
    3045             : {
    3046           0 :     if (!CheckRecursionLimit(cx))
    3047           0 :         return nullptr;
    3048             : 
    3049           0 :     if (ei.done())
    3050           0 :         return GetDebugEnvironmentForNonEnvironmentObject(ei);
    3051             : 
    3052           0 :     if (ei.hasAnyEnvironmentObject())
    3053           0 :         return GetDebugEnvironmentForEnvironmentObject(cx, ei);
    3054             : 
    3055           0 :     if (ei.scope().is<FunctionScope>() ||
    3056           0 :         ei.scope().is<LexicalScope>() ||
    3057           0 :         ei.scope().is<WasmFunctionScope>() ||
    3058           0 :         ei.scope().is<VarScope>())
    3059             :     {
    3060           0 :         return GetDebugEnvironmentForMissing(cx, ei);
    3061             :     }
    3062             : 
    3063           0 :     EnvironmentIter copy(cx, ei);
    3064           0 :     return GetDebugEnvironment(cx, ++copy);
    3065             : }
    3066             : 
    3067             : JSObject*
    3068           0 : js::GetDebugEnvironmentForFunction(JSContext* cx, HandleFunction fun)
    3069             : {
    3070           0 :     assertSameCompartment(cx, fun);
    3071           0 :     MOZ_ASSERT(CanUseDebugEnvironmentMaps(cx));
    3072           0 :     if (!DebugEnvironments::updateLiveEnvironments(cx))
    3073           0 :         return nullptr;
    3074           0 :     JSScript* script = JSFunction::getOrCreateScript(cx, fun);
    3075           0 :     if (!script)
    3076           0 :         return nullptr;
    3077           0 :     EnvironmentIter ei(cx, fun->environment(), script->enclosingScope());
    3078           0 :     return GetDebugEnvironment(cx, ei);
    3079             : }
    3080             : 
    3081             : JSObject*
    3082           0 : js::GetDebugEnvironmentForFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc)
    3083             : {
    3084           0 :     assertSameCompartment(cx, frame);
    3085           0 :     if (CanUseDebugEnvironmentMaps(cx) && !DebugEnvironments::updateLiveEnvironments(cx))
    3086           0 :         return nullptr;
    3087             : 
    3088           0 :     RootedObject env(cx);
    3089           0 :     RootedScope scope(cx);
    3090           0 :     if (!GetFrameEnvironmentAndScope(cx, frame, pc, &env, &scope))
    3091           0 :         return nullptr;
    3092             : 
    3093           0 :     EnvironmentIter ei(cx, env, scope, frame);
    3094           0 :     return GetDebugEnvironment(cx, ei);
    3095             : }
    3096             : 
    3097             : JSObject*
    3098           0 : js::GetDebugEnvironmentForGlobalLexicalEnvironment(JSContext* cx)
    3099             : {
    3100           0 :     EnvironmentIter ei(cx, &cx->global()->lexicalEnvironment(), &cx->global()->emptyGlobalScope());
    3101           0 :     return GetDebugEnvironment(cx, ei);
    3102             : }
    3103             : 
    3104             : bool
    3105         200 : js::CreateObjectsForEnvironmentChain(JSContext* cx, AutoObjectVector& chain,
    3106             :                                      HandleObject terminatingEnv, MutableHandleObject envObj)
    3107             : {
    3108             : #ifdef DEBUG
    3109        1791 :     for (size_t i = 0; i < chain.length(); ++i) {
    3110        1591 :         assertSameCompartment(cx, chain[i]);
    3111        1591 :         MOZ_ASSERT(!chain[i]->is<GlobalObject>());
    3112             :     }
    3113             : #endif
    3114             : 
    3115             :     // Construct With object wrappers for the things on this environment chain
    3116             :     // and use the result as the thing to scope the function to.
    3117         400 :     Rooted<WithEnvironmentObject*> withEnv(cx);
    3118         400 :     RootedObject enclosingEnv(cx, terminatingEnv);
    3119        1791 :     for (size_t i = chain.length(); i > 0; ) {
    3120        1591 :         withEnv = WithEnvironmentObject::createNonSyntactic(cx, chain[--i], enclosingEnv);
    3121        1591 :         if (!withEnv)
    3122           0 :             return false;
    3123        1591 :         enclosingEnv = withEnv;
    3124             :     }
    3125             : 
    3126         200 :     envObj.set(enclosingEnv);
    3127         200 :     return true;
    3128             : }
    3129             : 
    3130             : JSObject&
    3131        3221 : WithEnvironmentObject::object() const
    3132             : {
    3133        3221 :     return getReservedSlot(OBJECT_SLOT).toObject();
    3134             : }
    3135             : 
    3136             : JSObject*
    3137         490 : WithEnvironmentObject::withThis() const
    3138             : {
    3139         490 :     return &getReservedSlot(THIS_SLOT).toObject();
    3140             : }
    3141             : 
    3142             : bool
    3143        5081 : WithEnvironmentObject::isSyntactic() const
    3144             : {
    3145        5081 :     Value v = getReservedSlot(SCOPE_SLOT);
    3146        5081 :     MOZ_ASSERT(v.isPrivateGCThing() || v.isNull());
    3147        5081 :     return v.isPrivateGCThing();
    3148             : }
    3149             : 
    3150             : WithScope&
    3151           0 : WithEnvironmentObject::scope() const
    3152             : {
    3153           0 :     MOZ_ASSERT(isSyntactic());
    3154           0 :     return *static_cast<WithScope*>(getReservedSlot(SCOPE_SLOT).toGCThing());
    3155             : }
    3156             : 
    3157             : ModuleEnvironmentObject*
    3158           0 : js::GetModuleEnvironmentForScript(JSScript* script)
    3159             : {
    3160           0 :     for (ScopeIter si(script); si; si++) {
    3161           0 :         if (si.kind() == ScopeKind::Module)
    3162           0 :             return si.scope()->as<ModuleScope>().module()->environment();
    3163             :     }
    3164           0 :     return nullptr;
    3165             : }
    3166             : 
    3167             : bool
    3168           0 : js::GetThisValueForDebuggerMaybeOptimizedOut(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc,
    3169             :                                              MutableHandleValue res)
    3170             : {
    3171           0 :     RootedObject scopeChain(cx);
    3172           0 :     RootedScope scope(cx);
    3173           0 :     if (!GetFrameEnvironmentAndScope(cx, frame, pc, &scopeChain, &scope))
    3174           0 :         return false;
    3175             : 
    3176           0 :     for (EnvironmentIter ei(cx, scopeChain, scope, frame); ei; ei++) {
    3177           0 :         if (ei.scope().kind() == ScopeKind::Module) {
    3178           0 :             res.setUndefined();
    3179           0 :             return true;
    3180             :         }
    3181             : 
    3182           0 :         if (!ei.scope().is<FunctionScope>() ||
    3183           0 :             ei.scope().as<FunctionScope>().canonicalFunction()->hasLexicalThis())
    3184             :         {
    3185           0 :             continue;
    3186             :         }
    3187             : 
    3188           0 :         RootedScript script(cx, ei.scope().as<FunctionScope>().script());
    3189             : 
    3190             :         // Figure out if we executed JSOP_FUNCTIONTHIS and set it.
    3191           0 :         bool executedInitThisOp = false;
    3192           0 :         if (script->functionHasThisBinding()) {
    3193           0 :             for (jsbytecode* it = script->code(); it < script->codeEnd(); it = GetNextPc(it)) {
    3194           0 :                 if (*it == JSOP_FUNCTIONTHIS) {
    3195             :                     // The next op after JSOP_FUNCTIONTHIS always sets it.
    3196           0 :                     executedInitThisOp = pc > GetNextPc(it);
    3197           0 :                     break;
    3198             :                 }
    3199             :             }
    3200             :         }
    3201             : 
    3202           0 :         if (ei.withinInitialFrame() && !executedInitThisOp) {
    3203             :             // Either we're yet to initialize the this-binding
    3204             :             // (JSOP_FUNCTIONTHIS), or the script does not have a this-binding
    3205             :             // (because it doesn't use |this|).
    3206             : 
    3207             :             // If our this-argument is an object, or we're in strict mode,
    3208             :             // the this-binding is always the same as our this-argument.
    3209           0 :             if (frame.thisArgument().isObject() || script->strict()) {
    3210           0 :                 res.set(frame.thisArgument());
    3211           0 :                 return true;
    3212             :             }
    3213             : 
    3214             :             // We didn't initialize the this-binding yet. Determine the
    3215             :             // correct |this| value for this frame (box primitives if not
    3216             :             // in strict mode), and assign it to the this-argument slot so
    3217             :             // JSOP_FUNCTIONTHIS will use it and not box a second time.
    3218           0 :             if (!GetFunctionThis(cx, frame, res))
    3219           0 :                 return false;
    3220           0 :             frame.thisArgument() = res;
    3221           0 :             return true;
    3222             :         }
    3223             : 
    3224           0 :         if (!script->functionHasThisBinding()) {
    3225           0 :             res.setMagic(JS_OPTIMIZED_OUT);
    3226           0 :             return true;
    3227             :         }
    3228             : 
    3229           0 :         for (Rooted<BindingIter> bi(cx, BindingIter(script)); bi; bi++) {
    3230           0 :             if (bi.name() != cx->names().dotThis)
    3231           0 :                 continue;
    3232             : 
    3233           0 :             BindingLocation loc = bi.location();
    3234           0 :             if (loc.kind() == BindingLocation::Kind::Environment) {
    3235           0 :                 RootedObject callObj(cx, &ei.environment().as<CallObject>());
    3236           0 :                 return GetProperty(cx, callObj, callObj, bi.name()->asPropertyName(), res);
    3237             :             }
    3238             : 
    3239           0 :             if (loc.kind() == BindingLocation::Kind::Frame && ei.withinInitialFrame())
    3240           0 :                 res.set(frame.unaliasedLocal(loc.slot()));
    3241             :             else
    3242           0 :                 res.setMagic(JS_OPTIMIZED_OUT);
    3243             : 
    3244           0 :             return true;
    3245             :         }
    3246             : 
    3247           0 :         MOZ_CRASH("'this' binding must be found");
    3248             :     }
    3249             : 
    3250           0 :     return GetNonSyntacticGlobalThis(cx, scopeChain, res);
    3251             : }
    3252             : 
    3253             : bool
    3254        4900 : js::CheckLexicalNameConflict(JSContext* cx, Handle<LexicalEnvironmentObject*> lexicalEnv,
    3255             :                              HandleObject varObj, HandlePropertyName name)
    3256             : {
    3257        4900 :     const char* redeclKind = nullptr;
    3258        9800 :     RootedId id(cx, NameToId(name));
    3259        9800 :     RootedShape shape(cx);
    3260        4900 :     if (varObj->is<GlobalObject>() && varObj->compartment()->isInVarNames(name)) {
    3261             :         // ES 15.1.11 step 5.a
    3262           0 :         redeclKind = "var";
    3263        4900 :     } else if ((shape = lexicalEnv->lookup(cx, name))) {
    3264             :         // ES 15.1.11 step 5.b
    3265           0 :         redeclKind = shape->writable() ? "let" : "const";
    3266        4900 :     } else if (varObj->isNative() && (shape = varObj->as<NativeObject>().lookup(cx, name))) {
    3267             :         // Faster path for ES 15.1.11 step 5.c-d when the shape can be found
    3268             :         // without going through a resolve hook.
    3269           2 :         if (!shape->configurable())
    3270           0 :             redeclKind = "non-configurable global property";
    3271             :     } else {
    3272             :         // ES 15.1.11 step 5.c-d
    3273        9796 :         Rooted<PropertyDescriptor> desc(cx);
    3274        4898 :         if (!GetOwnPropertyDescriptor(cx, varObj, id, &desc))
    3275           0 :             return false;
    3276        4898 :         if (desc.object() && desc.hasConfigurable() && !desc.configurable())
    3277           0 :             redeclKind = "non-configurable global property";
    3278             :     }
    3279             : 
    3280        4900 :     if (redeclKind) {
    3281           0 :         ReportRuntimeRedeclaration(cx, name, redeclKind);
    3282           0 :         return false;
    3283             :     }
    3284             : 
    3285        4900 :     return true;
    3286             : }
    3287             : 
    3288             : bool
    3289        2446 : js::CheckVarNameConflict(JSContext* cx, Handle<LexicalEnvironmentObject*> lexicalEnv,
    3290             :                          HandlePropertyName name)
    3291             : {
    3292        2446 :     if (Shape* shape = lexicalEnv->lookup(cx, name)) {
    3293           0 :         ReportRuntimeRedeclaration(cx, name, shape->writable() ? "let" : "const");
    3294           0 :         return false;
    3295             :     }
    3296        2446 :     return true;
    3297             : }
    3298             : 
    3299             : static void
    3300           0 : ReportCannotDeclareGlobalBinding(JSContext* cx, HandlePropertyName name, const char* reason)
    3301             : {
    3302           0 :     JSAutoByteString printable;
    3303           0 :     if (AtomToPrintableString(cx, name, &printable)) {
    3304           0 :         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
    3305             :                                    JSMSG_CANT_DECLARE_GLOBAL_BINDING,
    3306           0 :                                    printable.ptr(), reason);
    3307             :     }
    3308           0 : }
    3309             : 
    3310             : bool
    3311        1645 : js::CheckCanDeclareGlobalBinding(JSContext* cx, Handle<GlobalObject*> global,
    3312             :                                  HandlePropertyName name, bool isFunction)
    3313             : {
    3314        3290 :     RootedId id(cx, NameToId(name));
    3315        3290 :     Rooted<PropertyDescriptor> desc(cx);
    3316        1645 :     if (!GetOwnPropertyDescriptor(cx, global, id, &desc))
    3317           0 :         return false;
    3318             : 
    3319             :     // ES 8.1.1.4.15 CanDeclareGlobalVar
    3320             :     // ES 8.1.1.4.16 CanDeclareGlobalFunction
    3321             : 
    3322             :     // Step 4.
    3323        1645 :     if (!desc.object()) {
    3324             :         // 8.1.14.15 step 6.
    3325             :         // 8.1.14.16 step 5.
    3326        1588 :         if (global->nonProxyIsExtensible())
    3327        1588 :             return true;
    3328             : 
    3329           0 :         ReportCannotDeclareGlobalBinding(cx, name, "global is non-extensible");
    3330           0 :         return false;
    3331             :     }
    3332             : 
    3333             :     // Global functions have additional restrictions.
    3334          57 :     if (isFunction) {
    3335             :         // 8.1.14.16 step 6.
    3336          44 :         if (desc.configurable())
    3337          12 :             return true;
    3338             : 
    3339             :         // 8.1.14.16 step 7.
    3340          32 :         if (desc.isDataDescriptor() && desc.writable() && desc.enumerable())
    3341          32 :             return true;
    3342             : 
    3343             :         ReportCannotDeclareGlobalBinding(cx, name,
    3344             :                                          "property must be configurable or "
    3345           0 :                                          "both writable and enumerable");
    3346           0 :         return false;
    3347             :     }
    3348             : 
    3349          13 :     return true;
    3350             : }
    3351             : 
    3352             : bool
    3353         495 : js::CheckGlobalDeclarationConflicts(JSContext* cx, HandleScript script,
    3354             :                                     Handle<LexicalEnvironmentObject*> lexicalEnv,
    3355             :                                     HandleObject varObj)
    3356             : {
    3357             :     // Due to the extensibility of the global lexical environment, we must
    3358             :     // check for redeclaring a binding.
    3359             :     //
    3360             :     // In the case of non-syntactic environment chains, we are checking
    3361             :     // redeclarations against the non-syntactic lexical environment and the
    3362             :     // variables object that the lexical environment corresponds to.
    3363         990 :     RootedPropertyName name(cx);
    3364         990 :     Rooted<BindingIter> bi(cx, BindingIter(script));
    3365             : 
    3366             :     // ES 15.1.11 GlobalDeclarationInstantiation
    3367             : 
    3368             :     // Step 6.
    3369             :     //
    3370             :     // Check 'var' declarations do not conflict with existing bindings in the
    3371             :     // global lexical environment.
    3372        4173 :     for (; bi; bi++) {
    3373        2135 :         if (bi.kind() != BindingKind::Var)
    3374         296 :             break;
    3375        1839 :         name = bi.name()->asPropertyName();
    3376        1839 :         if (!CheckVarNameConflict(cx, lexicalEnv, name))
    3377           0 :             return false;
    3378             : 
    3379             :         // Step 10 and 12.
    3380             :         //
    3381             :         // Check that global functions and vars may be declared.
    3382        1839 :         if (varObj->is<GlobalObject>()) {
    3383        1645 :             Handle<GlobalObject*> global = varObj.as<GlobalObject>();
    3384        1645 :             if (!CheckCanDeclareGlobalBinding(cx, global, name, bi.isTopLevelFunction()))
    3385           0 :                 return false;
    3386             :         }
    3387             :     }
    3388             : 
    3389             :     // Step 5.
    3390             :     //
    3391             :     // Check that lexical bindings do not conflict.
    3392        5395 :     for (; bi; bi++) {
    3393        2450 :         name = bi.name()->asPropertyName();
    3394        2450 :         if (!CheckLexicalNameConflict(cx, lexicalEnv, varObj, name))
    3395           0 :             return false;
    3396             :     }
    3397             : 
    3398         495 :     return true;
    3399             : }
    3400             : 
    3401             : static bool
    3402           0 : CheckVarNameConflictsInEnv(JSContext* cx, HandleScript script, HandleObject obj)
    3403             : {
    3404           0 :     Rooted<LexicalEnvironmentObject*> env(cx);
    3405             : 
    3406           0 :     if (obj->is<LexicalEnvironmentObject>()) {
    3407           0 :         env = &obj->as<LexicalEnvironmentObject>();
    3408           0 :     } else if (obj->is<DebugEnvironmentProxy>() &&
    3409           0 :                obj->as<DebugEnvironmentProxy>().environment().is<LexicalEnvironmentObject>())
    3410             :     {
    3411           0 :         env = &obj->as<DebugEnvironmentProxy>().environment().as<LexicalEnvironmentObject>();
    3412             :     } else {
    3413             :         // Environment cannot contain lexical bindings.
    3414           0 :         return true;
    3415             :     }
    3416             : 
    3417           0 :     if (env->isSyntactic() && !env->isGlobal() && env->scope().kind() == ScopeKind::SimpleCatch) {
    3418             :         // Annex B.3.5 allows redeclaring simple (non-destructured) catch
    3419             :         // parameters with var declarations, except when it appears in a
    3420             :         // for-of. The for-of allowance is computed in
    3421             :         // Parser::isVarRedeclaredInEval.
    3422           0 :         return true;
    3423             :     }
    3424             : 
    3425           0 :     RootedPropertyName name(cx);
    3426           0 :     for (BindingIter bi(script); bi; bi++) {
    3427           0 :         name = bi.name()->asPropertyName();
    3428           0 :         if (!CheckVarNameConflict(cx, env, name))
    3429           0 :             return false;
    3430             :     }
    3431             : 
    3432           0 :     return true;
    3433             : }
    3434             : 
    3435             : bool
    3436           0 : js::CheckEvalDeclarationConflicts(JSContext* cx, HandleScript script,
    3437             :                                   HandleObject scopeChain, HandleObject varObj)
    3438             : {
    3439           0 :     if (!script->bodyScope()->as<EvalScope>().hasBindings())
    3440           0 :         return true;
    3441             : 
    3442           0 :     RootedObject obj(cx, scopeChain);
    3443             : 
    3444             :     // ES 18.2.1.3.
    3445             : 
    3446             :     // Step 5.
    3447             :     //
    3448             :     // Check that a direct eval will not hoist 'var' bindings over lexical
    3449             :     // bindings with the same name.
    3450           0 :     while (obj != varObj) {
    3451           0 :         if (!CheckVarNameConflictsInEnv(cx, script, obj))
    3452           0 :             return false;
    3453           0 :         obj = obj->enclosingEnvironment();
    3454             :     }
    3455             : 
    3456             :     // Step 8.
    3457             :     //
    3458             :     // Check that global functions may be declared.
    3459           0 :     if (varObj->is<GlobalObject>()) {
    3460           0 :         Handle<GlobalObject*> global = varObj.as<GlobalObject>();
    3461           0 :         RootedPropertyName name(cx);
    3462           0 :         for (Rooted<BindingIter> bi(cx, BindingIter(script)); bi; bi++) {
    3463           0 :             name = bi.name()->asPropertyName();
    3464           0 :             if (!CheckCanDeclareGlobalBinding(cx, global, name, bi.isTopLevelFunction()))
    3465           0 :                 return false;
    3466             :         }
    3467             :     }
    3468             : 
    3469           0 :     return true;
    3470             : }
    3471             : 
    3472             : bool
    3473        4253 : js::InitFunctionEnvironmentObjects(JSContext* cx, AbstractFramePtr frame)
    3474             : {
    3475        4253 :     MOZ_ASSERT(frame.isFunctionFrame());
    3476        4253 :     MOZ_ASSERT(frame.callee()->needsSomeEnvironmentObject());
    3477             : 
    3478        8506 :     RootedFunction callee(cx, frame.callee());
    3479             : 
    3480             :     // Named lambdas may have an environment that holds itself for recursion.
    3481        4253 :     if (callee->needsNamedLambdaEnvironment()) {
    3482             :         NamedLambdaObject* declEnv;
    3483           2 :         if (callee->isAsync()) {
    3484             :             // Named async function needs special environment to return
    3485             :             // wrapped function for the binding.
    3486           4 :             RootedFunction fun(cx, GetWrappedAsyncFunction(callee));
    3487           2 :             declEnv = NamedLambdaObject::create(cx, frame, fun);
    3488             :         } else {
    3489           0 :             declEnv = NamedLambdaObject::create(cx, frame);
    3490             :         }
    3491           2 :         if (!declEnv)
    3492           0 :             return false;
    3493           2 :         frame.pushOnEnvironmentChain(*declEnv);
    3494             :     }
    3495             : 
    3496             :     // If the function has parameter default expressions, there may be an
    3497             :     // extra environment to hold the parameters.
    3498        4253 :     if (callee->needsCallObject()) {
    3499        4253 :         CallObject* callObj = CallObject::create(cx, frame);
    3500        4253 :         if (!callObj)
    3501           0 :             return false;
    3502        4253 :         frame.pushOnEnvironmentChain(*callObj);
    3503             :     }
    3504             : 
    3505        4253 :     return true;
    3506             : }
    3507             : 
    3508             : bool
    3509          41 : js::PushVarEnvironmentObject(JSContext* cx, HandleScope scope, AbstractFramePtr frame)
    3510             : {
    3511          41 :     VarEnvironmentObject* env = VarEnvironmentObject::create(cx, scope, frame);
    3512          41 :     if (!env)
    3513           0 :         return false;
    3514          41 :     frame.pushOnEnvironmentChain(*env);
    3515          41 :     return true;
    3516             : }
    3517             : 
    3518             : bool
    3519           0 : js::GetFrameEnvironmentAndScope(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc,
    3520             :                                 MutableHandleObject env, MutableHandleScope scope)
    3521             : {
    3522           0 :     env.set(frame.environmentChain());
    3523             : 
    3524           0 :     if (frame.isWasmDebugFrame()) {
    3525           0 :         RootedWasmInstanceObject instance(cx, frame.wasmInstance()->object());
    3526           0 :         uint32_t funcIndex = frame.asWasmDebugFrame()->funcIndex();
    3527           0 :         scope.set(WasmInstanceObject::getFunctionScope(cx, instance, funcIndex));
    3528           0 :         if (!scope)
    3529           0 :             return false;
    3530             :     } else {
    3531           0 :         scope.set(frame.script()->innermostScope(pc));
    3532             :     }
    3533           0 :     return true;
    3534             : }
    3535             : 
    3536             : 
    3537             : #ifdef DEBUG
    3538             : 
    3539             : typedef HashSet<PropertyName*> PropertyNameSet;
    3540             : 
    3541             : static bool
    3542           0 : RemoveReferencedNames(JSContext* cx, HandleScript script, PropertyNameSet& remainingNames)
    3543             : {
    3544             :     // Remove from remainingNames --- the closure variables in some outer
    3545             :     // script --- any free variables in this script. This analysis isn't perfect:
    3546             :     //
    3547             :     // - It will not account for free variables in an inner script which are
    3548             :     //   actually accessing some name in an intermediate script between the
    3549             :     //   inner and outer scripts. This can cause remainingNames to be an
    3550             :     //   underapproximation.
    3551             :     //
    3552             :     // - It will not account for new names introduced via eval. This can cause
    3553             :     //   remainingNames to be an overapproximation. This would be easy to fix
    3554             :     //   but is nice to have as the eval will probably not access these
    3555             :     //   these names and putting eval in an inner script is bad news if you
    3556             :     //   care about entraining variables unnecessarily.
    3557             : 
    3558           0 :     for (jsbytecode* pc = script->code(); pc != script->codeEnd(); pc += GetBytecodeLength(pc)) {
    3559             :         PropertyName* name;
    3560             : 
    3561           0 :         switch (JSOp(*pc)) {
    3562             :           case JSOP_GETNAME:
    3563             :           case JSOP_SETNAME:
    3564             :           case JSOP_STRICTSETNAME:
    3565           0 :             name = script->getName(pc);
    3566           0 :             break;
    3567             : 
    3568             :           case JSOP_GETGNAME:
    3569             :           case JSOP_SETGNAME:
    3570             :           case JSOP_STRICTSETGNAME:
    3571           0 :             if (script->hasNonSyntacticScope())
    3572           0 :                 name = script->getName(pc);
    3573             :             else
    3574           0 :                 name = nullptr;
    3575           0 :             break;
    3576             : 
    3577             :           case JSOP_GETALIASEDVAR:
    3578             :           case JSOP_SETALIASEDVAR:
    3579           0 :             name = EnvironmentCoordinateName(cx->caches().envCoordinateNameCache, script, pc);
    3580           0 :             break;
    3581             : 
    3582             :           default:
    3583           0 :             name = nullptr;
    3584           0 :             break;
    3585             :         }
    3586             : 
    3587           0 :         if (name)
    3588           0 :             remainingNames.remove(name);
    3589             :     }
    3590             : 
    3591           0 :     if (script->hasObjects()) {
    3592           0 :         ObjectArray* objects = script->objects();
    3593           0 :         RootedFunction fun(cx);
    3594           0 :         RootedScript innerScript(cx);
    3595           0 :         for (size_t i = 0; i < objects->length; i++) {
    3596           0 :             JSObject* obj = objects->vector[i];
    3597           0 :             if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) {
    3598           0 :                 fun = &obj->as<JSFunction>();
    3599           0 :                 innerScript = JSFunction::getOrCreateScript(cx, fun);
    3600           0 :                 if (!innerScript)
    3601           0 :                     return false;
    3602             : 
    3603           0 :                 if (!RemoveReferencedNames(cx, innerScript, remainingNames))
    3604           0 :                     return false;
    3605             :             }
    3606             :         }
    3607             :     }
    3608             : 
    3609           0 :     return true;
    3610             : }
    3611             : 
    3612             : static bool
    3613           0 : AnalyzeEntrainedVariablesInScript(JSContext* cx, HandleScript script, HandleScript innerScript)
    3614             : {
    3615           0 :     PropertyNameSet remainingNames(cx);
    3616           0 :     if (!remainingNames.init())
    3617           0 :         return false;
    3618             : 
    3619           0 :     for (BindingIter bi(script); bi; bi++) {
    3620           0 :         if (bi.closedOver()) {
    3621           0 :             PropertyName* name = bi.name()->asPropertyName();
    3622           0 :             PropertyNameSet::AddPtr p = remainingNames.lookupForAdd(name);
    3623           0 :             if (!p && !remainingNames.add(p, name))
    3624           0 :                 return false;
    3625             :         }
    3626             :     }
    3627             : 
    3628           0 :     if (!RemoveReferencedNames(cx, innerScript, remainingNames))
    3629           0 :         return false;
    3630             : 
    3631           0 :     if (!remainingNames.empty()) {
    3632           0 :         Sprinter buf(cx);
    3633           0 :         if (!buf.init())
    3634           0 :             return false;
    3635             : 
    3636           0 :         buf.printf("Script ");
    3637             : 
    3638           0 :         if (JSAtom* name = script->functionNonDelazifying()->displayAtom()) {
    3639           0 :             buf.putString(name);
    3640           0 :             buf.printf(" ");
    3641             :         }
    3642             : 
    3643           0 :         buf.printf("(%s:%" PRIuSIZE ") has variables entrained by ", script->filename(), script->lineno());
    3644             : 
    3645           0 :         if (JSAtom* name = innerScript->functionNonDelazifying()->displayAtom()) {
    3646           0 :             buf.putString(name);
    3647           0 :             buf.printf(" ");
    3648             :         }
    3649             : 
    3650           0 :         buf.printf("(%s:%" PRIuSIZE ") ::", innerScript->filename(), innerScript->lineno());
    3651             : 
    3652           0 :         for (PropertyNameSet::Range r = remainingNames.all(); !r.empty(); r.popFront()) {
    3653           0 :             buf.printf(" ");
    3654           0 :             buf.putString(r.front());
    3655             :         }
    3656             : 
    3657           0 :         printf("%s\n", buf.string());
    3658             :     }
    3659             : 
    3660           0 :     if (innerScript->hasObjects()) {
    3661           0 :         ObjectArray* objects = innerScript->objects();
    3662           0 :         RootedFunction fun(cx);
    3663           0 :         RootedScript innerInnerScript(cx);
    3664           0 :         for (size_t i = 0; i < objects->length; i++) {
    3665           0 :             JSObject* obj = objects->vector[i];
    3666           0 :             if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) {
    3667           0 :                 fun = &obj->as<JSFunction>();
    3668           0 :                 innerInnerScript = JSFunction::getOrCreateScript(cx, fun);
    3669           0 :                 if (!innerInnerScript ||
    3670           0 :                     !AnalyzeEntrainedVariablesInScript(cx, script, innerInnerScript))
    3671             :                 {
    3672           0 :                     return false;
    3673             :                 }
    3674             :             }
    3675             :         }
    3676             :     }
    3677             : 
    3678           0 :     return true;
    3679             : }
    3680             : 
    3681             : // Look for local variables in script or any other script inner to it, which are
    3682             : // part of the script's call object and are unnecessarily entrained by their own
    3683             : // inner scripts which do not refer to those variables. An example is:
    3684             : //
    3685             : // function foo() {
    3686             : //   var a, b;
    3687             : //   function bar() { return a; }
    3688             : //   function baz() { return b; }
    3689             : // }
    3690             : //
    3691             : // |bar| unnecessarily entrains |b|, and |baz| unnecessarily entrains |a|.
    3692             : bool
    3693           0 : js::AnalyzeEntrainedVariables(JSContext* cx, HandleScript script)
    3694             : {
    3695           0 :     if (!script->hasObjects())
    3696           0 :         return true;
    3697             : 
    3698           0 :     ObjectArray* objects = script->objects();
    3699           0 :     RootedFunction fun(cx);
    3700           0 :     RootedScript innerScript(cx);
    3701           0 :     for (size_t i = 0; i < objects->length; i++) {
    3702           0 :         JSObject* obj = objects->vector[i];
    3703           0 :         if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) {
    3704           0 :             fun = &obj->as<JSFunction>();
    3705           0 :             innerScript = JSFunction::getOrCreateScript(cx, fun);
    3706           0 :             if (!innerScript)
    3707           0 :                 return false;
    3708             : 
    3709           0 :             if (script->functionDelazifying() && script->functionDelazifying()->needsCallObject()) {
    3710           0 :                 if (!AnalyzeEntrainedVariablesInScript(cx, script, innerScript))
    3711           0 :                     return false;
    3712             :             }
    3713             : 
    3714           0 :             if (!AnalyzeEntrainedVariables(cx, innerScript))
    3715           0 :                 return false;
    3716             :         }
    3717             :     }
    3718             : 
    3719           0 :     return true;
    3720             : }
    3721             : 
    3722             : #endif

Generated by: LCOV version 1.13