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"  // ScopeStencilRef, CompilationStencil, CompilationState, CompilationAtomCache
17 #include "frontend/ParserAtom.h"  // frontend::ParserAtomsTable, frontend::ParserAtom
18 #include "frontend/ScriptIndex.h"  // ScriptIndex
19 #include "frontend/Stencil.h"
20 #include "gc/Allocator.h"
21 #include "gc/MaybeRooted.h"
22 #include "util/StringBuffer.h"
23 #include "vm/EnvironmentObject.h"
24 #include "vm/ErrorReporting.h"  // MaybePrintAndClearPendingException
25 #include "vm/JSScript.h"
26 #include "wasm/WasmInstance.h"
27 
28 #include "gc/FreeOp-inl.h"
29 #include "gc/ObjectKind-inl.h"
30 #include "vm/Shape-inl.h"
31 
32 using namespace js;
33 using namespace js::frontend;
34 
35 using mozilla::Maybe;
36 
BindingKindString(BindingKind kind)37 const char* js::BindingKindString(BindingKind kind) {
38   switch (kind) {
39     case BindingKind::Import:
40       return "import";
41     case BindingKind::FormalParameter:
42       return "formal parameter";
43     case BindingKind::Var:
44       return "var";
45     case BindingKind::Let:
46       return "let";
47     case BindingKind::Const:
48       return "const";
49     case BindingKind::NamedLambdaCallee:
50       return "named lambda callee";
51     case BindingKind::Synthetic:
52       return "synthetic";
53     case BindingKind::PrivateMethod:
54       return "private method";
55   }
56   MOZ_CRASH("Bad BindingKind");
57 }
58 
ScopeKindString(ScopeKind kind)59 const char* js::ScopeKindString(ScopeKind kind) {
60   switch (kind) {
61     case ScopeKind::Function:
62       return "function";
63     case ScopeKind::FunctionBodyVar:
64       return "function body var";
65     case ScopeKind::Lexical:
66       return "lexical";
67     case ScopeKind::SimpleCatch:
68     case ScopeKind::Catch:
69       return "catch";
70     case ScopeKind::NamedLambda:
71       return "named lambda";
72     case ScopeKind::StrictNamedLambda:
73       return "strict named lambda";
74     case ScopeKind::FunctionLexical:
75       return "function lexical";
76     case ScopeKind::ClassBody:
77       return "class body";
78     case ScopeKind::With:
79       return "with";
80     case ScopeKind::Eval:
81       return "eval";
82     case ScopeKind::StrictEval:
83       return "strict eval";
84     case ScopeKind::Global:
85       return "global";
86     case ScopeKind::NonSyntactic:
87       return "non-syntactic";
88     case ScopeKind::Module:
89       return "module";
90     case ScopeKind::WasmInstance:
91       return "wasm instance";
92     case ScopeKind::WasmFunction:
93       return "wasm function";
94   }
95   MOZ_CRASH("Bad ScopeKind");
96 }
97 
EmptyEnvironmentShape(JSContext * cx,const JSClass * cls,uint32_t numSlots,ObjectFlags objectFlags)98 Shape* js::EmptyEnvironmentShape(JSContext* cx, const JSClass* cls,
99                                  uint32_t numSlots, ObjectFlags objectFlags) {
100   // Put as many slots into the object header as possible.
101   uint32_t numFixed = gc::GetGCKindSlots(gc::GetGCObjectKind(numSlots));
102   return SharedShape::getInitialShape(
103       cx, cls, cx->realm(), TaggedProto(nullptr), numFixed, objectFlags);
104 }
105 
AddToEnvironmentMap(JSContext * cx,const JSClass * clasp,HandleId id,BindingKind bindKind,uint32_t slot,MutableHandle<SharedPropMap * > map,uint32_t * mapLength,ObjectFlags * objectFlags)106 static bool AddToEnvironmentMap(JSContext* cx, const JSClass* clasp,
107                                 HandleId id, BindingKind bindKind,
108                                 uint32_t slot,
109                                 MutableHandle<SharedPropMap*> map,
110                                 uint32_t* mapLength, ObjectFlags* objectFlags) {
111   PropertyFlags propFlags = {PropertyFlag::Enumerable};
112   switch (bindKind) {
113     case BindingKind::Const:
114     case BindingKind::NamedLambdaCallee:
115       // Non-writable.
116       break;
117     default:
118       propFlags.setFlag(PropertyFlag::Writable);
119       break;
120   }
121 
122   return SharedPropMap::addPropertyWithKnownSlot(cx, clasp, map, mapLength, id,
123                                                  propFlags, slot, objectFlags);
124 }
125 
CreateEnvironmentShape(JSContext * cx,BindingIter & bi,const JSClass * cls,uint32_t numSlots,ObjectFlags objectFlags)126 Shape* js::CreateEnvironmentShape(JSContext* cx, BindingIter& bi,
127                                   const JSClass* cls, uint32_t numSlots,
128                                   ObjectFlags objectFlags) {
129   Rooted<SharedPropMap*> map(cx);
130   uint32_t mapLength = 0;
131 
132   RootedId id(cx);
133   for (; bi; bi++) {
134     BindingLocation loc = bi.location();
135     if (loc.kind() == BindingLocation::Kind::Environment) {
136       JSAtom* name = bi.name();
137       cx->markAtom(name);
138       id = NameToId(name->asPropertyName());
139       if (!AddToEnvironmentMap(cx, cls, id, bi.kind(), loc.slot(), &map,
140                                &mapLength, &objectFlags)) {
141         return nullptr;
142       }
143     }
144   }
145 
146   uint32_t numFixed = gc::GetGCKindSlots(gc::GetGCObjectKind(numSlots));
147   return SharedShape::getInitialOrPropMapShape(cx, cls, cx->realm(),
148                                                TaggedProto(nullptr), numFixed,
149                                                map, mapLength, objectFlags);
150 }
151 
CreateEnvironmentShape(JSContext * cx,frontend::CompilationAtomCache & atomCache,AbstractBindingIter<frontend::TaggedParserAtomIndex> & bi,const JSClass * cls,uint32_t numSlots,ObjectFlags objectFlags)152 Shape* js::CreateEnvironmentShape(
153     JSContext* cx, frontend::CompilationAtomCache& atomCache,
154     AbstractBindingIter<frontend::TaggedParserAtomIndex>& bi,
155     const JSClass* cls, uint32_t numSlots, ObjectFlags objectFlags) {
156   Rooted<SharedPropMap*> map(cx);
157   uint32_t mapLength = 0;
158 
159   RootedId id(cx);
160   for (; bi; bi++) {
161     BindingLocation loc = bi.location();
162     if (loc.kind() == BindingLocation::Kind::Environment) {
163       JSAtom* name = atomCache.getExistingAtomAt(cx, bi.name());
164       MOZ_ASSERT(name);
165       cx->markAtom(name);
166       id = NameToId(name->asPropertyName());
167       if (!AddToEnvironmentMap(cx, cls, id, bi.kind(), loc.slot(), &map,
168                                &mapLength, &objectFlags)) {
169         return nullptr;
170       }
171     }
172   }
173 
174   uint32_t numFixed = gc::GetGCKindSlots(gc::GetGCObjectKind(numSlots));
175   return SharedShape::getInitialOrPropMapShape(cx, cls, cx->realm(),
176                                                TaggedProto(nullptr), numFixed,
177                                                map, mapLength, objectFlags);
178 }
179 
180 template <class DataT>
SizeOfAllocatedData(DataT * data)181 inline size_t SizeOfAllocatedData(DataT* data) {
182   return SizeOfScopeData<DataT>(data->length);
183 }
184 
185 template <typename ConcreteScope>
CopyScopeData(JSContext * cx,typename ConcreteScope::RuntimeData * data)186 static UniquePtr<typename ConcreteScope::RuntimeData> CopyScopeData(
187     JSContext* cx, typename ConcreteScope::RuntimeData* data) {
188   using Data = typename ConcreteScope::RuntimeData;
189 
190   // Make sure the binding names are marked in the context's zone, if we are
191   // copying data from another zone.
192   auto names = GetScopeDataTrailingNames(data);
193   for (auto binding : names) {
194     if (JSAtom* name = binding.name()) {
195       cx->markAtom(name);
196     }
197   }
198 
199   size_t size = SizeOfAllocatedData(data);
200   void* bytes = cx->pod_malloc<char>(size);
201   if (!bytes) {
202     return nullptr;
203   }
204 
205   auto* dataCopy = new (bytes) Data(*data);
206 
207   std::uninitialized_copy_n(GetScopeDataTrailingNamesPointer(data),
208                             data->length,
209                             GetScopeDataTrailingNamesPointer(dataCopy));
210 
211   return UniquePtr<Data>(dataCopy);
212 }
213 
214 template <typename ConcreteScope>
MarkParserScopeData(JSContext * cx,typename ConcreteScope::ParserData * data,frontend::CompilationState & compilationState)215 static void MarkParserScopeData(JSContext* cx,
216                                 typename ConcreteScope::ParserData* data,
217                                 frontend::CompilationState& compilationState) {
218   auto names = GetScopeDataTrailingNames(data);
219   for (auto& binding : names) {
220     auto index = binding.name();
221     if (!index) {
222       continue;
223     }
224     compilationState.parserAtoms.markUsedByStencil(
225         index, frontend::ParserAtom::Atomize::Yes);
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 */
create(JSContext * cx,ScopeKind kind,HandleScope enclosing,HandleShape envShape)360 Scope* Scope::create(JSContext* cx, ScopeKind kind, HandleScope enclosing,
361                      HandleShape envShape) {
362   Scope* scope = Allocate<Scope>(cx);
363   if (scope) {
364     new (scope) Scope(kind, enclosing, envShape);
365   }
366   return scope;
367 }
368 
369 template <typename ConcreteScope>
370 /* static */
create(JSContext * cx,ScopeKind kind,HandleScope enclosing,HandleShape envShape,MutableHandle<UniquePtr<typename ConcreteScope::RuntimeData>> data)371 ConcreteScope* Scope::create(
372     JSContext* cx, ScopeKind kind, HandleScope enclosing, HandleShape envShape,
373     MutableHandle<UniquePtr<typename ConcreteScope::RuntimeData>> data) {
374   Scope* scope = create(cx, kind, enclosing, envShape);
375   if (!scope) {
376     return nullptr;
377   }
378 
379   // It is an invariant that all Scopes that have data (currently, all
380   // ScopeKinds except With) must have non-null data.
381   MOZ_ASSERT(data);
382   scope->initData<ConcreteScope>(data);
383 
384   return &scope->as<ConcreteScope>();
385 }
386 
387 template <typename ConcreteScope>
initData(MutableHandle<UniquePtr<typename ConcreteScope::RuntimeData>> data)388 inline void Scope::initData(
389     MutableHandle<UniquePtr<typename ConcreteScope::RuntimeData>> data) {
390   MOZ_ASSERT(!rawData());
391 
392   AddCellMemory(this, SizeOfAllocatedData(data.get().get()),
393                 MemoryUse::ScopeData);
394 
395   setHeaderPtr(data.get().release());
396 }
397 
398 template <typename EnvironmentT>
updateEnvShapeIfRequired(JSContext * cx,MutableHandleShape envShape,bool needsEnvironment)399 bool Scope::updateEnvShapeIfRequired(JSContext* cx, MutableHandleShape envShape,
400                                      bool needsEnvironment) {
401   if (!envShape && needsEnvironment) {
402     envShape.set(EmptyEnvironmentShape<EnvironmentT>(cx));
403     if (!envShape) {
404       return false;
405     }
406   }
407   return true;
408 }
409 
410 template <typename EnvironmentT>
updateEnvShapeIfRequired(JSContext * cx,mozilla::Maybe<uint32_t> * envShape,bool needsEnvironment)411 bool Scope::updateEnvShapeIfRequired(JSContext* cx,
412                                      mozilla::Maybe<uint32_t>* envShape,
413                                      bool needsEnvironment) {
414   if (envShape->isNothing() && needsEnvironment) {
415     uint32_t numSlots = 0;
416     envShape->emplace(numSlots);
417   }
418   return true;
419 }
420 
firstFrameSlot() const421 uint32_t Scope::firstFrameSlot() const {
422   switch (kind()) {
423     case ScopeKind::Lexical:
424     case ScopeKind::SimpleCatch:
425     case ScopeKind::Catch:
426     case ScopeKind::FunctionLexical:
427       // For intra-frame scopes, find the enclosing scope's next frame slot.
428       MOZ_ASSERT(is<LexicalScope>());
429       return LexicalScope::nextFrameSlot(enclosing());
430 
431     case ScopeKind::NamedLambda:
432     case ScopeKind::StrictNamedLambda:
433       // Named lambda scopes cannot have frame slots.
434       return LOCALNO_LIMIT;
435 
436     case ScopeKind::ClassBody:
437       MOZ_ASSERT(is<ClassBodyScope>());
438       return ClassBodyScope::nextFrameSlot(enclosing());
439 
440     case ScopeKind::FunctionBodyVar:
441       if (enclosing()->is<FunctionScope>()) {
442         return enclosing()->as<FunctionScope>().nextFrameSlot();
443       }
444       break;
445 
446     default:
447       break;
448   }
449   return 0;
450 }
451 
chainLength() const452 uint32_t Scope::chainLength() const {
453   uint32_t length = 0;
454   for (ScopeIter si(const_cast<Scope*>(this)); si; si++) {
455     length++;
456   }
457   return length;
458 }
459 
environmentChainLength() const460 uint32_t Scope::environmentChainLength() const {
461   uint32_t length = 0;
462   for (ScopeIter si(const_cast<Scope*>(this)); si; si++) {
463     if (si.hasSyntacticEnvironment()) {
464       length++;
465     }
466   }
467   return length;
468 }
469 
finalize(JSFreeOp * fop)470 void Scope::finalize(JSFreeOp* fop) {
471   MOZ_ASSERT(CurrentThreadIsGCFinalizing());
472   applyScopeDataTyped([this, fop](auto data) {
473     fop->delete_(this, data, SizeOfAllocatedData(data), MemoryUse::ScopeData);
474   });
475   setHeaderPtr(nullptr);
476 }
477 
sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const478 size_t Scope::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
479   if (rawData()) {
480     return mallocSizeOf(rawData());
481   }
482   return 0;
483 }
484 
dump()485 void Scope::dump() {
486   JSContext* cx = TlsContext.get();
487   if (!cx) {
488     fprintf(stderr, "*** can't get JSContext for current thread\n");
489     return;
490   }
491   for (Rooted<ScopeIter> si(cx, ScopeIter(this)); si; si++) {
492     fprintf(stderr, "- %s [%p]\n", ScopeKindString(si.kind()), si.scope());
493     DumpBindings(cx, si.scope());
494     fprintf(stderr, "\n");
495   }
496   fprintf(stderr, "\n");
497 }
498 
499 #if defined(DEBUG) || defined(JS_JITSPEW)
500 
501 /* static */
dumpForDisassemble(JSContext * cx,JS::Handle<Scope * > scope,GenericPrinter & out,const char * indent)502 bool Scope::dumpForDisassemble(JSContext* cx, JS::Handle<Scope*> scope,
503                                GenericPrinter& out, const char* indent) {
504   if (!out.put(ScopeKindString(scope->kind()))) {
505     return false;
506   }
507   if (!out.put(" {")) {
508     return false;
509   }
510 
511   size_t i = 0;
512   for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++, i++) {
513     if (i == 0) {
514       if (!out.put("\n")) {
515         return false;
516       }
517     }
518     UniqueChars bytes = AtomToPrintableString(cx, bi.name());
519     if (!bytes) {
520       return false;
521     }
522     if (!out.put(indent)) {
523       return false;
524     }
525     if (!out.printf("  %2zu: %s %s ", i, BindingKindString(bi.kind()),
526                     bytes.get())) {
527       return false;
528     }
529     switch (bi.location().kind()) {
530       case BindingLocation::Kind::Global:
531         if (bi.isTopLevelFunction()) {
532           if (!out.put("(global function)\n")) {
533             return false;
534           }
535         } else {
536           if (!out.put("(global)\n")) {
537             return false;
538           }
539         }
540         break;
541       case BindingLocation::Kind::Argument:
542         if (!out.printf("(arg slot %u)\n", bi.location().argumentSlot())) {
543           return false;
544         }
545         break;
546       case BindingLocation::Kind::Frame:
547         if (!out.printf("(frame slot %u)\n", bi.location().slot())) {
548           return false;
549         }
550         break;
551       case BindingLocation::Kind::Environment:
552         if (!out.printf("(env slot %u)\n", bi.location().slot())) {
553           return false;
554         }
555         break;
556       case BindingLocation::Kind::NamedLambdaCallee:
557         if (!out.put("(named lambda callee)\n")) {
558           return false;
559         }
560         break;
561       case BindingLocation::Kind::Import:
562         if (!out.put("(import)\n")) {
563           return false;
564         }
565         break;
566     }
567   }
568   if (i > 0) {
569     if (!out.put(indent)) {
570       return false;
571     }
572   }
573   if (!out.put("}")) {
574     return false;
575   }
576 
577   ScopeIter si(scope);
578   si++;
579   for (; si; si++) {
580     if (!out.put(" -> ")) {
581       return false;
582     }
583     if (!out.put(ScopeKindString(si.kind()))) {
584       return false;
585     }
586   }
587   return true;
588 }
589 
590 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
591 
NextFrameSlot(Scope * scope)592 static uint32_t NextFrameSlot(Scope* scope) {
593   for (ScopeIter si(scope); si; si++) {
594     switch (si.kind()) {
595       case ScopeKind::With:
596         continue;
597 
598       case ScopeKind::Function:
599         return si.scope()->as<FunctionScope>().nextFrameSlot();
600 
601       case ScopeKind::FunctionBodyVar:
602         return si.scope()->as<VarScope>().nextFrameSlot();
603 
604       case ScopeKind::Lexical:
605       case ScopeKind::SimpleCatch:
606       case ScopeKind::Catch:
607       case ScopeKind::FunctionLexical:
608         return si.scope()->as<LexicalScope>().nextFrameSlot();
609 
610       case ScopeKind::ClassBody:
611         return si.scope()->as<ClassBodyScope>().nextFrameSlot();
612 
613       case ScopeKind::NamedLambda:
614       case ScopeKind::StrictNamedLambda:
615         // Named lambda scopes cannot have frame slots.
616         return 0;
617 
618       case ScopeKind::Eval:
619       case ScopeKind::StrictEval:
620         return si.scope()->as<EvalScope>().nextFrameSlot();
621 
622       case ScopeKind::Global:
623       case ScopeKind::NonSyntactic:
624         return 0;
625 
626       case ScopeKind::Module:
627         return si.scope()->as<ModuleScope>().nextFrameSlot();
628 
629       case ScopeKind::WasmInstance:
630       case ScopeKind::WasmFunction:
631         // Invalid; MOZ_CRASH below.
632         break;
633     }
634   }
635   MOZ_CRASH("Not an enclosing intra-frame Scope");
636 }
637 
638 /* static */
nextFrameSlot(Scope * scope)639 uint32_t LexicalScope::nextFrameSlot(Scope* scope) {
640   return NextFrameSlot(scope);
641 }
642 
643 /* static */
nextFrameSlot(Scope * scope)644 uint32_t ClassBodyScope::nextFrameSlot(Scope* scope) {
645   return NextFrameSlot(scope);
646 }
647 
648 template <typename AtomT, typename ShapeT>
prepareForScopeCreation(JSContext * cx,ScopeKind kind,uint32_t firstFrameSlot,typename MaybeRootedScopeData<LexicalScope,AtomT>::MutableHandleType data,ShapeT envShape)649 bool LexicalScope::prepareForScopeCreation(
650     JSContext* cx, ScopeKind kind, uint32_t firstFrameSlot,
651     typename MaybeRootedScopeData<LexicalScope, AtomT>::MutableHandleType data,
652     ShapeT envShape) {
653   bool isNamedLambda =
654       kind == ScopeKind::NamedLambda || kind == ScopeKind::StrictNamedLambda;
655 
656   MOZ_ASSERT_IF(isNamedLambda, firstFrameSlot == LOCALNO_LIMIT);
657 
658   AbstractBindingIter<AtomT> bi(*data, firstFrameSlot, isNamedLambda);
659   if (!PrepareScopeData<LexicalScope, AtomT, BlockLexicalEnvironmentObject>(
660           cx, bi, data, firstFrameSlot, envShape)) {
661     return false;
662   }
663   return true;
664 }
665 
666 /* static */
createWithData(JSContext * cx,ScopeKind kind,MutableHandle<UniquePtr<RuntimeData>> data,uint32_t firstFrameSlot,HandleScope enclosing)667 LexicalScope* LexicalScope::createWithData(
668     JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<RuntimeData>> data,
669     uint32_t firstFrameSlot, HandleScope enclosing) {
670   RootedShape envShape(cx);
671 
672   if (!prepareForScopeCreation<JSAtom>(cx, kind, firstFrameSlot, data,
673                                        &envShape)) {
674     return nullptr;
675   }
676 
677   auto scope = Scope::create<LexicalScope>(cx, kind, enclosing, envShape, data);
678   if (!scope) {
679     return nullptr;
680   }
681 
682   MOZ_ASSERT(scope->firstFrameSlot() == firstFrameSlot);
683   return scope;
684 }
685 
686 /* static */
getEmptyExtensibleEnvironmentShape(JSContext * cx)687 Shape* LexicalScope::getEmptyExtensibleEnvironmentShape(JSContext* cx) {
688   const JSClass* cls = &LexicalEnvironmentObject::class_;
689   return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), ObjectFlags());
690 }
691 
692 template <typename AtomT, typename ShapeT>
prepareForScopeCreation(JSContext * cx,ScopeKind kind,uint32_t firstFrameSlot,typename MaybeRootedScopeData<ClassBodyScope,AtomT>::MutableHandleType data,ShapeT envShape)693 bool ClassBodyScope::prepareForScopeCreation(
694     JSContext* cx, ScopeKind kind, uint32_t firstFrameSlot,
695     typename MaybeRootedScopeData<ClassBodyScope, AtomT>::MutableHandleType
696         data,
697     ShapeT envShape) {
698   MOZ_ASSERT(kind == ScopeKind::ClassBody);
699 
700   AbstractBindingIter<AtomT> bi(*data, firstFrameSlot);
701   return PrepareScopeData<ClassBodyScope, AtomT, BlockLexicalEnvironmentObject>(
702       cx, bi, data, firstFrameSlot, envShape);
703 }
704 
705 /* static */
createWithData(JSContext * cx,ScopeKind kind,MutableHandle<UniquePtr<RuntimeData>> data,uint32_t firstFrameSlot,HandleScope enclosing)706 ClassBodyScope* ClassBodyScope::createWithData(
707     JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<RuntimeData>> data,
708     uint32_t firstFrameSlot, HandleScope enclosing) {
709   RootedShape envShape(cx);
710 
711   if (!prepareForScopeCreation<JSAtom>(cx, kind, firstFrameSlot, data,
712                                        &envShape)) {
713     return nullptr;
714   }
715 
716   auto* scope =
717       Scope::create<ClassBodyScope>(cx, kind, enclosing, envShape, data);
718   if (!scope) {
719     return nullptr;
720   }
721 
722   MOZ_ASSERT(scope->firstFrameSlot() == firstFrameSlot);
723   return scope;
724 }
725 
SetCanonicalFunction(FunctionScope::RuntimeData & data,HandleFunction fun)726 static void SetCanonicalFunction(FunctionScope::RuntimeData& data,
727                                  HandleFunction fun) {
728   data.canonicalFunction.init(fun);
729 }
730 
SetCanonicalFunction(FunctionScope::ParserData & data,HandleFunction fun)731 static void SetCanonicalFunction(FunctionScope::ParserData& data,
732                                  HandleFunction fun) {}
733 
734 template <typename AtomT, typename ShapeT>
prepareForScopeCreation(JSContext * cx,typename MaybeRootedScopeData<FunctionScope,AtomT>::MutableHandleType data,bool hasParameterExprs,bool needsEnvironment,HandleFunction fun,ShapeT envShape)735 bool FunctionScope::prepareForScopeCreation(
736     JSContext* cx,
737     typename MaybeRootedScopeData<FunctionScope, AtomT>::MutableHandleType data,
738     bool hasParameterExprs, bool needsEnvironment, HandleFunction fun,
739     ShapeT envShape) {
740   uint32_t firstFrameSlot = 0;
741   AbstractBindingIter<AtomT> bi(*data, hasParameterExprs);
742   if (!PrepareScopeData<FunctionScope, AtomT, CallObject>(
743           cx, bi, data, firstFrameSlot, envShape)) {
744     return false;
745   }
746 
747   if (hasParameterExprs) {
748     data->slotInfo.setHasParameterExprs();
749   }
750   SetCanonicalFunction(*data, fun);
751 
752   // An environment may be needed regardless of existence of any closed over
753   // bindings:
754   //   - Extensible scopes (i.e., due to direct eval)
755   //   - Needing a home object
756   //   - Being a derived class constructor
757   //   - Being a generator or async function
758   // Also see |FunctionBox::needsExtraBodyVarEnvironmentRegardlessOfBindings()|.
759   return updateEnvShapeIfRequired<CallObject>(cx, envShape, needsEnvironment);
760 }
761 
762 /* static */
createWithData(JSContext * cx,MutableHandle<UniquePtr<RuntimeData>> data,bool hasParameterExprs,bool needsEnvironment,HandleFunction fun,HandleScope enclosing)763 FunctionScope* FunctionScope::createWithData(
764     JSContext* cx, MutableHandle<UniquePtr<RuntimeData>> data,
765     bool hasParameterExprs, bool needsEnvironment, HandleFunction fun,
766     HandleScope enclosing) {
767   MOZ_ASSERT(data);
768   MOZ_ASSERT(fun->isTenured());
769 
770   RootedShape envShape(cx);
771 
772   if (!prepareForScopeCreation<JSAtom>(cx, data, hasParameterExprs,
773                                        needsEnvironment, fun, &envShape)) {
774     return nullptr;
775   }
776 
777   return Scope::create<FunctionScope>(cx, ScopeKind::Function, enclosing,
778                                       envShape, data);
779 }
780 
script() const781 JSScript* FunctionScope::script() const {
782   return canonicalFunction()->nonLazyScript();
783 }
784 
785 /* static */
isSpecialName(JSContext * cx,JSAtom * name)786 bool FunctionScope::isSpecialName(JSContext* cx, JSAtom* name) {
787   return name == cx->names().arguments || name == cx->names().dotThis ||
788          name == cx->names().dotGenerator;
789 }
790 
791 /* static */
isSpecialName(JSContext * cx,frontend::TaggedParserAtomIndex name)792 bool FunctionScope::isSpecialName(JSContext* cx,
793                                   frontend::TaggedParserAtomIndex name) {
794   return name == frontend::TaggedParserAtomIndex::WellKnown::arguments() ||
795          name == frontend::TaggedParserAtomIndex::WellKnown::dotThis() ||
796          name == frontend::TaggedParserAtomIndex::WellKnown::dotGenerator();
797 }
798 
799 template <typename AtomT, typename ShapeT>
prepareForScopeCreation(JSContext * cx,ScopeKind kind,typename MaybeRootedScopeData<VarScope,AtomT>::MutableHandleType data,uint32_t firstFrameSlot,bool needsEnvironment,ShapeT envShape)800 bool VarScope::prepareForScopeCreation(
801     JSContext* cx, ScopeKind kind,
802     typename MaybeRootedScopeData<VarScope, AtomT>::MutableHandleType data,
803     uint32_t firstFrameSlot, bool needsEnvironment, ShapeT envShape) {
804   AbstractBindingIter<AtomT> bi(*data, firstFrameSlot);
805   if (!PrepareScopeData<VarScope, AtomT, VarEnvironmentObject>(
806           cx, bi, data, firstFrameSlot, envShape)) {
807     return false;
808   }
809 
810   // An environment may be needed regardless of existence of any closed over
811   // bindings:
812   //   - Extensible scopes (i.e., due to direct eval)
813   //   - Being a generator
814   return updateEnvShapeIfRequired<VarEnvironmentObject>(cx, envShape,
815                                                         needsEnvironment);
816 }
817 
818 /* static */
createWithData(JSContext * cx,ScopeKind kind,MutableHandle<UniquePtr<RuntimeData>> data,uint32_t firstFrameSlot,bool needsEnvironment,HandleScope enclosing)819 VarScope* VarScope::createWithData(JSContext* cx, ScopeKind kind,
820                                    MutableHandle<UniquePtr<RuntimeData>> data,
821                                    uint32_t firstFrameSlot,
822                                    bool needsEnvironment,
823                                    HandleScope enclosing) {
824   MOZ_ASSERT(data);
825 
826   RootedShape envShape(cx);
827   if (!prepareForScopeCreation<JSAtom>(cx, kind, data, firstFrameSlot,
828                                        needsEnvironment, &envShape)) {
829     return nullptr;
830   }
831 
832   return Scope::create<VarScope>(cx, kind, enclosing, envShape, data);
833 }
834 
835 /* static */
create(JSContext * cx,ScopeKind kind,Handle<RuntimeData * > dataArg)836 GlobalScope* GlobalScope::create(JSContext* cx, ScopeKind kind,
837                                  Handle<RuntimeData*> dataArg) {
838   // The data that's passed in is from the frontend and is LifoAlloc'd.
839   // Copy it now that we're creating a permanent VM scope.
840   Rooted<UniquePtr<RuntimeData>> data(
841       cx, dataArg ? CopyScopeData<GlobalScope>(cx, dataArg)
842                   : NewEmptyScopeData<GlobalScope, JSAtom>(cx));
843   if (!data) {
844     return nullptr;
845   }
846 
847   return createWithData(cx, kind, &data);
848 }
849 
850 /* static */
createWithData(JSContext * cx,ScopeKind kind,MutableHandle<UniquePtr<RuntimeData>> data)851 GlobalScope* GlobalScope::createWithData(
852     JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<RuntimeData>> data) {
853   MOZ_ASSERT(data);
854 
855   // The global scope has no environment shape. Its environment is the
856   // global lexical scope and the global object or non-syntactic objects
857   // created by embedding, all of which are not only extensible but may
858   // have names on them deleted.
859   return Scope::create<GlobalScope>(cx, kind, nullptr, nullptr, data);
860 }
861 
862 /* static */
create(JSContext * cx,HandleScope enclosing)863 WithScope* WithScope::create(JSContext* cx, HandleScope enclosing) {
864   Scope* scope = Scope::create(cx, ScopeKind::With, enclosing, nullptr);
865   return static_cast<WithScope*>(scope);
866 }
867 
868 template <typename AtomT, typename ShapeT>
prepareForScopeCreation(JSContext * cx,ScopeKind scopeKind,typename MaybeRootedScopeData<EvalScope,AtomT>::MutableHandleType data,ShapeT envShape)869 bool EvalScope::prepareForScopeCreation(
870     JSContext* cx, ScopeKind scopeKind,
871     typename MaybeRootedScopeData<EvalScope, AtomT>::MutableHandleType data,
872     ShapeT envShape) {
873   if (scopeKind == ScopeKind::StrictEval) {
874     uint32_t firstFrameSlot = 0;
875     AbstractBindingIter<AtomT> bi(*data, true);
876     if (!PrepareScopeData<EvalScope, AtomT, VarEnvironmentObject>(
877             cx, bi, data, firstFrameSlot, envShape)) {
878       return false;
879     }
880   }
881 
882   return true;
883 }
884 
885 /* static */
createWithData(JSContext * cx,ScopeKind scopeKind,MutableHandle<UniquePtr<RuntimeData>> data,HandleScope enclosing)886 EvalScope* EvalScope::createWithData(JSContext* cx, ScopeKind scopeKind,
887                                      MutableHandle<UniquePtr<RuntimeData>> data,
888                                      HandleScope enclosing) {
889   MOZ_ASSERT(data);
890 
891   RootedShape envShape(cx);
892   if (!prepareForScopeCreation<JSAtom>(cx, scopeKind, data, &envShape)) {
893     return nullptr;
894   }
895 
896   return Scope::create<EvalScope>(cx, scopeKind, enclosing, envShape, data);
897 }
898 
899 /* static */
nearestVarScopeForDirectEval(Scope * scope)900 Scope* EvalScope::nearestVarScopeForDirectEval(Scope* scope) {
901   for (ScopeIter si(scope); si; si++) {
902     switch (si.kind()) {
903       case ScopeKind::Function:
904       case ScopeKind::FunctionBodyVar:
905       case ScopeKind::Global:
906       case ScopeKind::NonSyntactic:
907         return scope;
908       default:
909         break;
910     }
911   }
912   return nullptr;
913 }
914 
RuntimeData(size_t length)915 ModuleScope::RuntimeData::RuntimeData(size_t length) {
916   PoisonNames(this, length);
917 }
918 
InitModule(ModuleScope::RuntimeData & data,HandleModuleObject module)919 static void InitModule(ModuleScope::RuntimeData& data,
920                        HandleModuleObject module) {
921   data.module.init(module);
922 }
923 
InitModule(ModuleScope::ParserData & data,HandleModuleObject module)924 static void InitModule(ModuleScope::ParserData& data,
925                        HandleModuleObject module) {}
926 
927 /* static */
928 template <typename AtomT, typename ShapeT>
prepareForScopeCreation(JSContext * cx,typename MaybeRootedScopeData<ModuleScope,AtomT>::MutableHandleType data,HandleModuleObject module,ShapeT envShape)929 bool ModuleScope::prepareForScopeCreation(
930     JSContext* cx,
931     typename MaybeRootedScopeData<ModuleScope, AtomT>::MutableHandleType data,
932     HandleModuleObject module, ShapeT envShape) {
933   uint32_t firstFrameSlot = 0;
934   AbstractBindingIter<AtomT> bi(*data);
935   if (!PrepareScopeData<ModuleScope, AtomT, ModuleEnvironmentObject>(
936           cx, bi, data, firstFrameSlot, envShape)) {
937     return false;
938   }
939 
940   InitModule(*data, module);
941 
942   // Modules always need an environment object for now.
943   bool needsEnvironment = true;
944 
945   return updateEnvShapeIfRequired<ModuleEnvironmentObject>(cx, envShape,
946                                                            needsEnvironment);
947 }
948 
949 /* static */
createWithData(JSContext * cx,MutableHandle<UniquePtr<RuntimeData>> data,HandleModuleObject module,HandleScope enclosing)950 ModuleScope* ModuleScope::createWithData(
951     JSContext* cx, MutableHandle<UniquePtr<RuntimeData>> data,
952     HandleModuleObject module, HandleScope enclosing) {
953   MOZ_ASSERT(data);
954   MOZ_ASSERT(enclosing->is<GlobalScope>());
955 
956   RootedShape envShape(cx);
957   if (!prepareForScopeCreation<JSAtom>(cx, data, module, &envShape)) {
958     return nullptr;
959   }
960 
961   return Scope::create<ModuleScope>(cx, ScopeKind::Module, enclosing, envShape,
962                                     data);
963 }
964 
965 template <size_t ArrayLength>
GenerateWasmName(JSContext * cx,const char (& prefix)[ArrayLength],uint32_t index)966 static JSAtom* GenerateWasmName(JSContext* cx,
967                                 const char (&prefix)[ArrayLength],
968                                 uint32_t index) {
969   StringBuffer sb(cx);
970   if (!sb.append(prefix)) {
971     return nullptr;
972   }
973   if (!NumberValueToStringBuffer(cx, Int32Value(index), sb)) {
974     return nullptr;
975   }
976 
977   return sb.finishAtom();
978 }
979 
InitializeTrailingName(AbstractBindingName<JSAtom> * trailingNames,size_t i,JSAtom * name)980 static void InitializeTrailingName(AbstractBindingName<JSAtom>* trailingNames,
981                                    size_t i, JSAtom* name) {
982   void* trailingName = &trailingNames[i];
983   new (trailingName) BindingName(name, false);
984 }
985 
986 template <class DataT>
InitializeNextTrailingName(const Rooted<UniquePtr<DataT>> & data,JSAtom * name)987 static void InitializeNextTrailingName(const Rooted<UniquePtr<DataT>>& data,
988                                        JSAtom* name) {
989   InitializeTrailingName(GetScopeDataTrailingNamesPointer(data.get().get()),
990                          data->length, name);
991   data->length++;
992 }
993 
RuntimeData(size_t length)994 WasmInstanceScope::RuntimeData::RuntimeData(size_t length) {
995   PoisonNames(this, length);
996 }
997 
998 /* static */
create(JSContext * cx,WasmInstanceObject * instance)999 WasmInstanceScope* WasmInstanceScope::create(JSContext* cx,
1000                                              WasmInstanceObject* instance) {
1001   size_t namesCount = 0;
1002   if (instance->instance().memory()) {
1003     namesCount++;
1004   }
1005   size_t globalsStart = namesCount;
1006   size_t globalsCount = instance->instance().metadata().globals.length();
1007   namesCount += globalsCount;
1008 
1009   Rooted<UniquePtr<RuntimeData>> data(
1010       cx, NewEmptyScopeData<WasmInstanceScope, JSAtom>(cx, namesCount));
1011   if (!data) {
1012     return nullptr;
1013   }
1014 
1015   if (instance->instance().memory()) {
1016     JSAtom* wasmName = GenerateWasmName(cx, "memory", /* index = */ 0);
1017     if (!wasmName) {
1018       return nullptr;
1019     }
1020 
1021     InitializeNextTrailingName(data, wasmName);
1022   }
1023 
1024   for (size_t i = 0; i < globalsCount; i++) {
1025     JSAtom* wasmName = GenerateWasmName(cx, "global", i);
1026     if (!wasmName) {
1027       return nullptr;
1028     }
1029 
1030     InitializeNextTrailingName(data, wasmName);
1031   }
1032 
1033   MOZ_ASSERT(data->length == namesCount);
1034 
1035   data->instance.init(instance);
1036   data->slotInfo.globalsStart = globalsStart;
1037 
1038   RootedScope enclosing(cx, &cx->global()->emptyGlobalScope());
1039   return Scope::create<WasmInstanceScope>(cx, ScopeKind::WasmInstance,
1040                                           enclosing,
1041                                           /* envShape = */ nullptr, &data);
1042 }
1043 
1044 /* static */
create(JSContext * cx,HandleScope enclosing,uint32_t funcIndex)1045 WasmFunctionScope* WasmFunctionScope::create(JSContext* cx,
1046                                              HandleScope enclosing,
1047                                              uint32_t funcIndex) {
1048   MOZ_ASSERT(enclosing->is<WasmInstanceScope>());
1049 
1050   Rooted<WasmFunctionScope*> wasmFunctionScope(cx);
1051 
1052   Rooted<WasmInstanceObject*> instance(
1053       cx, enclosing->as<WasmInstanceScope>().instance());
1054 
1055   // TODO pull the local variable names from the wasm function definition.
1056   wasm::ValTypeVector locals;
1057   size_t argsLength;
1058   wasm::StackResults unusedStackResults;
1059   if (!instance->instance().debug().debugGetLocalTypes(
1060           funcIndex, &locals, &argsLength, &unusedStackResults)) {
1061     return nullptr;
1062   }
1063   uint32_t namesCount = locals.length();
1064 
1065   Rooted<UniquePtr<RuntimeData>> data(
1066       cx, NewEmptyScopeData<WasmFunctionScope, JSAtom>(cx, namesCount));
1067   if (!data) {
1068     return nullptr;
1069   }
1070 
1071   for (size_t i = 0; i < namesCount; i++) {
1072     JSAtom* wasmName = GenerateWasmName(cx, "var", i);
1073     if (!wasmName) {
1074       return nullptr;
1075     }
1076 
1077     InitializeNextTrailingName(data, wasmName);
1078   }
1079   MOZ_ASSERT(data->length == namesCount);
1080 
1081   return Scope::create<WasmFunctionScope>(cx, ScopeKind::WasmFunction,
1082                                           enclosing,
1083                                           /* envShape = */ nullptr, &data);
1084 }
1085 
ScopeIter(JSScript * script)1086 ScopeIter::ScopeIter(JSScript* script) : scope_(script->bodyScope()) {}
1087 
hasSyntacticEnvironment() const1088 bool ScopeIter::hasSyntacticEnvironment() const {
1089   return scope()->hasEnvironment() &&
1090          scope()->kind() != ScopeKind::NonSyntactic;
1091 }
1092 
AbstractBindingIter(ScopeKind kind,BaseScopeData * data,uint32_t firstFrameSlot)1093 AbstractBindingIter<JSAtom>::AbstractBindingIter(ScopeKind kind,
1094                                                  BaseScopeData* data,
1095                                                  uint32_t firstFrameSlot)
1096     : BaseAbstractBindingIter<JSAtom>() {
1097   switch (kind) {
1098     case ScopeKind::Lexical:
1099     case ScopeKind::SimpleCatch:
1100     case ScopeKind::Catch:
1101     case ScopeKind::FunctionLexical:
1102       init(*static_cast<LexicalScope::RuntimeData*>(data), firstFrameSlot, 0);
1103       break;
1104     case ScopeKind::NamedLambda:
1105     case ScopeKind::StrictNamedLambda:
1106       init(*static_cast<LexicalScope::RuntimeData*>(data), LOCALNO_LIMIT,
1107            IsNamedLambda);
1108       break;
1109     case ScopeKind::ClassBody:
1110       init(*static_cast<ClassBodyScope::RuntimeData*>(data), firstFrameSlot);
1111       break;
1112     case ScopeKind::With:
1113       // With scopes do not have bindings.
1114       index_ = length_ = 0;
1115       MOZ_ASSERT(done());
1116       break;
1117     case ScopeKind::Function: {
1118       uint8_t flags = IgnoreDestructuredFormalParameters;
1119       if (static_cast<FunctionScope::RuntimeData*>(data)
1120               ->slotInfo.hasParameterExprs()) {
1121         flags |= HasFormalParameterExprs;
1122       }
1123       init(*static_cast<FunctionScope::RuntimeData*>(data), flags);
1124       break;
1125     }
1126     case ScopeKind::FunctionBodyVar:
1127       init(*static_cast<VarScope::RuntimeData*>(data), firstFrameSlot);
1128       break;
1129     case ScopeKind::Eval:
1130     case ScopeKind::StrictEval:
1131       init(*static_cast<EvalScope::RuntimeData*>(data),
1132            kind == ScopeKind::StrictEval);
1133       break;
1134     case ScopeKind::Global:
1135     case ScopeKind::NonSyntactic:
1136       init(*static_cast<GlobalScope::RuntimeData*>(data));
1137       break;
1138     case ScopeKind::Module:
1139       init(*static_cast<ModuleScope::RuntimeData*>(data));
1140       break;
1141     case ScopeKind::WasmInstance:
1142       init(*static_cast<WasmInstanceScope::RuntimeData*>(data));
1143       break;
1144     case ScopeKind::WasmFunction:
1145       init(*static_cast<WasmFunctionScope::RuntimeData*>(data));
1146       break;
1147   }
1148 }
1149 
AbstractBindingIter(Scope * scope)1150 AbstractBindingIter<JSAtom>::AbstractBindingIter(Scope* scope)
1151     : AbstractBindingIter<JSAtom>(scope->kind(), scope->rawData(),
1152                                   scope->firstFrameSlot()) {}
1153 
AbstractBindingIter(JSScript * script)1154 AbstractBindingIter<JSAtom>::AbstractBindingIter(JSScript* script)
1155     : AbstractBindingIter<JSAtom>(script->bodyScope()) {}
1156 
AbstractBindingIter(const frontend::ScopeStencilRef & ref)1157 AbstractBindingIter<frontend::TaggedParserAtomIndex>::AbstractBindingIter(
1158     const frontend::ScopeStencilRef& ref)
1159     : Base() {
1160   const ScopeStencil& scope = ref.scope();
1161   BaseParserScopeData* data = ref.context_.scopeNames[ref.scopeIndex_];
1162   switch (scope.kind()) {
1163     case ScopeKind::Lexical:
1164     case ScopeKind::SimpleCatch:
1165     case ScopeKind::Catch:
1166     case ScopeKind::FunctionLexical:
1167       init(*static_cast<LexicalScope::ParserData*>(data),
1168            scope.firstFrameSlot(), 0);
1169       break;
1170     case ScopeKind::NamedLambda:
1171     case ScopeKind::StrictNamedLambda:
1172       init(*static_cast<LexicalScope::ParserData*>(data), LOCALNO_LIMIT,
1173            IsNamedLambda);
1174       break;
1175     case ScopeKind::ClassBody:
1176       init(*static_cast<ClassBodyScope::ParserData*>(data),
1177            scope.firstFrameSlot());
1178       break;
1179     case ScopeKind::With:
1180       // With scopes do not have bindings.
1181       index_ = length_ = 0;
1182       MOZ_ASSERT(done());
1183       break;
1184     case ScopeKind::Function: {
1185       uint8_t flags = IgnoreDestructuredFormalParameters;
1186       if (static_cast<FunctionScope::ParserData*>(data)
1187               ->slotInfo.hasParameterExprs()) {
1188         flags |= HasFormalParameterExprs;
1189       }
1190       init(*static_cast<FunctionScope::ParserData*>(data), flags);
1191       break;
1192     }
1193     case ScopeKind::FunctionBodyVar:
1194       init(*static_cast<VarScope::ParserData*>(data), scope.firstFrameSlot());
1195       break;
1196     case ScopeKind::Eval:
1197     case ScopeKind::StrictEval:
1198       init(*static_cast<EvalScope::ParserData*>(data),
1199            scope.kind() == ScopeKind::StrictEval);
1200       break;
1201     case ScopeKind::Global:
1202     case ScopeKind::NonSyntactic:
1203       init(*static_cast<GlobalScope::ParserData*>(data));
1204       break;
1205     case ScopeKind::Module:
1206       init(*static_cast<ModuleScope::ParserData*>(data));
1207       break;
1208     case ScopeKind::WasmInstance:
1209       init(*static_cast<WasmInstanceScope::ParserData*>(data));
1210       break;
1211     case ScopeKind::WasmFunction:
1212       init(*static_cast<WasmFunctionScope::ParserData*>(data));
1213       break;
1214   }
1215 }
1216 
1217 template <typename NameT>
init(LexicalScope::AbstractData<NameT> & data,uint32_t firstFrameSlot,uint8_t flags)1218 void BaseAbstractBindingIter<NameT>::init(
1219     LexicalScope::AbstractData<NameT>& data, uint32_t firstFrameSlot,
1220     uint8_t flags) {
1221   auto& slotInfo = data.slotInfo;
1222 
1223   // Named lambda scopes can only have environment slots. If the callee
1224   // isn't closed over, it is accessed via JSOp::Callee.
1225   if (flags & IsNamedLambda) {
1226     // Named lambda binding is weird. Normal BindingKind ordering rules
1227     // don't apply.
1228     init(/* positionalFormalStart= */ 0,
1229          /* nonPositionalFormalStart= */ 0,
1230          /* varStart= */ 0,
1231          /* letStart= */ 0,
1232          /* constStart= */ 0,
1233          /* syntheticStart= */ data.length,
1234          /* privageMethodStart= */ data.length,
1235          /* flags= */ CanHaveEnvironmentSlots | flags,
1236          /* firstFrameSlot= */ firstFrameSlot,
1237          /* firstEnvironmentSlot= */
1238          JSSLOT_FREE(&LexicalEnvironmentObject::class_),
1239          /* names= */ GetScopeDataTrailingNames(&data));
1240   } else {
1241     //            imports - [0, 0)
1242     // positional formals - [0, 0)
1243     //      other formals - [0, 0)
1244     //               vars - [0, 0)
1245     //               lets - [0, slotInfo.constStart)
1246     //             consts - [slotInfo.constStart, data.length)
1247     //          synthetic - [data.length, data.length)
1248     //    private methods - [data.length, data.length)
1249     init(/* positionalFormalStart= */ 0,
1250          /* nonPositionalFormalStart= */ 0,
1251          /* varStart= */ 0,
1252          /* letStart= */ 0,
1253          /* constStart= */ slotInfo.constStart,
1254          /* syntheticStart= */ data.length,
1255          /* privateMethodStart= */ data.length,
1256          /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots | flags,
1257          /* firstFrameSlot= */ firstFrameSlot,
1258          /* firstEnvironmentSlot= */
1259          JSSLOT_FREE(&LexicalEnvironmentObject::class_),
1260          /* names= */ GetScopeDataTrailingNames(&data));
1261   }
1262 }
1263 
1264 template void BaseAbstractBindingIter<JSAtom>::init(
1265     LexicalScope::AbstractData<JSAtom>&, uint32_t, uint8_t);
1266 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1267     LexicalScope::AbstractData<frontend::TaggedParserAtomIndex>&, uint32_t,
1268     uint8_t);
1269 
1270 template <typename NameT>
init(ClassBodyScope::AbstractData<NameT> & data,uint32_t firstFrameSlot)1271 void BaseAbstractBindingIter<NameT>::init(
1272     ClassBodyScope::AbstractData<NameT>& data, uint32_t firstFrameSlot) {
1273   auto& slotInfo = data.slotInfo;
1274 
1275   //            imports - [0, 0)
1276   // positional formals - [0, 0)
1277   //      other formals - [0, 0)
1278   //               vars - [0, 0)
1279   //               lets - [0, 0)
1280   //             consts - [0, 0)
1281   //          synthetic - [0, slotInfo.privateMethodStart)
1282   //    private methods - [slotInfo.privateMethodStart, data.length)
1283   init(/* positionalFormalStart= */ 0,
1284        /* nonPositionalFormalStart= */ 0,
1285        /* varStart= */ 0,
1286        /* letStart= */ 0,
1287        /* constStart= */ 0,
1288        /* syntheticStart= */ 0,
1289        /* privateMethodStart= */ slotInfo.privateMethodStart,
1290        /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots,
1291        /* firstFrameSlot= */ firstFrameSlot,
1292        /* firstEnvironmentSlot= */
1293        JSSLOT_FREE(&ClassBodyLexicalEnvironmentObject::class_),
1294        /* names= */ GetScopeDataTrailingNames(&data));
1295 }
1296 
1297 template void BaseAbstractBindingIter<JSAtom>::init(
1298     ClassBodyScope::AbstractData<JSAtom>&, uint32_t);
1299 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1300     ClassBodyScope::AbstractData<frontend::TaggedParserAtomIndex>&, uint32_t);
1301 
1302 template <typename NameT>
init(FunctionScope::AbstractData<NameT> & data,uint8_t flags)1303 void BaseAbstractBindingIter<NameT>::init(
1304     FunctionScope::AbstractData<NameT>& data, uint8_t flags) {
1305   flags = CanHaveFrameSlots | CanHaveEnvironmentSlots | flags;
1306   if (!(flags & HasFormalParameterExprs)) {
1307     flags |= CanHaveArgumentSlots;
1308   }
1309 
1310   auto length = data.length;
1311   auto& slotInfo = data.slotInfo;
1312 
1313   //            imports - [0, 0)
1314   // positional formals - [0, slotInfo.nonPositionalFormalStart)
1315   //      other formals - [slotInfo.nonPositionalParamStart, slotInfo.varStart)
1316   //               vars - [slotInfo.varStart, length)
1317   //               lets - [length, length)
1318   //             consts - [length, length)
1319   //          synthetic - [length, length)
1320   //    private methods - [length, length)
1321   init(/* positionalFormalStart= */ 0,
1322        /* nonPositionalFormalStart= */ slotInfo.nonPositionalFormalStart,
1323        /* varStart= */ slotInfo.varStart,
1324        /* letStart= */ length,
1325        /* constStart= */ length,
1326        /* syntheticStart= */ length,
1327        /* privateMethodStart= */ length,
1328        /* flags= */ flags,
1329        /* firstFrameSlot= */ 0,
1330        /* firstEnvironmentSlot= */ JSSLOT_FREE(&CallObject::class_),
1331        /* names= */ GetScopeDataTrailingNames(&data));
1332 }
1333 template void BaseAbstractBindingIter<JSAtom>::init(
1334     FunctionScope::AbstractData<JSAtom>&, uint8_t);
1335 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1336     FunctionScope::AbstractData<frontend::TaggedParserAtomIndex>&, uint8_t);
1337 
1338 template <typename NameT>
init(VarScope::AbstractData<NameT> & data,uint32_t firstFrameSlot)1339 void BaseAbstractBindingIter<NameT>::init(VarScope::AbstractData<NameT>& data,
1340                                           uint32_t firstFrameSlot) {
1341   auto length = data.length;
1342 
1343   //            imports - [0, 0)
1344   // positional formals - [0, 0)
1345   //      other formals - [0, 0)
1346   //               vars - [0, length)
1347   //               lets - [length, length)
1348   //             consts - [length, length)
1349   //          synthetic - [length, length)
1350   //    private methods - [length, length)
1351   init(/* positionalFormalStart= */ 0,
1352        /* nonPositionalFormalStart= */ 0,
1353        /* varStart= */ 0,
1354        /* letStart= */ length,
1355        /* constStart= */ length,
1356        /* syntheticStart= */ length,
1357        /* privateMethodStart= */ length,
1358        /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots,
1359        /* firstFrameSlot= */ firstFrameSlot,
1360        /* firstEnvironmentSlot= */ JSSLOT_FREE(&VarEnvironmentObject::class_),
1361        /* names= */ GetScopeDataTrailingNames(&data));
1362 }
1363 template void BaseAbstractBindingIter<JSAtom>::init(
1364     VarScope::AbstractData<JSAtom>&, uint32_t);
1365 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1366     VarScope::AbstractData<frontend::TaggedParserAtomIndex>&, uint32_t);
1367 
1368 template <typename NameT>
init(GlobalScope::AbstractData<NameT> & data)1369 void BaseAbstractBindingIter<NameT>::init(
1370     GlobalScope::AbstractData<NameT>& data) {
1371   auto& slotInfo = data.slotInfo;
1372 
1373   //            imports - [0, 0)
1374   // positional formals - [0, 0)
1375   //      other formals - [0, 0)
1376   //               vars - [0, slotInfo.letStart)
1377   //               lets - [slotInfo.letStart, slotInfo.constStart)
1378   //             consts - [slotInfo.constStart, data.length)
1379   //          synthetic - [data.length, data.length)
1380   //    private methods - [data.length, data.length)
1381   init(/* positionalFormalStart= */ 0,
1382        /* nonPositionalFormalStart= */ 0,
1383        /* varStart= */ 0,
1384        /* letStart= */ slotInfo.letStart,
1385        /* constStart= */ slotInfo.constStart,
1386        /* syntheticStart= */ data.length,
1387        /* privateMethoodStart= */ data.length,
1388        /* flags= */ CannotHaveSlots,
1389        /* firstFrameSlot= */ UINT32_MAX,
1390        /* firstEnvironmentSlot= */ UINT32_MAX,
1391        /* names= */ GetScopeDataTrailingNames(&data));
1392 }
1393 template void BaseAbstractBindingIter<JSAtom>::init(
1394     GlobalScope::AbstractData<JSAtom>&);
1395 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1396     GlobalScope::AbstractData<frontend::TaggedParserAtomIndex>&);
1397 
1398 template <typename NameT>
init(EvalScope::AbstractData<NameT> & data,bool strict)1399 void BaseAbstractBindingIter<NameT>::init(EvalScope::AbstractData<NameT>& data,
1400                                           bool strict) {
1401   uint32_t flags;
1402   uint32_t firstFrameSlot;
1403   uint32_t firstEnvironmentSlot;
1404   if (strict) {
1405     flags = CanHaveFrameSlots | CanHaveEnvironmentSlots;
1406     firstFrameSlot = 0;
1407     firstEnvironmentSlot = JSSLOT_FREE(&VarEnvironmentObject::class_);
1408   } else {
1409     flags = CannotHaveSlots;
1410     firstFrameSlot = UINT32_MAX;
1411     firstEnvironmentSlot = UINT32_MAX;
1412   }
1413 
1414   auto length = data.length;
1415 
1416   //            imports - [0, 0)
1417   // positional formals - [0, 0)
1418   //      other formals - [0, 0)
1419   //               vars - [0, length)
1420   //               lets - [length, length)
1421   //             consts - [length, length)
1422   //          synthetic - [length, length)
1423   //    private methods - [length, length)
1424   init(/* positionalFormalStart= */ 0,
1425        /* nonPositionalFormalStart= */ 0,
1426        /* varStart= */ 0,
1427        /* letStart= */ length,
1428        /* constStart= */ length,
1429        /* syntheticStart= */ length,
1430        /* privateMethodStart= */ length,
1431        /* flags= */ flags,
1432        /* firstFrameSlot= */ firstFrameSlot,
1433        /* firstEnvironmentSlot= */ firstEnvironmentSlot,
1434        /* names= */ GetScopeDataTrailingNames(&data));
1435 }
1436 template void BaseAbstractBindingIter<JSAtom>::init(
1437     EvalScope::AbstractData<JSAtom>&, bool);
1438 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1439     EvalScope::AbstractData<frontend::TaggedParserAtomIndex>&, bool);
1440 
1441 template <typename NameT>
init(ModuleScope::AbstractData<NameT> & data)1442 void BaseAbstractBindingIter<NameT>::init(
1443     ModuleScope::AbstractData<NameT>& data) {
1444   auto& slotInfo = data.slotInfo;
1445 
1446   //            imports - [0, slotInfo.varStart)
1447   // positional formals - [slotInfo.varStart, slotInfo.varStart)
1448   //      other formals - [slotInfo.varStart, slotInfo.varStart)
1449   //               vars - [slotInfo.varStart, slotInfo.letStart)
1450   //               lets - [slotInfo.letStart, slotInfo.constStart)
1451   //             consts - [slotInfo.constStart, data.length)
1452   //          synthetic - [data.length, data.length)
1453   //    private methods - [data.length, data.length)
1454   init(
1455       /* positionalFormalStart= */ slotInfo.varStart,
1456       /* nonPositionalFormalStart= */ slotInfo.varStart,
1457       /* varStart= */ slotInfo.varStart,
1458       /* letStart= */ slotInfo.letStart,
1459       /* constStart= */ slotInfo.constStart,
1460       /* syntheticStart= */ data.length,
1461       /* privateMethodStart= */ data.length,
1462       /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots,
1463       /* firstFrameSlot= */ 0,
1464       /* firstEnvironmentSlot= */ JSSLOT_FREE(&ModuleEnvironmentObject::class_),
1465       /* names= */ GetScopeDataTrailingNames(&data));
1466 }
1467 template void BaseAbstractBindingIter<JSAtom>::init(
1468     ModuleScope::AbstractData<JSAtom>&);
1469 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1470     ModuleScope::AbstractData<frontend::TaggedParserAtomIndex>&);
1471 
1472 template <typename NameT>
init(WasmInstanceScope::AbstractData<NameT> & data)1473 void BaseAbstractBindingIter<NameT>::init(
1474     WasmInstanceScope::AbstractData<NameT>& data) {
1475   auto length = data.length;
1476 
1477   //            imports - [0, 0)
1478   // positional formals - [0, 0)
1479   //      other formals - [0, 0)
1480   //               vars - [0, length)
1481   //               lets - [length, length)
1482   //             consts - [length, length)
1483   //          synthetic - [length, length)
1484   //    private methods - [length, length)
1485   init(/* positionalFormalStart= */ 0,
1486        /* nonPositionalFormalStart= */ 0,
1487        /* varStart= */ 0,
1488        /* letStart= */ length,
1489        /* constStart= */ length,
1490        /* syntheticStart= */ length,
1491        /* privateMethodStart= */ length,
1492        /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots,
1493        /* firstFrameSlot= */ UINT32_MAX,
1494        /* firstEnvironmentSlot= */ UINT32_MAX,
1495        /* names= */ GetScopeDataTrailingNames(&data));
1496 }
1497 template void BaseAbstractBindingIter<JSAtom>::init(
1498     WasmInstanceScope::AbstractData<JSAtom>&);
1499 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1500     WasmInstanceScope::AbstractData<frontend::TaggedParserAtomIndex>&);
1501 
1502 template <typename NameT>
init(WasmFunctionScope::AbstractData<NameT> & data)1503 void BaseAbstractBindingIter<NameT>::init(
1504     WasmFunctionScope::AbstractData<NameT>& data) {
1505   auto length = data.length;
1506 
1507   //            imports - [0, 0)
1508   // positional formals - [0, 0)
1509   //      other formals - [0, 0)
1510   //               vars - [0, length)
1511   //               lets - [length, length)
1512   //             consts - [length, length)
1513   //          synthetic - [length, length)
1514   //    private methods - [length, length)
1515   init(/* positionalFormalStart = */ 0,
1516        /* nonPositionalFormalStart = */ 0,
1517        /* varStart= */ 0,
1518        /* letStart= */ length,
1519        /* constStart= */ length,
1520        /* syntheticStart= */ length,
1521        /* privateMethodStart= */ length,
1522        /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots,
1523        /* firstFrameSlot= */ UINT32_MAX,
1524        /* firstEnvironmentSlot= */ UINT32_MAX,
1525        /* names= */ GetScopeDataTrailingNames(&data));
1526 }
1527 template void BaseAbstractBindingIter<JSAtom>::init(
1528     WasmFunctionScope::AbstractData<JSAtom>&);
1529 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init(
1530     WasmFunctionScope::AbstractData<frontend::TaggedParserAtomIndex>&);
1531 
PositionalFormalParameterIter(Scope * scope)1532 PositionalFormalParameterIter::PositionalFormalParameterIter(Scope* scope)
1533     : BindingIter(scope) {
1534   // Reinit with flags = 0, i.e., iterate over all positional parameters.
1535   if (scope->is<FunctionScope>()) {
1536     init(scope->as<FunctionScope>().data(), /* flags = */ 0);
1537   }
1538   settle();
1539 }
1540 
PositionalFormalParameterIter(JSScript * script)1541 PositionalFormalParameterIter::PositionalFormalParameterIter(JSScript* script)
1542     : PositionalFormalParameterIter(script->bodyScope()) {}
1543 
DumpBindings(JSContext * cx,Scope * scopeArg)1544 void js::DumpBindings(JSContext* cx, Scope* scopeArg) {
1545   RootedScope scope(cx, scopeArg);
1546   for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
1547     UniqueChars bytes = AtomToPrintableString(cx, bi.name());
1548     if (!bytes) {
1549       MaybePrintAndClearPendingException(cx);
1550       return;
1551     }
1552     fprintf(stderr, "    %s %s ", BindingKindString(bi.kind()), bytes.get());
1553     switch (bi.location().kind()) {
1554       case BindingLocation::Kind::Global:
1555         if (bi.isTopLevelFunction()) {
1556           fprintf(stderr, "global function\n");
1557         } else {
1558           fprintf(stderr, "global\n");
1559         }
1560         break;
1561       case BindingLocation::Kind::Argument:
1562         fprintf(stderr, "arg slot %u\n", bi.location().argumentSlot());
1563         break;
1564       case BindingLocation::Kind::Frame:
1565         fprintf(stderr, "frame slot %u\n", bi.location().slot());
1566         break;
1567       case BindingLocation::Kind::Environment:
1568         fprintf(stderr, "env slot %u\n", bi.location().slot());
1569         break;
1570       case BindingLocation::Kind::NamedLambdaCallee:
1571         fprintf(stderr, "named lambda callee\n");
1572         break;
1573       case BindingLocation::Kind::Import:
1574         fprintf(stderr, "import\n");
1575         break;
1576     }
1577   }
1578 }
1579 
GetFrameSlotNameInScope(Scope * scope,uint32_t slot)1580 static JSAtom* GetFrameSlotNameInScope(Scope* scope, uint32_t slot) {
1581   for (BindingIter bi(scope); bi; bi++) {
1582     BindingLocation loc = bi.location();
1583     if (loc.kind() == BindingLocation::Kind::Frame && loc.slot() == slot) {
1584       return bi.name();
1585     }
1586   }
1587   return nullptr;
1588 }
1589 
FrameSlotName(JSScript * script,jsbytecode * pc)1590 JSAtom* js::FrameSlotName(JSScript* script, jsbytecode* pc) {
1591   MOZ_ASSERT(IsLocalOp(JSOp(*pc)));
1592   uint32_t slot = GET_LOCALNO(pc);
1593   MOZ_ASSERT(slot < script->nfixed());
1594 
1595   // Look for it in the body scope first.
1596   if (JSAtom* name = GetFrameSlotNameInScope(script->bodyScope(), slot)) {
1597     return name;
1598   }
1599 
1600   // If this is a function script and there is an extra var scope, look for
1601   // it there.
1602   if (script->functionHasExtraBodyVarScope()) {
1603     if (JSAtom* name = GetFrameSlotNameInScope(
1604             script->functionExtraBodyVarScope(), slot)) {
1605       return name;
1606     }
1607   }
1608   // If not found, look for it in a lexical scope.
1609   for (ScopeIter si(script->innermostScope(pc)); si; si++) {
1610     if (!si.scope()->is<LexicalScope>() && !si.scope()->is<ClassBodyScope>()) {
1611       continue;
1612     }
1613 
1614     // Is the slot within bounds of the current lexical scope?
1615     if (slot < si.scope()->firstFrameSlot()) {
1616       continue;
1617     }
1618     if (slot >= LexicalScope::nextFrameSlot(si.scope())) {
1619       break;
1620     }
1621 
1622     // If so, get the name.
1623     if (JSAtom* name = GetFrameSlotNameInScope(si.scope(), slot)) {
1624       return name;
1625     }
1626   }
1627 
1628   MOZ_CRASH("Frame slot not found");
1629 }
1630 
size(mozilla::MallocSizeOf mallocSizeOf) const1631 JS::ubi::Node::Size JS::ubi::Concrete<Scope>::size(
1632     mozilla::MallocSizeOf mallocSizeOf) const {
1633   return js::gc::Arena::thingSize(get().asTenured().getAllocKind()) +
1634          get().sizeOfExcludingThis(mallocSizeOf);
1635 }
1636 
1637 template <typename... Args>
appendScopeStencilAndData(JSContext * cx,CompilationState & compilationState,BaseParserScopeData * data,ScopeIndex * indexOut,Args &&...args)1638 /* static */ bool ScopeStencil::appendScopeStencilAndData(
1639     JSContext* cx, CompilationState& compilationState,
1640     BaseParserScopeData* data, ScopeIndex* indexOut, Args&&... args) {
1641   *indexOut = ScopeIndex(compilationState.scopeData.length());
1642   if (uint32_t(*indexOut) >= TaggedScriptThingIndex::IndexLimit) {
1643     ReportAllocationOverflow(cx);
1644     return false;
1645   }
1646 
1647   if (!compilationState.scopeData.emplaceBack(std::forward<Args>(args)...)) {
1648     js::ReportOutOfMemory(cx);
1649     return false;
1650   }
1651   if (!compilationState.scopeNames.append(data)) {
1652     compilationState.scopeData.popBack();
1653     MOZ_ASSERT(compilationState.scopeData.length() ==
1654                compilationState.scopeNames.length());
1655 
1656     js::ReportOutOfMemory(cx);
1657     return false;
1658   }
1659 
1660   return true;
1661 }
1662 
1663 /* static */
createForFunctionScope(JSContext * cx,frontend::CompilationState & compilationState,FunctionScope::ParserData * data,bool hasParameterExprs,bool needsEnvironment,ScriptIndex functionIndex,bool isArrow,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)1664 bool ScopeStencil::createForFunctionScope(
1665     JSContext* cx, frontend::CompilationState& compilationState,
1666     FunctionScope::ParserData* data, bool hasParameterExprs,
1667     bool needsEnvironment, ScriptIndex functionIndex, bool isArrow,
1668     mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index) {
1669   auto kind = ScopeKind::Function;
1670   using ScopeType = FunctionScope;
1671   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
1672 
1673   if (data) {
1674     MarkParserScopeData<ScopeType>(cx, data, compilationState);
1675   } else {
1676     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
1677     if (!data) {
1678       return false;
1679     }
1680   }
1681 
1682   // We do not initialize the canonical function while the data is owned by the
1683   // ScopeStencil. It gets set in ScopeStencil::releaseData.
1684   RootedFunction fun(cx, nullptr);
1685 
1686   uint32_t firstFrameSlot = 0;
1687   mozilla::Maybe<uint32_t> envShape;
1688   if (!FunctionScope::prepareForScopeCreation<frontend::TaggedParserAtomIndex>(
1689           cx, &data, hasParameterExprs, needsEnvironment, fun, &envShape)) {
1690     return false;
1691   }
1692 
1693   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
1694                                    enclosing, firstFrameSlot, envShape,
1695                                    mozilla::Some(functionIndex), isArrow);
1696 }
1697 
1698 /* static */
createForLexicalScope(JSContext * cx,frontend::CompilationState & compilationState,ScopeKind kind,LexicalScope::ParserData * data,uint32_t firstFrameSlot,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)1699 bool ScopeStencil::createForLexicalScope(
1700     JSContext* cx, frontend::CompilationState& compilationState, ScopeKind kind,
1701     LexicalScope::ParserData* data, uint32_t firstFrameSlot,
1702     mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index) {
1703   using ScopeType = LexicalScope;
1704   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
1705 
1706   if (data) {
1707     MarkParserScopeData<ScopeType>(cx, data, compilationState);
1708   } else {
1709     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
1710     if (!data) {
1711       return false;
1712     }
1713   }
1714 
1715   mozilla::Maybe<uint32_t> envShape;
1716   if (!ScopeType::prepareForScopeCreation<frontend::TaggedParserAtomIndex>(
1717           cx, kind, firstFrameSlot, &data, &envShape)) {
1718     return false;
1719   }
1720 
1721   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
1722                                    enclosing, firstFrameSlot, envShape);
1723 }
1724 
1725 /* static */
createForClassBodyScope(JSContext * cx,frontend::CompilationState & compilationState,ScopeKind kind,ClassBodyScope::ParserData * data,uint32_t firstFrameSlot,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)1726 bool ScopeStencil::createForClassBodyScope(
1727     JSContext* cx, frontend::CompilationState& compilationState, ScopeKind kind,
1728     ClassBodyScope::ParserData* data, uint32_t firstFrameSlot,
1729     mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index) {
1730   using ScopeType = ClassBodyScope;
1731   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
1732 
1733   if (data) {
1734     MarkParserScopeData<ScopeType>(cx, data, compilationState);
1735   } else {
1736     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
1737     if (!data) {
1738       return false;
1739     }
1740   }
1741 
1742   mozilla::Maybe<uint32_t> envShape;
1743   if (!ScopeType::prepareForScopeCreation<frontend::TaggedParserAtomIndex>(
1744           cx, kind, firstFrameSlot, &data, &envShape)) {
1745     return false;
1746   }
1747 
1748   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
1749                                    enclosing, firstFrameSlot, envShape);
1750 }
1751 
createForVarScope(JSContext * cx,frontend::CompilationState & compilationState,ScopeKind kind,VarScope::ParserData * data,uint32_t firstFrameSlot,bool needsEnvironment,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)1752 bool ScopeStencil::createForVarScope(
1753     JSContext* cx, frontend::CompilationState& compilationState, ScopeKind kind,
1754     VarScope::ParserData* data, uint32_t firstFrameSlot, bool needsEnvironment,
1755     mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index) {
1756   using ScopeType = VarScope;
1757   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
1758 
1759   if (data) {
1760     MarkParserScopeData<ScopeType>(cx, data, compilationState);
1761   } else {
1762     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
1763     if (!data) {
1764       return false;
1765     }
1766   }
1767 
1768   mozilla::Maybe<uint32_t> envShape;
1769   if (!VarScope::prepareForScopeCreation<frontend::TaggedParserAtomIndex>(
1770           cx, kind, &data, firstFrameSlot, needsEnvironment, &envShape)) {
1771     return false;
1772   }
1773 
1774   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
1775                                    enclosing, firstFrameSlot, envShape);
1776 }
1777 
1778 /* static */
createForGlobalScope(JSContext * cx,frontend::CompilationState & compilationState,ScopeKind kind,GlobalScope::ParserData * data,ScopeIndex * index)1779 bool ScopeStencil::createForGlobalScope(
1780     JSContext* cx, frontend::CompilationState& compilationState, ScopeKind kind,
1781     GlobalScope::ParserData* data, ScopeIndex* index) {
1782   using ScopeType = GlobalScope;
1783   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
1784 
1785   if (data) {
1786     MarkParserScopeData<ScopeType>(cx, data, compilationState);
1787   } else {
1788     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
1789     if (!data) {
1790       return false;
1791     }
1792   }
1793 
1794   // The global scope has no environment shape. Its environment is the
1795   // global lexical scope and the global object or non-syntactic objects
1796   // created by embedding, all of which are not only extensible but may
1797   // have names on them deleted.
1798   uint32_t firstFrameSlot = 0;
1799   mozilla::Maybe<uint32_t> envShape;
1800 
1801   mozilla::Maybe<ScopeIndex> enclosing;
1802 
1803   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
1804                                    enclosing, firstFrameSlot, envShape);
1805 }
1806 
1807 /* static */
createForEvalScope(JSContext * cx,frontend::CompilationState & compilationState,ScopeKind kind,EvalScope::ParserData * data,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)1808 bool ScopeStencil::createForEvalScope(
1809     JSContext* cx, frontend::CompilationState& compilationState, ScopeKind kind,
1810     EvalScope::ParserData* data, mozilla::Maybe<ScopeIndex> enclosing,
1811     ScopeIndex* index) {
1812   using ScopeType = EvalScope;
1813   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
1814 
1815   if (data) {
1816     MarkParserScopeData<ScopeType>(cx, data, compilationState);
1817   } else {
1818     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
1819     if (!data) {
1820       return false;
1821     }
1822   }
1823 
1824   uint32_t firstFrameSlot = 0;
1825   mozilla::Maybe<uint32_t> envShape;
1826   if (!EvalScope::prepareForScopeCreation<frontend::TaggedParserAtomIndex>(
1827           cx, kind, &data, &envShape)) {
1828     return false;
1829   }
1830 
1831   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
1832                                    enclosing, firstFrameSlot, envShape);
1833 }
1834 
1835 /* static */
createForModuleScope(JSContext * cx,frontend::CompilationState & compilationState,ModuleScope::ParserData * data,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)1836 bool ScopeStencil::createForModuleScope(
1837     JSContext* cx, frontend::CompilationState& compilationState,
1838     ModuleScope::ParserData* data, mozilla::Maybe<ScopeIndex> enclosing,
1839     ScopeIndex* index) {
1840   auto kind = ScopeKind::Module;
1841   using ScopeType = ModuleScope;
1842   MOZ_ASSERT(matchScopeKind<ScopeType>(kind));
1843 
1844   if (data) {
1845     MarkParserScopeData<ScopeType>(cx, data, compilationState);
1846   } else {
1847     data = NewEmptyParserScopeData<ScopeType>(cx, compilationState.alloc);
1848     if (!data) {
1849       return false;
1850     }
1851   }
1852 
1853   MOZ_ASSERT(enclosing.isNothing());
1854 
1855   // We do not initialize the canonical module while the data is owned by the
1856   // ScopeStencil. It gets set in ScopeStencil::releaseData.
1857   RootedModuleObject module(cx, nullptr);
1858 
1859   // The data that's passed in is from the frontend and is LifoAlloc'd.
1860   // Copy it now that we're creating a permanent VM scope.
1861   uint32_t firstFrameSlot = 0;
1862   mozilla::Maybe<uint32_t> envShape;
1863   if (!ModuleScope::prepareForScopeCreation<frontend::TaggedParserAtomIndex>(
1864           cx, &data, module, &envShape)) {
1865     return false;
1866   }
1867 
1868   return appendScopeStencilAndData(cx, compilationState, data, index, kind,
1869                                    enclosing, firstFrameSlot, envShape);
1870 }
1871 
1872 template <typename SpecificEnvironmentT>
createSpecificShape(JSContext * cx,ScopeKind kind,BaseScopeData * scopeData,MutableHandleShape shape) const1873 bool ScopeStencil::createSpecificShape(JSContext* cx, ScopeKind kind,
1874                                        BaseScopeData* scopeData,
1875                                        MutableHandleShape shape) const {
1876   const JSClass* cls = &SpecificEnvironmentT::class_;
1877   constexpr ObjectFlags objectFlags = SpecificEnvironmentT::OBJECT_FLAGS;
1878 
1879   if (hasEnvironmentShape()) {
1880     if (numEnvironmentSlots() > 0) {
1881       BindingIter bi(kind, scopeData, firstFrameSlot_);
1882       shape.set(CreateEnvironmentShape(cx, bi, cls, numEnvironmentSlots(),
1883                                        objectFlags));
1884       return shape;
1885     }
1886 
1887     shape.set(EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), objectFlags));
1888     return shape;
1889   }
1890 
1891   return true;
1892 }
1893 
1894 /* static */
createForWithScope(JSContext * cx,CompilationState & compilationState,mozilla::Maybe<ScopeIndex> enclosing,ScopeIndex * index)1895 bool ScopeStencil::createForWithScope(JSContext* cx,
1896                                       CompilationState& compilationState,
1897                                       mozilla::Maybe<ScopeIndex> enclosing,
1898                                       ScopeIndex* index) {
1899   auto kind = ScopeKind::With;
1900   MOZ_ASSERT(matchScopeKind<WithScope>(kind));
1901 
1902   uint32_t firstFrameSlot = 0;
1903   mozilla::Maybe<uint32_t> envShape;
1904 
1905   return appendScopeStencilAndData(cx, compilationState, nullptr, index, kind,
1906                                    enclosing, firstFrameSlot, envShape);
1907 }
1908 
1909 template <typename SpecificScopeT>
1910 UniquePtr<typename SpecificScopeT::RuntimeData>
createSpecificScopeData(JSContext * cx,CompilationAtomCache & atomCache,BaseParserScopeData * baseData) const1911 ScopeStencil::createSpecificScopeData(JSContext* cx,
1912                                       CompilationAtomCache& atomCache,
1913                                       BaseParserScopeData* baseData) const {
1914   return LiftParserScopeData<SpecificScopeT>(cx, atomCache, baseData);
1915 }
1916 
1917 template <>
1918 UniquePtr<FunctionScope::RuntimeData>
createSpecificScopeData(JSContext * cx,CompilationAtomCache & atomCache,BaseParserScopeData * baseData) const1919 ScopeStencil::createSpecificScopeData<FunctionScope>(
1920     JSContext* cx, CompilationAtomCache& atomCache,
1921     BaseParserScopeData* baseData) const {
1922   // Allocate a new vm function-scope.
1923   UniquePtr<FunctionScope::RuntimeData> data =
1924       LiftParserScopeData<FunctionScope>(cx, atomCache, baseData);
1925   if (!data) {
1926     return nullptr;
1927   }
1928 
1929   return data;
1930 }
1931 
1932 template <>
1933 UniquePtr<ModuleScope::RuntimeData>
createSpecificScopeData(JSContext * cx,CompilationAtomCache & atomCache,BaseParserScopeData * baseData) const1934 ScopeStencil::createSpecificScopeData<ModuleScope>(
1935     JSContext* cx, CompilationAtomCache& atomCache,
1936     BaseParserScopeData* baseData) const {
1937   // Allocate a new vm module-scope.
1938   UniquePtr<ModuleScope::RuntimeData> data =
1939       LiftParserScopeData<ModuleScope>(cx, atomCache, baseData);
1940   if (!data) {
1941     return nullptr;
1942   }
1943 
1944   return data;
1945 }
1946 
1947 // WithScope does not use binding data.
1948 template <>
createSpecificScope(JSContext * cx,CompilationAtomCache & atomCache,HandleScope enclosingScope,BaseParserScopeData * baseData) const1949 Scope* ScopeStencil::createSpecificScope<WithScope, std::nullptr_t>(
1950     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
1951     BaseParserScopeData* baseData) const {
1952   return Scope::create(cx, ScopeKind::With, enclosingScope, nullptr);
1953 }
1954 
1955 // GlobalScope has bindings but no environment shape.
1956 template <>
createSpecificScope(JSContext * cx,CompilationAtomCache & atomCache,HandleScope enclosingScope,BaseParserScopeData * baseData) const1957 Scope* ScopeStencil::createSpecificScope<GlobalScope, std::nullptr_t>(
1958     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
1959     BaseParserScopeData* baseData) const {
1960   Rooted<UniquePtr<GlobalScope::RuntimeData>> rootedData(
1961       cx, createSpecificScopeData<GlobalScope>(cx, atomCache, baseData));
1962   if (!rootedData) {
1963     return nullptr;
1964   }
1965 
1966   MOZ_ASSERT(!hasEnclosing());
1967   MOZ_ASSERT(!enclosingScope);
1968 
1969   // Because we already baked the data here, we needn't do it again.
1970   return Scope::create<GlobalScope>(cx, kind(), nullptr, nullptr, &rootedData);
1971 }
1972 
1973 template <typename SpecificScopeT, typename SpecificEnvironmentT>
createSpecificScope(JSContext * cx,CompilationAtomCache & atomCache,HandleScope enclosingScope,BaseParserScopeData * baseData) const1974 Scope* ScopeStencil::createSpecificScope(JSContext* cx,
1975                                          CompilationAtomCache& atomCache,
1976                                          HandleScope enclosingScope,
1977                                          BaseParserScopeData* baseData) const {
1978   Rooted<UniquePtr<typename SpecificScopeT::RuntimeData>> rootedData(
1979       cx, createSpecificScopeData<SpecificScopeT>(cx, atomCache, baseData));
1980   if (!rootedData) {
1981     return nullptr;
1982   }
1983 
1984   RootedShape shape(cx);
1985   if (!createSpecificShape<SpecificEnvironmentT>(
1986           cx, kind(), rootedData.get().get(), &shape)) {
1987     return nullptr;
1988   }
1989 
1990   // Because we already baked the data here, we needn't do it again.
1991   return Scope::create<SpecificScopeT>(cx, kind(), enclosingScope, shape,
1992                                        &rootedData);
1993 }
1994 
1995 template Scope* ScopeStencil::createSpecificScope<FunctionScope, CallObject>(
1996     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
1997     BaseParserScopeData* baseData) const;
1998 template Scope*
1999 ScopeStencil::createSpecificScope<LexicalScope, BlockLexicalEnvironmentObject>(
2000     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2001     BaseParserScopeData* baseData) const;
2002 template Scope* ScopeStencil::createSpecificScope<
2003     ClassBodyScope, BlockLexicalEnvironmentObject>(
2004     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2005     BaseParserScopeData* baseData) const;
2006 template Scope*
2007 ScopeStencil::createSpecificScope<EvalScope, VarEnvironmentObject>(
2008     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2009     BaseParserScopeData* baseData) const;
2010 template Scope*
2011 ScopeStencil::createSpecificScope<VarScope, VarEnvironmentObject>(
2012     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2013     BaseParserScopeData* baseData) const;
2014 template Scope*
2015 ScopeStencil::createSpecificScope<ModuleScope, ModuleEnvironmentObject>(
2016     JSContext* cx, CompilationAtomCache& atomCache, HandleScope enclosingScope,
2017     BaseParserScopeData* baseData) const;
2018