LCOV - code coverage report
Current view: top level - js/src/vm - Scope.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 429 720 59.6 %
Date: 2017-07-14 16:53:18 Functions: 74 112 66.1 %
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/Scope.h"
       8             : 
       9             : #include "mozilla/ScopeExit.h"
      10             : 
      11             : #include "jsscript.h"
      12             : #include "builtin/ModuleObject.h"
      13             : #include "gc/Allocator.h"
      14             : #include "vm/EnvironmentObject.h"
      15             : #include "vm/Runtime.h"
      16             : #include "vm/StringBuffer.h"
      17             : #include "wasm/WasmInstance.h"
      18             : 
      19             : #include "vm/Shape-inl.h"
      20             : 
      21             : using namespace js;
      22             : 
      23             : using mozilla::Maybe;
      24             : using mozilla::MakeScopeExit;
      25             : using mozilla::Move;
      26             : using mozilla::Nothing;
      27             : using mozilla::Some;
      28             : 
      29             : const char*
      30           0 : js::BindingKindString(BindingKind kind)
      31             : {
      32           0 :     switch (kind) {
      33             :       case BindingKind::Import:
      34           0 :         return "import";
      35             :       case BindingKind::FormalParameter:
      36           0 :         return "formal parameter";
      37             :       case BindingKind::Var:
      38           0 :         return "var";
      39             :       case BindingKind::Let:
      40           0 :         return "let";
      41             :       case BindingKind::Const:
      42           0 :         return "const";
      43             :       case BindingKind::NamedLambdaCallee:
      44           0 :         return "named lambda callee";
      45             :     }
      46           0 :     MOZ_CRASH("Bad BindingKind");
      47             : }
      48             : 
      49             : const char*
      50           0 : js::ScopeKindString(ScopeKind kind)
      51             : {
      52           0 :     switch (kind) {
      53             :       case ScopeKind::Function:
      54           0 :         return "function";
      55             :       case ScopeKind::FunctionBodyVar:
      56           0 :         return "function body var";
      57             :       case ScopeKind::ParameterExpressionVar:
      58           0 :         return "parameter expression var";
      59             :       case ScopeKind::Lexical:
      60           0 :         return "lexical";
      61             :       case ScopeKind::SimpleCatch:
      62             :       case ScopeKind::Catch:
      63           0 :         return "catch";
      64             :       case ScopeKind::NamedLambda:
      65           0 :         return "named lambda";
      66             :       case ScopeKind::StrictNamedLambda:
      67           0 :         return "strict named lambda";
      68             :       case ScopeKind::With:
      69           0 :         return "with";
      70             :       case ScopeKind::Eval:
      71           0 :         return "eval";
      72             :       case ScopeKind::StrictEval:
      73           0 :         return "strict eval";
      74             :       case ScopeKind::Global:
      75           0 :         return "global";
      76             :       case ScopeKind::NonSyntactic:
      77           0 :         return "non-syntactic";
      78             :       case ScopeKind::Module:
      79           0 :         return "module";
      80             :       case ScopeKind::WasmFunction:
      81           0 :         return "wasm function";
      82             :     }
      83           0 :     MOZ_CRASH("Bad ScopeKind");
      84             : }
      85             : 
      86             : static Shape*
      87        4269 : EmptyEnvironmentShape(JSContext* cx, const Class* cls, uint32_t numSlots,
      88             :                       uint32_t baseShapeFlags)
      89             : {
      90             :     // Put as many slots into the object header as possible.
      91        4269 :     uint32_t numFixed = gc::GetGCKindSlots(gc::GetGCObjectKind(numSlots));
      92        8538 :     return EmptyShape::getInitialShape(cx, cls, TaggedProto(nullptr), numFixed,
      93        8538 :                                        baseShapeFlags);
      94             : }
      95             : 
      96             : static Shape*
      97        6878 : NextEnvironmentShape(JSContext* cx, HandleAtom name, BindingKind bindKind, uint32_t slot,
      98             :                      StackBaseShape& stackBase, HandleShape shape)
      99             : {
     100        6878 :     UnownedBaseShape* base = BaseShape::getUnowned(cx, stackBase);
     101        6878 :     if (!base)
     102           0 :         return nullptr;
     103             : 
     104        6878 :     unsigned attrs = JSPROP_PERMANENT | JSPROP_ENUMERATE;
     105        6878 :     switch (bindKind) {
     106             :       case BindingKind::Const:
     107             :       case BindingKind::NamedLambdaCallee:
     108         238 :         attrs |= JSPROP_READONLY;
     109         238 :         break;
     110             :       default:
     111        6640 :         break;
     112             :     }
     113             : 
     114        6878 :     jsid id = NameToId(name->asPropertyName());
     115       13756 :     Rooted<StackShape> child(cx, StackShape(base, id, slot, attrs, 0));
     116        6878 :     return cx->zone()->propertyTree().getChild(cx, shape, child);
     117             : }
     118             : 
     119             : static Shape*
     120        3758 : CreateEnvironmentShape(JSContext* cx, BindingIter& bi, const Class* cls,
     121             :                        uint32_t numSlots, uint32_t baseShapeFlags)
     122             : {
     123        7516 :     RootedShape shape(cx, EmptyEnvironmentShape(cx, cls, numSlots, baseShapeFlags));
     124        3758 :     if (!shape)
     125           0 :         return nullptr;
     126             : 
     127        7516 :     RootedAtom name(cx);
     128        3758 :     StackBaseShape stackBase(cx, cls, baseShapeFlags);
     129       23258 :     for (; bi; bi++) {
     130        9750 :         BindingLocation loc = bi.location();
     131        9750 :         if (loc.kind() == BindingLocation::Kind::Environment) {
     132        6878 :             name = bi.name();
     133        6878 :             cx->markAtom(name);
     134        6878 :             shape = NextEnvironmentShape(cx, name, bi.kind(), loc.slot(), stackBase, shape);
     135        6878 :             if (!shape)
     136           0 :                 return nullptr;
     137             :         }
     138             :     }
     139             : 
     140        3758 :     return shape;
     141             : }
     142             : 
     143             : template <typename ConcreteScope>
     144             : static UniquePtr<typename ConcreteScope::Data>
     145       24268 : CopyScopeData(JSContext* cx, Handle<typename ConcreteScope::Data*> data)
     146             : {
     147             :     // Make sure the binding names are marked in the context's zone, if we are
     148             :     // copying data from another zone.
     149       24268 :     BindingName* names = nullptr;
     150       24268 :     uint32_t length = 0;
     151       24268 :     ConcreteScope::getDataNamesAndLength(data, &names, &length);
     152       75802 :     for (size_t i = 0; i < length; i++) {
     153       51534 :         if (JSAtom* name = names[i].name())
     154       51447 :             cx->markAtom(name);
     155             :     }
     156             : 
     157       24268 :     size_t dataSize = ConcreteScope::sizeOfData(data->length);
     158       24268 :     size_t headerSize = sizeof(typename ConcreteScope::Data);
     159       24268 :     MOZ_ASSERT(dataSize >= headerSize);
     160       24268 :     size_t extraSize = dataSize - headerSize;
     161             : 
     162       24268 :     uint8_t* copyBytes = cx->zone()->pod_malloc<uint8_t>(dataSize);
     163       24268 :     if (!copyBytes) {
     164           0 :         ReportOutOfMemory(cx);
     165           0 :         return nullptr;
     166             :     }
     167             : 
     168       24268 :     auto dataCopy = reinterpret_cast<typename ConcreteScope::Data*>(copyBytes);
     169       24268 :     new (dataCopy) typename ConcreteScope::Data(*data);
     170             : 
     171       24268 :     uint8_t* extra = reinterpret_cast<uint8_t*>(data.get()) + headerSize;
     172       24268 :     uint8_t* extraCopy = copyBytes + headerSize;
     173             : 
     174       24268 :     mozilla::PodCopy<uint8_t>(extraCopy, extra, extraSize);
     175       24268 :     return UniquePtr<typename ConcreteScope::Data>(dataCopy);
     176             : }
     177             : 
     178             : template <typename ConcreteScope>
     179             : static bool
     180       25242 : PrepareScopeData(JSContext* cx, BindingIter& bi, Handle<UniquePtr<typename ConcreteScope::Data>> data,
     181             :                  const Class* cls, uint32_t baseShapeFlags, MutableHandleShape envShape)
     182             : {
     183             :     // Copy a fresh BindingIter for use below.
     184       25242 :     BindingIter freshBi(bi);
     185             : 
     186             :     // Iterate through all bindings. This counts the number of environment
     187             :     // slots needed and computes the maximum frame slot.
     188      116370 :     while (bi)
     189       45563 :         bi++;
     190       25242 :     data->nextFrameSlot = bi.canHaveFrameSlots() ? bi.nextFrameSlot() : LOCALNO_LIMIT;
     191             : 
     192             :     // Make a new environment shape if any environment slots were used.
     193       25242 :     if (bi.nextEnvironmentSlot() == JSSLOT_FREE(cls)) {
     194       22030 :         envShape.set(nullptr);
     195             :     } else {
     196        3212 :         envShape.set(CreateEnvironmentShape(cx, freshBi, cls, bi.nextEnvironmentSlot(),
     197             :                                             baseShapeFlags));
     198        3212 :         if (!envShape)
     199           0 :             return false;
     200             :     }
     201             : 
     202       25242 :     return true;
     203             : }
     204             : 
     205             : template <typename ConcreteScope>
     206             : static UniquePtr<typename ConcreteScope::Data>
     207       18072 : NewEmptyScopeData(JSContext* cx, uint32_t length = 0)
     208             : {
     209       18072 :     uint8_t* bytes = cx->zone()->pod_calloc<uint8_t>(ConcreteScope::sizeOfData(length));
     210       18072 :     if (!bytes)
     211           0 :         ReportOutOfMemory(cx);
     212       18072 :     auto data = reinterpret_cast<typename ConcreteScope::Data*>(bytes);
     213       18072 :     if (data)
     214       18072 :         new (data) typename ConcreteScope::Data();
     215       18072 :     return UniquePtr<typename ConcreteScope::Data>(data);
     216             : }
     217             : 
     218             : static bool
     219        9173 : XDRBindingName(XDRState<XDR_ENCODE>* xdr, BindingName* bindingName)
     220             : {
     221        9173 :     JSContext* cx = xdr->cx();
     222             : 
     223       18346 :     RootedAtom atom(cx, bindingName->name());
     224        9173 :     bool hasAtom = !!atom;
     225             : 
     226        9173 :     uint8_t u8 = uint8_t(hasAtom << 1) | uint8_t(bindingName->closedOver());
     227        9173 :     if (!xdr->codeUint8(&u8))
     228           0 :         return false;
     229             : 
     230        9173 :     if (atom && !XDRAtom(xdr, &atom))
     231           0 :         return false;
     232             : 
     233        9173 :     return true;
     234             : }
     235             : 
     236             : static bool
     237       29924 : XDRBindingName(XDRState<XDR_DECODE>* xdr, BindingName* bindingName)
     238             : {
     239       29924 :     JSContext* cx = xdr->cx();
     240             : 
     241             :     uint8_t u8;
     242       29924 :     if (!xdr->codeUint8(&u8))
     243           0 :         return false;
     244             : 
     245       29924 :     bool closedOver = u8 & 1;
     246       29924 :     bool hasAtom = u8 >> 1;
     247             : 
     248       59848 :     RootedAtom atom(cx);
     249       29924 :     if (hasAtom && !XDRAtom(xdr, &atom))
     250           0 :         return false;
     251             : 
     252       29924 :     *bindingName = BindingName(atom, closedOver);
     253             : 
     254       29924 :     return true;
     255             : }
     256             : 
     257             : template <typename ConcreteScopeData>
     258             : static void
     259           0 : DeleteScopeData(ConcreteScopeData* data)
     260             : {
     261             :     // Some scope Data classes have GCManagedDeletePolicy because then contain
     262             :     // GCPtrs. Dispose of them in the appropriate way.
     263           0 :     JS::DeletePolicy<ConcreteScopeData>()(data);
     264           0 : }
     265             : 
     266             : template <typename ConcreteScope, XDRMode mode>
     267             : /* static */ bool
     268       21561 : Scope::XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
     269             :                             MutableHandle<typename ConcreteScope::Data*> data)
     270             : {
     271       21561 :     MOZ_ASSERT(!data);
     272             : 
     273       21561 :     JSContext* cx = xdr->cx();
     274             : 
     275             :     uint32_t length;
     276             :     if (mode == XDR_ENCODE)
     277        5213 :         length = scope->data().length;
     278       21561 :     if (!xdr->codeUint32(&length))
     279           0 :         return false;
     280             : 
     281             :     if (mode == XDR_ENCODE) {
     282        5213 :         data.set(&scope->data());
     283             :     } else {
     284       16348 :         data.set(NewEmptyScopeData<ConcreteScope>(cx, length).release());
     285       16348 :         if (!data)
     286           0 :             return false;
     287       16348 :         data->length = length;
     288             :     }
     289             : 
     290       60657 :     for (uint32_t i = 0; i < length; i++) {
     291       39096 :         if (!XDRBindingName(xdr, &data->names[i])) {
     292             :             if (mode == XDR_DECODE) {
     293           0 :                 DeleteScopeData(data.get());
     294           0 :                 data.set(nullptr);
     295             :             }
     296             : 
     297           0 :             return false;
     298             :         }
     299             :     }
     300             : 
     301       21561 :     return true;
     302             : }
     303             : 
     304             : /* static */ Scope*
     305       42340 : Scope::create(JSContext* cx, ScopeKind kind, HandleScope enclosing, HandleShape envShape)
     306             : {
     307       42340 :     Scope* scope = Allocate<Scope>(cx);
     308       42340 :     if (scope)
     309       42340 :         new (scope) Scope(kind, enclosing, envShape);
     310       42340 :     return scope;
     311             : }
     312             : 
     313             : template <typename T, typename D>
     314             : /* static */ Scope*
     315       18230 : Scope::create(JSContext* cx, ScopeKind kind, HandleScope enclosing,
     316             :               HandleShape envShape, mozilla::UniquePtr<T, D> data)
     317             : {
     318       18230 :     Scope* scope = create(cx, kind, enclosing, envShape);
     319       18230 :     if (!scope)
     320           0 :         return nullptr;
     321             : 
     322             :     // It is an invariant that all Scopes that have data (currently, all
     323             :     // ScopeKinds except With) must have non-null data.
     324       18230 :     MOZ_ASSERT(data);
     325       18230 :     scope->initData(Move(data));
     326             : 
     327       18230 :     return scope;
     328             : }
     329             : 
     330             : uint32_t
     331           0 : Scope::chainLength() const
     332             : {
     333           0 :     uint32_t length = 0;
     334           0 :     for (ScopeIter si(const_cast<Scope*>(this)); si; si++)
     335           0 :         length++;
     336           0 :     return length;
     337             : }
     338             : 
     339             : uint32_t
     340        1422 : Scope::environmentChainLength() const
     341             : {
     342        1422 :     uint32_t length = 0;
     343        3765 :     for (ScopeIter si(const_cast<Scope*>(this)); si; si++) {
     344        2343 :         if (si.hasSyntacticEnvironment())
     345        1507 :             length++;
     346             :     }
     347        1422 :     return length;
     348             : }
     349             : 
     350             : Shape*
     351        1753 : Scope::maybeCloneEnvironmentShape(JSContext* cx)
     352             : {
     353             :     // Clone the environment shape if cloning into a different zone.
     354        1753 :     if (environmentShape_ && environmentShape_->zoneFromAnyThread() != cx->zone()) {
     355         546 :         BindingIter bi(this);
     356        1638 :         return CreateEnvironmentShape(cx, bi,
     357         546 :                                       environmentShape_->getObjectClass(),
     358         546 :                                       environmentShape_->slotSpan(),
     359        1092 :                                       environmentShape_->getObjectFlags());
     360             :     }
     361        1207 :     return environmentShape_;
     362             : }
     363             : 
     364             : /* static */ Scope*
     365        6444 : Scope::clone(JSContext* cx, HandleScope scope, HandleScope enclosing)
     366             : {
     367       12888 :     RootedShape envShape(cx);
     368        6444 :     if (scope->environmentShape()) {
     369         825 :         envShape = scope->maybeCloneEnvironmentShape(cx);
     370         825 :         if (!envShape)
     371           0 :             return nullptr;
     372             :     }
     373             : 
     374        6444 :     switch (scope->kind_) {
     375             :       case ScopeKind::Function: {
     376           0 :         RootedScript script(cx, scope->as<FunctionScope>().script());
     377           0 :         const char* filename = script->filename();
     378             :         // If the script has an internal URL, include it in the crash reason. If
     379             :         // not, it may be a web URL, and therefore privacy-sensitive.
     380           0 :         if (!strncmp(filename, "chrome:", 7) || !strncmp(filename, "resource:", 9))
     381           0 :             MOZ_CRASH_UNSAFE_PRINTF("Use FunctionScope::clone (script URL: %s)", filename);
     382             : 
     383           0 :         MOZ_CRASH("Use FunctionScope::clone.");
     384             :         break;
     385             :       }
     386             : 
     387             :       case ScopeKind::FunctionBodyVar:
     388             :       case ScopeKind::ParameterExpressionVar: {
     389         190 :         Rooted<VarScope::Data*> original(cx, &scope->as<VarScope>().data());
     390         190 :         UniquePtr<VarScope::Data> dataClone = CopyScopeData<VarScope>(cx, original);
     391          95 :         if (!dataClone)
     392           0 :             return nullptr;
     393          95 :         return create(cx, scope->kind_, enclosing, envShape, Move(dataClone));
     394             :       }
     395             : 
     396             :       case ScopeKind::Lexical:
     397             :       case ScopeKind::SimpleCatch:
     398             :       case ScopeKind::Catch:
     399             :       case ScopeKind::NamedLambda:
     400             :       case ScopeKind::StrictNamedLambda: {
     401       12698 :         Rooted<LexicalScope::Data*> original(cx, &scope->as<LexicalScope>().data());
     402       12698 :         UniquePtr<LexicalScope::Data> dataClone = CopyScopeData<LexicalScope>(cx, original);
     403        6349 :         if (!dataClone)
     404           0 :             return nullptr;
     405        6349 :         return create(cx, scope->kind_, enclosing, envShape, Move(dataClone));
     406             :       }
     407             : 
     408             :       case ScopeKind::With:
     409           0 :         return create(cx, scope->kind_, enclosing, envShape);
     410             : 
     411             :       case ScopeKind::Eval:
     412             :       case ScopeKind::StrictEval: {
     413           0 :         Rooted<EvalScope::Data*> original(cx, &scope->as<EvalScope>().data());
     414           0 :         UniquePtr<EvalScope::Data> dataClone = CopyScopeData<EvalScope>(cx, original);
     415           0 :         if (!dataClone)
     416           0 :             return nullptr;
     417           0 :         return create(cx, scope->kind_, enclosing, envShape, Move(dataClone));
     418             :       }
     419             : 
     420             :       case ScopeKind::Global:
     421             :       case ScopeKind::NonSyntactic:
     422           0 :         MOZ_CRASH("Use GlobalScope::clone.");
     423             :         break;
     424             : 
     425             :       case ScopeKind::WasmFunction:
     426           0 :         MOZ_CRASH("wasm functions are not nested in JSScript");
     427             :         break;
     428             : 
     429             :       case ScopeKind::Module:
     430           0 :         MOZ_CRASH("NYI");
     431             :         break;
     432             : 
     433             :     }
     434             : 
     435           0 :     return nullptr;
     436             : }
     437             : 
     438             : void
     439           0 : Scope::finalize(FreeOp* fop)
     440             : {
     441           0 :     MOZ_ASSERT(CurrentThreadIsGCSweeping());
     442           0 :     if (data_) {
     443             :         // We don't need to call the destructors for any GCPtrs in Data because
     444             :         // this only happens during a GC.
     445           0 :         fop->free_(reinterpret_cast<void*>(data_));
     446           0 :         data_ = 0;
     447             :     }
     448           0 : }
     449             : 
     450             : size_t
     451           0 : Scope::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
     452             : {
     453           0 :     if (data_)
     454           0 :         return mallocSizeOf(reinterpret_cast<void*>(data_));
     455           0 :     return 0;
     456             : }
     457             : 
     458             : void
     459           0 : Scope::dump()
     460             : {
     461           0 :     for (ScopeIter si(this); si; si++) {
     462           0 :         fprintf(stderr, "%s [%p]", ScopeKindString(si.kind()), si.scope());
     463           0 :         if (si.scope()->enclosing())
     464           0 :             fprintf(stderr, " -> ");
     465             :     }
     466           0 :     fprintf(stderr, "\n");
     467           0 : }
     468             : 
     469             : uint32_t
     470       13998 : LexicalScope::firstFrameSlot() const
     471             : {
     472       13998 :     switch (kind()) {
     473             :       case ScopeKind::Lexical:
     474             :       case ScopeKind::SimpleCatch:
     475             :       case ScopeKind::Catch:
     476             :         // For intra-frame scopes, find the enclosing scope's next frame slot.
     477       12297 :         return nextFrameSlot(enclosing());
     478             :       case ScopeKind::NamedLambda:
     479             :       case ScopeKind::StrictNamedLambda:
     480             :         // Named lambda scopes cannot have frame slots.
     481        1701 :         return LOCALNO_LIMIT;
     482             :       default:
     483             :         // Otherwise start at 0.
     484           0 :         break;
     485             :     }
     486           0 :     return 0;
     487             : }
     488             : 
     489             : /* static */ uint32_t
     490       18104 : LexicalScope::nextFrameSlot(Scope* scope)
     491             : {
     492       18104 :     for (ScopeIter si(scope); si; si++) {
     493       18104 :         switch (si.kind()) {
     494             :           case ScopeKind::Function:
     495       27761 :             return si.scope()->as<FunctionScope>().nextFrameSlot();
     496             :           case ScopeKind::FunctionBodyVar:
     497             :           case ScopeKind::ParameterExpressionVar:
     498         388 :             return si.scope()->as<VarScope>().nextFrameSlot();
     499             :           case ScopeKind::Lexical:
     500             :           case ScopeKind::SimpleCatch:
     501             :           case ScopeKind::Catch:
     502        7771 :             return si.scope()->as<LexicalScope>().nextFrameSlot();
     503             :           case ScopeKind::NamedLambda:
     504             :           case ScopeKind::StrictNamedLambda:
     505             :             // Named lambda scopes cannot have frame slots.
     506           0 :             return 0;
     507             :           case ScopeKind::With:
     508           0 :             continue;
     509             :           case ScopeKind::Eval:
     510             :           case ScopeKind::StrictEval:
     511          32 :             return si.scope()->as<EvalScope>().nextFrameSlot();
     512             :           case ScopeKind::Global:
     513             :           case ScopeKind::NonSyntactic:
     514         256 :             return 0;
     515             :           case ScopeKind::Module:
     516           0 :             return si.scope()->as<ModuleScope>().nextFrameSlot();
     517             :           case ScopeKind::WasmFunction:
     518             :             // TODO return si.scope()->as<WasmFunctionScope>().nextFrameSlot();
     519           0 :             return 0;
     520             :         }
     521             :     }
     522           0 :     MOZ_CRASH("Not an enclosing intra-frame Scope");
     523             : }
     524             : 
     525             : /* static */ LexicalScope*
     526        3332 : LexicalScope::create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
     527             :                      uint32_t firstFrameSlot, HandleScope enclosing)
     528             : {
     529        3332 :     MOZ_ASSERT(data, "LexicalScopes should not be created if there are no bindings.");
     530             : 
     531             :     // The data that's passed in is from the frontend and is LifoAlloc'd.
     532             :     // Copy it now that we're creating a permanent VM scope.
     533        6664 :     Rooted<UniquePtr<Data>> copy(cx, CopyScopeData<LexicalScope>(cx, data));
     534        3332 :     if (!copy)
     535           0 :         return nullptr;
     536             : 
     537        3332 :     return createWithData(cx, kind, &copy, firstFrameSlot, enclosing);
     538             : }
     539             : 
     540             : /* static */ LexicalScope*
     541       10320 : LexicalScope::createWithData(JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data,
     542             :                              uint32_t firstFrameSlot, HandleScope enclosing)
     543             : {
     544       10320 :     bool isNamedLambda = kind == ScopeKind::NamedLambda || kind == ScopeKind::StrictNamedLambda;
     545             : 
     546       10320 :     MOZ_ASSERT_IF(!isNamedLambda && firstFrameSlot != 0,
     547             :                   firstFrameSlot == nextFrameSlot(enclosing));
     548       10320 :     MOZ_ASSERT_IF(isNamedLambda, firstFrameSlot == LOCALNO_LIMIT);
     549             : 
     550       20640 :     RootedShape envShape(cx);
     551       10320 :     BindingIter bi(*data, firstFrameSlot, isNamedLambda);
     552       10320 :     if (!PrepareScopeData<LexicalScope>(cx, bi, data, &LexicalEnvironmentObject::class_,
     553             :                                         BaseShape::NOT_EXTENSIBLE | BaseShape::DELEGATE, &envShape))
     554             :     {
     555           0 :         return nullptr;
     556             :     }
     557             : 
     558       10320 :     Scope* scope = Scope::create(cx, kind, enclosing, envShape, Move(data.get()));
     559       10320 :     if (!scope)
     560           0 :         return nullptr;
     561       10320 :     MOZ_ASSERT(scope->as<LexicalScope>().firstFrameSlot() == firstFrameSlot);
     562       10320 :     return &scope->as<LexicalScope>();
     563             : }
     564             : 
     565             : /* static */ Shape*
     566         419 : LexicalScope::getEmptyExtensibleEnvironmentShape(JSContext* cx)
     567             : {
     568         419 :     const Class* cls = &LexicalEnvironmentObject::class_;
     569         419 :     return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), BaseShape::DELEGATE);
     570             : }
     571             : 
     572             : template <XDRMode mode>
     573             : /* static */ bool
     574        9276 : LexicalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
     575             :                   MutableHandleScope scope)
     576             : {
     577        9276 :     JSContext* cx = xdr->cx();
     578             : 
     579       18552 :     Rooted<Data*> data(cx);
     580        9276 :     if (!XDRSizedBindingNames<LexicalScope>(xdr, scope.as<LexicalScope>(), &data))
     581           0 :         return false;
     582             : 
     583             :     {
     584       18552 :         Maybe<Rooted<UniquePtr<Data>>> uniqueData;
     585             :         if (mode == XDR_DECODE)
     586        6988 :             uniqueData.emplace(cx, data);
     587             : 
     588             :         uint32_t firstFrameSlot;
     589             :         uint32_t nextFrameSlot;
     590             :         if (mode == XDR_ENCODE) {
     591        2288 :             firstFrameSlot = scope->as<LexicalScope>().firstFrameSlot();
     592        2288 :             nextFrameSlot = data->nextFrameSlot;
     593             :         }
     594             : 
     595        9276 :         if (!xdr->codeUint32(&data->constStart))
     596           0 :             return false;
     597        9276 :         if (!xdr->codeUint32(&firstFrameSlot))
     598           0 :             return false;
     599        9276 :         if (!xdr->codeUint32(&nextFrameSlot))
     600           0 :             return false;
     601             : 
     602             :         if (mode == XDR_DECODE) {
     603        6988 :             scope.set(createWithData(cx, kind, &uniqueData.ref(), firstFrameSlot, enclosing));
     604        6988 :             if (!scope)
     605           0 :                 return false;
     606             : 
     607             :             // nextFrameSlot is used only for this correctness check.
     608        6988 :             MOZ_ASSERT(nextFrameSlot == scope->as<LexicalScope>().data().nextFrameSlot);
     609             :         }
     610             :     }
     611             : 
     612        9276 :     return true;
     613             : }
     614             : 
     615             : template
     616             : /* static */ bool
     617             : LexicalScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind, HandleScope enclosing,
     618             :                   MutableHandleScope scope);
     619             : 
     620             : template
     621             : /* static */ bool
     622             : LexicalScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind, HandleScope enclosing,
     623             :                   MutableHandleScope scope);
     624             : 
     625             : static inline uint32_t
     626       14793 : FunctionScopeEnvShapeFlags(bool hasParameterExprs)
     627             : {
     628       14793 :     if (hasParameterExprs)
     629         383 :         return BaseShape::DELEGATE;
     630       14410 :     return BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE;
     631             : }
     632             : 
     633             : Zone*
     634           0 : FunctionScope::Data::zone() const
     635             : {
     636           0 :     return canonicalFunction ? canonicalFunction->zone() : nullptr;
     637             : }
     638             : 
     639             : /* static */ FunctionScope*
     640        5715 : FunctionScope::create(JSContext* cx, Handle<Data*> dataArg,
     641             :                       bool hasParameterExprs, bool needsEnvironment,
     642             :                       HandleFunction fun, HandleScope enclosing)
     643             : {
     644             :     // The data that's passed in is from the frontend and is LifoAlloc'd.
     645             :     // Copy it now that we're creating a permanent VM scope.
     646       11430 :     Rooted<UniquePtr<Data>> data(cx, dataArg ? CopyScopeData<FunctionScope>(cx, dataArg)
     647       17145 :                                              : NewEmptyScopeData<FunctionScope>(cx));
     648        5715 :     if (!data)
     649           0 :         return nullptr;
     650             : 
     651        5715 :     return createWithData(cx, &data, hasParameterExprs, needsEnvironment, fun, enclosing);
     652             : }
     653             : 
     654             : /* static */ FunctionScope*
     655       14706 : FunctionScope::createWithData(JSContext* cx, MutableHandle<UniquePtr<Data>> data,
     656             :                               bool hasParameterExprs, bool needsEnvironment,
     657             :                               HandleFunction fun, HandleScope enclosing)
     658             : {
     659       14706 :     MOZ_ASSERT(data);
     660       14706 :     MOZ_ASSERT(fun->isTenured());
     661             : 
     662             :     // FunctionScope::Data has GCManagedDeletePolicy because it contains a
     663             :     // GCPtr. Destruction of |data| below may trigger calls into the GC.
     664       29412 :     Rooted<FunctionScope*> funScope(cx);
     665             : 
     666             :     {
     667       29412 :         RootedShape envShape(cx);
     668             : 
     669       14706 :         BindingIter bi(*data, hasParameterExprs);
     670       14706 :         uint32_t shapeFlags = FunctionScopeEnvShapeFlags(hasParameterExprs);
     671       14706 :         if (!PrepareScopeData<FunctionScope>(cx, bi, data, &CallObject::class_, shapeFlags,
     672             :                                              &envShape))
     673             :         {
     674           0 :             return nullptr;
     675             :         }
     676             : 
     677       14706 :         data->hasParameterExprs = hasParameterExprs;
     678       14706 :         data->canonicalFunction.init(fun);
     679             : 
     680             :         // An environment may be needed regardless of existence of any closed over
     681             :         // bindings:
     682             :         //   - Extensible scopes (i.e., due to direct eval)
     683             :         //   - Needing a home object
     684             :         //   - Being a derived class constructor
     685             :         //   - Being a generator
     686       14706 :         if (!envShape && needsEnvironment) {
     687          87 :             envShape = getEmptyEnvironmentShape(cx, hasParameterExprs);
     688          87 :             if (!envShape)
     689           0 :                 return nullptr;
     690             :         }
     691             : 
     692       14706 :         Scope* scope = Scope::create(cx, ScopeKind::Function, enclosing, envShape);
     693       14706 :         if (!scope)
     694           0 :             return nullptr;
     695             : 
     696       14706 :         funScope = &scope->as<FunctionScope>();
     697       14706 :         funScope->initData(Move(data.get()));
     698             :     }
     699             : 
     700       14706 :     return funScope;
     701             : }
     702             : 
     703             : JSScript*
     704        6090 : FunctionScope::script() const
     705             : {
     706        6090 :     return canonicalFunction()->nonLazyScript();
     707             : }
     708             : 
     709             : /* static */ bool
     710         115 : FunctionScope::isSpecialName(JSContext* cx, JSAtom* name)
     711             : {
     712         230 :     return name == cx->names().arguments ||
     713         116 :            name == cx->names().dotThis ||
     714         116 :            name == cx->names().dotGenerator;
     715             : }
     716             : 
     717             : /* static */ Shape*
     718          87 : FunctionScope::getEmptyEnvironmentShape(JSContext* cx, bool hasParameterExprs)
     719             : {
     720          87 :     const Class* cls = &CallObject::class_;
     721          87 :     uint32_t shapeFlags = FunctionScopeEnvShapeFlags(hasParameterExprs);
     722          87 :     return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), shapeFlags);
     723             : }
     724             : 
     725             : /* static */ FunctionScope*
     726        9404 : FunctionScope::clone(JSContext* cx, Handle<FunctionScope*> scope, HandleFunction fun,
     727             :                      HandleScope enclosing)
     728             : {
     729        9404 :     MOZ_ASSERT(fun != scope->canonicalFunction());
     730             : 
     731             :     // FunctionScope::Data has GCManagedDeletePolicy because it contains a
     732             :     // GCPtr. Destruction of |dataClone| below may trigger calls into the GC.
     733       18808 :     Rooted<FunctionScope*> funScopeClone(cx);
     734             : 
     735             :     {
     736       18808 :         RootedShape envShape(cx);
     737        9404 :         if (scope->environmentShape()) {
     738         928 :             envShape = scope->maybeCloneEnvironmentShape(cx);
     739         928 :             if (!envShape)
     740           0 :                 return nullptr;
     741             :         }
     742             : 
     743       18808 :         Rooted<Data*> dataOriginal(cx, &scope->as<FunctionScope>().data());
     744       18808 :         Rooted<UniquePtr<Data>> dataClone(cx, CopyScopeData<FunctionScope>(cx, dataOriginal));
     745        9404 :         if (!dataClone)
     746           0 :             return nullptr;
     747             : 
     748        9404 :         dataClone->canonicalFunction.init(fun);
     749             : 
     750        9404 :         Scope* scopeClone = Scope::create(cx, scope->kind(), enclosing, envShape);
     751        9404 :         if (!scopeClone)
     752           0 :             return nullptr;
     753             : 
     754        9404 :         funScopeClone = &scopeClone->as<FunctionScope>();
     755        9404 :         funScopeClone->initData(Move(dataClone.get()));
     756             :     }
     757             : 
     758        9404 :     return funScopeClone;
     759             : }
     760             : 
     761             : template <XDRMode mode>
     762             : /* static */ bool
     763       11802 : FunctionScope::XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosing,
     764             :                    MutableHandleScope scope)
     765             : {
     766       11802 :     JSContext* cx = xdr->cx();
     767       23604 :     Rooted<Data*> data(cx);
     768       11802 :     if (!XDRSizedBindingNames<FunctionScope>(xdr, scope.as<FunctionScope>(), &data))
     769           0 :         return false;
     770             : 
     771             :     {
     772       23604 :         Maybe<Rooted<UniquePtr<Data>>> uniqueData;
     773             :         if (mode == XDR_DECODE)
     774        8991 :             uniqueData.emplace(cx, data);
     775             : 
     776             :         uint8_t needsEnvironment;
     777             :         uint8_t hasParameterExprs;
     778             :         uint32_t nextFrameSlot;
     779             :         if (mode == XDR_ENCODE) {
     780        2811 :             needsEnvironment = scope->hasEnvironment();
     781        2811 :             hasParameterExprs = data->hasParameterExprs;
     782        2811 :             nextFrameSlot = data->nextFrameSlot;
     783             :         }
     784       11802 :         if (!xdr->codeUint8(&needsEnvironment))
     785           0 :             return false;
     786       11802 :         if (!xdr->codeUint8(&hasParameterExprs))
     787           0 :             return false;
     788       11802 :         if (!xdr->codeUint16(&data->nonPositionalFormalStart))
     789           0 :             return false;
     790       11802 :         if (!xdr->codeUint16(&data->varStart))
     791           0 :             return false;
     792       11802 :         if (!xdr->codeUint32(&nextFrameSlot))
     793           0 :             return false;
     794             : 
     795             :         if (mode == XDR_DECODE) {
     796        8991 :             if (!data->length) {
     797        1287 :                 MOZ_ASSERT(!data->nonPositionalFormalStart);
     798        1287 :                 MOZ_ASSERT(!data->varStart);
     799        1287 :                 MOZ_ASSERT(!data->nextFrameSlot);
     800             :             }
     801             : 
     802        8991 :             scope.set(createWithData(cx, &uniqueData.ref(), hasParameterExprs, needsEnvironment, fun,
     803             :                                      enclosing));
     804        8991 :             if (!scope)
     805           0 :                 return false;
     806             : 
     807             :             // nextFrameSlot is used only for this correctness check.
     808        8991 :             MOZ_ASSERT(nextFrameSlot == scope->as<FunctionScope>().data().nextFrameSlot);
     809             :         }
     810             :     }
     811             : 
     812       11802 :     return true;
     813             : }
     814             : 
     815             : template
     816             : /* static */ bool
     817             : FunctionScope::XDR(XDRState<XDR_ENCODE>* xdr, HandleFunction fun, HandleScope enclosing,
     818             :                    MutableHandleScope scope);
     819             : 
     820             : template
     821             : /* static */ bool
     822             : FunctionScope::XDR(XDRState<XDR_DECODE>* xdr, HandleFunction fun, HandleScope enclosing,
     823             :                    MutableHandleScope scope);
     824             : 
     825             : static const uint32_t VarScopeEnvShapeFlags =
     826             :     BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE;
     827             : 
     828             : static UniquePtr<VarScope::Data>
     829           0 : NewEmptyVarScopeData(JSContext* cx, uint32_t firstFrameSlot)
     830             : {
     831           0 :     UniquePtr<VarScope::Data> data(NewEmptyScopeData<VarScope>(cx));
     832           0 :     if (data)
     833           0 :         data->nextFrameSlot = firstFrameSlot;
     834             : 
     835           0 :     return data;
     836             : }
     837             : 
     838             : /* static */ VarScope*
     839         104 : VarScope::create(JSContext* cx, ScopeKind kind, Handle<Data*> dataArg,
     840             :                  uint32_t firstFrameSlot, bool needsEnvironment, HandleScope enclosing)
     841             : {
     842             :     // The data that's passed in is from the frontend and is LifoAlloc'd.
     843             :     // Copy it now that we're creating a permanent VM scope.
     844         208 :     Rooted<UniquePtr<Data>> data(cx, dataArg ? CopyScopeData<VarScope>(cx, dataArg)
     845         312 :                                              : NewEmptyVarScopeData(cx, firstFrameSlot));
     846         104 :     if (!data)
     847           0 :         return nullptr;
     848             : 
     849         104 :     return createWithData(cx, kind, &data, firstFrameSlot, needsEnvironment, enclosing);
     850             : }
     851             : 
     852             : /* static */ VarScope*
     853         214 : VarScope::createWithData(JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data,
     854             :                          uint32_t firstFrameSlot, bool needsEnvironment, HandleScope enclosing)
     855             : {
     856         214 :     MOZ_ASSERT(data);
     857             : 
     858         428 :     RootedShape envShape(cx);
     859         214 :     BindingIter bi(*data, firstFrameSlot);
     860         214 :     if (!PrepareScopeData<VarScope>(cx, bi, data, &VarEnvironmentObject::class_, VarScopeEnvShapeFlags,
     861             :                                     &envShape))
     862             :     {
     863           0 :         return nullptr;
     864             :     }
     865             : 
     866             :     // An environment may be needed regardless of existence of any closed over
     867             :     // bindings:
     868             :     //   - Extensible scopes (i.e., due to direct eval)
     869             :     //   - Being a generator
     870         214 :     if (!envShape && needsEnvironment) {
     871           5 :         envShape = getEmptyEnvironmentShape(cx);
     872           5 :         if (!envShape)
     873           0 :             return nullptr;
     874             :     }
     875             : 
     876         214 :     Scope* scope = Scope::create(cx, kind, enclosing, envShape, Move(data.get()));
     877         214 :     if (!scope)
     878           0 :         return nullptr;
     879         214 :     return &scope->as<VarScope>();
     880             : }
     881             : 
     882             : /* static */ Shape*
     883           5 : VarScope::getEmptyEnvironmentShape(JSContext* cx)
     884             : {
     885           5 :     const Class* cls = &VarEnvironmentObject::class_;
     886           5 :     return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), VarScopeEnvShapeFlags);
     887             : }
     888             : 
     889             : uint32_t
     890          47 : VarScope::firstFrameSlot() const
     891             : {
     892          47 :     if (enclosing()->is<FunctionScope>())
     893          47 :         return enclosing()->as<FunctionScope>().nextFrameSlot();
     894           0 :     return 0;
     895             : }
     896             : 
     897             : template <XDRMode mode>
     898             : /* static */ bool
     899         142 : VarScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
     900             :               MutableHandleScope scope)
     901             : {
     902         142 :     JSContext* cx = xdr->cx();
     903         284 :     Rooted<Data*> data(cx);
     904         142 :     if (!XDRSizedBindingNames<VarScope>(xdr, scope.as<VarScope>(), &data))
     905           0 :         return false;
     906             : 
     907             :     {
     908         284 :         Maybe<Rooted<UniquePtr<Data>>> uniqueData;
     909             :         if (mode == XDR_DECODE)
     910         110 :             uniqueData.emplace(cx, data);
     911             : 
     912             :         uint8_t needsEnvironment;
     913             :         uint32_t firstFrameSlot;
     914             :         uint32_t nextFrameSlot;
     915             :         if (mode == XDR_ENCODE) {
     916          32 :             needsEnvironment = scope->hasEnvironment();
     917          32 :             firstFrameSlot = scope->as<VarScope>().firstFrameSlot();
     918          32 :             nextFrameSlot = data->nextFrameSlot;
     919             :         }
     920         142 :         if (!xdr->codeUint8(&needsEnvironment))
     921           0 :             return false;
     922         142 :         if (!xdr->codeUint32(&firstFrameSlot))
     923           0 :             return false;
     924         142 :         if (!xdr->codeUint32(&nextFrameSlot))
     925           0 :             return false;
     926             : 
     927             :         if (mode == XDR_DECODE) {
     928         110 :             if (!data->length) {
     929           5 :                 MOZ_ASSERT(!data->nextFrameSlot);
     930             :             }
     931             : 
     932         110 :             scope.set(createWithData(cx, kind, &uniqueData.ref(), firstFrameSlot, needsEnvironment,
     933             :                                      enclosing));
     934         110 :             if (!scope)
     935           0 :                 return false;
     936             : 
     937             :             // nextFrameSlot is used only for this correctness check.
     938         110 :             MOZ_ASSERT(nextFrameSlot == scope->as<VarScope>().data().nextFrameSlot);
     939             :         }
     940             :     }
     941             : 
     942         142 :     return true;
     943             : }
     944             : 
     945             : template
     946             : /* static */ bool
     947             : VarScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind, HandleScope enclosing,
     948             :               MutableHandleScope scope);
     949             : 
     950             : template
     951             : /* static */ bool
     952             : VarScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind, HandleScope enclosing,
     953             :               MutableHandleScope scope);
     954             : 
     955             : /* static */ GlobalScope*
     956         762 : GlobalScope::create(JSContext* cx, ScopeKind kind, Handle<Data*> dataArg)
     957             : {
     958             :     // The data that's passed in is from the frontend and is LifoAlloc'd.
     959             :     // Copy it now that we're creating a permanent VM scope.
     960        1524 :     Rooted<UniquePtr<Data>> data(cx, dataArg ? CopyScopeData<GlobalScope>(cx, dataArg)
     961        2286 :                                              : NewEmptyScopeData<GlobalScope>(cx));
     962         762 :     if (!data)
     963           0 :         return nullptr;
     964             : 
     965         762 :     return createWithData(cx, kind, &data);
     966             : }
     967             : 
     968             : /* static */ GlobalScope*
     969        1022 : GlobalScope::createWithData(JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data)
     970             : {
     971        1022 :     MOZ_ASSERT(data);
     972             : 
     973             :     // The global scope has no environment shape. Its environment is the
     974             :     // global lexical scope and the global object or non-syntactic objects
     975             :     // created by embedding, all of which are not only extensible but may
     976             :     // have names on them deleted.
     977        1022 :     Scope* scope = Scope::create(cx, kind, nullptr, nullptr, Move(data.get()));
     978        1022 :     if (!scope)
     979           0 :         return nullptr;
     980        1022 :     return &scope->as<GlobalScope>();
     981             : }
     982             : 
     983             : /* static */ GlobalScope*
     984         228 : GlobalScope::clone(JSContext* cx, Handle<GlobalScope*> scope, ScopeKind kind)
     985             : {
     986         456 :     Rooted<Data*> dataOriginal(cx, &scope->as<GlobalScope>().data());
     987         456 :     Rooted<UniquePtr<Data>> dataClone(cx, CopyScopeData<GlobalScope>(cx, dataOriginal));
     988         228 :     if (!dataClone)
     989           0 :         return nullptr;
     990             : 
     991         228 :     Scope* scopeClone = Scope::create(cx, kind, nullptr, nullptr, Move(dataClone.get()));
     992         228 :     if (!scopeClone)
     993           0 :         return nullptr;
     994         228 :     return &scopeClone->as<GlobalScope>();
     995             : }
     996             : 
     997             : template <XDRMode mode>
     998             : /* static */ bool
     999         342 : GlobalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope)
    1000             : {
    1001         342 :     MOZ_ASSERT((mode == XDR_DECODE) == !scope);
    1002             : 
    1003         342 :     JSContext* cx = xdr->cx();
    1004         684 :     Rooted<Data*> data(cx);
    1005         342 :     if (!XDRSizedBindingNames<GlobalScope>(xdr, scope.as<GlobalScope>(), &data))
    1006           0 :         return false;
    1007             : 
    1008             :     {
    1009         684 :         Maybe<Rooted<UniquePtr<Data>>> uniqueData;
    1010             :         if (mode == XDR_DECODE)
    1011         260 :             uniqueData.emplace(cx, data);
    1012             : 
    1013         342 :         if (!xdr->codeUint32(&data->varStart))
    1014           0 :             return false;
    1015         342 :         if (!xdr->codeUint32(&data->letStart))
    1016           0 :             return false;
    1017         342 :         if (!xdr->codeUint32(&data->constStart))
    1018           0 :             return false;
    1019             : 
    1020             :         if (mode == XDR_DECODE) {
    1021         260 :             if (!data->length) {
    1022          14 :                 MOZ_ASSERT(!data->varStart);
    1023          14 :                 MOZ_ASSERT(!data->letStart);
    1024          14 :                 MOZ_ASSERT(!data->constStart);
    1025             :             }
    1026             : 
    1027         260 :             scope.set(createWithData(cx, kind, &uniqueData.ref()));
    1028         260 :             if (!scope)
    1029           0 :                 return false;
    1030             :         }
    1031             :     }
    1032             : 
    1033         342 :     return true;
    1034             : }
    1035             : 
    1036             : template
    1037             : /* static */ bool
    1038             : GlobalScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind, MutableHandleScope scope);
    1039             : 
    1040             : template
    1041             : /* static */ bool
    1042             : GlobalScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind, MutableHandleScope scope);
    1043             : 
    1044             : /* static */ WithScope*
    1045           0 : WithScope::create(JSContext* cx, HandleScope enclosing)
    1046             : {
    1047           0 :     Scope* scope = Scope::create(cx, ScopeKind::With, enclosing, nullptr);
    1048           0 :     return static_cast<WithScope*>(scope);
    1049             : }
    1050             : 
    1051             : static const uint32_t EvalScopeEnvShapeFlags =
    1052             :     BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE;
    1053             : 
    1054             : /* static */ EvalScope*
    1055           2 : EvalScope::create(JSContext* cx, ScopeKind scopeKind, Handle<Data*> dataArg,
    1056             :                   HandleScope enclosing)
    1057             : {
    1058             :     // The data that's passed in is from the frontend and is LifoAlloc'd.
    1059             :     // Copy it now that we're creating a permanent VM scope.
    1060           4 :     Rooted<UniquePtr<Data>> data(cx, dataArg ? CopyScopeData<EvalScope>(cx, dataArg)
    1061           6 :                                              : NewEmptyScopeData<EvalScope>(cx));
    1062           2 :     if (!data)
    1063           0 :         return nullptr;
    1064             : 
    1065           2 :     return createWithData(cx, scopeKind, &data, enclosing);
    1066             : }
    1067             : 
    1068             : /* static */ EvalScope*
    1069           2 : EvalScope::createWithData(JSContext* cx, ScopeKind scopeKind, MutableHandle<UniquePtr<Data>> data,
    1070             :                           HandleScope enclosing)
    1071             : {
    1072           2 :     MOZ_ASSERT(data);
    1073             : 
    1074           4 :     RootedShape envShape(cx);
    1075           2 :     if (scopeKind == ScopeKind::StrictEval) {
    1076           2 :         BindingIter bi(*data, true);
    1077           2 :         if (!PrepareScopeData<EvalScope>(cx, bi, data, &VarEnvironmentObject::class_,
    1078             :                                          EvalScopeEnvShapeFlags, &envShape))
    1079             :         {
    1080           0 :             return nullptr;
    1081             :         }
    1082             :     }
    1083             : 
    1084             :     // Strict eval and direct eval in parameter expressions always get their own
    1085             :     // var environment even if there are no bindings.
    1086           2 :     if (!envShape && scopeKind == ScopeKind::StrictEval) {
    1087           0 :         envShape = getEmptyEnvironmentShape(cx);
    1088           0 :         if (!envShape)
    1089           0 :             return nullptr;
    1090             :     }
    1091             : 
    1092           2 :     Scope* scope = Scope::create(cx, scopeKind, enclosing, envShape, Move(data.get()));
    1093           2 :     if (!scope)
    1094           0 :         return nullptr;
    1095           2 :     return &scope->as<EvalScope>();
    1096             : }
    1097             : 
    1098             : /* static */ Scope*
    1099           0 : EvalScope::nearestVarScopeForDirectEval(Scope* scope)
    1100             : {
    1101           0 :     for (ScopeIter si(scope); si; si++) {
    1102           0 :         switch (si.kind()) {
    1103             :           case ScopeKind::Function:
    1104             :           case ScopeKind::FunctionBodyVar:
    1105             :           case ScopeKind::ParameterExpressionVar:
    1106             :           case ScopeKind::Global:
    1107             :           case ScopeKind::NonSyntactic:
    1108           0 :             return scope;
    1109             :           default:
    1110           0 :             break;
    1111             :         }
    1112             :     }
    1113           0 :     return nullptr;
    1114             : }
    1115             : 
    1116             : /* static */ Shape*
    1117           0 : EvalScope::getEmptyEnvironmentShape(JSContext* cx)
    1118             : {
    1119           0 :     const Class* cls = &VarEnvironmentObject::class_;
    1120           0 :     return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), EvalScopeEnvShapeFlags);
    1121             : }
    1122             : 
    1123             : template <XDRMode mode>
    1124             : /* static */ bool
    1125           0 : EvalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
    1126             :                MutableHandleScope scope)
    1127             : {
    1128           0 :     JSContext* cx = xdr->cx();
    1129           0 :     Rooted<Data*> data(cx);
    1130             : 
    1131             :     {
    1132           0 :         Maybe<Rooted<UniquePtr<Data>>> uniqueData;
    1133             :         if (mode == XDR_DECODE)
    1134           0 :             uniqueData.emplace(cx, data);
    1135             : 
    1136           0 :         if (!XDRSizedBindingNames<EvalScope>(xdr, scope.as<EvalScope>(), &data))
    1137           0 :             return false;
    1138             : 
    1139             :         if (mode == XDR_DECODE) {
    1140           0 :             if (!data->length)
    1141           0 :                 MOZ_ASSERT(!data->nextFrameSlot);
    1142             : 
    1143           0 :             scope.set(createWithData(cx, kind, &uniqueData.ref(), enclosing));
    1144           0 :             if (!scope)
    1145           0 :                 return false;
    1146             :         }
    1147             :     }
    1148             : 
    1149           0 :     return true;
    1150             : }
    1151             : 
    1152             : template
    1153             : /* static */ bool
    1154             : EvalScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind, HandleScope enclosing,
    1155             :                MutableHandleScope scope);
    1156             : 
    1157             : template
    1158             : /* static */ bool
    1159             : EvalScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind, HandleScope enclosing,
    1160             :                MutableHandleScope scope);
    1161             : 
    1162             : static const uint32_t ModuleScopeEnvShapeFlags =
    1163             :     BaseShape::NOT_EXTENSIBLE | BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE;
    1164             : 
    1165             : Zone*
    1166           0 : ModuleScope::Data::zone() const
    1167             : {
    1168           0 :     return module ? module->zone() : nullptr;
    1169             : }
    1170             : 
    1171             : /* static */ ModuleScope*
    1172           0 : ModuleScope::create(JSContext* cx, Handle<Data*> dataArg,
    1173             :                     HandleModuleObject module, HandleScope enclosing)
    1174             : {
    1175           0 :     Rooted<UniquePtr<Data>> data(cx, dataArg ? CopyScopeData<ModuleScope>(cx, dataArg)
    1176           0 :                                              : NewEmptyScopeData<ModuleScope>(cx));
    1177           0 :     if (!data)
    1178           0 :         return nullptr;
    1179             : 
    1180           0 :     return createWithData(cx, &data, module, enclosing);
    1181             : }
    1182             : 
    1183             : /* static */ ModuleScope*
    1184           0 : ModuleScope::createWithData(JSContext* cx, MutableHandle<UniquePtr<Data>> data,
    1185             :                             HandleModuleObject module, HandleScope enclosing)
    1186             : {
    1187           0 :     MOZ_ASSERT(data);
    1188           0 :     MOZ_ASSERT(enclosing->is<GlobalScope>());
    1189             : 
    1190             :     // ModuleScope::Data has GCManagedDeletePolicy because it contains a
    1191             :     // GCPtr. Destruction of |copy| below may trigger calls into the GC.
    1192           0 :     Rooted<ModuleScope*> moduleScope(cx);
    1193             : 
    1194             :     {
    1195             :         // The data that's passed in is from the frontend and is LifoAlloc'd.
    1196             :         // Copy it now that we're creating a permanent VM scope.
    1197           0 :         RootedShape envShape(cx);
    1198           0 :         BindingIter bi(*data);
    1199           0 :         if (!PrepareScopeData<ModuleScope>(cx, bi, data, &ModuleEnvironmentObject::class_,
    1200             :                                            ModuleScopeEnvShapeFlags, &envShape))
    1201             :         {
    1202           0 :             return nullptr;
    1203             :         }
    1204             : 
    1205             :         // Modules always need an environment object for now.
    1206           0 :         if (!envShape) {
    1207           0 :             envShape = getEmptyEnvironmentShape(cx);
    1208           0 :             if (!envShape)
    1209           0 :                 return nullptr;
    1210             :         }
    1211             : 
    1212           0 :         Scope* scope = Scope::create(cx, ScopeKind::Module, enclosing, envShape);
    1213           0 :         if (!scope)
    1214           0 :             return nullptr;
    1215             : 
    1216           0 :         data->module.init(module);
    1217             : 
    1218           0 :         moduleScope = &scope->as<ModuleScope>();
    1219           0 :         moduleScope->initData(Move(data.get()));
    1220             :     }
    1221             : 
    1222           0 :     return moduleScope;
    1223             : }
    1224             : 
    1225             : /* static */ Shape*
    1226           0 : ModuleScope::getEmptyEnvironmentShape(JSContext* cx)
    1227             : {
    1228           0 :     const Class* cls = &ModuleEnvironmentObject::class_;
    1229           0 :     return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), ModuleScopeEnvShapeFlags);
    1230             : }
    1231             : 
    1232             : JSScript*
    1233           0 : ModuleScope::script() const
    1234             : {
    1235           0 :     return module()->script();
    1236             : }
    1237             : 
    1238             : // TODO Check what Debugger behavior should be when it evaluates a
    1239             : // var declaration.
    1240             : static const uint32_t WasmFunctionEnvShapeFlags =
    1241             :     BaseShape::NOT_EXTENSIBLE | BaseShape::DELEGATE;
    1242             : 
    1243             : static JSAtom*
    1244           0 : GenerateWasmVariableName(JSContext* cx, uint32_t index)
    1245             : {
    1246           0 :     StringBuffer sb(cx);
    1247           0 :     if (!sb.append("var"))
    1248           0 :         return nullptr;
    1249           0 :     if (!NumberValueToStringBuffer(cx, Int32Value(index), sb))
    1250           0 :         return nullptr;
    1251             : 
    1252           0 :     return sb.finishAtom();
    1253             : }
    1254             : 
    1255             : /* static */ WasmFunctionScope*
    1256           0 : WasmFunctionScope::create(JSContext* cx, WasmInstanceObject* instance, uint32_t funcIndex)
    1257             : {
    1258             :     // WasmFunctionScope::Data has GCManagedDeletePolicy because it contains a
    1259             :     // GCPtr. Destruction of |data| below may trigger calls into the GC.
    1260           0 :     Rooted<WasmFunctionScope*> wasmFunctionScope(cx);
    1261             : 
    1262             :     {
    1263             :         // TODO pull the local variable names from the wasm function definition.
    1264           0 :         wasm::ValTypeVector locals;
    1265             :         size_t argsLength;
    1266           0 :         if (!instance->instance().debug().debugGetLocalTypes(funcIndex, &locals, &argsLength))
    1267           0 :             return nullptr;
    1268           0 :         uint32_t namesCount = locals.length();
    1269             : 
    1270           0 :         Rooted<UniquePtr<Data>> data(cx, NewEmptyScopeData<WasmFunctionScope>(cx, namesCount));
    1271           0 :         if (!data)
    1272           0 :             return nullptr;
    1273             : 
    1274           0 :         Rooted<Scope*> enclosingScope(cx, &cx->global()->emptyGlobalScope());
    1275             : 
    1276           0 :         data->instance.init(instance);
    1277           0 :         data->funcIndex = funcIndex;
    1278           0 :         data->length = namesCount;
    1279           0 :         for (size_t i = 0; i < namesCount; i++) {
    1280           0 :             RootedAtom name(cx, GenerateWasmVariableName(cx, i));
    1281           0 :             if (!name)
    1282           0 :                 return nullptr;
    1283           0 :             data->names[i] = BindingName(name, false);
    1284             :         }
    1285             : 
    1286           0 :         Scope* scope = Scope::create(cx, ScopeKind::WasmFunction, enclosingScope, /* envShape = */ nullptr);
    1287           0 :         if (!scope)
    1288           0 :             return nullptr;
    1289             : 
    1290           0 :         wasmFunctionScope = &scope->as<WasmFunctionScope>();
    1291           0 :         wasmFunctionScope->initData(Move(data.get()));
    1292             :     }
    1293             : 
    1294           0 :     return wasmFunctionScope;
    1295             : }
    1296             : 
    1297             : /* static */ Shape*
    1298           0 : WasmFunctionScope::getEmptyEnvironmentShape(JSContext* cx)
    1299             : {
    1300           0 :     const Class* cls = &WasmFunctionCallObject::class_;
    1301           0 :     return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), WasmFunctionEnvShapeFlags);
    1302             : }
    1303             : 
    1304           0 : ScopeIter::ScopeIter(JSScript* script)
    1305           0 :   : scope_(script->bodyScope())
    1306           0 : { }
    1307             : 
    1308             : bool
    1309       71574 : ScopeIter::hasSyntacticEnvironment() const
    1310             : {
    1311       71574 :     return scope()->hasEnvironment() && scope()->kind() != ScopeKind::NonSyntactic;
    1312             : }
    1313             : 
    1314       36941 : BindingIter::BindingIter(Scope* scope)
    1315             : {
    1316       36941 :     switch (scope->kind()) {
    1317             :       case ScopeKind::Lexical:
    1318             :       case ScopeKind::SimpleCatch:
    1319             :       case ScopeKind::Catch:
    1320        1388 :         init(scope->as<LexicalScope>().data(),
    1321        2776 :              scope->as<LexicalScope>().firstFrameSlot(), 0);
    1322        1388 :         break;
    1323             :       case ScopeKind::NamedLambda:
    1324             :       case ScopeKind::StrictNamedLambda:
    1325          17 :         init(scope->as<LexicalScope>().data(), LOCALNO_LIMIT, IsNamedLambda);
    1326          17 :         break;
    1327             :       case ScopeKind::With:
    1328             :         // With scopes do not have bindings.
    1329           0 :         index_ = length_ = 0;
    1330           0 :         MOZ_ASSERT(done());
    1331           0 :         break;
    1332             :       case ScopeKind::Function: {
    1333       33017 :         uint8_t flags = IgnoreDestructuredFormalParameters;
    1334       33017 :         if (scope->as<FunctionScope>().hasParameterExprs())
    1335         483 :             flags |= HasFormalParameterExprs;
    1336       33017 :         init(scope->as<FunctionScope>().data(), flags);
    1337       33017 :         break;
    1338             :       }
    1339             :       case ScopeKind::FunctionBodyVar:
    1340             :       case ScopeKind::ParameterExpressionVar:
    1341          15 :         init(scope->as<VarScope>().data(),
    1342          30 :              scope->as<VarScope>().firstFrameSlot());
    1343          15 :         break;
    1344             :       case ScopeKind::Eval:
    1345             :       case ScopeKind::StrictEval:
    1346          30 :         init(scope->as<EvalScope>().data(), scope->kind() == ScopeKind::StrictEval);
    1347          30 :         break;
    1348             :       case ScopeKind::Global:
    1349             :       case ScopeKind::NonSyntactic:
    1350        2474 :         init(scope->as<GlobalScope>().data());
    1351        2474 :         break;
    1352             :       case ScopeKind::Module:
    1353           0 :         init(scope->as<ModuleScope>().data());
    1354           0 :         break;
    1355             :       case ScopeKind::WasmFunction:
    1356           0 :         init(scope->as<WasmFunctionScope>().data());
    1357           0 :         break;
    1358             :     }
    1359       36941 : }
    1360             : 
    1361       31883 : BindingIter::BindingIter(JSScript* script)
    1362       31883 :   : BindingIter(script->bodyScope())
    1363       31883 : { }
    1364             : 
    1365             : void
    1366       15057 : BindingIter::init(LexicalScope::Data& data, uint32_t firstFrameSlot, uint8_t flags)
    1367             : {
    1368             :     // Named lambda scopes can only have environment slots. If the callee
    1369             :     // isn't closed over, it is accessed via JSOP_CALLEE.
    1370       15057 :     if (flags & IsNamedLambda) {
    1371             :         // Named lambda binding is weird. Normal BindingKind ordering rules
    1372             :         // don't apply.
    1373        5436 :         init(0, 0, 0, 0, 0, 0,
    1374        1812 :              CanHaveEnvironmentSlots | flags,
    1375        1812 :              firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_),
    1376        1812 :              data.names, data.length);
    1377             :     } else {
    1378             :         //            imports - [0, 0)
    1379             :         // positional formals - [0, 0)
    1380             :         //      other formals - [0, 0)
    1381             :         //    top-level funcs - [0, 0)
    1382             :         //               vars - [0, 0)
    1383             :         //               lets - [0, data.constStart)
    1384             :         //             consts - [data.constStart, data.length)
    1385       39735 :         init(0, 0, 0, 0, 0, data.constStart,
    1386       13245 :              CanHaveFrameSlots | CanHaveEnvironmentSlots | flags,
    1387       13245 :              firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_),
    1388       13245 :              data.names, data.length);
    1389             :     }
    1390       15057 : }
    1391             : 
    1392             : void
    1393       84012 : BindingIter::init(FunctionScope::Data& data, uint8_t flags)
    1394             : {
    1395       84012 :     flags = CanHaveFrameSlots | CanHaveEnvironmentSlots | flags;
    1396       84012 :     if (!(flags & HasFormalParameterExprs))
    1397       82693 :         flags |= CanHaveArgumentSlots;
    1398             : 
    1399             :     //            imports - [0, 0)
    1400             :     // positional formals - [0, data.nonPositionalFormalStart)
    1401             :     //      other formals - [data.nonPositionalParamStart, data.varStart)
    1402             :     //    top-level funcs - [data.varStart, data.varStart)
    1403             :     //               vars - [data.varStart, data.length)
    1404             :     //               lets - [data.length, data.length)
    1405             :     //             consts - [data.length, data.length)
    1406      168024 :     init(0, data.nonPositionalFormalStart, data.varStart, data.varStart, data.length, data.length,
    1407             :          flags,
    1408       84012 :          0, JSSLOT_FREE(&CallObject::class_),
    1409       84012 :          data.names, data.length);
    1410       84010 : }
    1411             : 
    1412             : void
    1413         333 : BindingIter::init(VarScope::Data& data, uint32_t firstFrameSlot)
    1414             : {
    1415             :     //            imports - [0, 0)
    1416             :     // positional formals - [0, 0)
    1417             :     //      other formals - [0, 0)
    1418             :     //    top-level funcs - [0, 0)
    1419             :     //               vars - [0, data.length)
    1420             :     //               lets - [data.length, data.length)
    1421             :     //             consts - [data.length, data.length)
    1422         666 :     init(0, 0, 0, 0, data.length, data.length,
    1423             :          CanHaveFrameSlots | CanHaveEnvironmentSlots,
    1424         333 :          firstFrameSlot, JSSLOT_FREE(&VarEnvironmentObject::class_),
    1425         333 :          data.names, data.length);
    1426         333 : }
    1427             : 
    1428             : void
    1429        2604 : BindingIter::init(GlobalScope::Data& data)
    1430             : {
    1431             :     //            imports - [0, 0)
    1432             :     // positional formals - [0, 0)
    1433             :     //      other formals - [0, 0)
    1434             :     //    top-level funcs - [0, data.varStart)
    1435             :     //               vars - [data.varStart, data.letStart)
    1436             :     //               lets - [data.letStart, data.constStart)
    1437             :     //             consts - [data.constStart, data.length)
    1438        2604 :     init(0, 0, 0, data.varStart, data.letStart, data.constStart,
    1439             :          CannotHaveSlots,
    1440             :          UINT32_MAX, UINT32_MAX,
    1441        2604 :          data.names, data.length);
    1442        2604 : }
    1443             : 
    1444             : void
    1445          32 : BindingIter::init(EvalScope::Data& data, bool strict)
    1446             : {
    1447             :     uint32_t flags;
    1448             :     uint32_t firstFrameSlot;
    1449             :     uint32_t firstEnvironmentSlot;
    1450          32 :     if (strict) {
    1451          32 :         flags = CanHaveFrameSlots | CanHaveEnvironmentSlots;
    1452          32 :         firstFrameSlot = 0;
    1453          32 :         firstEnvironmentSlot = JSSLOT_FREE(&VarEnvironmentObject::class_);
    1454             :     } else {
    1455           0 :         flags = CannotHaveSlots;
    1456           0 :         firstFrameSlot = UINT32_MAX;
    1457           0 :         firstEnvironmentSlot = UINT32_MAX;
    1458             :     }
    1459             : 
    1460             :     //            imports - [0, 0)
    1461             :     // positional formals - [0, 0)
    1462             :     //      other formals - [0, 0)
    1463             :     //    top-level funcs - [0, data.varStart)
    1464             :     //               vars - [data.varStart, data.length)
    1465             :     //               lets - [data.length, data.length)
    1466             :     //             consts - [data.length, data.length)
    1467          32 :     init(0, 0, 0, data.varStart, data.length, data.length,
    1468             :          flags, firstFrameSlot, firstEnvironmentSlot,
    1469          32 :          data.names, data.length);
    1470          32 : }
    1471             : 
    1472             : void
    1473           0 : BindingIter::init(ModuleScope::Data& data)
    1474             : {
    1475             :     //            imports - [0, data.varStart)
    1476             :     // positional formals - [data.varStart, data.varStart)
    1477             :     //      other formals - [data.varStart, data.varStart)
    1478             :     //    top-level funcs - [data.varStart, data.varStart)
    1479             :     //               vars - [data.varStart, data.letStart)
    1480             :     //               lets - [data.letStart, data.constStart)
    1481             :     //             consts - [data.constStart, data.length)
    1482           0 :     init(data.varStart, data.varStart, data.varStart, data.varStart, data.letStart, data.constStart,
    1483             :          CanHaveFrameSlots | CanHaveEnvironmentSlots,
    1484           0 :          0, JSSLOT_FREE(&ModuleEnvironmentObject::class_),
    1485           0 :          data.names, data.length);
    1486           0 : }
    1487             : 
    1488             : void
    1489           0 : BindingIter::init(WasmFunctionScope::Data& data)
    1490             : {
    1491             :     //            imports - [0, 0)
    1492             :     // positional formals - [0, 0)
    1493             :     //      other formals - [0, 0)
    1494             :     //    top-level funcs - [0, 0)
    1495             :     //               vars - [0, data.length)
    1496             :     //               lets - [data.length, data.length)
    1497             :     //             consts - [data.length, data.length)
    1498           0 :     init(0, 0, 0, 0, data.length, data.length,
    1499             :          CanHaveFrameSlots | CanHaveEnvironmentSlots,
    1500             :          UINT32_MAX, UINT32_MAX,
    1501           0 :          data.names, data.length);
    1502           0 : }
    1503             : 
    1504       31388 : PositionalFormalParameterIter::PositionalFormalParameterIter(JSScript* script)
    1505       31388 :   : BindingIter(script)
    1506             : {
    1507             :     // Reinit with flags = 0, i.e., iterate over all positional parameters.
    1508       31388 :     if (script->bodyScope()->is<FunctionScope>())
    1509       31388 :         init(script->bodyScope()->as<FunctionScope>().data(), /* flags = */ 0);
    1510       31388 :     settle();
    1511       31388 : }
    1512             : 
    1513             : void
    1514           0 : js::DumpBindings(JSContext* cx, Scope* scopeArg)
    1515             : {
    1516           0 :     RootedScope scope(cx, scopeArg);
    1517           0 :     for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
    1518           0 :         JSAutoByteString bytes;
    1519           0 :         if (!AtomToPrintableString(cx, bi.name(), &bytes))
    1520           0 :             return;
    1521           0 :         fprintf(stderr, "%s %s ", BindingKindString(bi.kind()), bytes.ptr());
    1522           0 :         switch (bi.location().kind()) {
    1523             :           case BindingLocation::Kind::Global:
    1524           0 :             if (bi.isTopLevelFunction())
    1525           0 :                 fprintf(stderr, "global function\n");
    1526             :             else
    1527           0 :                 fprintf(stderr, "global\n");
    1528           0 :             break;
    1529             :           case BindingLocation::Kind::Argument:
    1530           0 :             fprintf(stderr, "arg slot %u\n", bi.location().argumentSlot());
    1531           0 :             break;
    1532             :           case BindingLocation::Kind::Frame:
    1533           0 :             fprintf(stderr, "frame slot %u\n", bi.location().slot());
    1534           0 :             break;
    1535             :           case BindingLocation::Kind::Environment:
    1536           0 :             fprintf(stderr, "env slot %u\n", bi.location().slot());
    1537           0 :             break;
    1538             :           case BindingLocation::Kind::NamedLambdaCallee:
    1539           0 :             fprintf(stderr, "named lambda callee\n");
    1540           0 :             break;
    1541             :           case BindingLocation::Kind::Import:
    1542           0 :             fprintf(stderr, "import\n");
    1543           0 :             break;
    1544             :         }
    1545             :     }
    1546             : }
    1547             : 
    1548             : static JSAtom*
    1549           2 : GetFrameSlotNameInScope(Scope* scope, uint32_t slot)
    1550             : {
    1551           5 :     for (BindingIter bi(scope); bi; bi++) {
    1552           4 :         BindingLocation loc = bi.location();
    1553           4 :         if (loc.kind() == BindingLocation::Kind::Frame && loc.slot() == slot)
    1554           1 :             return bi.name();
    1555             :     }
    1556           1 :     return nullptr;
    1557             : }
    1558             : 
    1559             : JSAtom*
    1560           1 : js::FrameSlotName(JSScript* script, jsbytecode* pc)
    1561             : {
    1562           1 :     MOZ_ASSERT(IsLocalOp(JSOp(*pc)));
    1563           1 :     uint32_t slot = GET_LOCALNO(pc);
    1564           1 :     MOZ_ASSERT(slot < script->nfixed());
    1565             : 
    1566             :     // Look for it in the body scope first.
    1567           1 :     if (JSAtom* name = GetFrameSlotNameInScope(script->bodyScope(), slot))
    1568           0 :         return name;
    1569             : 
    1570             :     // If this is a function script and there is an extra var scope, look for
    1571             :     // it there.
    1572           1 :     if (script->functionHasExtraBodyVarScope()) {
    1573           0 :         if (JSAtom* name = GetFrameSlotNameInScope(script->functionExtraBodyVarScope(), slot))
    1574           0 :             return name;
    1575             :     }
    1576             : 
    1577             :     // If not found, look for it in a lexical scope.
    1578           2 :     for (ScopeIter si(script->innermostScope(pc)); si; si++) {
    1579           2 :         if (!si.scope()->is<LexicalScope>())
    1580           0 :             continue;
    1581           2 :         LexicalScope& lexicalScope = si.scope()->as<LexicalScope>();
    1582             : 
    1583             :         // Is the slot within bounds of the current lexical scope?
    1584           2 :         if (slot < lexicalScope.firstFrameSlot())
    1585           1 :             continue;
    1586           1 :         if (slot >= lexicalScope.nextFrameSlot())
    1587           0 :             break;
    1588             : 
    1589             :         // If so, get the name.
    1590           1 :         if (JSAtom* name = GetFrameSlotNameInScope(&lexicalScope, slot))
    1591           1 :             return name;
    1592             :     }
    1593             : 
    1594           0 :     MOZ_CRASH("Frame slot not found");
    1595             : }
    1596             : 
    1597             : JS::ubi::Node::Size
    1598           0 : JS::ubi::Concrete<Scope>::size(mozilla::MallocSizeOf mallocSizeOf) const
    1599             : {
    1600           0 :     return js::gc::Arena::thingSize(get().asTenured().getAllocKind()) +
    1601           0 :            get().sizeOfExcludingThis(mallocSizeOf);
    1602             : }

Generated by: LCOV version 1.13