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