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