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