1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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/OperatorNewExtensions.h"  // mozilla::KnownNotNull
10 #include "mozilla/ScopeExit.h"
11 
12 #include <memory>
13 #include <new>
14 
15 #include "builtin/ModuleObject.h"
16 #include "frontend/CompilationStencil.h"  // CompilationState, CompilationAtomCache
17 #include "frontend/Parser.h"              // Copy*ScopeData
18 #include "frontend/ScriptIndex.h"         // ScriptIndex
19 #include "frontend/SharedContext.h"
20 #include "frontend/Stencil.h"
21 #include "gc/Allocator.h"
22 #include "gc/MaybeRooted.h"
23 #include "util/StringBuffer.h"
24 #include "vm/EnvironmentObject.h"
25 #include "vm/ErrorReporting.h"  // MaybePrintAndClearPendingException
26 #include "vm/JSScript.h"
27 #include "wasm/WasmInstance.h"
28 
29 #include "gc/FreeOp-inl.h"
30 #include "gc/ObjectKind-inl.h"
31 #include "vm/Shape-inl.h"
32 
33 using namespace js;
34 using namespace js::frontend;
35 
36 using mozilla::Maybe;
37 
BindingKindString(BindingKind kind)38 const char* js::BindingKindString(BindingKind kind) {
39   switch (kind) {
40     case BindingKind::Import:
41       return "import";
42     case BindingKind::FormalParameter:
43       return "formal parameter";
44     case BindingKind::Var:
45       return "var";
46     case BindingKind::Let:
47       return "let";
48     case BindingKind::Const:
49       return "const";
50     case BindingKind::NamedLambdaCallee:
51       return "named lambda callee";
52     case BindingKind::Synthetic:
53       return "synthetic";
54     case BindingKind::PrivateMethod:
55       return "private method";
56   }
57   MOZ_CRASH("Bad BindingKind");
58 }
59 
ScopeKindString(ScopeKind kind)60 const char* js::ScopeKindString(ScopeKind kind) {
61   switch (kind) {
62     case ScopeKind::Function:
63       return "function";
64     case ScopeKind::FunctionBodyVar:
65       return "function body var";
66     case ScopeKind::Lexical:
67       return "lexical";
68     case ScopeKind::SimpleCatch:
69     case ScopeKind::Catch:
70       return "catch";
71     case ScopeKind::NamedLambda:
72       return "named lambda";
73     case ScopeKind::StrictNamedLambda:
74       return "strict named lambda";
75     case ScopeKind::FunctionLexical:
76       return "function lexical";
77     case ScopeKind::ClassBody:
78       return "class body";
79     case ScopeKind::With:
80       return "with";
81     case ScopeKind::Eval:
82       return "eval";
83     case ScopeKind::StrictEval:
84       return "strict eval";
85     case ScopeKind::Global:
86       return "global";
87     case ScopeKind::NonSyntactic:
88       return "non-syntactic";
89     case ScopeKind::Module:
90       return "module";
91     case ScopeKind::WasmInstance:
92       return "wasm instance";
93     case ScopeKind::WasmFunction:
94       return "wasm function";
95   }
96   MOZ_CRASH("Bad ScopeKind");
97 }
98 
EmptyEnvironmentShape(JSContext * cx,const JSClass * cls,uint32_t numSlots,ObjectFlags objectFlags)99 Shape* js::EmptyEnvironmentShape(JSContext* cx, const JSClass* cls,
100                                  uint32_t numSlots, ObjectFlags objectFlags) {
101   // Put as many slots into the object header as possible.
102   uint32_t numFixed = gc::GetGCKindSlots(gc::GetGCObjectKind(numSlots));
103   return SharedShape::getInitialShape(
104       cx, cls, cx->realm(), TaggedProto(nullptr), numFixed, objectFlags);
105 }
106 
AddToEnvironmentMap(JSContext * cx,const JSClass * clasp,HandleId id,BindingKind bindKind,uint32_t slot,MutableHandle<SharedPropMap * > map,uint32_t * mapLength,ObjectFlags * objectFlags)107 static bool AddToEnvironmentMap(JSContext* cx, const JSClass* clasp,
108                                 HandleId id, BindingKind bindKind,
109                                 uint32_t slot,
110                                 MutableHandle<SharedPropMap*> map,
111                                 uint32_t* mapLength, ObjectFlags* objectFlags) {
112   PropertyFlags propFlags = {PropertyFlag::Enumerable};
113   switch (bindKind) {
114     case BindingKind::Const:
115     case BindingKind::NamedLambdaCallee:
116       // Non-writable.
117       break;
118     default:
119       propFlags.setFlag(PropertyFlag::Writable);
120       break;
121   }
122 
123   return SharedPropMap::addPropertyWithKnownSlot(cx, clasp, map, mapLength, id,
124                                                  propFlags, slot, objectFlags);
125 }
126 
CreateEnvironmentShape(JSContext * cx,BindingIter & bi,const JSClass * cls,uint32_t numSlots,ObjectFlags objectFlags)127 Shape* js::CreateEnvironmentShape(JSContext* cx, BindingIter& bi,
128                                   const JSClass* cls, uint32_t numSlots,
129                                   ObjectFlags objectFlags) {
130   Rooted<SharedPropMap*> map(cx);
131   uint32_t mapLength = 0;
132 
133   RootedId id(cx);
134   for (; bi; bi++) {
135     BindingLocation loc = bi.location();
136     if (loc.kind() == BindingLocation::Kind::Environment) {
137       JSAtom* name = bi.name();
138       cx->markAtom(name);
139       id = NameToId(name->asPropertyName());
140       if (!AddToEnvironmentMap(cx, cls, id, bi.kind(), loc.slot(), &map,
141                                &mapLength, &objectFlags)) {
142         return nullptr;
143       }
144     }
145   }
146 
147   uint32_t numFixed = gc::GetGCKindSlots(gc::GetGCObjectKind(numSlots));
148   return SharedShape::getInitialOrPropMapShape(cx, cls, cx->realm(),
149                                                TaggedProto(nullptr), numFixed,
150                                                map, mapLength, objectFlags);
151 }
152 
CreateEnvironmentShape(JSContext * cx,frontend::CompilationAtomCache & atomCache,AbstractBindingIter<frontend::TaggedParserAtomIndex> & bi,const JSClass * cls,uint32_t numSlots,ObjectFlags objectFlags)153 Shape* js::CreateEnvironmentShape(
154     JSContext* cx, frontend::CompilationAtomCache& atomCache,
155     AbstractBindingIter<frontend::TaggedParserAtomIndex>& bi,
156     const JSClass* cls, uint32_t numSlots, ObjectFlags objectFlags) {
157   Rooted<SharedPropMap*> map(cx);
158   uint32_t mapLength = 0;
159 
160   RootedId id(cx);
161   for (; bi; bi++) {
162     BindingLocation loc = bi.location();
163     if (loc.kind() == BindingLocation::Kind::Environment) {
164       JSAtom* name = atomCache.getExistingAtomAt(cx, bi.name());
165       MOZ_ASSERT(name);
166       cx->markAtom(name);
167       id = NameToId(name->asPropertyName());
168       if (!AddToEnvironmentMap(cx, cls, id, bi.kind(), loc.slot(), &map,
169                                &mapLength, &objectFlags)) {
170         return nullptr;
171       }
172     }
173   }
174 
175   uint32_t numFixed = gc::GetGCKindSlots(gc::GetGCObjectKind(numSlots));
176   return SharedShape::getInitialOrPropMapShape(cx, cls, cx->realm(),
177                                                TaggedProto(nullptr), numFixed,
178                                                map, mapLength, objectFlags);
179 }
180 
181 template <class DataT>
SizeOfAllocatedData(DataT * data)182 inline size_t SizeOfAllocatedData(DataT* data) {
183   return SizeOfScopeData<DataT>(data->length);
184 }
185 
186 template <typename ConcreteScope>
CopyScopeData(JSContext * cx,typename ConcreteScope::RuntimeData * data)187 static UniquePtr<typename ConcreteScope::RuntimeData> CopyScopeData(
188     JSContext* cx, typename ConcreteScope::RuntimeData* data) {
189   using Data = typename ConcreteScope::RuntimeData;
190 
191   // Make sure the binding names are marked in the context's zone, if we are
192   // copying data from another zone.
193   auto names = GetScopeDataTrailingNames(data);
194   for (auto binding : names) {
195     if (JSAtom* name = binding.name()) {
196       cx->markAtom(name);
197     }
198   }
199 
200   size_t size = SizeOfAllocatedData(data);
201   void* bytes = cx->pod_malloc<char>(size);
202   if (!bytes) {
203     return nullptr;
204   }
205 
206   auto* dataCopy = new (bytes) Data(*data);
207 
208   std::uninitialized_copy_n(GetScopeDataTrailingNamesPointer(data),
209                             data->length,
210                             GetScopeDataTrailingNamesPointer(dataCopy));
211 
212   return UniquePtr<Data>(dataCopy);
213 }
214 
215 template <typename ConcreteScope>
MarkParserScopeData(JSContext * cx,typename ConcreteScope::ParserData * data,frontend::CompilationState & compilationState)216 static void MarkParserScopeData(JSContext* cx,
217                                 typename ConcreteScope::ParserData* data,
218                                 frontend::CompilationState& compilationState) {
219   auto names = GetScopeDataTrailingNames(data);
220   for (auto& binding : names) {
221     auto index = binding.name();
222     if (!index) {
223       continue;
224     }
225     compilationState.parserAtoms.markUsedByStencil(index);
226   }
227 }
228 
SetEnvironmentShape(JSContext * cx,BindingIter & freshBi,BindingIter & bi,const JSClass * cls,uint32_t firstFrameSlot,ObjectFlags objectFlags,MutableHandleShape envShape)229 static bool SetEnvironmentShape(JSContext* cx, BindingIter& freshBi,
230                                 BindingIter& bi, const JSClass* cls,
231                                 uint32_t firstFrameSlot,
232                                 ObjectFlags objectFlags,
233                                 MutableHandleShape envShape) {
234   envShape.set(CreateEnvironmentShape(cx, freshBi, cls,
235                                       bi.nextEnvironmentSlot(), objectFlags));
236   return envShape;
237 }
238 
SetEnvironmentShape(JSContext * cx,ParserBindingIter & freshBi,ParserBindingIter & bi,const JSClass * cls,uint32_t firstFrameSlot,ObjectFlags objectFlags,mozilla::Maybe<uint32_t> * envShape)239 static bool SetEnvironmentShape(JSContext* cx, ParserBindingIter& freshBi,
240                                 ParserBindingIter& bi, const JSClass* cls,
241                                 uint32_t firstFrameSlot,
242                                 ObjectFlags objectFlags,
243                                 mozilla::Maybe<uint32_t>* envShape) {
244   envShape->emplace(bi.nextEnvironmentSlot());
245   return true;
246 }
247 
248 template <typename ConcreteScope, typename AtomT, typename EnvironmentT,
249           typename ShapeT>
PrepareScopeData(JSContext * cx,AbstractBindingIter<AtomT> & bi,typename MaybeRootedScopeData<ConcreteScope,AtomT>::HandleType data,uint32_t firstFrameSlot,ShapeT envShape)250 static bool PrepareScopeData(
251     JSContext* cx, AbstractBindingIter<AtomT>& bi,
252     typename MaybeRootedScopeData<ConcreteScope, AtomT>::HandleType data,
253     uint32_t firstFrameSlot, ShapeT envShape) {
254   const JSClass* cls = &EnvironmentT::class_;
255   constexpr ObjectFlags objectFlags = EnvironmentT::OBJECT_FLAGS;
256 
257   // Copy a fresh BindingIter for use below.
258   AbstractBindingIter<AtomT> freshBi(bi);
259 
260   // Iterate through all bindings. This counts the number of environment
261   // slots needed and computes the maximum frame slot.
262   while (bi) {
263     bi++;
264   }
265   data->slotInfo.nextFrameSlot =
266       bi.canHaveFrameSlots() ? bi.nextFrameSlot() : LOCALNO_LIMIT;
267 
268   // Data is not used after this point.  Before this point, gc cannot
269   // occur, so `data` is fine as a raw pointer.
270 
271   // Make a new environment shape if any environment slots were used.
272   if (bi.nextEnvironmentSlot() != JSSLOT_FREE(cls)) {
273     if (!SetEnvironmentShape(cx, freshBi, bi, cls, firstFrameSlot, objectFlags,
274                              envShape)) {
275       return false;
276     }
277   }
278 
279   return true;
280 }
281 
282 template <typename ConcreteScope>
NewEmptyParserScopeData(JSContext * cx,LifoAlloc & alloc,uint32_t length=0)283 static typename ConcreteScope::ParserData* NewEmptyParserScopeData(
284     JSContext* cx, LifoAlloc& alloc, uint32_t length = 0) {
285   using Data = typename ConcreteScope::ParserData;
286 
287   size_t dataSize = SizeOfScopeData<Data>(length);
288   void* raw = alloc.alloc(dataSize);
289   if (!raw) {
290     js::ReportOutOfMemory(cx);
291     return nullptr;
292   }
293 
294   return new (raw) Data(length);
295 }
296 
297 template <typename ConcreteScope, typename AtomT>
NewEmptyScopeData(JSContext * cx,uint32_t length=0)298 static UniquePtr<AbstractScopeData<ConcreteScope, AtomT>> NewEmptyScopeData(
299     JSContext* cx, uint32_t length = 0) {
300   using Data = AbstractScopeData<ConcreteScope, AtomT>;
301 
302   size_t dataSize = SizeOfScopeData<Data>(length);
303   uint8_t* bytes = cx->pod_malloc<uint8_t>(dataSize);
304   auto data = reinterpret_cast<Data*>(bytes);
305   if (data) {
306     new (data) Data(length);
307   }
308   return UniquePtr<Data>(data);
309 }
310 
311 template <typename ConcreteScope>
LiftParserScopeData(JSContext * cx,frontend::CompilationAtomCache & atomCache,BaseParserScopeData * baseData)312 static UniquePtr<typename ConcreteScope::RuntimeData> LiftParserScopeData(
313     JSContext* cx, frontend::CompilationAtomCache& atomCache,
314     BaseParserScopeData* baseData) {
315   using ConcreteData = typename ConcreteScope::RuntimeData;
316 
317   auto* data = static_cast<typename ConcreteScope::ParserData*>(baseData);
318 
319   // Convert all scope ParserAtoms to rooted JSAtoms.
320   // Rooting is necessary as conversion can gc.
321   JS::RootedVector<JSAtom*> jsatoms(cx);
322   if (!jsatoms.reserve(data->length)) {
323     return nullptr;
324   }
325   auto names = GetScopeDataTrailingNames(data);
326   for (size_t i = 0; i < names.size(); i++) {
327     JSAtom* jsatom = nullptr;
328     if (names[i].name()) {
329       jsatom = atomCache.getExistingAtomAt(cx, names[i].name());
330       MOZ_ASSERT(jsatom);
331     }
332     jsatoms.infallibleAppend(jsatom);
333   }
334 
335   // Allocate a new scope-data of the right kind.
336   UniquePtr<ConcreteData> scopeData(
337       NewEmptyScopeData<ConcreteScope, JSAtom>(cx, data->length));
338   if (!scopeData) {
339     return nullptr;
340   }
341 
342   // NOTE: There shouldn't be any fallible operation or GC between setting
343   //       `length` and filling `trailingNames`.
344   scopeData.get()->length = data->length;
345 
346   memcpy(&scopeData.get()->slotInfo, &data->slotInfo,
347          sizeof(typename ConcreteScope::SlotInfo));
348 
349   // Initialize new scoped names.
350   auto namesOut = GetScopeDataTrailingNames(scopeData.get());
351   MOZ_ASSERT(data->length == namesOut.size());
352   for (size_t i = 0; i < namesOut.size(); i++) {
353     namesOut[i] = names[i].copyWithNewAtom(jsatoms[i].get());
354   }
355 
356   return scopeData;
357 }
358 
359 static constexpr size_t HasAtomMask = 1;
360 static constexpr size_t HasAtomShift = 1;
361 
XDRTrailingName(XDRState<XDR_ENCODE> * xdr,BindingName * bindingName,const uint32_t * length)362 static XDRResult XDRTrailingName(XDRState<XDR_ENCODE>* xdr,
363                                  BindingName* bindingName,
364                                  const uint32_t* length) {
365   JSContext* cx = xdr->cx();
366 
367   RootedAtom atom(cx, bindingName->name());
368   bool hasAtom = !!atom;
369 
370   uint8_t flags = bindingName->flagsForXDR();
371   MOZ_ASSERT(((flags << HasAtomShift) >> HasAtomShift) == flags);
372   uint8_t u8 = (flags << HasAtomShift) | uint8_t(hasAtom);
373   MOZ_TRY(xdr->codeUint8(&u8));
374 
375   if (hasAtom) {
376     MOZ_TRY(XDRAtom(xdr, &atom));
377   }
378 
379   return Ok();
380 }
381 
XDRTrailingName(XDRState<XDR_DECODE> * xdr,void * bindingName,uint32_t * length)382 static XDRResult XDRTrailingName(XDRState<XDR_DECODE>* xdr, void* bindingName,
383                                  uint32_t* length) {
384   JSContext* cx = xdr->cx();
385 
386   uint8_t u8;
387   MOZ_TRY(xdr->codeUint8(&u8));
388 
389   bool hasAtom = u8 & HasAtomMask;
390   RootedAtom atom(cx);
391   if (hasAtom) {
392     MOZ_TRY(XDRAtom(xdr, &atom));
393   }
394 
395   uint8_t flags = u8 >> HasAtomShift;
396   new (bindingName) BindingName(BindingName::fromXDR(atom, flags));
397   ++*length;
398 
399   return Ok();
400 }
401 
402 template <typename ConcreteScope, XDRMode mode>
403 /* static */
XDRSizedBindingNames(XDRState<mode> * xdr,Handle<ConcreteScope * > scope,MutableHandle<typename ConcreteScope::RuntimeData * > data)404 XDRResult Scope::XDRSizedBindingNames(
405     XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
406     MutableHandle<typename ConcreteScope::RuntimeData*> data) {
407   MOZ_ASSERT(!data);
408 
409   JSContext* cx = xdr->cx();
410 
411   uint32_t length;
412   if (mode == XDR_ENCODE) {
413     length = scope->data().length;
414   }
415   MOZ_TRY(xdr->codeUint32(&length));
416 
417   if (mode == XDR_ENCODE) {
418     data.set(&scope->data());
419   } else {
420     data.set(NewEmptyScopeData<ConcreteScope, JSAtom>(cx, length).release());
421     if (!data) {
422       return xdr->fail(JS::TranscodeResult::Throw);
423     }
424   }
425 
426   auto dataGuard = mozilla::MakeScopeExit([&]() {
427     if (mode == XDR_DECODE) {
428       js_delete(data.get());
429       data.set(nullptr);
430     }
431   });
432 
433   BindingName* names = GetScopeDataTrailingNamesPointer(data.get());
434   for (uint32_t i = 0; i < length; i++) {
435     if (mode == XDR_DECODE) {
436       MOZ_ASSERT(i == data->length, "must be decoding at the end");
437     }
438     MOZ_TRY(XDRTrailingName(xdr, &names[i], &data->length));
439   }
440 
441   dataGuard.release();
442   return Ok();
443 }
444 
445 /* static */
create(JSContext * cx,ScopeKind kind,HandleScope enclosing,HandleShape envShape)446 Scope* Scope::create(JSContext* cx, ScopeKind kind, HandleScope enclosing,
447                      HandleShape envShape) {
448   Scope* scope = Allocate<Scope>(cx);
449   if (scope) {
450     new (scope) Scope(kind, enclosing, envShape);
451   }
452   return scope;
453 }
454 
455 template <typename ConcreteScope>
456 /* static */
create(JSContext * cx,ScopeKind kind,HandleScope enclosing,HandleShape envShape,MutableHandle<UniquePtr<typename ConcreteScope::RuntimeData>> data)457 ConcreteScope* Scope::create(
458     JSContext* cx, ScopeKind kind, HandleScope enclosing, HandleShape envShape,
459     MutableHandle<UniquePtr<typename ConcreteScope::RuntimeData>> data) {
460   Scope* scope = create(cx, kind, enclosing, envShape);
461   if (!scope) {
462     return nullptr;
463   }
464 
465   // It is an invariant that all Scopes that have data (currently, all
466   // ScopeKinds except With) must have non-null data.
467   MOZ_ASSERT(data);
468   scope->initData<ConcreteScope>(data);
469 
470   return &scope->as<ConcreteScope>();
471 }
472 
473 template <typename ConcreteScope>
initData(MutableHandle<UniquePtr<typename ConcreteScope::RuntimeData>> data)474 inline void Scope::initData(
475     MutableHandle<UniquePtr<typename ConcreteScope::RuntimeData>> data) {
476   MOZ_ASSERT(!rawData());
477 
478   AddCellMemory(this, SizeOfAllocatedData(data.get().get()),
479                 MemoryUse::ScopeData);
480 
481   setHeaderPtr(data.get().release());
482 }
483 
484 template <typename EnvironmentT>
updateEnvShapeIfRequired(JSContext * cx,MutableHandleShape envShape,bool needsEnvironment)485 bool Scope::updateEnvShapeIfRequired(JSContext* cx, MutableHandleShape envShape,
486                                      bool needsEnvironment) {
487   if (!envShape && needsEnvironment) {
488     envShape.set(EmptyEnvironmentShape<EnvironmentT>(cx));
489     if (!envShape) {
490       return false;
491     }
492   }
493   return true;
494 }
495 
496 template <typename EnvironmentT>
updateEnvShapeIfRequired(JSContext * cx,mozilla::Maybe<uint32_t> * envShape,bool needsEnvironment)497 bool Scope::updateEnvShapeIfRequired(JSContext* cx,
498                                      mozilla::Maybe<uint32_t>* envShape,
499                                      bool needsEnvironment) {
500   if (envShape->isNothing() && needsEnvironment) {
501     uint32_t numSlots = 0;
502     envShape->emplace(numSlots);
503   }
504   return true;
505 }
506 
firstFrameSlot() const507 uint32_t Scope::firstFrameSlot() const {
508   switch (kind()) {
509     case ScopeKind::Lexical:
510     case ScopeKind::SimpleCatch:
511     case ScopeKind::Catch:
512     case ScopeKind::FunctionLexical:
513       // For intra-frame scopes, find the enclosing scope's next frame slot.
514       MOZ_ASSERT(is<LexicalScope>());
515       return LexicalScope::nextFrameSlot(enclosing());
516 
517     case ScopeKind::NamedLambda:
518     case ScopeKind::StrictNamedLambda:
519       // Named lambda scopes cannot have frame slots.
520       return LOCALNO_LIMIT;
521 
522     case ScopeKind::ClassBody:
523       MOZ_ASSERT(is<ClassBodyScope>());
524       return ClassBodyScope::nextFrameSlot(enclosing());
525 
526     case ScopeKind::FunctionBodyVar:
527       if (enclosing()->is<FunctionScope>()) {
528         return enclosing()->as<FunctionScope>().nextFrameSlot();
529       }
530       break;
531 
532     default:
533       break;
534   }
535   return 0;
536 }
537 
chainLength() const538 uint32_t Scope::chainLength() const {
539   uint32_t length = 0;
540   for (ScopeIter si(const_cast<Scope*>(this)); si; si++) {
541     length++;
542   }
543   return length;
544 }
545 
environmentChainLength() const546 uint32_t Scope::environmentChainLength() const {
547   uint32_t length = 0;
548   for (ScopeIter si(const_cast<Scope*>(this)); si; si++) {
549     if (si.hasSyntacticEnvironment()) {
550       length++;
551     }
552   }
553   return length;
554 }
555 
maybeCloneEnvironmentShape(JSContext * cx)556 Shape* Scope::maybeCloneEnvironmentShape(JSContext* cx) {
557   // Clone the environment shape if cloning into a different realm.
558   Shape* shape = environmentShape();
559   if (shape && shape->realm() != cx->realm()) {
560     BindingIter bi(this);
561     return CreateEnvironmentShape(cx, bi, shape->getObjectClass(),
562                                   shape->slotSpan(), shape->objectFlags());
563   }
564   return shape;
565 }
566 
567 /* static */
clone(JSContext * cx,HandleScope scope,HandleScope enclosing)568 Scope* Scope::clone(JSContext* cx, HandleScope scope, HandleScope enclosing) {
569   RootedShape envShape(cx);
570   if (scope->environmentShape()) {
571     envShape = scope->maybeCloneEnvironmentShape(cx);
572     if (!envShape) {
573       return nullptr;
574     }
575   }
576 
577   switch (scope->kind_) {
578     case ScopeKind::Function: {
579       RootedScript script(cx, scope->as<FunctionScope>().script());
580       const char* filename = script->filename();
581       // If the script has an internal URL, include it in the crash reason. If
582       // not, it may be a web URL, and therefore privacy-sensitive.
583       if (!strncmp(filename, "chrome:", 7) ||
584           !strncmp(filename, "resource:", 9)) {
585         MOZ_CRASH_UNSAFE_PRINTF("Use FunctionScope::clone (script URL: %s)",
586                                 filename);
587       }
588 
589       MOZ_CRASH("Use FunctionScope::clone.");
590       break;
591     }
592 
593     case ScopeKind::FunctionBodyVar: {
594       Rooted<UniquePtr<VarScope::RuntimeData>> dataClone(cx);
595       dataClone = CopyScopeData<VarScope>(cx, &scope->as<VarScope>().data());
596       if (!dataClone) {
597         return nullptr;
598       }
599       return create<VarScope>(cx, scope->kind_, enclosing, envShape,
600                               &dataClone);
601     }
602 
603     case ScopeKind::Lexical:
604     case ScopeKind::SimpleCatch:
605     case ScopeKind::Catch:
606     case ScopeKind::NamedLambda:
607     case ScopeKind::StrictNamedLambda:
608     case ScopeKind::FunctionLexical: {
609       Rooted<UniquePtr<LexicalScope::RuntimeData>> dataClone(cx);
610       dataClone =
611           CopyScopeData<LexicalScope>(cx, &scope->as<LexicalScope>().data());
612       if (!dataClone) {
613         return nullptr;
614       }
615       return create<LexicalScope>(cx, scope->kind_, enclosing, envShape,
616                                   &dataClone);
617     }
618 
619     case ScopeKind::ClassBody: {
620       Rooted<UniquePtr<ClassBodyScope::RuntimeData>> dataClone(cx);
621       dataClone = CopyScopeData<ClassBodyScope>(
622           cx, &scope->as<ClassBodyScope>().data());
623       if (!dataClone) {
624         return nullptr;
625       }
626       return create<ClassBodyScope>(cx, scope->kind_, enclosing, envShape,
627                                     &dataClone);
628     }
629 
630     case ScopeKind::With:
631       return create(cx, scope->kind_, enclosing, envShape);
632 
633     case ScopeKind::Eval:
634     case ScopeKind::StrictEval: {
635       Rooted<UniquePtr<EvalScope::RuntimeData>> dataClone(cx);
636       dataClone = CopyScopeData<EvalScope>(cx, &scope->as<EvalScope>().data());
637       if (!dataClone) {
638         return nullptr;
639       }
640       return create<EvalScope>(cx, scope->kind_, enclosing, envShape,
641                                &dataClone);
642     }
643 
644     case ScopeKind::Global:
645     case ScopeKind::NonSyntactic:
646       MOZ_CRASH("Use GlobalScope::clone.");
647       break;
648 
649     case ScopeKind::WasmFunction:
650       MOZ_CRASH("wasm functions are not nested in JSScript");
651       break;
652 
653     case ScopeKind::Module:
654     case ScopeKind::WasmInstance:
655       MOZ_CRASH("NYI");
656       break;
657   }
658 
659   return nullptr;
660 }
661 
finalize(JSFreeOp * fop)662 void Scope::finalize(JSFreeOp* fop) {
663   MOZ_ASSERT(CurrentThreadIsGCFinalizing());
664   applyScopeDataTyped([this, fop](auto data) {
665     fop->delete_(this, data, SizeOfAllocatedData(data), MemoryUse::ScopeData);
666   });
667   setHeaderPtr(nullptr);
668 }
669 
sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const670 size_t Scope::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
671   if (rawData()) {
672     return mallocSizeOf(rawData());
673   }
674   return 0;
675 }
676 
dump()677 void Scope::dump() {
678   JSContext* cx = TlsContext.get();
679   if (!cx) {
680     fprintf(stderr, "*** can't get JSContext for current thread\n");
681     return;
682   }
683   for (Rooted<ScopeIter> si(cx, ScopeIter(this)); si; si++) {
684     fprintf(stderr, "- %s [%p]\n", ScopeKindString(si.kind()), si.scope());
685     DumpBindings(cx, si.scope());
686     fprintf(stderr, "\n");
687   }
688   fprintf(stderr, "\n");
689 }
690 
691 #if defined(DEBUG) || defined(JS_JITSPEW)
692 
693 /* static */
dumpForDisassemble(JSContext * cx,JS::Handle<Scope * > scope,GenericPrinter & out,const char * indent)694 bool Scope::dumpForDisassemble(JSContext* cx, JS::Handle<Scope*> scope,
695                                GenericPrinter& out, const char* indent) {
696   if (!out.put(ScopeKindString(scope->kind()))) {
697     return false;
698   }
699   if (!out.put(" {")) {
700     return false;
701   }
702 
703   size_t i = 0;
704   for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++, i++) {
705     if (i == 0) {
706       if (!out.put("\n")) {
707         return false;
708       }
709     }
710     UniqueChars bytes = AtomToPrintableString(cx, bi.name());
711     if (!bytes) {
712       return false;
713     }
714     if (!out.put(indent)) {
715       return false;
716     }
717     if (!out.printf("  %2zu: %s %s ", i, BindingKindString(bi.kind()),
718                     bytes.get())) {
719       return false;
720     }
721     switch (bi.location().kind()) {
722       case BindingLocation::Kind::Global:
723         if (bi.isTopLevelFunction()) {
724           if (!out.put("(global function)\n")) {
725             return false;
726           }
727         } else {
728           if (!out.put("(global)\n")) {
729             return false;
730           }
731         }
732         break;
733       case BindingLocation::Kind::Argument:
734         if (!out.printf("(arg slot %u)\n", bi.location().argumentSlot())) {
735           return false;
736         }
737         break;
738       case BindingLocation::Kind::Frame:
739         if (!out.printf("(frame slot %u)\n", bi.location().slot())) {
740           return false;
741         }
742         break;
743       case BindingLocation::Kind::Environment:
744         if (!out.printf("(env slot %u)\n", bi.location().slot())) {
745           return false;
746         }
747         break;
748       case BindingLocation::Kind::NamedLambdaCallee:
749         if (!out.put("(named lambda callee)\n")) {
750           return false;
751         }
752         break;
753       case BindingLocation::Kind::Import:
754         if (!out.put("(import)\n")) {
755           return false;
756         }
757         break;
758     }
759   }
760   if (i > 0) {
761     if (!out.put(indent)) {
762       return false;
763     }
764   }
765   if (!out.put("}")) {
766     return false;
767   }
768 
769   ScopeIter si(scope);
770   si++;
771   for (; si; si++) {
772     if (!out.put(" -> ")) {
773       return false;
774     }
775     if (!out.put(ScopeKindString(si.kind()))) {
776       return false;
777     }
778   }
779   return true;
780 }
781 
782 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
783 
NextFrameSlot(Scope * scope)784 static uint32_t NextFrameSlot(Scope* scope) {
785   for (ScopeIter si(scope); si; si++) {
786     switch (si.kind()) {
787       case ScopeKind::With:
788         continue;
789 
790       case ScopeKind::Function:
791         return si.scope()->as<FunctionScope>().nextFrameSlot();
792 
793       case ScopeKind::FunctionBodyVar:
794         return si.scope()->as<VarScope>().nextFrameSlot();
795 
796       case ScopeKind::Lexical:
797       case ScopeKind::SimpleCatch:
798       case ScopeKind::Catch:
799       case ScopeKind::FunctionLexical:
800         return si.scope()->as<LexicalScope>().nextFrameSlot();
801 
802       case ScopeKind::ClassBody:
803         return si.scope()->as<ClassBodyScope>().nextFrameSlot();
804 
805       case ScopeKind::NamedLambda:
806       case ScopeKind::StrictNamedLambda:
807         // Named lambda scopes cannot have frame slots.
808         return 0;
809 
810       case ScopeKind::Eval:
811       case ScopeKind::StrictEval:
812         return si.scope()->as<EvalScope>().nextFrameSlot();
813 
814       case ScopeKind::Global:
815       case ScopeKind::NonSyntactic:
816         return 0;
817 
818       case ScopeKind::Module:
819         return si.scope()->as<ModuleScope>().nextFrameSlot();
820 
821       case ScopeKind::WasmInstance:
822       case ScopeKind::WasmFunction:
823         // Invalid; MOZ_CRASH below.
824         break;
825     }
826   }
827   MOZ_CRASH("Not an enclosing intra-frame Scope");
828 }
829 
830 /* static */
nextFrameSlot(Scope * scope)831 uint32_t LexicalScope::nextFrameSlot(Scope* scope) {
832   return NextFrameSlot(scope);
833 }
834 
835 /* static */
nextFrameSlot(Scope * scope)836 uint32_t ClassBodyScope::nextFrameSlot(Scope* scope) {
837   return NextFrameSlot(scope);
838 }
839 
840 template <typename AtomT, typename ShapeT>
prepareForScopeCreation(JSContext * cx,ScopeKind kind,uint32_t firstFrameSlot,typename MaybeRootedScopeData<LexicalScope,AtomT>::MutableHandleType data,ShapeT envShape)841 bool LexicalScope::prepareForScopeCreation(
842     JSContext* cx, ScopeKind kind, uint32_t firstFrameSlot,
843     typename MaybeRootedScopeData<LexicalScope, AtomT>::MutableHandleType data,
844     ShapeT envShape) {
845   bool isNamedLambda =
846       kind == ScopeKind::NamedLambda || kind == ScopeKind::StrictNamedLambda;
847 
848   MOZ_ASSERT_IF(isNamedLambda, firstFrameSlot == LOCALNO_LIMIT);
849 
850   AbstractBindingIter<AtomT> bi(*data, firstFrameSlot, isNamedLambda);
851   if (!PrepareScopeData<LexicalScope, AtomT, BlockLexicalEnvironmentObject>(
852           cx, bi, data, firstFrameSlot, envShape)) {
853     return false;
854   }
855   return true;
856 }
857 
858 /* static */
createWithData(JSContext * cx,ScopeKind kind,MutableHandle<UniquePtr<RuntimeData>> data,uint32_t firstFrameSlot,HandleScope enclosing)859 LexicalScope* LexicalScope::createWithData(
860     JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<RuntimeData>> data,
861     uint32_t firstFrameSlot, HandleScope enclosing) {
862   RootedShape envShape(cx);
863 
864   if (!prepareForScopeCreation<JSAtom>(cx, kind, firstFrameSlot, data,
865                                        &envShape)) {
866     return nullptr;
867   }
868 
869   auto scope = Scope::create<LexicalScope>(cx, kind, enclosing, envShape, data);
870   if (!scope) {
871     return nullptr;
872   }
873 
874   MOZ_ASSERT(scope->firstFrameSlot() == firstFrameSlot);
875   return scope;
876 }
877 
878 /* static */
getEmptyExtensibleEnvironmentShape(JSContext * cx)879 Shape* LexicalScope::getEmptyExtensibleEnvironmentShape(JSContext* cx) {
880   const JSClass* cls = &LexicalEnvironmentObject::class_;
881   return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), ObjectFlags());
882 }
883 
884 template <XDRMode mode>
885 /* static */
XDR(XDRState<mode> * xdr,ScopeKind kind,HandleScope enclosing,MutableHandleScope scope)886 XDRResult LexicalScope::XDR(XDRState<mode>* xdr, ScopeKind kind,
887                             HandleScope enclosing, MutableHandleScope scope) {
888   JSContext* cx = xdr->cx();
889 
890   Rooted<RuntimeData*> data(cx);
891   MOZ_TRY(
892       XDRSizedBindingNames<LexicalScope>(xdr, scope.as<LexicalScope>(), &data));
893 
894   {
895     Maybe<Rooted<UniquePtr<RuntimeData>>> uniqueData;
896     if (mode == XDR_DECODE) {
897       uniqueData.emplace(cx, data);
898     }
899 
900     uint32_t firstFrameSlot;
901     uint32_t nextFrameSlot;
902     if (mode == XDR_ENCODE) {
903       firstFrameSlot = scope->firstFrameSlot();
904       nextFrameSlot = data->slotInfo.nextFrameSlot;
905     }
906 
907     MOZ_TRY(xdr->codeUint32(&data->slotInfo.constStart));
908     MOZ_TRY(xdr->codeUint32(&firstFrameSlot));
909     MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
910 
911     if (mode == XDR_DECODE) {
912       scope.set(createWithData(cx, kind, &uniqueData.ref(), firstFrameSlot,
913                                enclosing));
914       if (!scope) {
915         return xdr->fail(JS::TranscodeResult::Throw);
916       }
917 
918       // nextFrameSlot is used only for this correctness check.
919       MOZ_ASSERT(nextFrameSlot ==
920                  scope->as<LexicalScope>().data().slotInfo.nextFrameSlot);
921     }
922   }
923 
924   return Ok();
925 }
926 
927 template
928     /* static */
929     XDRResult
930     LexicalScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind,
931                       HandleScope enclosing, MutableHandleScope scope);
932 
933 template
934     /* static */
935     XDRResult
936     LexicalScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind,
937                       HandleScope enclosing, MutableHandleScope scope);
938 
939 template <typename AtomT, typename ShapeT>
prepareForScopeCreation(JSContext * cx,ScopeKind kind,uint32_t firstFrameSlot,typename MaybeRootedScopeData<ClassBodyScope,AtomT>::MutableHandleType data,ShapeT envShape)940 bool ClassBodyScope::prepareForScopeCreation(
941     JSContext* cx, ScopeKind kind, uint32_t firstFrameSlot,
942     typename MaybeRootedScopeData<ClassBodyScope, AtomT>::MutableHandleType
943         data,
944     ShapeT envShape) {
945   MOZ_ASSERT(kind == ScopeKind::ClassBody);
946 
947   AbstractBindingIter<AtomT> bi(*data, firstFrameSlot);
948   return PrepareScopeData<ClassBodyScope, AtomT, BlockLexicalEnvironmentObject>(
949       cx, bi, data, firstFrameSlot, envShape);
950 }
951 
952 /* static */
createWithData(JSContext * cx,ScopeKind kind,MutableHandle<UniquePtr<RuntimeData>> data,uint32_t firstFrameSlot,HandleScope enclosing)953 ClassBodyScope* ClassBodyScope::createWithData(
954     JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<RuntimeData>> data,
955     uint32_t firstFrameSlot, HandleScope enclosing) {
956   RootedShape envShape(cx);
957 
958   if (!prepareForScopeCreation<JSAtom>(cx, kind, firstFrameSlot, data,
959                                        &envShape)) {
960     return nullptr;
961   }
962 
963   auto* scope =
964       Scope::create<ClassBodyScope>(cx, kind, enclosing, envShape, data);
965   if (!scope) {
966     return nullptr;
967   }
968 
969   MOZ_ASSERT(scope->firstFrameSlot() == firstFrameSlot);
970   return scope;
971 }
972 
973 template <XDRMode mode>
974 /* static */
XDR(XDRState<mode> * xdr,ScopeKind kind,HandleScope enclosing,MutableHandleScope scope)975 XDRResult ClassBodyScope::XDR(XDRState<mode>* xdr, ScopeKind kind,
976                               HandleScope enclosing, MutableHandleScope scope) {
977   JSContext* cx = xdr->cx();
978 
979   Rooted<RuntimeData*> data(cx);
980   MOZ_TRY(XDRSizedBindingNames<ClassBodyScope>(xdr, scope.as<ClassBodyScope>(),
981                                                &data));
982 
983   {
984     Maybe<Rooted<UniquePtr<RuntimeData>>> uniqueData;
985     if (mode == XDR_DECODE) {
986       uniqueData.emplace(cx, data);
987     }
988 
989     uint32_t firstFrameSlot;
990     uint32_t nextFrameSlot;
991     if (mode == XDR_ENCODE) {
992       firstFrameSlot = scope->firstFrameSlot();
993       nextFrameSlot = data->slotInfo.nextFrameSlot;
994     }
995 
996     MOZ_TRY(xdr->codeUint32(&firstFrameSlot));
997     MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
998 
999     if (mode == XDR_DECODE) {
1000       scope.set(createWithData(cx, kind, &uniqueData.ref(), firstFrameSlot,
1001                                enclosing));
1002       if (!scope) {
1003         return xdr->fail(JS::TranscodeResult::Throw);
1004       }
1005 
1006       // nextFrameSlot is used only for this correctness check.
1007       MOZ_ASSERT(nextFrameSlot ==
1008                  scope->as<ClassBodyScope>().data().slotInfo.nextFrameSlot);
1009     }
1010   }
1011 
1012   return Ok();
1013 }
1014 
1015 template
1016     /* static */
1017     XDRResult
1018     ClassBodyScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind,
1019                         HandleScope enclosing, MutableHandleScope scope);
1020 
1021 template
1022     /* static */
1023     XDRResult
1024     ClassBodyScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind,
1025                         HandleScope enclosing, MutableHandleScope scope);
1026 
SetCanonicalFunction(FunctionScope::RuntimeData & data,HandleFunction fun)1027 static void SetCanonicalFunction(FunctionScope::RuntimeData& data,
1028                                  HandleFunction fun) {
1029   data.canonicalFunction.init(fun);
1030 }
1031 
SetCanonicalFunction(FunctionScope::ParserData & data,HandleFunction fun)1032 static void SetCanonicalFunction(FunctionScope::ParserData& data,
1033                                  HandleFunction fun) {}
1034 
1035 template <typename AtomT, typename ShapeT>
prepareForScopeCreation(JSContext * cx,typename MaybeRootedScopeData<FunctionScope,AtomT>::MutableHandleType data,bool hasParameterExprs,bool needsEnvironment,HandleFunction fun,ShapeT envShape)1036 bool FunctionScope::prepareForScopeCreation(
1037     JSContext* cx,
1038     typename MaybeRootedScopeData<FunctionScope, AtomT>::MutableHandleType data,
1039     bool hasParameterExprs, bool needsEnvironment, HandleFunction fun,
1040     ShapeT envShape) {
1041   uint32_t firstFrameSlot = 0;
1042   AbstractBindingIter<AtomT> bi(*data, hasParameterExprs);
1043   if (!PrepareScopeData<FunctionScope, AtomT, CallObject>(
1044           cx, bi, data, firstFrameSlot, envShape)) {
1045     return false;
1046   }
1047 
1048   if (hasParameterExprs) {
1049     data->slotInfo.setHasParameterExprs();
1050   }
1051   SetCanonicalFunction(*data, fun);
1052 
1053   // An environment may be needed regardless of existence of any closed over
1054   // bindings:
1055   //   - Extensible scopes (i.e., due to direct eval)
1056   //   - Needing a home object
1057   //   - Being a derived class constructor
1058   //   - Being a generator or async function
1059   // Also see |FunctionBox::needsExtraBodyVarEnvironmentRegardlessOfBindings()|.
1060   return updateEnvShapeIfRequired<CallObject>(cx, envShape, needsEnvironment);
1061 }
1062 
1063 /* static */
createWithData(JSContext * cx,MutableHandle<UniquePtr<RuntimeData>> data,bool hasParameterExprs,bool needsEnvironment,HandleFunction fun,HandleScope enclosing)1064 FunctionScope* FunctionScope::createWithData(
1065     JSContext* cx, MutableHandle<UniquePtr<RuntimeData>> data,
1066     bool hasParameterExprs, bool needsEnvironment, HandleFunction fun,
1067     HandleScope enclosing) {
1068   MOZ_ASSERT(data);
1069   MOZ_ASSERT(fun->isTenured());
1070 
1071   RootedShape envShape(cx);
1072 
1073   if (!prepareForScopeCreation<JSAtom>(cx, data, hasParameterExprs,
1074                                        needsEnvironment, fun, &envShape)) {
1075     return nullptr;
1076   }
1077 
1078   return Scope::create<FunctionScope>(cx, ScopeKind::Function, enclosing,
1079                                       envShape, data);
1080 }
1081 
script() const1082 JSScript* FunctionScope::script() const {
1083   return canonicalFunction()->nonLazyScript();
1084 }
1085 
1086 /* static */
isSpecialName(JSContext * cx,JSAtom * name)1087 bool FunctionScope::isSpecialName(JSContext* cx, JSAtom* name) {
1088   return name == cx->names().arguments || name == cx->names().dotThis ||
1089          name == cx->names().dotGenerator;
1090 }
1091 
1092 /* static */
isSpecialName(JSContext * cx,frontend::TaggedParserAtomIndex name)1093 bool FunctionScope::isSpecialName(JSContext* cx,
1094                                   frontend::TaggedParserAtomIndex name) {
1095   return name == frontend::TaggedParserAtomIndex::WellKnown::arguments() ||
1096          name == frontend::TaggedParserAtomIndex::WellKnown::dotThis() ||
1097          name == frontend::TaggedParserAtomIndex::WellKnown::dotGenerator();
1098 }
1099 
1100 /* static */
clone(JSContext * cx,Handle<FunctionScope * > scope,HandleFunction fun,HandleScope enclosing)1101 FunctionScope* FunctionScope::clone(JSContext* cx, Handle<FunctionScope*> scope,
1102                                     HandleFunction fun, HandleScope enclosing) {
1103   MOZ_ASSERT(fun != scope->canonicalFunction());
1104 
1105   RootedShape envShape(cx);
1106   if (scope->environmentShape()) {
1107     envShape = scope->maybeCloneEnvironmentShape(cx);
1108     if (!envShape) {
1109       return nullptr;
1110     }
1111   }
1112 
1113   Rooted<RuntimeData*> dataOriginal(cx, &scope->as<FunctionScope>().data());
1114   Rooted<UniquePtr<RuntimeData>> dataClone(
1115       cx, CopyScopeData<FunctionScope>(cx, dataOriginal));
1116   if (!dataClone) {
1117     return nullptr;
1118   }
1119 
1120   dataClone->canonicalFunction = fun;
1121 
1122   return Scope::create<FunctionScope>(cx, scope->kind(), enclosing, envShape,
1123                                       &dataClone);
1124 }
1125 
1126 template <XDRMode mode>
1127 /* static */
XDR(XDRState<mode> * xdr,HandleFunction fun,HandleScope enclosing,MutableHandleScope scope)1128 XDRResult FunctionScope::XDR(XDRState<mode>* xdr, HandleFunction fun,
1129                              HandleScope enclosing, MutableHandleScope scope) {
1130   JSContext* cx = xdr->cx();
1131   Rooted<RuntimeData*> data(cx);
1132   MOZ_TRY(XDRSizedBindingNames<FunctionScope>(xdr, scope.as<FunctionScope>(),
1133                                               &data));
1134 
1135   {
1136     Maybe<Rooted<UniquePtr<RuntimeData>>> uniqueData;
1137     if (mode == XDR_DECODE) {
1138       uniqueData.emplace(cx, data);
1139     }
1140 
1141     uint8_t needsEnvironment;
1142     uint8_t hasParameterExprs;
1143     uint32_t nextFrameSlot;
1144     if (mode == XDR_ENCODE) {
1145       needsEnvironment = scope->hasEnvironment();
1146       hasParameterExprs = data->slotInfo.hasParameterExprs();
1147       nextFrameSlot = data->slotInfo.nextFrameSlot;
1148     }
1149     MOZ_TRY(xdr->codeUint8(&needsEnvironment));
1150     MOZ_TRY(xdr->codeUint8(&hasParameterExprs));
1151     MOZ_TRY(xdr->codeUint16(&data->slotInfo.nonPositionalFormalStart));
1152     MOZ_TRY(xdr->codeUint16(&data->slotInfo.varStart));
1153     MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
1154 
1155     if (mode == XDR_DECODE) {
1156       if (!data->length) {
1157         MOZ_ASSERT(!data->slotInfo.nonPositionalFormalStart);
1158         MOZ_ASSERT(!data->slotInfo.varStart);
1159         MOZ_ASSERT(!data->slotInfo.nextFrameSlot);
1160       }
1161 
1162       scope.set(createWithData(cx, &uniqueData.ref(), hasParameterExprs,
1163                                needsEnvironment, fun, enclosing));
1164       if (!scope) {
1165         return xdr->fail(JS::TranscodeResult::Throw);
1166       }
1167 
1168       // nextFrameSlot is used only for this correctness check.
1169       MOZ_ASSERT(nextFrameSlot ==
1170                  scope->as<FunctionScope>().data().slotInfo.nextFrameSlot);
1171     }
1172   }
1173 
1174   return Ok();
1175 }
1176 
1177 template
1178     /* static */
1179     XDRResult
1180     FunctionScope::XDR(XDRState<XDR_ENCODE>* xdr, HandleFunction fun,
1181                        HandleScope enclosing, MutableHandleScope scope);
1182 
1183 template
1184     /* static */
1185     XDRResult
1186     FunctionScope::XDR(XDRState<XDR_DECODE>* xdr, HandleFunction fun,
1187                        HandleScope enclosing, MutableHandleScope scope);
1188 
1189 template <typename AtomT, typename ShapeT>
prepareForScopeCreation(JSContext * cx,ScopeKind kind,typename MaybeRootedScopeData<VarScope,AtomT>::MutableHandleType data,uint32_t firstFrameSlot,bool needsEnvironment,ShapeT envShape)1190 bool VarScope::prepareForScopeCreation(
1191     JSContext* cx, ScopeKind kind,
1192     typename MaybeRootedScopeData<VarScope, AtomT>::MutableHandleType data,
1193     uint32_t firstFrameSlot, bool needsEnvironment, ShapeT envShape) {
1194   AbstractBindingIter<AtomT> bi(*data, firstFrameSlot);
1195   if (!PrepareScopeData<VarScope, AtomT, VarEnvironmentObject>(
1196           cx, bi, data, firstFrameSlot, envShape)) {
1197     return false;
1198   }
1199 
1200   // An environment may be needed regardless of existence of any closed over
1201   // bindings:
1202   //   - Extensible scopes (i.e., due to direct eval)
1203   //   - Being a generator
1204   return updateEnvShapeIfRequired<VarEnvironmentObject>(cx, envShape,
1205                                                         needsEnvironment);
1206 }
1207 
1208 /* static */
createWithData(JSContext * cx,ScopeKind kind,MutableHandle<UniquePtr<RuntimeData>> data,uint32_t firstFrameSlot,bool needsEnvironment,HandleScope enclosing)1209 VarScope* VarScope::createWithData(JSContext* cx, ScopeKind kind,
1210                                    MutableHandle<UniquePtr<RuntimeData>> data,
1211                                    uint32_t firstFrameSlot,
1212                                    bool needsEnvironment,
1213                                    HandleScope enclosing) {
1214   MOZ_ASSERT(data);
1215 
1216   RootedShape envShape(cx);
1217   if (!prepareForScopeCreation<JSAtom>(cx, kind, data, firstFrameSlot,
1218                                        needsEnvironment, &envShape)) {
1219     return nullptr;
1220   }
1221 
1222   return Scope::create<VarScope>(cx, kind, enclosing, envShape, data);
1223 }
1224 
1225 template <XDRMode mode>
1226 /* static */
XDR(XDRState<mode> * xdr,ScopeKind kind,HandleScope enclosing,MutableHandleScope scope)1227 XDRResult VarScope::XDR(XDRState<mode>* xdr, ScopeKind kind,
1228                         HandleScope enclosing, MutableHandleScope scope) {
1229   JSContext* cx = xdr->cx();
1230   Rooted<RuntimeData*> data(cx);
1231   MOZ_TRY(XDRSizedBindingNames<VarScope>(xdr, scope.as<VarScope>(), &data));
1232 
1233   {
1234     Maybe<Rooted<UniquePtr<RuntimeData>>> uniqueData;
1235     if (mode == XDR_DECODE) {
1236       uniqueData.emplace(cx, data);
1237     }
1238 
1239     uint8_t needsEnvironment;
1240     uint32_t firstFrameSlot;
1241     uint32_t nextFrameSlot;
1242     if (mode == XDR_ENCODE) {
1243       needsEnvironment = scope->hasEnvironment();
1244       firstFrameSlot = scope->firstFrameSlot();
1245       nextFrameSlot = data->slotInfo.nextFrameSlot;
1246     }
1247     MOZ_TRY(xdr->codeUint8(&needsEnvironment));
1248     MOZ_TRY(xdr->codeUint32(&firstFrameSlot));
1249     MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
1250 
1251     if (mode == XDR_DECODE) {
1252       if (!data->length) {
1253         MOZ_ASSERT(!data->slotInfo.nextFrameSlot);
1254       }
1255 
1256       scope.set(createWithData(cx, kind, &uniqueData.ref(), firstFrameSlot,
1257                                needsEnvironment, enclosing));
1258       if (!scope) {
1259         return xdr->fail(JS::TranscodeResult::Throw);
1260       }
1261 
1262       // nextFrameSlot is used only for this correctness check.
1263       MOZ_ASSERT(nextFrameSlot ==
1264                  scope->as<VarScope>().data().slotInfo.nextFrameSlot);
1265     }
1266   }
1267 
1268   return Ok();
1269 }
1270 
1271 template
1272     /* static */
1273     XDRResult
1274     VarScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind,
1275                   HandleScope enclosing, MutableHandleScope scope);
1276 
1277 template
1278     /* static */
1279     XDRResult
1280     VarScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind,
1281                   HandleScope enclosing, MutableHandleScope scope);
1282 
1283 /* static */
create(JSContext * cx,ScopeKind kind,Handle<RuntimeData * > dataArg)1284 GlobalScope* GlobalScope::create(JSContext* cx, ScopeKind kind,
1285                                  Handle<RuntimeData*> dataArg) {
1286   // The data that's passed in is from the frontend and is LifoAlloc'd.
1287   // Copy it now that we're creating a permanent VM scope.
1288   Rooted<UniquePtr<RuntimeData>> data(
1289       cx, dataArg ? CopyScopeData<GlobalScope>(cx, dataArg)
1290                   : NewEmptyScopeData<GlobalScope, JSAtom>(cx));
1291   if (!data) {
1292     return nullptr;
1293   }
1294 
1295   return createWithData(cx, kind, &data);
1296 }
1297 
1298 /* static */
createWithData(JSContext * cx,ScopeKind kind,MutableHandle<UniquePtr<RuntimeData>> data)1299 GlobalScope* GlobalScope::createWithData(
1300     JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<RuntimeData>> data) {
1301   MOZ_ASSERT(data);
1302 
1303   // The global scope has no environment shape. Its environment is the
1304   // global lexical scope and the global object or non-syntactic objects
1305   // created by embedding, all of which are not only extensible but may
1306   // have names on them deleted.
1307   return Scope::create<GlobalScope>(cx, kind, nullptr, nullptr, data);
1308 }
1309 
1310 /* static */
clone(JSContext * cx,Handle<GlobalScope * > scope)1311 GlobalScope* GlobalScope::clone(JSContext* cx, Handle<GlobalScope*> scope) {
1312   Rooted<RuntimeData*> dataOriginal(cx, &scope->as<GlobalScope>().data());
1313   Rooted<UniquePtr<RuntimeData>> dataClone(
1314       cx, CopyScopeData<GlobalScope>(cx, dataOriginal));
1315   if (!dataClone) {
1316     return nullptr;
1317   }
1318   return Scope::create<GlobalScope>(cx, scope->kind(), nullptr, nullptr,
1319                                     &dataClone);
1320 }
1321 
1322 template <XDRMode mode>
1323 /* static */
XDR(XDRState<mode> * xdr,ScopeKind kind,MutableHandleScope scope)1324 XDRResult GlobalScope::XDR(XDRState<mode>* xdr, ScopeKind kind,
1325                            MutableHandleScope scope) {
1326   MOZ_ASSERT((mode == XDR_DECODE) == !scope);
1327 
1328   JSContext* cx = xdr->cx();
1329   Rooted<RuntimeData*> data(cx);
1330   MOZ_TRY(
1331       XDRSizedBindingNames<GlobalScope>(xdr, scope.as<GlobalScope>(), &data));
1332 
1333   {
1334     Maybe<Rooted<UniquePtr<RuntimeData>>> uniqueData;
1335     if (mode == XDR_DECODE) {
1336       uniqueData.emplace(cx, data);
1337     }
1338 
1339     MOZ_TRY(xdr->codeUint32(&data->slotInfo.letStart));
1340     MOZ_TRY(xdr->codeUint32(&data->slotInfo.constStart));
1341 
1342     if (mode == XDR_DECODE) {
1343       if (!data->length) {
1344         MOZ_ASSERT(!data->slotInfo.letStart);
1345         MOZ_ASSERT(!data->slotInfo.constStart);
1346       }
1347 
1348       scope.set(createWithData(cx, kind, &uniqueData.ref()));
1349       if (!scope) {
1350         return xdr->fail(JS::TranscodeResult::Throw);
1351       }
1352     }
1353   }
1354 
1355   return Ok();
1356 }
1357 
1358 template
1359     /* static */
1360     XDRResult
1361     GlobalScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind,
1362                      MutableHandleScope scope);
1363 
1364 template
1365     /* static */
1366     XDRResult
1367     GlobalScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind,
1368                      MutableHandleScope scope);
1369 
1370 /* static */
create(JSContext * cx,HandleScope enclosing)1371 WithScope* WithScope::create(JSContext* cx, HandleScope enclosing) {
1372   Scope* scope = Scope::create(cx, ScopeKind::With, enclosing, nullptr);
1373   return static_cast<WithScope*>(scope);
1374 }
1375 
1376 template <XDRMode mode>
1377 /* static */
XDR(XDRState<mode> * xdr,HandleScope enclosing,MutableHandleScope scope)1378 XDRResult WithScope::XDR(XDRState<mode>* xdr, HandleScope enclosing,
1379                          MutableHandleScope scope) {
1380   JSContext* cx = xdr->cx();
1381   if (mode == XDR_DECODE) {
1382     scope.set(create(cx, enclosing));
1383     if (!scope) {
1384       return xdr->fail(JS::TranscodeResult::Throw);
1385     }
1386   }
1387 
1388   return Ok();
1389 }
1390 
1391 template
1392     /* static */
1393     XDRResult
1394     WithScope::XDR(XDRState<XDR_ENCODE>* xdr, HandleScope enclosing,
1395                    MutableHandleScope scope);
1396 
1397 template
1398     /* static */
1399     XDRResult
1400     WithScope::XDR(XDRState<XDR_DECODE>* xdr, HandleScope enclosing,
1401                    MutableHandleScope scope);
1402 
1403 template <typename AtomT, typename ShapeT>
prepareForScopeCreation(JSContext * cx,ScopeKind scopeKind,typename MaybeRootedScopeData<EvalScope,AtomT>::MutableHandleType data,ShapeT envShape)1404 bool EvalScope::prepareForScopeCreation(
1405     JSContext* cx, ScopeKind scopeKind,
1406     typename MaybeRootedScopeData<EvalScope, AtomT>::MutableHandleType data,
1407     ShapeT envShape) {
1408   if (scopeKind == ScopeKind::StrictEval) {
1409     uint32_t firstFrameSlot = 0;
1410     AbstractBindingIter<AtomT> bi(*data, true);
1411     if (!PrepareScopeData<EvalScope, AtomT, VarEnvironmentObject>(
1412             cx, bi, data, firstFrameSlot, envShape)) {
1413       return false;
1414     }
1415   }
1416 
1417   return true;
1418 }
1419 
1420 /* static */
createWithData(JSContext * cx,ScopeKind scopeKind,MutableHandle<UniquePtr<RuntimeData>> data,HandleScope enclosing)1421 EvalScope* EvalScope::createWithData(JSContext* cx, ScopeKind scopeKind,
1422                                      MutableHandle<UniquePtr<RuntimeData>> data,
1423                                      HandleScope enclosing) {
1424   MOZ_ASSERT(data);
1425 
1426   RootedShape envShape(cx);
1427   if (!prepareForScopeCreation<JSAtom>(cx, scopeKind, data, &envShape)) {
1428     return nullptr;
1429   }
1430 
1431   return Scope::create<EvalScope>(cx, scopeKind, enclosing, envShape, data);
1432 }
1433 
1434 /* static */
nearestVarScopeForDirectEval(Scope * scope)1435 Scope* EvalScope::nearestVarScopeForDirectEval(Scope* scope) {
1436   for (ScopeIter si(scope); si; si++) {
1437     switch (si.kind()) {
1438       case ScopeKind::Function:
1439       case ScopeKind::FunctionBodyVar:
1440       case ScopeKind::Global:
1441       case ScopeKind::NonSyntactic:
1442         return scope;
1443       default:
1444         break;
1445     }
1446   }
1447   return nullptr;
1448 }
1449 
1450 template <XDRMode mode>
1451 /* static */
XDR(XDRState<mode> * xdr,ScopeKind kind,HandleScope enclosing,MutableHandleScope scope)1452 XDRResult EvalScope::XDR(XDRState<mode>* xdr, ScopeKind kind,
1453                          HandleScope enclosing, MutableHandleScope scope) {
1454   JSContext* cx = xdr->cx();
1455   Rooted<RuntimeData*> data(cx);
1456 
1457   {
1458     Maybe<Rooted<UniquePtr<RuntimeData>>> uniqueData;
1459     if (mode == XDR_DECODE) {
1460       uniqueData.emplace(cx, data);
1461     }
1462 
1463     MOZ_TRY(XDRSizedBindingNames<EvalScope>(xdr, scope.as<EvalScope>(), &data));
1464 
1465     if (mode == XDR_DECODE) {
1466       if (!data->length) {
1467         MOZ_ASSERT(!data->slotInfo.nextFrameSlot);
1468       }
1469       scope.set(createWithData(cx, kind, &uniqueData.ref(), enclosing));
1470       if (!scope) {
1471         return xdr->fail(JS::TranscodeResult::Throw);
1472       }
1473     }
1474   }
1475 
1476   return Ok();
1477 }
1478 
1479 template
1480     /* static */
1481     XDRResult
1482     EvalScope::XDR(XDRState<XDR_ENCODE>* xdr, ScopeKind kind,
1483                    HandleScope enclosing, MutableHandleScope scope);
1484 
1485 template
1486     /* static */
1487     XDRResult
1488     EvalScope::XDR(XDRState<XDR_DECODE>* xdr, ScopeKind kind,
1489                    HandleScope enclosing, MutableHandleScope scope);
1490 
RuntimeData(size_t length)1491 ModuleScope::RuntimeData::RuntimeData(size_t length) {
1492   PoisonNames(this, length);
1493 }
1494 
InitModule(ModuleScope::RuntimeData & data,HandleModuleObject module)1495 static void InitModule(ModuleScope::RuntimeData& data,
1496                        HandleModuleObject module) {
1497   data.module.init(module);
1498 }
1499 
InitModule(ModuleScope::ParserData & data,HandleModuleObject module)1500 static void InitModule(ModuleScope::ParserData& data,
1501                        HandleModuleObject module) {}
1502 
1503 /* static */
1504 template <typename AtomT, typename ShapeT>
prepareForScopeCreation(JSContext * cx,typename MaybeRootedScopeData<ModuleScope,AtomT>::MutableHandleType data,HandleModuleObject module,ShapeT envShape)1505 bool ModuleScope::prepareForScopeCreation(
1506     JSContext* cx,
1507     typename MaybeRootedScopeData<ModuleScope, AtomT>::MutableHandleType data,
1508     HandleModuleObject module, ShapeT envShape) {
1509   uint32_t firstFrameSlot = 0;
1510   AbstractBindingIter<AtomT> bi(*data);
1511   if (!PrepareScopeData<ModuleScope, AtomT, ModuleEnvironmentObject>(
1512           cx, bi, data, firstFrameSlot, envShape)) {
1513     return false;
1514   }
1515 
1516   InitModule(*data, module);
1517 
1518   // Modules always need an environment object for now.
1519   bool needsEnvironment = true;
1520 
1521   return updateEnvShapeIfRequired<ModuleEnvironmentObject>(cx, envShape,
1522                                                            needsEnvironment);
1523 }
1524 
1525 /* static */
createWithData(JSContext * cx,MutableHandle<UniquePtr<RuntimeData>> data,HandleModuleObject module,HandleScope enclosing)1526 ModuleScope* ModuleScope::createWithData(
1527     JSContext* cx, MutableHandle<UniquePtr<RuntimeData>> data,
1528     HandleModuleObject module, HandleScope enclosing) {
1529   MOZ_ASSERT(data);
1530   MOZ_ASSERT(enclosing->is<GlobalScope>());
1531 
1532   RootedShape envShape(cx);
1533   if (!prepareForScopeCreation<JSAtom>(cx, data, module, &envShape)) {
1534     return nullptr;
1535   }
1536 
1537   return Scope::create<ModuleScope>(cx, ScopeKind::Module, enclosing, envShape,
1538                                     data);
1539 }
1540 
1541 template <size_t ArrayLength>
GenerateWasmName(JSContext * cx,const char (& prefix)[ArrayLength],uint32_t index)1542 static JSAtom* GenerateWasmName(JSContext* cx,
1543                                 const char (&prefix)[ArrayLength],
1544                                 uint32_t index) {
1545   StringBuffer sb(cx);
1546   if (!sb.append(prefix)) {
1547     return nullptr;
1548   }
1549   if (!NumberValueToStringBuffer(cx, Int32Value(index), sb)) {
1550     return nullptr;
1551   }
1552 
1553   return sb.finishAtom();
1554 }
1555 
1556 template <XDRMode mode>
1557 /* static */
XDR(XDRState<mode> * xdr,HandleModuleObject module,HandleScope enclosing,MutableHandleScope scope)1558 XDRResult ModuleScope::XDR(XDRState<mode>* xdr, HandleModuleObject module,
1559                            HandleScope enclosing, MutableHandleScope scope) {
1560   JSContext* cx = xdr->cx();
1561   Rooted<RuntimeData*> data(cx);
1562   MOZ_TRY(
1563       XDRSizedBindingNames<ModuleScope>(xdr, scope.as<ModuleScope>(), &data));
1564 
1565   {
1566     Maybe<Rooted<UniquePtr<RuntimeData>>> uniqueData;
1567     if (mode == XDR_DECODE) {
1568       uniqueData.emplace(cx, data);
1569     }
1570 
1571     uint32_t nextFrameSlot;
1572     if (mode == XDR_ENCODE) {
1573       nextFrameSlot = data->slotInfo.nextFrameSlot;
1574     }
1575 
1576     MOZ_TRY(xdr->codeUint32(&data->slotInfo.varStart));
1577     MOZ_TRY(xdr->codeUint32(&data->slotInfo.letStart));
1578     MOZ_TRY(xdr->codeUint32(&data->slotInfo.constStart));
1579     MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
1580 
1581     if (mode == XDR_DECODE) {
1582       if (!data->length) {
1583         MOZ_ASSERT(!data->slotInfo.varStart);
1584         MOZ_ASSERT(!data->slotInfo.letStart);
1585         MOZ_ASSERT(!data->slotInfo.constStart);
1586         MOZ_ASSERT(!data->slotInfo.nextFrameSlot);
1587       }
1588 
1589       scope.set(createWithData(cx, &uniqueData.ref(), module, enclosing));
1590       if (!scope) {
1591         return xdr->fail(JS::TranscodeResult::Throw);
1592       }
1593 
1594       // nextFrameSlot is used only for this correctness check.
1595       MOZ_ASSERT(nextFrameSlot ==
1596                  scope->as<ModuleScope>().data().slotInfo.nextFrameSlot);
1597     }
1598   }
1599 
1600   return Ok();
1601 }
1602 
1603 template
1604     /* static */
1605     XDRResult
1606     ModuleScope::XDR(XDRState<XDR_ENCODE>* xdr, HandleModuleObject module,
1607                      HandleScope enclosing, MutableHandleScope scope);
1608 
1609 template
1610     /* static */
1611     XDRResult
1612     ModuleScope::XDR(XDRState<XDR_DECODE>* xdr, HandleModuleObject module,
1613                      HandleScope enclosing, MutableHandleScope scope);
1614 
InitializeTrailingName(AbstractBindingName<JSAtom> * trailingNames,size_t i,JSAtom * name)1615 static void InitializeTrailingName(AbstractBindingName<JSAtom>* trailingNames,
1616                                    size_t i, JSAtom* name) {
1617   void* trailingName = &trailingNames[i];
1618   new (trailingName) BindingName(name, false);
1619 }
1620 
1621 template <class DataT>
InitializeNextTrailingName(const Rooted<UniquePtr<DataT>> & data,JSAtom * name)1622 static void InitializeNextTrailingName(const Rooted<UniquePtr<DataT>>& data,
1623                                        JSAtom* name) {
1624   InitializeTrailingName(GetScopeDataTrailingNamesPointer(data.get().get()),
1625                          data->length, name);
1626   data->length++;
1627 }
1628 
RuntimeData(size_t length)1629 WasmInstanceScope::RuntimeData::RuntimeData(size_t length) {
1630   PoisonNames(this, length);
1631 }
1632 
1633 /* static */
create(JSContext * cx,WasmInstanceObject * instance)1634 WasmInstanceScope* WasmInstanceScope::create(JSContext* cx,
1635                                              WasmInstanceObject* instance) {
1636   size_t namesCount = 0;
1637   if (instance->instance().memory()) {
1638     namesCount++;
1639   }
1640   size_t globalsStart = namesCount;
1641   size_t globalsCount = instance->instance().metadata().globals.length();
1642   namesCount += globalsCount;
1643 
1644   Rooted<UniquePtr<RuntimeData>> data(
1645       cx, NewEmptyScopeData<WasmInstanceScope, JSAtom>(cx, namesCount));
1646   if (!data) {
1647     return nullptr;
1648   }
1649 
1650   if (instance->instance().memory()) {
1651     JSAtom* wasmName = GenerateWasmName(cx, "memory", /* index = */ 0);
1652     if (!wasmName) {
1653       return nullptr;
1654     }
1655 
1656     InitializeNextTrailingName(data, wasmName);
1657   }
1658 
1659   for (size_t i = 0; i < globalsCount; i++) {
1660     JSAtom* wasmName = GenerateWasmName(cx, "global", i);
1661     if (!wasmName) {
1662       return nullptr;
1663     }
1664 
1665     InitializeNextTrailingName(data, wasmName);
1666   }
1667 
1668   MOZ_ASSERT(data->length == namesCount);
1669 
1670   data->instance.init(instance);
1671   data->slotInfo.globalsStart = globalsStart;
1672 
1673   RootedScope enclosing(cx, &cx->global()->emptyGlobalScope());
1674   return Scope::create<WasmInstanceScope>(cx, ScopeKind::WasmInstance,
1675                                           enclosing,
1676                                           /* envShape = */ nullptr, &data);
1677 }
1678 
1679 /* static */
create(JSContext * cx,HandleScope enclosing,uint32_t funcIndex)1680 WasmFunctionScope* WasmFunctionScope::create(JSContext* cx,
1681                                              HandleScope enclosing,
1682                                              uint32_t funcIndex) {
1683   MOZ_ASSERT(enclosing->is<WasmInstanceScope>());
1684 
1685   Rooted<WasmFunctionScope*> wasmFunctionScope(cx);
1686 
1687   Rooted<WasmInstanceObject*> instance(
1688       cx, enclosing->as<WasmInstanceScope>().instance());
1689 
1690   // TODO pull the local variable names from the wasm function definition.
1691   wasm::ValTypeVector locals;
1692   size_t argsLength;
1693   wasm::StackResults unusedStackResults;
1694   if (!instance->instance().debug().debugGetLocalTypes(
1695           funcIndex, &locals, &argsLength, &unusedStackResults)) {
1696     return nullptr;
1697   }
1698   uint32_t namesCount = locals.length();
1699 
1700   Rooted<UniquePtr<RuntimeData>> data(
1701       cx, NewEmptyScopeData<WasmFunctionScope, JSAtom>(cx, namesCount));
1702   if (!data) {
1703     return nullptr;
1704   }
1705 
1706   for (size_t i = 0; i < namesCount; i++) {
1707     JSAtom* wasmName = GenerateWasmName(cx, "var", i);
1708     if (!wasmName) {
1709       return nullptr;
1710     }
1711 
1712     InitializeNextTrailingName(data, wasmName);
1713   }
1714   MOZ_ASSERT(data->length == namesCount);
1715 
1716   return Scope::create<WasmFunctionScope>(cx, ScopeKind::WasmFunction,
1717                                           enclosing,
1718                                           /* envShape = */ nullptr, &data);
1719 }
1720 
ScopeIter(JSScript * script)1721 ScopeIter::ScopeIter(JSScript* script) : scope_(script->bodyScope()) {}
1722 
hasSyntacticEnvironment() const1723 bool ScopeIter::hasSyntacticEnvironment() const {
1724   return scope()->hasEnvironment() &&
1725          scope()->kind() != ScopeKind::NonSyntactic;
1726 }
1727 
AbstractBindingIter(ScopeKind kind,BaseScopeData * data,uint32_t firstFrameSlot)1728 AbstractBindingIter<JSAtom>::AbstractBindingIter(ScopeKind kind,
1729                                                  BaseScopeData* data,
1730                                                  uint32_t firstFrameSlot)
1731     : BaseAbstractBindingIter<JSAtom>() {
1732   switch (kind) {
1733     case ScopeKind::Lexical:
1734     case ScopeKind::SimpleCatch:
1735     case ScopeKind::Catch:
1736     case ScopeKind::FunctionLexical:
1737       init(*static_cast<LexicalScope::RuntimeData*>(data), firstFrameSlot, 0);
1738       break;
1739     case ScopeKind::NamedLambda:
1740     case ScopeKind::StrictNamedLambda:
1741       init(*static_cast<LexicalScope::RuntimeData*>(data), LOCALNO_LIMIT,
1742            IsNamedLambda);
1743       break;
1744     case ScopeKind::ClassBody:
1745       init(*static_cast<ClassBodyScope::RuntimeData*>(data), firstFrameSlot);
1746       break;
1747     case ScopeKind::With:
1748       // With scopes do not have bindings.
1749       index_ = length_ = 0;
1750       MOZ_ASSERT(done());
1751       break;
1752     case ScopeKind::Function: {
1753       uint8_t flags = IgnoreDestructuredFormalParameters;
1754       if (static_cast<FunctionScope::RuntimeData*>(data)
1755               ->slotInfo.hasParameterExprs()) {
1756         flags |= HasFormalParameterExprs;
1757       }
1758       init(*static_cast<FunctionScope::RuntimeData*>(data), flags);
1759       break;
1760     }
1761     case ScopeKind::FunctionBodyVar:
1762       init(*static_cast<VarScope::RuntimeData*>(data), firstFrameSlot);
1763       break;
1764     case ScopeKind::Eval:
1765     case ScopeKind::StrictEval:
1766       init(*static_cast<EvalScope::RuntimeData*>(data),
1767            kind == ScopeKind::StrictEval);
1768       break;
1769     case ScopeKind::Global:
1770     case ScopeKind::NonSyntactic:
1771       init(*static_cast<GlobalScope::RuntimeData*>(data));
1772       break;
1773     case ScopeKind::Module:
1774       init(*static_cast<ModuleScope::RuntimeData*>(data));
1775       break;
1776     case ScopeKind::WasmInstance:
1777       init(*static_cast<WasmInstanceScope::RuntimeData*>(data));
1778       break;
1779     case ScopeKind::WasmFunction:
1780       init(*static_cast<WasmFunctionScope::RuntimeData*>(data));
1781       break;
1782   }
1783 }
1784 
AbstractBindingIter(Scope * scope)1785 AbstractBindingIter<JSAtom>::AbstractBindingIter(Scope* scope)
1786     : AbstractBindingIter<JSAtom>(scope->kind(), scope->rawData(),
1787                                   scope->firstFrameSlot()) {}
1788 
AbstractBindingIter(JSScript * script)1789 AbstractBindingIter<JSAtom>::AbstractBindingIter(JSScript* script)
1790     : AbstractBindingIter<JSAtom>(script->bodyScope()) {}
1791 
1792 template <typename NameT>
init(LexicalScope::AbstractData<NameT> & data,uint32_t firstFrameSlot,uint8_t flags)1793 void BaseAbstractBindingIter<NameT>::init(
1794     LexicalScope::AbstractData<NameT>& data, uint32_t firstFrameSlot,
1795     uint8_t flags) {
1796   auto& slotInfo = data.slotInfo;
1797 
1798   // Named lambda scopes can only have environment slots. If the callee
1799   // isn't closed over, it is accessed via JSOp::Callee.
1800   if (flags & IsNamedLambda) {
1801     // Named lambda binding is weird. Normal BindingKind ordering rules
1802     // don't apply.
1803     init(/* positionalFormalStart= */ 0,
1804          /* nonPositionalFormalStart= */ 0,
1805          /* varStart= */ 0,
1806          /* letStart= */ 0,
1807          /* constStart= */ 0,
1808          /* syntheticStart= */ data.length,
1809          /* privageMethodStart= */ data.length,
1810          /* flags= */ CanHaveEnvironmentSlots | flags,
1811          /* firstFrameSlot= */ firstFrameSlot,
1812          /* firstEnvironmentSlot= */
1813          JSSLOT_FREE(&LexicalEnvironmentObject::class_),
1814          /* names= */ GetScopeDataTrailingNames(&data));
1815   } else {
1816     //            imports - [0, 0)
1817     // positional formals - [0, 0)
1818     //      other formals - [0, 0)
1819     //               vars - [0, 0)
1820     //               lets - [0, slotInfo.constStart)
1821     //             consts - [slotInfo.constStart, data.length)
1822     //          synthetic - [data.length, data.length)
1823     //    private methods - [data.length, data.length)
1824     init(/* positionalFormalStart= */ 0,
1825          /* nonPositionalFormalStart= */ 0,
1826          /* varStart= */ 0,
1827          /* letStart= */ 0,
1828          /* constStart= */ slotInfo.constStart,
1829          /* syntheticStart= */ data.length,
1830          /* privateMethodStart= */ data.length,
1831          /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots | flags,
1832          /* firstFrameSlot= */ firstFrameSlot,
1833          /* firstEnvironmentSlot= */
1834          JSSLOT_FREE(&LexicalEnvironmentObject::class_),
1835          /* names= */ GetScopeDataTrailingNames(&data));
1836   }
1837 }
1838 
1839 template void BaseAbstractBindingIter<JSAtom>::init(
1840     LexicalScope::AbstractData<JSAtom>&, uint32_t, uint8_t);
1841 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1842     LexicalScope::AbstractData<frontend::TaggedParserAtomIndex>&, uint32_t,
1843     uint8_t);
1844 
1845 template <typename NameT>
init(ClassBodyScope::AbstractData<NameT> & data,uint32_t firstFrameSlot)1846 void BaseAbstractBindingIter<NameT>::init(
1847     ClassBodyScope::AbstractData<NameT>& data, uint32_t firstFrameSlot) {
1848   auto& slotInfo = data.slotInfo;
1849 
1850   //            imports - [0, 0)
1851   // positional formals - [0, 0)
1852   //      other formals - [0, 0)
1853   //               vars - [0, 0)
1854   //               lets - [0, 0)
1855   //             consts - [0, 0)
1856   //          synthetic - [0, slotInfo.privateMethodStart)
1857   //    private methods - [slotInfo.privateMethodStart, data.length)
1858   init(/* positionalFormalStart= */ 0,
1859        /* nonPositionalFormalStart= */ 0,
1860        /* varStart= */ 0,
1861        /* letStart= */ 0,
1862        /* constStart= */ 0,
1863        /* syntheticStart= */ 0,
1864        /* privateMethodStart= */ slotInfo.privateMethodStart,
1865        /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots,
1866        /* firstFrameSlot= */ firstFrameSlot,
1867        /* firstEnvironmentSlot= */
1868        JSSLOT_FREE(&ClassBodyLexicalEnvironmentObject::class_),
1869        /* names= */ GetScopeDataTrailingNames(&data));
1870 }
1871 
1872 template void BaseAbstractBindingIter<JSAtom>::init(
1873     ClassBodyScope::AbstractData<JSAtom>&, uint32_t);
1874 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1875     ClassBodyScope::AbstractData<frontend::TaggedParserAtomIndex>&, uint32_t);
1876 
1877 template <typename NameT>
init(FunctionScope::AbstractData<NameT> & data,uint8_t flags)1878 void BaseAbstractBindingIter<NameT>::init(
1879     FunctionScope::AbstractData<NameT>& data, uint8_t flags) {
1880   flags = CanHaveFrameSlots | CanHaveEnvironmentSlots | flags;
1881   if (!(flags & HasFormalParameterExprs)) {
1882     flags |= CanHaveArgumentSlots;
1883   }
1884 
1885   auto length = data.length;
1886   auto& slotInfo = data.slotInfo;
1887 
1888   //            imports - [0, 0)
1889   // positional formals - [0, slotInfo.nonPositionalFormalStart)
1890   //      other formals - [slotInfo.nonPositionalParamStart, slotInfo.varStart)
1891   //               vars - [slotInfo.varStart, length)
1892   //               lets - [length, length)
1893   //             consts - [length, length)
1894   //          synthetic - [length, length)
1895   //    private methods - [length, length)
1896   init(/* positionalFormalStart= */ 0,
1897        /* nonPositionalFormalStart= */ slotInfo.nonPositionalFormalStart,
1898        /* varStart= */ slotInfo.varStart,
1899        /* letStart= */ length,
1900        /* constStart= */ length,
1901        /* syntheticStart= */ length,
1902        /* privateMethodStart= */ length,
1903        /* flags= */ flags,
1904        /* firstFrameSlot= */ 0,
1905        /* firstEnvironmentSlot= */ JSSLOT_FREE(&CallObject::class_),
1906        /* names= */ GetScopeDataTrailingNames(&data));
1907 }
1908 template void BaseAbstractBindingIter<JSAtom>::init(
1909     FunctionScope::AbstractData<JSAtom>&, uint8_t);
1910 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1911     FunctionScope::AbstractData<frontend::TaggedParserAtomIndex>&, uint8_t);
1912 
1913 template <typename NameT>
init(VarScope::AbstractData<NameT> & data,uint32_t firstFrameSlot)1914 void BaseAbstractBindingIter<NameT>::init(VarScope::AbstractData<NameT>& data,
1915                                           uint32_t firstFrameSlot) {
1916   auto length = data.length;
1917 
1918   //            imports - [0, 0)
1919   // positional formals - [0, 0)
1920   //      other formals - [0, 0)
1921   //               vars - [0, length)
1922   //               lets - [length, length)
1923   //             consts - [length, length)
1924   //          synthetic - [length, length)
1925   //    private methods - [length, length)
1926   init(/* positionalFormalStart= */ 0,
1927        /* nonPositionalFormalStart= */ 0,
1928        /* varStart= */ 0,
1929        /* letStart= */ length,
1930        /* constStart= */ length,
1931        /* syntheticStart= */ length,
1932        /* privateMethodStart= */ length,
1933        /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots,
1934        /* firstFrameSlot= */ firstFrameSlot,
1935        /* firstEnvironmentSlot= */ JSSLOT_FREE(&VarEnvironmentObject::class_),
1936        /* names= */ GetScopeDataTrailingNames(&data));
1937 }
1938 template void BaseAbstractBindingIter<JSAtom>::init(
1939     VarScope::AbstractData<JSAtom>&, uint32_t);
1940 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1941     VarScope::AbstractData<frontend::TaggedParserAtomIndex>&, uint32_t);
1942 
1943 template <typename NameT>
init(GlobalScope::AbstractData<NameT> & data)1944 void BaseAbstractBindingIter<NameT>::init(
1945     GlobalScope::AbstractData<NameT>& data) {
1946   auto& slotInfo = data.slotInfo;
1947 
1948   //            imports - [0, 0)
1949   // positional formals - [0, 0)
1950   //      other formals - [0, 0)
1951   //               vars - [0, slotInfo.letStart)
1952   //               lets - [slotInfo.letStart, slotInfo.constStart)
1953   //             consts - [slotInfo.constStart, data.length)
1954   //          synthetic - [data.length, data.length)
1955   //    private methods - [data.length, data.length)
1956   init(/* positionalFormalStart= */ 0,
1957        /* nonPositionalFormalStart= */ 0,
1958        /* varStart= */ 0,
1959        /* letStart= */ slotInfo.letStart,
1960        /* constStart= */ slotInfo.constStart,
1961        /* syntheticStart= */ data.length,
1962        /* privateMethoodStart= */ data.length,
1963        /* flags= */ CannotHaveSlots,
1964        /* firstFrameSlot= */ UINT32_MAX,
1965        /* firstEnvironmentSlot= */ UINT32_MAX,
1966        /* names= */ GetScopeDataTrailingNames(&data));
1967 }
1968 template void BaseAbstractBindingIter<JSAtom>::init(
1969     GlobalScope::AbstractData<JSAtom>&);
1970 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1971     GlobalScope::AbstractData<frontend::TaggedParserAtomIndex>&);
1972 
1973 template <typename NameT>
init(EvalScope::AbstractData<NameT> & data,bool strict)1974 void BaseAbstractBindingIter<NameT>::init(EvalScope::AbstractData<NameT>& data,
1975                                           bool strict) {
1976   uint32_t flags;
1977   uint32_t firstFrameSlot;
1978   uint32_t firstEnvironmentSlot;
1979   if (strict) {
1980     flags = CanHaveFrameSlots | CanHaveEnvironmentSlots;
1981     firstFrameSlot = 0;
1982     firstEnvironmentSlot = JSSLOT_FREE(&VarEnvironmentObject::class_);
1983   } else {
1984     flags = CannotHaveSlots;
1985     firstFrameSlot = UINT32_MAX;
1986     firstEnvironmentSlot = UINT32_MAX;
1987   }
1988 
1989   auto length = data.length;
1990 
1991   //            imports - [0, 0)
1992   // positional formals - [0, 0)
1993   //      other formals - [0, 0)
1994   //               vars - [0, length)
1995   //               lets - [length, length)
1996   //             consts - [length, length)
1997   //          synthetic - [length, length)
1998   //    private methods - [length, length)
1999   init(/* positionalFormalStart= */ 0,
2000        /* nonPositionalFormalStart= */ 0,
2001        /* varStart= */ 0,
2002        /* letStart= */ length,
2003        /* constStart= */ length,
2004        /* syntheticStart= */ length,
2005        /* privateMethodStart= */ length,
2006        /* flags= */ flags,
2007        /* firstFrameSlot= */ firstFrameSlot,
2008        /* firstEnvironmentSlot= */ firstEnvironmentSlot,
2009        /* names= */ GetScopeDataTrailingNames(&data));
2010 }
2011 template void BaseAbstractBindingIter<JSAtom>::init(
2012     EvalScope::AbstractData<JSAtom>&, bool);
2013 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
2014     EvalScope::AbstractData<frontend::TaggedParserAtomIndex>&, bool);
2015 
2016 template <typename NameT>
init(ModuleScope::AbstractData<NameT> & data)2017 void BaseAbstractBindingIter<NameT>::init(
2018     ModuleScope::AbstractData<NameT>& data) {
2019   auto& slotInfo = data.slotInfo;
2020 
2021   //            imports - [0, slotInfo.varStart)
2022   // positional formals - [slotInfo.varStart, slotInfo.varStart)
2023   //      other formals - [slotInfo.varStart, slotInfo.varStart)
2024   //               vars - [slotInfo.varStart, slotInfo.letStart)
2025   //               lets - [slotInfo.letStart, slotInfo.constStart)
2026   //             consts - [slotInfo.constStart, data.length)
2027   //          synthetic - [data.length, data.length)
2028   //    private methods - [data.length, data.length)
2029   init(
2030       /* positionalFormalStart= */ slotInfo.varStart,
2031       /* nonPositionalFormalStart= */ slotInfo.varStart,
2032       /* varStart= */ slotInfo.varStart,
2033       /* letStart= */ slotInfo.letStart,
2034       /* constStart= */ slotInfo.constStart,
2035       /* syntheticStart= */ data.length,
2036       /* privateMethodStart= */ data.length,
2037       /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots,
2038       /* firstFrameSlot= */ 0,
2039       /* firstEnvironmentSlot= */ JSSLOT_FREE(&ModuleEnvironmentObject::class_),
2040       /* names= */ GetScopeDataTrailingNames(&data));
2041 }
2042 template void BaseAbstractBindingIter<JSAtom>::init(
2043     ModuleScope::AbstractData<JSAtom>&);
2044 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
2045     ModuleScope::AbstractData<frontend::TaggedParserAtomIndex>&);
2046 
2047 template <typename NameT>
init(WasmInstanceScope::AbstractData<NameT> & data)2048 void BaseAbstractBindingIter<NameT>::init(
2049     WasmInstanceScope::AbstractData<NameT>& data) {
2050   auto length = data.length;
2051 
2052   //            imports - [0, 0)
2053   // positional formals - [0, 0)
2054   //      other formals - [0, 0)
2055   //               vars - [0, length)
2056   //               lets - [length, length)
2057   //             consts - [length, length)
2058   //          synthetic - [length, length)
2059   //    private methods - [length, length)
2060   init(/* positionalFormalStart= */ 0,
2061        /* nonPositionalFormalStart= */ 0,
2062        /* varStart= */ 0,
2063        /* letStart= */ length,
2064        /* constStart= */ length,
2065        /* syntheticStart= */ length,
2066        /* privateMethodStart= */ length,
2067        /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots,
2068        /* firstFrameSlot= */ UINT32_MAX,
2069        /* firstEnvironmentSlot= */ UINT32_MAX,
2070        /* names= */ GetScopeDataTrailingNames(&data));
2071 }
2072 template void BaseAbstractBindingIter<JSAtom>::init(
2073     WasmInstanceScope::AbstractData<JSAtom>&);
2074 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
2075     WasmInstanceScope::AbstractData<frontend::TaggedParserAtomIndex>&);
2076 
2077 template <typename NameT>
init(WasmFunctionScope::AbstractData<NameT> & data)2078 void BaseAbstractBindingIter<NameT>::init(
2079     WasmFunctionScope::AbstractData<NameT>& data) {
2080   auto length = data.length;
2081 
2082   //            imports - [0, 0)
2083   // positional formals - [0, 0)
2084   //      other formals - [0, 0)
2085   //               vars - [0, length)
2086   //               lets - [length, length)
2087   //             consts - [length, length)
2088   //          synthetic - [length, length)
2089   //    private methods - [length, length)
2090   init(/* positionalFormalStart = */ 0,
2091        /* nonPositionalFormalStart = */ 0,
2092        /* varStart= */ 0,
2093        /* letStart= */ length,
2094        /* constStart= */ length,
2095        /* syntheticStart= */ length,
2096        /* privateMethodStart= */ length,
2097        /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots,
2098        /* firstFrameSlot= */ UINT32_MAX,
2099        /* firstEnvironmentSlot= */ UINT32_MAX,
2100        /* names= */ GetScopeDataTrailingNames(&data));
2101 }
2102 template void BaseAbstractBindingIter<JSAtom>::init(
2103     WasmFunctionScope::AbstractData<JSAtom>&);
2104 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
2105     WasmFunctionScope::AbstractData<frontend::TaggedParserAtomIndex>&);
2106 
PositionalFormalParameterIter(Scope * scope)2107 PositionalFormalParameterIter::PositionalFormalParameterIter(Scope* scope)
2108     : BindingIter(scope) {
2109   // Reinit with flags = 0, i.e., iterate over all positional parameters.
2110   if (scope->is<FunctionScope>()) {
2111     init(scope->as<FunctionScope>().data(), /* flags = */ 0);
2112   }
2113   settle();
2114 }
2115 
PositionalFormalParameterIter(JSScript * script)2116 PositionalFormalParameterIter::PositionalFormalParameterIter(JSScript* script)
2117     : PositionalFormalParameterIter(script->bodyScope()) {}
2118 
DumpBindings(JSContext * cx,Scope * scopeArg)2119 void js::DumpBindings(JSContext* cx, Scope* scopeArg) {
2120   RootedScope scope(cx, scopeArg);
2121   for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
2122     UniqueChars bytes = AtomToPrintableString(cx, bi.name());
2123     if (!bytes) {
2124       MaybePrintAndClearPendingException(cx);
2125       return;
2126     }
2127     fprintf(stderr, "    %s %s ", BindingKindString(bi.kind()), bytes.get());
2128     switch (bi.location().kind()) {
2129       case BindingLocation::Kind::Global:
2130         if (bi.isTopLevelFunction()) {
2131           fprintf(stderr, "global function\n");
2132         } else {
2133           fprintf(stderr, "global\n");
2134         }
2135         break;
2136       case BindingLocation::Kind::Argument:
2137         fprintf(stderr, "arg slot %u\n", bi.location().argumentSlot());
2138         break;
2139       case BindingLocation::Kind::Frame:
2140         fprintf(stderr, "frame slot %u\n", bi.location().slot());
2141         break;
2142       case BindingLocation::Kind::Environment:
2143         fprintf(stderr, "env slot %u\n", bi.location().slot());
2144         break;
2145       case BindingLocation::Kind::NamedLambdaCallee:
2146         fprintf(stderr, "named lambda callee\n");
2147         break;
2148       case BindingLocation::Kind::Import:
2149         fprintf(stderr, "import\n");
2150         break;
2151     }
2152   }
2153 }
2154 
GetFrameSlotNameInScope(Scope * scope,uint32_t slot)2155 static JSAtom* GetFrameSlotNameInScope(Scope* scope, uint32_t slot) {
2156   for (BindingIter bi(scope); bi; bi++) {
2157     BindingLocation loc = bi.location();
2158     if (loc.kind() == BindingLocation::Kind::Frame && loc.slot() == slot) {
2159       return bi.name();
2160     }
2161   }
2162   return nullptr;
2163 }
2164 
FrameSlotName(JSScript * script,jsbytecode * pc)2165 JSAtom* js::FrameSlotName(JSScript* script, jsbytecode* pc) {
2166   MOZ_ASSERT(IsLocalOp(JSOp(*pc)));
2167   uint32_t slot = GET_LOCALNO(pc);
2168   MOZ_ASSERT(slot < script->nfixed());
2169 
2170   // Look for it in the body scope first.
2171   if (JSAtom* name = GetFrameSlotNameInScope(script->bodyScope(), slot)) {
2172     return name;
2173   }
2174 
2175   // If this is a function script and there is an extra var scope, look for
2176   // it there.
2177   if (script->functionHasExtraBodyVarScope()) {
2178     if (JSAtom* name = GetFrameSlotNameInScope(
2179             script->functionExtraBodyVarScope(), slot)) {
2180       return name;
2181     }
2182   }
2183   // If not found, look for it in a lexical scope.
2184   for (ScopeIter si(script->innermostScope(pc)); si; si++) {
2185     if (!si.scope()->is<LexicalScope>() && !si.scope()->is<ClassBodyScope>()) {
2186       continue;
2187     }
2188 
2189     // Is the slot within bounds of the current lexical scope?
2190     if (slot < si.scope()->firstFrameSlot()) {
2191       continue;
2192     }
2193     if (slot >= LexicalScope::nextFrameSlot(si.scope())) {
2194       break;
2195     }
2196 
2197     // If so, get the name.
2198     if (JSAtom* name = GetFrameSlotNameInScope(si.scope(), slot)) {
2199       return name;
2200     }
2201   }
2202 
2203   MOZ_CRASH("Frame slot not found");
2204 }
2205 
size(mozilla::MallocSizeOf mallocSizeOf) const2206 JS::ubi::Node::Size JS::ubi::Concrete<Scope>::size(
2207     mozilla::MallocSizeOf mallocSizeOf) const {
2208   return js::gc::Arena::thingSize(get().asTenured().getAllocKind()) +
2209          get().sizeOfExcludingThis(mallocSizeOf);
2210 }
2211 
2212 template <typename... Args>
appendScopeStencilAndData(JSContext * cx,CompilationState & compilationState,BaseParserScopeData * data,ScopeIndex * indexOut,Args &&...args)2213 /* static */ bool ScopeStencil::appendScopeStencilAndData(
2214     JSContext* cx, CompilationState& compilationState,
2215     BaseParserScopeData* data, ScopeIndex* indexOut, Args&&... args) {
2216   *indexOut = ScopeIndex(compilationState.scopeData.length());
2217   if (uint32_t(*indexOut) >= TaggedScriptThingIndex::IndexLimit) {
2218     ReportAllocationOverflow(cx);
2219     return false;
2220   }
2221 
2222   if (!compilationState.scopeData.emplaceBack(std::forward<Args>(args)...)) {
2223     js::ReportOutOfMemory(cx);
2224     return false;
2225   }
2226   if (!compilationState.scopeNames.append(data)) {
2227     compilationState.scopeData.popBack();
2228     MOZ_ASSERT(compilationState.scopeData.length() ==
2229                compilationState.scopeNames.length());
2230 
2231     js::ReportOutOfMemory(cx);
2232     return false;
2233   }
2234 
2235   return true;
2236 }
2237 
2238 /* static */
createForFunctionScope(JSContext * cx,frontend::CompilationState & compilationState,FunctionScope::ParserData * data,bool hasParameterExprs,bool needsEnvironment,ScriptIndex functionIndex,bool isArrow,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)2239 bool ScopeStencil::createForFunctionScope(
2240     JSContext* cx, frontend::CompilationState& compilationState,
2241     FunctionScope::ParserData* data, bool hasParameterExprs,
2242     bool needsEnvironment, ScriptIndex functionIndex, bool isArrow,
2243     mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index) {
2244   auto kind = ScopeKind::Function;
2245   using ScopeType = FunctionScope;
2246   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
2247 
2248   if (data) {
2249     MarkParserScopeData<ScopeType>(cx, data, compilationState);
2250   } else {
2251     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
2252     if (!data) {
2253       return false;
2254     }
2255   }
2256 
2257   // We do not initialize the canonical function while the data is owned by the
2258   // ScopeStencil. It gets set in ScopeStencil::releaseData.
2259   RootedFunction fun(cx, nullptr);
2260 
2261   uint32_t firstFrameSlot = 0;
2262   mozilla::Maybe<uint32_t> envShape;
2263   if (!FunctionScope::prepareForScopeCreation<frontend::TaggedParserAtomIndex>(
2264           cx, &data, hasParameterExprs, needsEnvironment, fun, &envShape)) {
2265     return false;
2266   }
2267 
2268   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
2269                                    enclosing, firstFrameSlot, envShape,
2270                                    mozilla::Some(functionIndex), isArrow);
2271 }
2272 
2273 /* static */
createForLexicalScope(JSContext * cx,frontend::CompilationState & compilationState,ScopeKind kind,LexicalScope::ParserData * data,uint32_t firstFrameSlot,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)2274 bool ScopeStencil::createForLexicalScope(
2275     JSContext* cx, frontend::CompilationState& compilationState, ScopeKind kind,
2276     LexicalScope::ParserData* data, uint32_t firstFrameSlot,
2277     mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index) {
2278   using ScopeType = LexicalScope;
2279   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
2280 
2281   if (data) {
2282     MarkParserScopeData<ScopeType>(cx, data, compilationState);
2283   } else {
2284     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
2285     if (!data) {
2286       return false;
2287     }
2288   }
2289 
2290   mozilla::Maybe<uint32_t> envShape;
2291   if (!ScopeType::prepareForScopeCreation<frontend::TaggedParserAtomIndex>(
2292           cx, kind, firstFrameSlot, &data, &envShape)) {
2293     return false;
2294   }
2295 
2296   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
2297                                    enclosing, firstFrameSlot, envShape);
2298 }
2299 
2300 /* static */
createForClassBodyScope(JSContext * cx,frontend::CompilationState & compilationState,ScopeKind kind,ClassBodyScope::ParserData * data,uint32_t firstFrameSlot,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)2301 bool ScopeStencil::createForClassBodyScope(
2302     JSContext* cx, frontend::CompilationState& compilationState, ScopeKind kind,
2303     ClassBodyScope::ParserData* data, uint32_t firstFrameSlot,
2304     mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index) {
2305   using ScopeType = ClassBodyScope;
2306   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
2307 
2308   if (data) {
2309     MarkParserScopeData<ScopeType>(cx, data, compilationState);
2310   } else {
2311     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
2312     if (!data) {
2313       return false;
2314     }
2315   }
2316 
2317   mozilla::Maybe<uint32_t> envShape;
2318   if (!ScopeType::prepareForScopeCreation<frontend::TaggedParserAtomIndex>(
2319           cx, kind, firstFrameSlot, &data, &envShape)) {
2320     return false;
2321   }
2322 
2323   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
2324                                    enclosing, firstFrameSlot, envShape);
2325 }
2326 
createForVarScope(JSContext * cx,frontend::CompilationState & compilationState,ScopeKind kind,VarScope::ParserData * data,uint32_t firstFrameSlot,bool needsEnvironment,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)2327 bool ScopeStencil::createForVarScope(
2328     JSContext* cx, frontend::CompilationState& compilationState, ScopeKind kind,
2329     VarScope::ParserData* data, uint32_t firstFrameSlot, bool needsEnvironment,
2330     mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index) {
2331   using ScopeType = VarScope;
2332   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
2333 
2334   if (data) {
2335     MarkParserScopeData<ScopeType>(cx, data, compilationState);
2336   } else {
2337     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
2338     if (!data) {
2339       return false;
2340     }
2341   }
2342 
2343   mozilla::Maybe<uint32_t> envShape;
2344   if (!VarScope::prepareForScopeCreation<frontend::TaggedParserAtomIndex>(
2345           cx, kind, &data, firstFrameSlot, needsEnvironment, &envShape)) {
2346     return false;
2347   }
2348 
2349   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
2350                                    enclosing, firstFrameSlot, envShape);
2351 }
2352 
2353 /* static */
createForGlobalScope(JSContext * cx,frontend::CompilationState & compilationState,ScopeKind kind,GlobalScope::ParserData * data,ScopeIndex * index)2354 bool ScopeStencil::createForGlobalScope(
2355     JSContext* cx, frontend::CompilationState& compilationState, ScopeKind kind,
2356     GlobalScope::ParserData* data, ScopeIndex* index) {
2357   using ScopeType = GlobalScope;
2358   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
2359 
2360   if (data) {
2361     MarkParserScopeData<ScopeType>(cx, data, compilationState);
2362   } else {
2363     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
2364     if (!data) {
2365       return false;
2366     }
2367   }
2368 
2369   // The global scope has no environment shape. Its environment is the
2370   // global lexical scope and the global object or non-syntactic objects
2371   // created by embedding, all of which are not only extensible but may
2372   // have names on them deleted.
2373   uint32_t firstFrameSlot = 0;
2374   mozilla::Maybe<uint32_t> envShape;
2375 
2376   mozilla::Maybe<ScopeIndex> enclosing;
2377 
2378   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
2379                                    enclosing, firstFrameSlot, envShape);
2380 }
2381 
2382 /* static */
createForEvalScope(JSContext * cx,frontend::CompilationState & compilationState,ScopeKind kind,EvalScope::ParserData * data,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)2383 bool ScopeStencil::createForEvalScope(
2384     JSContext* cx, frontend::CompilationState& compilationState, ScopeKind kind,
2385     EvalScope::ParserData* data, mozilla::Maybe<ScopeIndex> enclosing,
2386     ScopeIndex* index) {
2387   using ScopeType = EvalScope;
2388   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
2389 
2390   if (data) {
2391     MarkParserScopeData<ScopeType>(cx, data, compilationState);
2392   } else {
2393     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
2394     if (!data) {
2395       return false;
2396     }
2397   }
2398 
2399   uint32_t firstFrameSlot = 0;
2400   mozilla::Maybe<uint32_t> envShape;
2401   if (!EvalScope::prepareForScopeCreation<frontend::TaggedParserAtomIndex>(
2402           cx, kind, &data, &envShape)) {
2403     return false;
2404   }
2405 
2406   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
2407                                    enclosing, firstFrameSlot, envShape);
2408 }
2409 
2410 /* static */
createForModuleScope(JSContext * cx,frontend::CompilationState & compilationState,ModuleScope::ParserData * data,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)2411 bool ScopeStencil::createForModuleScope(
2412     JSContext* cx, frontend::CompilationState& compilationState,
2413     ModuleScope::ParserData* data, mozilla::Maybe<ScopeIndex> enclosing,
2414     ScopeIndex* index) {
2415   auto kind = ScopeKind::Module;
2416   using ScopeType = ModuleScope;
2417   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
2418 
2419   if (data) {
2420     MarkParserScopeData<ScopeType>(cx, data, compilationState);
2421   } else {
2422     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
2423     if (!data) {
2424       return false;
2425     }
2426   }
2427 
2428   MOZ_ASSERT(enclosing.isNothing());
2429 
2430   // We do not initialize the canonical module while the data is owned by the
2431   // ScopeStencil. It gets set in ScopeStencil::releaseData.
2432   RootedModuleObject module(cx, nullptr);
2433 
2434   // The data that's passed in is from the frontend and is LifoAlloc'd.
2435   // Copy it now that we're creating a permanent VM scope.
2436   uint32_t firstFrameSlot = 0;
2437   mozilla::Maybe<uint32_t> envShape;
2438   if (!ModuleScope::prepareForScopeCreation<frontend::TaggedParserAtomIndex>(
2439           cx, &data, module, &envShape)) {
2440     return false;
2441   }
2442 
2443   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
2444                                    enclosing, firstFrameSlot, envShape);
2445 }
2446 
2447 template <typename SpecificEnvironmentT>
createSpecificShape(JSContext * cx,ScopeKind kind,BaseScopeData * scopeData,MutableHandleShape shape) const2448 bool ScopeStencil::createSpecificShape(JSContext* cx, ScopeKind kind,
2449                                        BaseScopeData* scopeData,
2450                                        MutableHandleShape shape) const {
2451   const JSClass* cls = &SpecificEnvironmentT::class_;
2452   constexpr ObjectFlags objectFlags = SpecificEnvironmentT::OBJECT_FLAGS;
2453 
2454   if (hasEnvironmentShape()) {
2455     if (numEnvironmentSlots() > 0) {
2456       BindingIter bi(kind, scopeData, firstFrameSlot_);
2457       shape.set(CreateEnvironmentShape(cx, bi, cls, numEnvironmentSlots(),
2458                                        objectFlags));
2459       return shape;
2460     }
2461 
2462     shape.set(EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), objectFlags));
2463     return shape;
2464   }
2465 
2466   return true;
2467 }
2468 
2469 /* static */
createForWithScope(JSContext * cx,CompilationState & compilationState,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)2470 bool ScopeStencil::createForWithScope(JSContext* cx,
2471                                       CompilationState& compilationState,
2472                                       mozilla::Maybe<ScopeIndex> enclosing,
2473                                       ScopeIndex* index) {
2474   auto kind = ScopeKind::With;
2475   MOZ_ASSERT(matchScopeKind<WithScope>(kind));
2476 
2477   uint32_t firstFrameSlot = 0;
2478   mozilla::Maybe<uint32_t> envShape;
2479 
2480   return appendScopeStencilAndData(cx, compilationState, nullptr, index, kind,
2481                                    enclosing, firstFrameSlot, envShape);
2482 }
2483 
2484 template <typename SpecificScopeT>
2485 UniquePtr<typename SpecificScopeT::RuntimeData>
createSpecificScopeData(JSContext * cx,CompilationAtomCache & atomCache,BaseParserScopeData * baseData) const2486 ScopeStencil::createSpecificScopeData(JSContext* cx,
2487                                       CompilationAtomCache& atomCache,
2488                                       BaseParserScopeData* baseData) const {
2489   return LiftParserScopeData<SpecificScopeT>(cx, atomCache, baseData);
2490 }
2491 
2492 template <>
2493 UniquePtr<FunctionScope::RuntimeData>
createSpecificScopeData(JSContext * cx,CompilationAtomCache & atomCache,BaseParserScopeData * baseData) const2494 ScopeStencil::createSpecificScopeData<FunctionScope>(
2495     JSContext* cx, CompilationAtomCache& atomCache,
2496     BaseParserScopeData* baseData) const {
2497   // Allocate a new vm function-scope.
2498   UniquePtr<FunctionScope::RuntimeData> data =
2499       LiftParserScopeData<FunctionScope>(cx, atomCache, baseData);
2500   if (!data) {
2501     return nullptr;
2502   }
2503 
2504   return data;
2505 }
2506 
2507 template <>
2508 UniquePtr<ModuleScope::RuntimeData>
createSpecificScopeData(JSContext * cx,CompilationAtomCache & atomCache,BaseParserScopeData * baseData) const2509 ScopeStencil::createSpecificScopeData<ModuleScope>(
2510     JSContext* cx, CompilationAtomCache& atomCache,
2511     BaseParserScopeData* baseData) const {
2512   // Allocate a new vm module-scope.
2513   UniquePtr<ModuleScope::RuntimeData> data =
2514       LiftParserScopeData<ModuleScope>(cx, atomCache, baseData);
2515   if (!data) {
2516     return nullptr;
2517   }
2518 
2519   return data;
2520 }
2521 
2522 // WithScope does not use binding data.
2523 template <>
createSpecificScope(JSContext * cx,CompilationAtomCache & atomCache,HandleScope enclosingScope,BaseParserScopeData * baseData) const2524 Scope* ScopeStencil::createSpecificScope<WithScope, std::nullptr_t>(
2525     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2526     BaseParserScopeData* baseData) const {
2527   return Scope::create(cx, ScopeKind::With, enclosingScope, nullptr);
2528 }
2529 
2530 // GlobalScope has bindings but no environment shape.
2531 template <>
createSpecificScope(JSContext * cx,CompilationAtomCache & atomCache,HandleScope enclosingScope,BaseParserScopeData * baseData) const2532 Scope* ScopeStencil::createSpecificScope<GlobalScope, std::nullptr_t>(
2533     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2534     BaseParserScopeData* baseData) const {
2535   Rooted<UniquePtr<GlobalScope::RuntimeData>> rootedData(
2536       cx, createSpecificScopeData<GlobalScope>(cx, atomCache, baseData));
2537   if (!rootedData) {
2538     return nullptr;
2539   }
2540 
2541   MOZ_ASSERT(!hasEnclosing());
2542   MOZ_ASSERT(!enclosingScope);
2543 
2544   // Because we already baked the data here, we needn't do it again.
2545   return Scope::create<GlobalScope>(cx, kind(), nullptr, nullptr, &rootedData);
2546 }
2547 
2548 template <typename SpecificScopeT, typename SpecificEnvironmentT>
createSpecificScope(JSContext * cx,CompilationAtomCache & atomCache,HandleScope enclosingScope,BaseParserScopeData * baseData) const2549 Scope* ScopeStencil::createSpecificScope(JSContext* cx,
2550                                          CompilationAtomCache& atomCache,
2551                                          HandleScope enclosingScope,
2552                                          BaseParserScopeData* baseData) const {
2553   Rooted<UniquePtr<typename SpecificScopeT::RuntimeData>> rootedData(
2554       cx, createSpecificScopeData<SpecificScopeT>(cx, atomCache, baseData));
2555   if (!rootedData) {
2556     return nullptr;
2557   }
2558 
2559   RootedShape shape(cx);
2560   if (!createSpecificShape<SpecificEnvironmentT>(
2561           cx, kind(), rootedData.get().get(), &shape)) {
2562     return nullptr;
2563   }
2564 
2565   // Because we already baked the data here, we needn't do it again.
2566   return Scope::create<SpecificScopeT>(cx, kind(), enclosingScope, shape,
2567                                        &rootedData);
2568 }
2569 
2570 template Scope* ScopeStencil::createSpecificScope<FunctionScope, CallObject>(
2571     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2572     BaseParserScopeData* baseData) const;
2573 template Scope*
2574 ScopeStencil::createSpecificScope<LexicalScope, BlockLexicalEnvironmentObject>(
2575     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2576     BaseParserScopeData* baseData) const;
2577 template Scope* ScopeStencil::createSpecificScope<
2578     ClassBodyScope, BlockLexicalEnvironmentObject>(
2579     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2580     BaseParserScopeData* baseData) const;
2581 template Scope*
2582 ScopeStencil::createSpecificScope<EvalScope, VarEnvironmentObject>(
2583     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2584     BaseParserScopeData* baseData) const;
2585 template Scope*
2586 ScopeStencil::createSpecificScope<VarScope, VarEnvironmentObject>(
2587     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2588     BaseParserScopeData* baseData) const;
2589 template Scope*
2590 ScopeStencil::createSpecificScope<ModuleScope, ModuleEnvironmentObject>(
2591     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2592     BaseParserScopeData* baseData) const;
2593