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