1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "frontend/Stencil.h"
9 #include "mozilla/AlreadyAddRefed.h" // already_AddRefed
10 #include "mozilla/Assertions.h" // MOZ_RELEASE_ASSERT
11 #include "mozilla/Maybe.h" // mozilla::Maybe
12 #include "mozilla/OperatorNewExtensions.h" // mozilla::KnownNotNull
13 #include "mozilla/PodOperations.h" // mozilla::PodCopy
14 #include "mozilla/RefPtr.h" // RefPtr
15 #include "mozilla/ScopeExit.h" // mozilla::ScopeExit
16 #include "mozilla/Sprintf.h" // SprintfLiteral
18 #include <algorithm> // std::fill
19 #include <string.h> // strlen
21 #include "ds/LifoAlloc.h" // LifoAlloc
22 #include "frontend/AbstractScopePtr.h" // ScopeIndex
23 #include "frontend/BytecodeCompiler.h" // CompileGlobalScriptToStencil, InstantiateStencils, CanLazilyParse, ParseModuleToStencil
24 #include "frontend/BytecodeSection.h" // EmitScriptThingsVector
25 #include "frontend/CompilationStencil.h" // CompilationStencil, CompilationState, ExtensibleCompilationStencil, CompilationGCOutput, CompilationStencilMerger
26 #include "frontend/FrontendContext.h"
27 #include "frontend/NameAnalysisTypes.h" // EnvironmentCoordinate
28 #include "frontend/ParserAtom.h" // ParserAtom, ParserAtomIndex, TaggedParserAtomIndex, ParserAtomsTable, Length{1,2,3}StaticParserString, InstantiateMarkedAtoms, InstantiateMarkedAtomsAsPermanent, GetWellKnownAtom
29 #include "frontend/ScopeBindingCache.h" // ScopeBindingCache
30 #include "frontend/SharedContext.h"
31 #include "frontend/StencilXdr.h" // XDRStencilEncoder, XDRStencilDecoder
32 #include "gc/AllocKind.h" // gc::AllocKind
33 #include "gc/Tracer.h" // TraceNullableRoot
34 #include "js/CallArgs.h" // JSNative
35 #include "js/CompileOptions.h" // JS::DecodeOptions, JS::ReadOnlyDecodeOptions
36 #include "js/experimental/JSStencil.h" // JS::Stencil
37 #include "js/GCAPI.h" // JS::AutoCheckCannotGC
38 #include "js/Printer.h" // js::Fprinter
39 #include "js/RealmOptions.h" // JS::RealmBehaviors
40 #include "js/RootingAPI.h" // Rooted
41 #include "js/Transcoding.h" // JS::TranscodeBuffer
42 #include "js/Utility.h" // js_malloc, js_calloc, js_free
43 #include "js/Value.h" // ObjectValue
44 #include "js/WasmModule.h" // JS::WasmModule
45 #include "vm/BigIntType.h" // ParseBigIntLiteral, BigIntLiteralIsZero
46 #include "vm/BindingKind.h" // BindingKind
47 #include "vm/EnvironmentObject.h"
48 #include "vm/GeneratorAndAsyncKind.h" // GeneratorKind, FunctionAsyncKind
49 #include "vm/JSContext.h" // JSContext
50 #include "vm/JSFunction.h" // JSFunction, GetFunctionPrototype, NewFunctionWithProto
51 #include "vm/JSObject.h" // JSObject, TenuredObject
52 #include "vm/JSONPrinter.h" // js::JSONPrinter
53 #include "vm/JSScript.h" // BaseScript, JSScript
54 #include "vm/Realm.h" // JS::Realm
55 #include "vm/RegExpObject.h" // js::RegExpObject
56 #include "vm/Scope.h" // Scope, *Scope, ScopeKind::*, ScopeKindString, ScopeIter, ScopeKindIsCatch, BindingIter, GetScopeDataTrailingNames, SizeOfParserScopeData
57 #include "vm/ScopeKind.h" // ScopeKind
58 #include "vm/SelfHosting.h" // SetClonedSelfHostedFunctionName
59 #include "vm/StaticStrings.h"
60 #include "vm/StencilEnums.h" // ImmutableScriptFlagsEnum
61 #include "vm/StringType.h" // JSAtom, js::CopyChars
62 #include "wasm/AsmJS.h" // InstantiateAsmJS
64 #include "vm/EnvironmentObject-inl.h" // JSObject::enclosingEnvironment
65 #include "vm/JSFunction-inl.h" // JSFunction::create
68 using namespace js::frontend
;
70 // These 2 functions are used to write the same code with lambda using auto
71 // arguments. The auto argument type is set by the Variant.match function of the
72 // InputScope variant. Thus dispatching to either a Scope* or to a
73 // ScopeStencilRef. This function can then be used as a way to specialize the
74 // code within the lambda without duplicating the code.
76 // Identically, an InputName is constructed using the scope type and the
77 // matching binding name type. This way, functions which are called by this
78 // lambda can manipulate an InputName and do not have to be duplicated.
80 // for (InputScopeIter si(...); si; si++) {
81 // si.scope().match([](auto& scope) {
82 // for (auto bi = InputBindingIter(scope); bi; bi++) {
83 // InputName name(scope, bi.name());
87 static js::BindingIter
InputBindingIter(Scope
* ptr
) {
88 return js::BindingIter(ptr
);
91 static ParserBindingIter
InputBindingIter(const ScopeStencilRef
& ref
) {
92 return ParserBindingIter(ref
);
95 static ParserBindingIter
InputBindingIter(const FakeStencilGlobalScope
&) {
96 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No bindings on empty global.");
99 InputName
InputScript::displayAtom() const {
100 return script_
.match(
101 [](BaseScript
* ptr
) {
102 return InputName(ptr
, ptr
->function()->fullDisplayAtom());
104 [](const ScriptStencilRef
& ref
) {
105 return InputName(ref
, ref
.scriptData().functionAtom
);
109 TaggedParserAtomIndex
InputName::internInto(FrontendContext
* fc
,
110 ParserAtomsTable
& parserAtoms
,
111 CompilationAtomCache
& atomCache
) {
112 return variant_
.match(
113 [&](JSAtom
* ptr
) -> TaggedParserAtomIndex
{
114 return parserAtoms
.internJSAtom(fc
, atomCache
, ptr
);
116 [&](NameStencilRef
& ref
) -> TaggedParserAtomIndex
{
117 return parserAtoms
.internExternalParserAtomIndex(fc
, ref
.context_
,
122 bool InputName::isEqualTo(FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
,
123 CompilationAtomCache
& atomCache
,
124 TaggedParserAtomIndex other
,
125 JSAtom
** otherCached
) const {
126 return variant_
.match(
127 [&](const JSAtom
* ptr
) -> bool {
128 if (ptr
->hash() != parserAtoms
.hash(other
)) {
132 // JSAtom variant is used only on the main thread delazification,
133 // where JSContext is always available.
134 JSContext
* cx
= fc
->maybeCurrentJSContext();
139 // Here, we convert our name into a JSAtom*, and hard-crash on failure
140 // to allocate. This conversion should not be required as we should be
141 // able to iterate up snapshotted scope chains that use parser atoms.
143 // This will be fixed when the enclosing scopes are snapshotted.
146 AutoEnterOOMUnsafeRegion oomUnsafe
;
147 *otherCached
= parserAtoms
.toJSAtom(cx
, fc
, other
, atomCache
);
149 oomUnsafe
.crash("InputName::isEqualTo");
152 MOZ_ASSERT(atomCache
.getExistingAtomAt(cx
, other
) == *otherCached
);
154 return ptr
== *otherCached
;
156 [&](const NameStencilRef
& ref
) -> bool {
157 return parserAtoms
.isEqualToExternalParserAtomIndex(other
, ref
.context_
,
162 GenericAtom::GenericAtom(FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
,
163 CompilationAtomCache
& atomCache
,
164 TaggedParserAtomIndex index
)
165 : ref(EmitterName(fc
, parserAtoms
, atomCache
, index
)) {
166 hash
= parserAtoms
.hash(index
);
169 GenericAtom::GenericAtom(const CompilationStencil
& context
,
170 TaggedParserAtomIndex index
)
171 : ref(StencilName
{context
, index
}) {
172 if (index
.isParserAtomIndex()) {
173 ParserAtom
* atom
= context
.parserAtomData
[index
.toParserAtomIndex()];
176 hash
= index
.staticOrWellKnownHash();
180 GenericAtom::GenericAtom(ScopeStencilRef
& scope
, TaggedParserAtomIndex index
)
181 : GenericAtom(scope
.context_
, index
) {}
183 BindingHasher
<TaggedParserAtomIndex
>::Lookup::Lookup(ScopeStencilRef
& scope_ref
,
184 const GenericAtom
& other
)
185 : keyStencil(scope_ref
.context_
), other(other
) {}
187 bool GenericAtom::operator==(const GenericAtom
& other
) const {
189 [&other
](const EmitterName
& name
) -> bool {
190 return other
.ref
.match(
191 [&name
](const EmitterName
& other
) -> bool {
192 // We never have multiple Emitter context at the same time.
193 MOZ_ASSERT(name
.fc
== other
.fc
);
194 MOZ_ASSERT(&name
.parserAtoms
== &other
.parserAtoms
);
195 MOZ_ASSERT(&name
.atomCache
== &other
.atomCache
);
196 return name
.index
== other
.index
;
198 [&name
](const StencilName
& other
) -> bool {
199 return name
.parserAtoms
.isEqualToExternalParserAtomIndex(
200 name
.index
, other
.stencil
, other
.index
);
202 [&name
](JSAtom
* other
) -> bool {
203 // JSAtom variant is used only on the main thread delazification,
204 // where JSContext is always available.
205 JSContext
* cx
= name
.fc
->maybeCurrentJSContext();
207 AutoEnterOOMUnsafeRegion oomUnsafe
;
208 JSAtom
* namePtr
= name
.parserAtoms
.toJSAtom(
209 cx
, name
.fc
, name
.index
, name
.atomCache
);
211 oomUnsafe
.crash("GenericAtom(EmitterName == JSAtom*)");
213 return namePtr
== other
;
216 [&other
](const StencilName
& name
) -> bool {
217 return other
.ref
.match(
218 [&name
](const EmitterName
& other
) -> bool {
219 return other
.parserAtoms
.isEqualToExternalParserAtomIndex(
220 other
.index
, name
.stencil
, name
.index
);
222 [&name
](const StencilName
& other
) -> bool {
223 // Technically it is possible to have multiple stencils, but in
224 // this particular case let's assume we never encounter a case
225 // where we are comparing names from different stencils.
227 // The reason this assumption is safe today is that we are only
228 // using this in the context of a stencil-delazification, where
229 // the only StencilNames are coming from the CompilationStencil
230 // provided to CompilationInput::initFromStencil.
231 MOZ_ASSERT(&name
.stencil
== &other
.stencil
);
232 return name
.index
== other
.index
;
234 [](JSAtom
* other
) -> bool {
235 MOZ_CRASH("Never used.");
239 [&other
](JSAtom
* name
) -> bool {
240 return other
.ref
.match(
241 [&name
](const EmitterName
& other
) -> bool {
242 // JSAtom variant is used only on the main thread delazification,
243 // where JSContext is always available.
244 JSContext
* cx
= other
.fc
->maybeCurrentJSContext();
246 AutoEnterOOMUnsafeRegion oomUnsafe
;
247 JSAtom
* otherPtr
= other
.parserAtoms
.toJSAtom(
248 cx
, other
.fc
, other
.index
, other
.atomCache
);
250 oomUnsafe
.crash("GenericAtom(JSAtom* == EmitterName)");
252 return name
== otherPtr
;
254 [](const StencilName
& other
) -> bool {
255 MOZ_CRASH("Never used.");
258 [&name
](JSAtom
* other
) -> bool { return name
== other
; });
263 template <typename SpanT
, typename VecT
>
264 void AssertBorrowingSpan(const SpanT
& span
, const VecT
& vec
) {
265 MOZ_ASSERT(span
.size() == vec
.length());
266 MOZ_ASSERT(span
.data() == vec
.begin());
270 bool ScopeBindingCache::canCacheFor(Scope
* ptr
) {
271 MOZ_CRASH("Unexpected scope chain type: Scope*");
274 bool ScopeBindingCache::canCacheFor(ScopeStencilRef ref
) {
275 MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef");
278 bool ScopeBindingCache::canCacheFor(const FakeStencilGlobalScope
& ref
) {
279 MOZ_CRASH("Unexpected scope chain type: FakeStencilGlobalScope");
282 BindingMap
<JSAtom
*>* ScopeBindingCache::createCacheFor(Scope
* ptr
) {
283 MOZ_CRASH("Unexpected scope chain type: Scope*");
286 BindingMap
<JSAtom
*>* ScopeBindingCache::lookupScope(Scope
* ptr
,
287 CacheGeneration gen
) {
288 MOZ_CRASH("Unexpected scope chain type: Scope*");
291 BindingMap
<TaggedParserAtomIndex
>* ScopeBindingCache::createCacheFor(
292 ScopeStencilRef ref
) {
293 MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef");
296 BindingMap
<TaggedParserAtomIndex
>* ScopeBindingCache::lookupScope(
297 ScopeStencilRef ref
, CacheGeneration gen
) {
298 MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef");
301 BindingMap
<TaggedParserAtomIndex
>* ScopeBindingCache::createCacheFor(
302 const FakeStencilGlobalScope
& ref
) {
303 MOZ_CRASH("Unexpected scope chain type: FakeStencilGlobalScope");
306 BindingMap
<TaggedParserAtomIndex
>* ScopeBindingCache::lookupScope(
307 const FakeStencilGlobalScope
& ref
, CacheGeneration gen
) {
308 MOZ_CRASH("Unexpected scope chain type: FakeStencilGlobalScope");
311 bool NoScopeBindingCache::canCacheFor(Scope
* ptr
) { return false; }
313 bool NoScopeBindingCache::canCacheFor(ScopeStencilRef ref
) { return false; }
315 bool NoScopeBindingCache::canCacheFor(const FakeStencilGlobalScope
& ref
) {
319 bool RuntimeScopeBindingCache::canCacheFor(Scope
* ptr
) { return true; }
321 BindingMap
<JSAtom
*>* RuntimeScopeBindingCache::createCacheFor(Scope
* ptr
) {
322 BaseScopeData
* dataPtr
= ptr
->rawData();
323 BindingMap
<JSAtom
*> bindingCache
;
324 if (!scopeMap
.putNew(dataPtr
, std::move(bindingCache
))) {
328 return lookupScope(ptr
, cacheGeneration
);
331 BindingMap
<JSAtom
*>* RuntimeScopeBindingCache::lookupScope(
332 Scope
* ptr
, CacheGeneration gen
) {
333 MOZ_ASSERT(gen
== cacheGeneration
);
334 BaseScopeData
* dataPtr
= ptr
->rawData();
335 auto valuePtr
= scopeMap
.lookup(dataPtr
);
339 return &valuePtr
->value();
342 bool StencilScopeBindingCache::canCacheFor(ScopeStencilRef ref
) { return true; }
344 BindingMap
<TaggedParserAtomIndex
>* StencilScopeBindingCache::createCacheFor(
345 ScopeStencilRef ref
) {
347 AssertBorrowingSpan(ref
.context_
.scopeNames
, merger_
.getResult().scopeNames
);
349 auto* dataPtr
= ref
.context_
.scopeNames
[ref
.scopeIndex_
];
350 BindingMap
<TaggedParserAtomIndex
> bindingCache
;
351 if (!scopeMap
.putNew(dataPtr
, std::move(bindingCache
))) {
355 return lookupScope(ref
, 1);
358 BindingMap
<TaggedParserAtomIndex
>* StencilScopeBindingCache::lookupScope(
359 ScopeStencilRef ref
, CacheGeneration gen
) {
361 AssertBorrowingSpan(ref
.context_
.scopeNames
, merger_
.getResult().scopeNames
);
363 auto* dataPtr
= ref
.context_
.scopeNames
[ref
.scopeIndex_
];
364 auto ptr
= scopeMap
.lookup(dataPtr
);
368 return &ptr
->value();
371 static AbstractBaseScopeData
<TaggedParserAtomIndex
>
372 moduleGlobalAbstractScopeData
;
374 bool StencilScopeBindingCache::canCacheFor(const FakeStencilGlobalScope
& ref
) {
378 BindingMap
<TaggedParserAtomIndex
>* StencilScopeBindingCache::createCacheFor(
379 const FakeStencilGlobalScope
& ref
) {
380 auto* dataPtr
= &moduleGlobalAbstractScopeData
;
381 BindingMap
<TaggedParserAtomIndex
> bindingCache
;
382 if (!scopeMap
.putNew(dataPtr
, std::move(bindingCache
))) {
386 return lookupScope(ref
, 1);
389 BindingMap
<TaggedParserAtomIndex
>* StencilScopeBindingCache::lookupScope(
390 const FakeStencilGlobalScope
& ref
, CacheGeneration gen
) {
391 auto* dataPtr
= &moduleGlobalAbstractScopeData
;
392 auto ptr
= scopeMap
.lookup(dataPtr
);
396 return &ptr
->value();
399 bool ScopeContext::init(FrontendContext
* fc
, CompilationInput
& input
,
400 ParserAtomsTable
& parserAtoms
,
401 ScopeBindingCache
* scopeCache
, InheritThis inheritThis
,
402 JSObject
* enclosingEnv
) {
403 // Record the scopeCache to be used while looking up NameLocation bindings.
404 this->scopeCache
= scopeCache
;
405 scopeCacheGen
= scopeCache
->getCurrentGeneration();
407 InputScope
maybeNonDefaultEnclosingScope(
408 input
.maybeNonDefaultEnclosingScope());
410 // If this eval is in response to Debugger.Frame.eval, we may have an
411 // incomplete scope chain. In order to provide a better debugging experience,
412 // we inspect the (optional) environment chain to determine it's enclosing
413 // FunctionScope if there is one. If there is no such scope, we use the
414 // orignal scope provided.
416 // NOTE: This is used to compute the ThisBinding kind and to allow access to
417 // private fields and methods, while other contextual information only
418 // uses the actual scope passed to the compile.
419 auto effectiveScope
=
420 determineEffectiveScope(maybeNonDefaultEnclosingScope
, enclosingEnv
);
422 if (inheritThis
== InheritThis::Yes
) {
423 computeThisBinding(effectiveScope
);
424 computeThisEnvironment(maybeNonDefaultEnclosingScope
);
426 computeInScope(maybeNonDefaultEnclosingScope
);
428 cacheEnclosingScope(input
.enclosingScope
);
430 if (input
.target
== CompilationInput::CompilationTarget::Eval
) {
431 if (!cacheEnclosingScopeBindingForEval(fc
, input
, parserAtoms
)) {
434 if (!cachePrivateFieldsForEval(fc
, input
, enclosingEnv
, effectiveScope
,
443 void ScopeContext::computeThisEnvironment(const InputScope
& enclosingScope
) {
444 uint32_t envCount
= 0;
445 for (InputScopeIter
si(enclosingScope
); si
; si
++) {
446 if (si
.kind() == ScopeKind::Function
) {
447 // Arrow function inherit the "this" environment of the enclosing script,
448 // so continue ignore them.
449 if (!si
.scope().isArrow()) {
450 allowNewTarget
= true;
452 if (si
.scope().allowSuperProperty()) {
453 allowSuperProperty
= true;
454 enclosingThisEnvironmentHops
= envCount
;
457 if (si
.scope().isClassConstructor()) {
459 si
.scope().useMemberInitializers()
460 ? mozilla::Some(si
.scope().getMemberInitializers())
461 : mozilla::Some(MemberInitializers::Empty());
462 MOZ_ASSERT(memberInitializers
->valid
);
464 if (si
.scope().isSyntheticFunction()) {
465 allowArguments
= false;
469 if (si
.scope().isDerivedClassConstructor()) {
470 allowSuperCall
= true;
473 // Found the effective "this" environment, so stop.
478 if (si
.scope().hasEnvironment()) {
484 void ScopeContext::computeThisBinding(const InputScope
& scope
) {
485 // Inspect the scope-chain.
486 for (InputScopeIter
si(scope
); si
; si
++) {
487 if (si
.kind() == ScopeKind::Module
) {
488 thisBinding
= ThisBinding::Module
;
492 if (si
.kind() == ScopeKind::Function
) {
493 // Arrow functions don't have their own `this` binding.
494 if (si
.scope().isArrow()) {
498 // Derived class constructors (and their nested arrow functions and evals)
499 // use ThisBinding::DerivedConstructor, which ensures TDZ checks happen
500 // when accessing |this|.
501 if (si
.scope().isDerivedClassConstructor()) {
502 thisBinding
= ThisBinding::DerivedConstructor
;
504 thisBinding
= ThisBinding::Function
;
511 thisBinding
= ThisBinding::Global
;
514 void ScopeContext::computeInScope(const InputScope
& enclosingScope
) {
515 for (InputScopeIter
si(enclosingScope
); si
; si
++) {
516 if (si
.kind() == ScopeKind::ClassBody
) {
520 if (si
.kind() == ScopeKind::With
) {
526 void ScopeContext::cacheEnclosingScope(const InputScope
& enclosingScope
) {
527 if (enclosingScope
.isNull()) {
531 enclosingScopeEnvironmentChainLength
=
532 enclosingScope
.environmentChainLength();
533 enclosingScopeKind
= enclosingScope
.kind();
535 if (enclosingScopeKind
== ScopeKind::Function
) {
536 enclosingScopeIsArrow
= enclosingScope
.isArrow();
539 enclosingScopeHasEnvironment
= enclosingScope
.hasEnvironment();
542 hasNonSyntacticScopeOnChain
=
543 enclosingScope
.hasOnChain(ScopeKind::NonSyntactic
);
545 // This computes a general answer for the query "does the enclosing scope
546 // have a function scope that needs a home object?", but it's only asserted
547 // if the parser parses eval body that contains `super` that needs a home
549 for (InputScopeIter
si(enclosingScope
); si
; si
++) {
550 if (si
.kind() == ScopeKind::Function
) {
551 if (si
.scope().isArrow()) {
554 if (si
.scope().allowSuperProperty() && si
.scope().needsHomeObject()) {
555 hasFunctionNeedsHomeObjectOnChain
= true;
562 // Pre-fill the scope cache by iterating over all the names. Stop iterating
563 // as soon as we find a scope which already has a filled scope cache.
564 AutoEnterOOMUnsafeRegion oomUnsafe
;
565 for (InputScopeIter
si(enclosingScope
); si
; si
++) {
566 // If the current scope already exists, then there is no need to go deeper
567 // as the scope which are encoded after this one should already be present
569 bool hasScopeCache
= si
.scope().match([&](auto& scope_ref
) -> bool {
570 MOZ_ASSERT(scopeCache
->canCacheFor(scope_ref
));
571 return scopeCache
->lookupScope(scope_ref
, scopeCacheGen
);
577 bool hasEnv
= si
.hasSyntacticEnvironment();
578 auto setCatchAll
= [&](NameLocation loc
) {
579 return si
.scope().match([&](auto& scope_ref
) {
580 using BindingMapPtr
= decltype(scopeCache
->createCacheFor(scope_ref
));
581 BindingMapPtr bindingMapPtr
= scopeCache
->createCacheFor(scope_ref
);
582 if (!bindingMapPtr
) {
584 "ScopeContext::cacheEnclosingScope: scopeCache->createCacheFor");
588 bindingMapPtr
->catchAll
.emplace(loc
);
591 auto createEmpty
= [&]() {
592 return si
.scope().match([&](auto& scope_ref
) {
593 using BindingMapPtr
= decltype(scopeCache
->createCacheFor(scope_ref
));
594 BindingMapPtr bindingMapPtr
= scopeCache
->createCacheFor(scope_ref
);
595 if (!bindingMapPtr
) {
597 "ScopeContext::cacheEnclosingScope: scopeCache->createCacheFor");
604 case ScopeKind::Function
:
606 if (si
.scope().funHasExtensibleScope()) {
607 setCatchAll(NameLocation::Dynamic());
611 si
.scope().match([&](auto& scope_ref
) {
612 using BindingMapPtr
=
613 decltype(scopeCache
->createCacheFor(scope_ref
));
615 typename
std::remove_pointer_t
<BindingMapPtr
>::Lookup
;
616 BindingMapPtr bindingMapPtr
= scopeCache
->createCacheFor(scope_ref
);
617 if (!bindingMapPtr
) {
619 "ScopeContext::cacheEnclosingScope: "
620 "scopeCache->createCacheFor");
624 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
625 NameLocation loc
= bi
.nameLocation();
626 if (loc
.kind() != NameLocation::Kind::EnvironmentCoordinate
) {
629 auto ctxFreeKey
= bi
.name();
630 GenericAtom
ctxKey(scope_ref
, ctxFreeKey
);
631 Lookup
ctxLookup(scope_ref
, ctxKey
);
632 if (!bindingMapPtr
->hashMap
.put(ctxLookup
, ctxFreeKey
, loc
)) {
634 "ScopeContext::cacheEnclosingScope: bindingMapPtr->put");
644 case ScopeKind::StrictEval
:
645 case ScopeKind::FunctionBodyVar
:
646 case ScopeKind::Lexical
:
647 case ScopeKind::NamedLambda
:
648 case ScopeKind::StrictNamedLambda
:
649 case ScopeKind::SimpleCatch
:
650 case ScopeKind::Catch
:
651 case ScopeKind::FunctionLexical
:
652 case ScopeKind::ClassBody
:
654 si
.scope().match([&](auto& scope_ref
) {
655 using BindingMapPtr
=
656 decltype(scopeCache
->createCacheFor(scope_ref
));
658 typename
std::remove_pointer_t
<BindingMapPtr
>::Lookup
;
659 BindingMapPtr bindingMapPtr
= scopeCache
->createCacheFor(scope_ref
);
660 if (!bindingMapPtr
) {
662 "ScopeContext::cacheEnclosingScope: "
663 "scopeCache->createCacheFor");
667 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
668 NameLocation loc
= bi
.nameLocation();
669 if (loc
.kind() != NameLocation::Kind::EnvironmentCoordinate
) {
672 auto ctxFreeKey
= bi
.name();
673 GenericAtom
ctxKey(scope_ref
, ctxFreeKey
);
674 Lookup
ctxLookup(scope_ref
, ctxKey
);
675 if (!bindingMapPtr
->hashMap
.putNew(ctxLookup
, ctxFreeKey
, loc
)) {
677 "ScopeContext::cacheEnclosingScope: bindingMapPtr->put");
687 case ScopeKind::Module
:
688 // This case is used only when delazifying a function inside
690 // Initial compilation of module doesn't have enlcosing scope.
692 si
.scope().match([&](auto& scope_ref
) {
693 using BindingMapPtr
=
694 decltype(scopeCache
->createCacheFor(scope_ref
));
696 typename
std::remove_pointer_t
<BindingMapPtr
>::Lookup
;
697 BindingMapPtr bindingMapPtr
= scopeCache
->createCacheFor(scope_ref
);
698 if (!bindingMapPtr
) {
700 "ScopeContext::cacheEnclosingScope: "
701 "scopeCache->createCacheFor");
705 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
706 // Imports are on the environment but are indirect
707 // bindings and must be accessed dynamically instead of
708 // using an EnvironmentCoordinate.
709 NameLocation loc
= bi
.nameLocation();
710 if (loc
.kind() != NameLocation::Kind::EnvironmentCoordinate
&&
711 loc
.kind() != NameLocation::Kind::Import
) {
714 auto ctxFreeKey
= bi
.name();
715 GenericAtom
ctxKey(scope_ref
, ctxFreeKey
);
716 Lookup
ctxLookup(scope_ref
, ctxKey
);
717 if (!bindingMapPtr
->hashMap
.putNew(ctxLookup
, ctxFreeKey
, loc
)) {
719 "ScopeContext::cacheEnclosingScope: bindingMapPtr->put");
729 case ScopeKind::Eval
:
730 // As an optimization, if the eval doesn't have its own var
731 // environment and its immediate enclosing scope is a global
732 // scope, all accesses are global.
734 ScopeKind kind
= si
.scope().enclosing().kind();
735 if (kind
== ScopeKind::Global
|| kind
== ScopeKind::NonSyntactic
) {
736 setCatchAll(NameLocation::Global(BindingKind::Var
));
741 setCatchAll(NameLocation::Dynamic());
744 case ScopeKind::Global
:
745 setCatchAll(NameLocation::Global(BindingKind::Var
));
748 case ScopeKind::With
:
749 case ScopeKind::NonSyntactic
:
750 setCatchAll(NameLocation::Dynamic());
753 case ScopeKind::WasmInstance
:
754 case ScopeKind::WasmFunction
:
755 MOZ_CRASH("No direct eval inside wasm functions");
759 MOZ_CRASH("Malformed scope chain");
762 // Given an input scope, possibly refine this to a more precise scope.
763 // This is used during eval in the debugger to provide the appropriate scope and
764 // ThisBinding kind and environment, which is key to making private field eval
767 // The trick here is that an eval may have a non-syntatic scope but nevertheless
768 // have an 'interesting' environment which can be traversed to find the
769 // appropriate scope the the eval to function as desired. See the diagram below.
771 // Eval Scope Eval Env Frame Env Frame Scope
772 // ============ ============= ========= =============
777 // null DebugEnvProxy LexicalScope
780 // DebugEnvProxy --> CallObj --> FunctionScope
785 InputScope
ScopeContext::determineEffectiveScope(InputScope
& scope
,
786 JSObject
* environment
) {
787 MOZ_ASSERT(effectiveScopeHops
== 0);
788 // If the scope-chain is non-syntactic, we may still determine a more precise
789 // effective-scope to use instead.
790 if (environment
&& scope
.hasOnChain(ScopeKind::NonSyntactic
)) {
791 JSObject
* env
= environment
;
793 // Look at target of any DebugEnvironmentProxy, but be sure to use
794 // enclosingEnvironment() of the proxy itself.
795 JSObject
* unwrapped
= env
;
796 if (env
->is
<DebugEnvironmentProxy
>()) {
797 unwrapped
= &env
->as
<DebugEnvironmentProxy
>().environment();
799 enclosingEnvironmentIsDebugProxy_
= true;
803 if (unwrapped
->is
<CallObject
>()) {
804 JSFunction
* callee
= &unwrapped
->as
<CallObject
>().callee();
805 return InputScope(callee
->nonLazyScript()->bodyScope());
808 env
= env
->enclosingEnvironment();
809 effectiveScopeHops
++;
816 static uint32_t DepthOfNearestVarScopeForDirectEval(const InputScope
& scope
) {
818 if (scope
.isNull()) {
821 for (InputScopeIter
si(scope
); si
; si
++) {
823 switch (si
.scope().kind()) {
824 case ScopeKind::Function
:
825 case ScopeKind::FunctionBodyVar
:
826 case ScopeKind::Global
:
827 case ScopeKind::NonSyntactic
:
836 bool ScopeContext::cacheEnclosingScopeBindingForEval(
837 FrontendContext
* fc
, CompilationInput
& input
,
838 ParserAtomsTable
& parserAtoms
) {
839 enclosingLexicalBindingCache_
.emplace();
841 uint32_t varScopeDepth
=
842 DepthOfNearestVarScopeForDirectEval(input
.enclosingScope
);
844 for (InputScopeIter
si(input
.enclosingScope
); si
; si
++) {
845 bool success
= si
.scope().match([&](auto& scope_ref
) {
846 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
848 case BindingKind::Let
: {
849 // Annex B.3.5 allows redeclaring simple (non-destructured)
850 // catch parameters with var declarations.
851 bool annexB35Allowance
= si
.kind() == ScopeKind::SimpleCatch
;
852 if (!annexB35Allowance
) {
853 auto kind
= ScopeKindIsCatch(si
.kind())
854 ? EnclosingLexicalBindingKind::CatchParameter
855 : EnclosingLexicalBindingKind::Let
;
856 InputName
binding(scope_ref
, bi
.name());
857 if (!addToEnclosingLexicalBindingCache(
858 fc
, parserAtoms
, input
.atomCache
, binding
, kind
)) {
865 case BindingKind::Const
: {
866 InputName
binding(scope_ref
, bi
.name());
867 if (!addToEnclosingLexicalBindingCache(
868 fc
, parserAtoms
, input
.atomCache
, binding
,
869 EnclosingLexicalBindingKind::Const
)) {
875 case BindingKind::Synthetic
: {
876 InputName
binding(scope_ref
, bi
.name());
877 if (!addToEnclosingLexicalBindingCache(
878 fc
, parserAtoms
, input
.atomCache
, binding
,
879 EnclosingLexicalBindingKind::Synthetic
)) {
885 case BindingKind::PrivateMethod
: {
886 InputName
binding(scope_ref
, bi
.name());
887 if (!addToEnclosingLexicalBindingCache(
888 fc
, parserAtoms
, input
.atomCache
, binding
,
889 EnclosingLexicalBindingKind::PrivateMethod
)) {
895 case BindingKind::Import
:
896 case BindingKind::FormalParameter
:
897 case BindingKind::Var
:
898 case BindingKind::NamedLambdaCallee
:
908 if (++depth
== varScopeDepth
) {
916 bool ScopeContext::addToEnclosingLexicalBindingCache(
917 FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
,
918 CompilationAtomCache
& atomCache
, InputName
& name
,
919 EnclosingLexicalBindingKind kind
) {
920 TaggedParserAtomIndex parserName
=
921 name
.internInto(fc
, parserAtoms
, atomCache
);
926 // Same lexical binding can appear multiple times across scopes.
928 // enclosingLexicalBindingCache_ map is used for detecting conflicting
929 // `var` binding, and inner binding should be reported in the error.
931 // cacheEnclosingScopeBindingForEval iterates from inner scope, and
932 // inner-most binding is added to the map first.
934 // Do not overwrite the value with outer bindings.
935 auto p
= enclosingLexicalBindingCache_
->lookupForAdd(parserName
);
937 if (!enclosingLexicalBindingCache_
->add(p
, parserName
, kind
)) {
938 ReportOutOfMemory(fc
);
946 static bool IsPrivateField(Scope
*, JSAtom
* atom
) {
947 MOZ_ASSERT(atom
->length() > 0);
949 JS::AutoCheckCannotGC nogc
;
950 if (atom
->hasLatin1Chars()) {
951 return atom
->latin1Chars(nogc
)[0] == '#';
954 return atom
->twoByteChars(nogc
)[0] == '#';
957 static bool IsPrivateField(ScopeStencilRef
& scope
, TaggedParserAtomIndex atom
) {
958 if (atom
.isParserAtomIndex()) {
959 const CompilationStencil
& context
= scope
.context_
;
960 ParserAtom
* parserAtom
= context
.parserAtomData
[atom
.toParserAtomIndex()];
961 return parserAtom
->isPrivateName();
965 if (atom
.isWellKnownAtomId()) {
966 const auto& info
= GetWellKnownAtomInfo(atom
.toWellKnownAtomId());
967 // #constructor is a well-known term, but it is invalid private name.
968 MOZ_ASSERT(!(info
.length
> 1 && info
.content
[0] == '#'));
969 } else if (atom
.isLength2StaticParserString()) {
971 ParserAtomsTable::getLength2Content(atom
.toLength2StaticParserString(),
973 // # character is not part of the allowed character of static strings.
974 MOZ_ASSERT(content
[0] != '#');
981 static bool IsPrivateField(const FakeStencilGlobalScope
&,
982 TaggedParserAtomIndex
) {
983 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No private fields on empty global.");
986 bool ScopeContext::cachePrivateFieldsForEval(FrontendContext
* fc
,
987 CompilationInput
& input
,
988 JSObject
* enclosingEnvironment
,
989 const InputScope
& effectiveScope
,
990 ParserAtomsTable
& parserAtoms
) {
991 effectiveScopePrivateFieldCache_
.emplace();
993 // We compute an environment coordinate relative to the effective scope
994 // environment. In order to safely consume these environment coordinates,
995 // we re-map them to include the hops to get the to the effective scope:
996 // see EmitterScope::lookupPrivate
997 uint32_t hops
= effectiveScopeHops
;
998 for (InputScopeIter
si(effectiveScope
); si
; si
++) {
999 if (si
.scope().kind() == ScopeKind::ClassBody
) {
1001 bool success
= si
.scope().match([&](auto& scope_ref
) {
1002 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
1003 if (bi
.kind() == BindingKind::PrivateMethod
||
1004 (bi
.kind() == BindingKind::Synthetic
&&
1005 IsPrivateField(scope_ref
, bi
.name()))) {
1006 InputName
binding(scope_ref
, bi
.name());
1008 binding
.internInto(fc
, parserAtoms
, input
.atomCache
);
1013 NameLocation loc
= NameLocation::DebugEnvironmentCoordinate(
1014 bi
.kind(), hops
, slots
);
1016 if (!effectiveScopePrivateFieldCache_
->put(parserName
, loc
)) {
1017 ReportOutOfMemory(fc
);
1030 // Hops is only consumed by GetAliasedDebugVar, which uses this to
1031 // traverse the debug environment chain. See the [SMDOC] for Debug
1032 // Environment Chain, which explains why we don't check for
1033 // isEnvironment when computing hops here (basically, debug proxies
1034 // pretend all scopes have environments, even if they were actually
1043 static bool NameIsOnEnvironment(FrontendContext
* fc
,
1044 ParserAtomsTable
& parserAtoms
,
1045 CompilationAtomCache
& atomCache
,
1046 InputScope
& scope
, TaggedParserAtomIndex name
) {
1047 JSAtom
* jsname
= nullptr;
1048 return scope
.match([&](auto& scope_ref
) {
1049 if (std::is_same_v
<decltype(scope_ref
), FakeStencilGlobalScope
&>) {
1050 // This condition is added to handle the FakeStencilGlobalScope which is
1051 // used to emulate the global object when delazifying while executing, and
1052 // which is not provided by the Stencil.
1055 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
1056 // If found, the name must already be on the environment or an import,
1057 // or else there is a bug in the closed-over name analysis in the
1059 InputName
binding(scope_ref
, bi
.name());
1060 if (binding
.isEqualTo(fc
, parserAtoms
, atomCache
, name
, &jsname
)) {
1061 BindingLocation::Kind kind
= bi
.location().kind();
1063 if (bi
.hasArgumentSlot()) {
1064 // The following is equivalent to
1065 // functionScope.script()->functionAllowsParameterRedeclaration()
1066 if (scope
.hasMappedArgsObj()) {
1067 // Check for duplicate positional formal parameters.
1068 using InputBindingIter
= decltype(bi
);
1069 for (InputBindingIter
bi2(bi
); bi2
&& bi2
.hasArgumentSlot();
1071 InputName
binding2(scope_ref
, bi2
.name());
1072 if (binding2
.isEqualTo(fc
, parserAtoms
, atomCache
, name
,
1074 kind
= bi2
.location().kind();
1080 return kind
== BindingLocation::Kind::Global
||
1081 kind
== BindingLocation::Kind::Environment
||
1082 kind
== BindingLocation::Kind::Import
;
1086 // If not found, assume it's on the global or dynamically accessed.
1092 NameLocation
ScopeContext::searchInEnclosingScope(FrontendContext
* fc
,
1093 CompilationInput
& input
,
1094 ParserAtomsTable
& parserAtoms
,
1095 TaggedParserAtomIndex name
) {
1096 MOZ_ASSERT(input
.target
==
1097 CompilationInput::CompilationTarget::Delazification
||
1098 input
.target
== CompilationInput::CompilationTarget::Eval
);
1100 MOZ_ASSERT(scopeCache
);
1101 if (scopeCacheGen
!= scopeCache
->getCurrentGeneration()) {
1102 return searchInEnclosingScopeNoCache(fc
, input
, parserAtoms
, name
);
1106 // Catch assertion failures in the NoCache variant before looking at the
1108 NameLocation expect
=
1109 searchInEnclosingScopeNoCache(fc
, input
, parserAtoms
, name
);
1112 NameLocation found
=
1113 searchInEnclosingScopeWithCache(fc
, input
, parserAtoms
, name
);
1114 MOZ_ASSERT(expect
== found
);
1118 NameLocation
ScopeContext::searchInEnclosingScopeWithCache(
1119 FrontendContext
* fc
, CompilationInput
& input
, ParserAtomsTable
& parserAtoms
,
1120 TaggedParserAtomIndex name
) {
1121 MOZ_ASSERT(input
.target
==
1122 CompilationInput::CompilationTarget::Delazification
||
1123 input
.target
== CompilationInput::CompilationTarget::Eval
);
1125 // Generic atom of the looked up name.
1126 GenericAtom
genName(fc
, parserAtoms
, input
.atomCache
, name
);
1127 mozilla::Maybe
<NameLocation
> found
;
1129 // Number of enclosing scope we walked over.
1132 for (InputScopeIter
si(input
.enclosingScope
); si
; si
++) {
1133 MOZ_ASSERT(NameIsOnEnvironment(fc
, parserAtoms
, input
.atomCache
, si
.scope(),
1136 // If the result happens to be in the cached content of the scope that we
1137 // are iterating over, then return it.
1138 si
.scope().match([&](auto& scope_ref
) {
1139 using BindingMapPtr
=
1140 decltype(scopeCache
->lookupScope(scope_ref
, scopeCacheGen
));
1141 BindingMapPtr bindingMapPtr
=
1142 scopeCache
->lookupScope(scope_ref
, scopeCacheGen
);
1143 MOZ_ASSERT(bindingMapPtr
);
1145 auto& bindingMap
= *bindingMapPtr
;
1146 if (bindingMap
.catchAll
.isSome()) {
1147 found
= bindingMap
.catchAll
;
1151 // The scope_ref is given as argument to know where to lookup the key
1152 // index of the hash table if the names have to be compared.
1153 using Lookup
= typename
std::remove_pointer_t
<BindingMapPtr
>::Lookup
;
1154 Lookup
ctxName(scope_ref
, genName
);
1155 auto ptr
= bindingMap
.hashMap
.lookup(ctxName
);
1160 found
.emplace(ptr
->value());
1163 if (found
.isSome()) {
1164 // Cached entries do not store the number of hops, as it might be reused
1165 // by multiple inner functions, which might different number of hops.
1166 found
= found
.map([&hops
](NameLocation loc
) {
1167 if (loc
.kind() != NameLocation::Kind::EnvironmentCoordinate
) {
1170 return loc
.addHops(hops
);
1172 return found
.value();
1175 bool hasEnv
= si
.hasSyntacticEnvironment();
1178 MOZ_ASSERT(hops
< ENVCOORD_HOPS_LIMIT
- 1);
1183 MOZ_CRASH("Malformed scope chain");
1186 NameLocation
ScopeContext::searchInEnclosingScopeNoCache(
1187 FrontendContext
* fc
, CompilationInput
& input
, ParserAtomsTable
& parserAtoms
,
1188 TaggedParserAtomIndex name
) {
1189 MOZ_ASSERT(input
.target
==
1190 CompilationInput::CompilationTarget::Delazification
||
1191 input
.target
== CompilationInput::CompilationTarget::Eval
);
1193 // Cached JSAtom equivalent of the TaggedParserAtomIndex `name` argument.
1194 JSAtom
* jsname
= nullptr;
1196 // NameLocation which contains relative locations to access `name`.
1197 mozilla::Maybe
<NameLocation
> result
;
1199 // Number of enclosing scoep we walked over.
1202 for (InputScopeIter
si(input
.enclosingScope
); si
; si
++) {
1203 MOZ_ASSERT(NameIsOnEnvironment(fc
, parserAtoms
, input
.atomCache
, si
.scope(),
1206 bool hasEnv
= si
.hasSyntacticEnvironment();
1207 switch (si
.kind()) {
1208 case ScopeKind::Function
:
1210 if (si
.scope().funHasExtensibleScope()) {
1211 return NameLocation::Dynamic();
1214 si
.scope().match([&](auto& scope_ref
) {
1215 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
1216 InputName
binding(scope_ref
, bi
.name());
1217 if (!binding
.isEqualTo(fc
, parserAtoms
, input
.atomCache
, name
,
1222 BindingLocation bindLoc
= bi
.location();
1223 // hasMappedArgsObj == script.functionAllowsParameterRedeclaration
1224 if (bi
.hasArgumentSlot() && si
.scope().hasMappedArgsObj()) {
1225 // Check for duplicate positional formal parameters.
1226 using InputBindingIter
= decltype(bi
);
1227 for (InputBindingIter
bi2(bi
); bi2
&& bi2
.hasArgumentSlot();
1229 if (bi
.name() == bi2
.name()) {
1230 bindLoc
= bi2
.location();
1235 MOZ_ASSERT(bindLoc
.kind() == BindingLocation::Kind::Environment
);
1236 result
.emplace(NameLocation::EnvironmentCoordinate(
1237 bi
.kind(), hops
, bindLoc
.slot()));
1244 case ScopeKind::StrictEval
:
1245 case ScopeKind::FunctionBodyVar
:
1246 case ScopeKind::Lexical
:
1247 case ScopeKind::NamedLambda
:
1248 case ScopeKind::StrictNamedLambda
:
1249 case ScopeKind::SimpleCatch
:
1250 case ScopeKind::Catch
:
1251 case ScopeKind::FunctionLexical
:
1252 case ScopeKind::ClassBody
:
1254 si
.scope().match([&](auto& scope_ref
) {
1255 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
1256 InputName
binding(scope_ref
, bi
.name());
1257 if (!binding
.isEqualTo(fc
, parserAtoms
, input
.atomCache
, name
,
1262 // The name must already have been marked as closed
1263 // over. If this assertion is hit, there is a bug in the
1265 BindingLocation bindLoc
= bi
.location();
1266 MOZ_ASSERT(bindLoc
.kind() == BindingLocation::Kind::Environment
);
1267 result
.emplace(NameLocation::EnvironmentCoordinate(
1268 bi
.kind(), hops
, bindLoc
.slot()));
1275 case ScopeKind::Module
:
1276 // This case is used only when delazifying a function inside
1278 // Initial compilation of module doesn't have enlcosing scope.
1280 si
.scope().match([&](auto& scope_ref
) {
1281 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
1282 InputName
binding(scope_ref
, bi
.name());
1283 if (!binding
.isEqualTo(fc
, parserAtoms
, input
.atomCache
, name
,
1288 BindingLocation bindLoc
= bi
.location();
1290 // Imports are on the environment but are indirect
1291 // bindings and must be accessed dynamically instead of
1292 // using an EnvironmentCoordinate.
1293 if (bindLoc
.kind() == BindingLocation::Kind::Import
) {
1294 MOZ_ASSERT(si
.kind() == ScopeKind::Module
);
1295 result
.emplace(NameLocation::Import());
1299 MOZ_ASSERT(bindLoc
.kind() == BindingLocation::Kind::Environment
);
1300 result
.emplace(NameLocation::EnvironmentCoordinate(
1301 bi
.kind(), hops
, bindLoc
.slot()));
1308 case ScopeKind::Eval
:
1309 // As an optimization, if the eval doesn't have its own var
1310 // environment and its immediate enclosing scope is a global
1311 // scope, all accesses are global.
1313 ScopeKind kind
= si
.scope().enclosing().kind();
1314 if (kind
== ScopeKind::Global
|| kind
== ScopeKind::NonSyntactic
) {
1315 return NameLocation::Global(BindingKind::Var
);
1318 return NameLocation::Dynamic();
1320 case ScopeKind::Global
:
1321 return NameLocation::Global(BindingKind::Var
);
1323 case ScopeKind::With
:
1324 case ScopeKind::NonSyntactic
:
1325 return NameLocation::Dynamic();
1327 case ScopeKind::WasmInstance
:
1328 case ScopeKind::WasmFunction
:
1329 MOZ_CRASH("No direct eval inside wasm functions");
1332 if (result
.isSome()) {
1333 return result
.value();
1337 MOZ_ASSERT(hops
< ENVCOORD_HOPS_LIMIT
- 1);
1342 MOZ_CRASH("Malformed scope chain");
1345 mozilla::Maybe
<ScopeContext::EnclosingLexicalBindingKind
>
1346 ScopeContext::lookupLexicalBindingInEnclosingScope(TaggedParserAtomIndex name
) {
1347 auto p
= enclosingLexicalBindingCache_
->lookup(name
);
1349 return mozilla::Nothing();
1352 return mozilla::Some(p
->value());
1355 bool ScopeContext::effectiveScopePrivateFieldCacheHas(
1356 TaggedParserAtomIndex name
) {
1357 return effectiveScopePrivateFieldCache_
->has(name
);
1360 mozilla::Maybe
<NameLocation
> ScopeContext::getPrivateFieldLocation(
1361 TaggedParserAtomIndex name
) {
1362 // The locations returned by this method are only valid for
1363 // traversing debug environments.
1365 // See the comment in cachePrivateFieldsForEval
1366 MOZ_ASSERT(enclosingEnvironmentIsDebugProxy_
);
1367 auto p
= effectiveScopePrivateFieldCache_
->lookup(name
);
1369 return mozilla::Nothing();
1371 return mozilla::Some(p
->value());
1374 bool CompilationInput::initScriptSource(FrontendContext
* fc
) {
1375 source
= do_AddRef(fc
->getAllocator()->new_
<ScriptSource
>());
1380 return source
->initFromOptions(fc
, options
);
1383 bool CompilationInput::initForStandaloneFunctionInNonSyntacticScope(
1384 FrontendContext
* fc
, Handle
<Scope
*> functionEnclosingScope
) {
1385 MOZ_ASSERT(!functionEnclosingScope
->as
<GlobalScope
>().isSyntactic());
1387 target
= CompilationTarget::StandaloneFunctionInNonSyntacticScope
;
1388 if (!initScriptSource(fc
)) {
1391 enclosingScope
= InputScope(functionEnclosingScope
);
1395 FunctionSyntaxKind
CompilationInput::functionSyntaxKind() const {
1396 if (functionFlags().isClassConstructor()) {
1397 if (functionFlags().hasBaseScript() && isDerivedClassConstructor()) {
1398 return FunctionSyntaxKind::DerivedClassConstructor
;
1400 return FunctionSyntaxKind::ClassConstructor
;
1402 if (functionFlags().isMethod()) {
1403 if (functionFlags().hasBaseScript() && isSyntheticFunction()) {
1404 // return FunctionSyntaxKind::FieldInitializer;
1405 MOZ_ASSERT_UNREACHABLE(
1406 "Lazy parsing of class field initializers not supported (yet)");
1408 return FunctionSyntaxKind::Method
;
1410 if (functionFlags().isGetter()) {
1411 return FunctionSyntaxKind::Getter
;
1413 if (functionFlags().isSetter()) {
1414 return FunctionSyntaxKind::Setter
;
1416 if (functionFlags().isArrow()) {
1417 return FunctionSyntaxKind::Arrow
;
1419 return FunctionSyntaxKind::Statement
;
1422 bool CompilationInput::internExtraBindings(FrontendContext
* fc
,
1423 ParserAtomsTable
& parserAtoms
) {
1424 MOZ_ASSERT(hasExtraBindings());
1426 for (auto& bindingInfo
: *maybeExtraBindings_
) {
1427 if (bindingInfo
.isShadowed
) {
1431 const char* chars
= bindingInfo
.nameChars
.get();
1432 auto index
= parserAtoms
.internUtf8(
1433 fc
, reinterpret_cast<const mozilla::Utf8Unit
*>(chars
), strlen(chars
));
1438 bindingInfo
.nameIndex
= index
;
1444 void InputScope::trace(JSTracer
* trc
) {
1445 using ScopePtr
= Scope
*;
1446 if (scope_
.is
<ScopePtr
>()) {
1447 ScopePtr
* ptrAddr
= &scope_
.as
<ScopePtr
>();
1448 TraceNullableRoot(trc
, ptrAddr
, "compilation-input-scope");
1452 void InputScript::trace(JSTracer
* trc
) {
1453 using ScriptPtr
= BaseScript
*;
1454 if (script_
.is
<ScriptPtr
>()) {
1455 ScriptPtr
* ptrAddr
= &script_
.as
<ScriptPtr
>();
1456 TraceNullableRoot(trc
, ptrAddr
, "compilation-input-lazy");
1460 void CompilationInput::trace(JSTracer
* trc
) {
1461 atomCache
.trace(trc
);
1463 enclosingScope
.trace(trc
);
1466 bool CompilationSyntaxParseCache::init(FrontendContext
* fc
, LifoAlloc
& alloc
,
1467 ParserAtomsTable
& parseAtoms
,
1468 CompilationAtomCache
& atomCache
,
1469 const InputScript
& lazy
) {
1470 if (!copyFunctionInfo(fc
, parseAtoms
, atomCache
, lazy
)) {
1473 bool success
= lazy
.raw().match([&](auto& ref
) {
1474 if (!copyScriptInfo(fc
, alloc
, parseAtoms
, atomCache
, ref
)) {
1477 if (!copyClosedOverBindings(fc
, alloc
, parseAtoms
, atomCache
, ref
)) {
1486 isInitialized
= true;
1491 bool CompilationSyntaxParseCache::copyFunctionInfo(
1492 FrontendContext
* fc
, ParserAtomsTable
& parseAtoms
,
1493 CompilationAtomCache
& atomCache
, const InputScript
& lazy
) {
1494 InputName name
= lazy
.displayAtom();
1495 if (!name
.isNull()) {
1496 displayAtom_
= name
.internInto(fc
, parseAtoms
, atomCache
);
1497 if (!displayAtom_
) {
1502 funExtra_
.immutableFlags
= lazy
.immutableFlags();
1503 funExtra_
.extent
= lazy
.extent();
1504 if (funExtra_
.useMemberInitializers()) {
1505 funExtra_
.setMemberInitializers(lazy
.getMemberInitializers());
1511 bool CompilationSyntaxParseCache::copyScriptInfo(
1512 FrontendContext
* fc
, LifoAlloc
& alloc
, ParserAtomsTable
& parseAtoms
,
1513 CompilationAtomCache
& atomCache
, BaseScript
* lazy
) {
1514 using GCThingsSpan
= mozilla::Span
<TaggedScriptThingIndex
>;
1515 using ScriptDataSpan
= mozilla::Span
<ScriptStencil
>;
1516 using ScriptExtraSpan
= mozilla::Span
<ScriptStencilExtra
>;
1517 cachedGCThings_
= GCThingsSpan(nullptr);
1518 cachedScriptData_
= ScriptDataSpan(nullptr);
1519 cachedScriptExtra_
= ScriptExtraSpan(nullptr);
1521 auto gcthings
= lazy
->gcthings();
1522 size_t length
= gcthings
.Length();
1527 // Reduce the length to the first element which is not a function.
1528 for (size_t i
= 0; i
< length
; i
++) {
1529 gc::Cell
* cell
= gcthings
[i
].asCell();
1530 if (!cell
|| !cell
->is
<JSObject
>()) {
1534 MOZ_ASSERT(cell
->as
<JSObject
>()->is
<JSFunction
>());
1537 TaggedScriptThingIndex
* gcThingsData
=
1538 alloc
.newArrayUninitialized
<TaggedScriptThingIndex
>(length
);
1539 ScriptStencil
* scriptData
=
1540 alloc
.newArrayUninitialized
<ScriptStencil
>(length
);
1541 ScriptStencilExtra
* scriptExtra
=
1542 alloc
.newArrayUninitialized
<ScriptStencilExtra
>(length
);
1543 if (!gcThingsData
|| !scriptData
|| !scriptExtra
) {
1544 ReportOutOfMemory(fc
);
1548 for (size_t i
= 0; i
< length
; i
++) {
1549 gc::Cell
* cell
= gcthings
[i
].asCell();
1550 JSFunction
* fun
= &cell
->as
<JSObject
>()->as
<JSFunction
>();
1551 gcThingsData
[i
] = TaggedScriptThingIndex(ScriptIndex(i
));
1552 new (mozilla::KnownNotNull
, &scriptData
[i
]) ScriptStencil();
1553 ScriptStencil
& data
= scriptData
[i
];
1554 new (mozilla::KnownNotNull
, &scriptExtra
[i
]) ScriptStencilExtra();
1555 ScriptStencilExtra
& extra
= scriptExtra
[i
];
1557 if (fun
->fullDisplayAtom()) {
1558 TaggedParserAtomIndex displayAtom
=
1559 parseAtoms
.internJSAtom(fc
, atomCache
, fun
->fullDisplayAtom());
1563 data
.functionAtom
= displayAtom
;
1565 data
.functionFlags
= fun
->flags();
1567 BaseScript
* lazy
= fun
->baseScript();
1568 extra
.immutableFlags
= lazy
->immutableFlags();
1569 extra
.extent
= lazy
->extent();
1571 // Info derived from parent compilation should not be set yet for our inner
1572 // lazy functions. Instead that info will be updated when we finish our
1574 MOZ_ASSERT(lazy
->hasEnclosingScript());
1577 cachedGCThings_
= GCThingsSpan(gcThingsData
, length
);
1578 cachedScriptData_
= ScriptDataSpan(scriptData
, length
);
1579 cachedScriptExtra_
= ScriptExtraSpan(scriptExtra
, length
);
1583 bool CompilationSyntaxParseCache::copyScriptInfo(
1584 FrontendContext
* fc
, LifoAlloc
& alloc
, ParserAtomsTable
& parseAtoms
,
1585 CompilationAtomCache
& atomCache
, const ScriptStencilRef
& lazy
) {
1586 using GCThingsSpan
= mozilla::Span
<TaggedScriptThingIndex
>;
1587 using ScriptDataSpan
= mozilla::Span
<ScriptStencil
>;
1588 using ScriptExtraSpan
= mozilla::Span
<ScriptStencilExtra
>;
1589 cachedGCThings_
= GCThingsSpan(nullptr);
1590 cachedScriptData_
= ScriptDataSpan(nullptr);
1591 cachedScriptExtra_
= ScriptExtraSpan(nullptr);
1593 size_t offset
= lazy
.scriptData().gcThingsOffset
.index
;
1594 size_t length
= lazy
.scriptData().gcThingsLength
;
1599 // Reduce the length to the first element which is not a function.
1600 for (size_t i
= offset
; i
< offset
+ length
; i
++) {
1601 if (!lazy
.context_
.gcThingData
[i
].isFunction()) {
1602 length
= i
- offset
;
1607 TaggedScriptThingIndex
* gcThingsData
=
1608 alloc
.newArrayUninitialized
<TaggedScriptThingIndex
>(length
);
1609 ScriptStencil
* scriptData
=
1610 alloc
.newArrayUninitialized
<ScriptStencil
>(length
);
1611 ScriptStencilExtra
* scriptExtra
=
1612 alloc
.newArrayUninitialized
<ScriptStencilExtra
>(length
);
1613 if (!gcThingsData
|| !scriptData
|| !scriptExtra
) {
1614 ReportOutOfMemory(fc
);
1618 for (size_t i
= 0; i
< length
; i
++) {
1619 ScriptStencilRef inner
{lazy
.context_
,
1620 lazy
.context_
.gcThingData
[i
+ offset
].toFunction()};
1621 gcThingsData
[i
] = TaggedScriptThingIndex(ScriptIndex(i
));
1622 new (mozilla::KnownNotNull
, &scriptData
[i
]) ScriptStencil();
1623 ScriptStencil
& data
= scriptData
[i
];
1624 ScriptStencilExtra
& extra
= scriptExtra
[i
];
1626 InputName name
{inner
, inner
.scriptData().functionAtom
};
1627 if (!name
.isNull()) {
1628 auto displayAtom
= name
.internInto(fc
, parseAtoms
, atomCache
);
1632 data
.functionAtom
= displayAtom
;
1634 data
.functionFlags
= inner
.scriptData().functionFlags
;
1636 extra
= inner
.scriptExtra();
1639 cachedGCThings_
= GCThingsSpan(gcThingsData
, length
);
1640 cachedScriptData_
= ScriptDataSpan(scriptData
, length
);
1641 cachedScriptExtra_
= ScriptExtraSpan(scriptExtra
, length
);
1645 bool CompilationSyntaxParseCache::copyClosedOverBindings(
1646 FrontendContext
* fc
, LifoAlloc
& alloc
, ParserAtomsTable
& parseAtoms
,
1647 CompilationAtomCache
& atomCache
, BaseScript
* lazy
) {
1648 using ClosedOverBindingsSpan
= mozilla::Span
<TaggedParserAtomIndex
>;
1649 closedOverBindings_
= ClosedOverBindingsSpan(nullptr);
1651 // The gcthings() array contains the inner function list followed by the
1652 // closed-over bindings data. Skip the inner function list, as it is already
1653 // cached in cachedGCThings_. See also: BaseScript::CreateLazy.
1654 size_t start
= cachedGCThings_
.Length();
1655 auto gcthings
= lazy
->gcthings();
1656 size_t length
= gcthings
.Length();
1657 MOZ_ASSERT(start
<= length
);
1658 if (length
- start
== 0) {
1662 TaggedParserAtomIndex
* closedOverBindings
=
1663 alloc
.newArrayUninitialized
<TaggedParserAtomIndex
>(length
- start
);
1664 if (!closedOverBindings
) {
1665 ReportOutOfMemory(fc
);
1669 for (size_t i
= start
; i
< length
; i
++) {
1670 gc::Cell
* cell
= gcthings
[i
].asCell();
1672 closedOverBindings
[i
- start
] = TaggedParserAtomIndex::null();
1676 MOZ_ASSERT(cell
->as
<JSString
>()->isAtom());
1678 auto name
= static_cast<JSAtom
*>(cell
);
1679 auto parserAtom
= parseAtoms
.internJSAtom(fc
, atomCache
, name
);
1684 closedOverBindings
[i
- start
] = parserAtom
;
1687 closedOverBindings_
=
1688 ClosedOverBindingsSpan(closedOverBindings
, length
- start
);
1692 bool CompilationSyntaxParseCache::copyClosedOverBindings(
1693 FrontendContext
* fc
, LifoAlloc
& alloc
, ParserAtomsTable
& parseAtoms
,
1694 CompilationAtomCache
& atomCache
, const ScriptStencilRef
& lazy
) {
1695 using ClosedOverBindingsSpan
= mozilla::Span
<TaggedParserAtomIndex
>;
1696 closedOverBindings_
= ClosedOverBindingsSpan(nullptr);
1698 // The gcthings array contains the inner function list followed by the
1699 // closed-over bindings data. Skip the inner function list, as it is already
1700 // cached in cachedGCThings_. See also: BaseScript::CreateLazy.
1701 size_t offset
= lazy
.scriptData().gcThingsOffset
.index
;
1702 size_t length
= lazy
.scriptData().gcThingsLength
;
1703 size_t start
= cachedGCThings_
.Length();
1704 MOZ_ASSERT(start
<= length
);
1705 if (length
- start
== 0) {
1711 // Atoms from the lazy.context (CompilationStencil) are not registered in the
1712 // the parseAtoms table. Thus we create a new span which will contain all the
1714 TaggedParserAtomIndex
* closedOverBindings
=
1715 alloc
.newArrayUninitialized
<TaggedParserAtomIndex
>(length
);
1716 if (!closedOverBindings
) {
1717 ReportOutOfMemory(fc
);
1721 for (size_t i
= 0; i
< length
; i
++) {
1722 auto gcThing
= lazy
.context_
.gcThingData
[i
+ start
];
1723 if (gcThing
.isNull()) {
1724 closedOverBindings
[i
] = TaggedParserAtomIndex::null();
1728 MOZ_ASSERT(gcThing
.isAtom());
1729 InputName
name(lazy
, gcThing
.toAtom());
1730 auto parserAtom
= name
.internInto(fc
, parseAtoms
, atomCache
);
1735 closedOverBindings
[i
] = parserAtom
;
1738 closedOverBindings_
= ClosedOverBindingsSpan(closedOverBindings
, length
);
1742 template <typename T
>
1743 PreAllocateableGCArray
<T
>::~PreAllocateableGCArray() {
1750 template <typename T
>
1751 bool PreAllocateableGCArray
<T
>::allocate(size_t length
) {
1752 MOZ_ASSERT(empty());
1757 inlineElem_
= nullptr;
1761 elems_
= reinterpret_cast<T
*>(js_calloc(sizeof(T
) * length_
));
1769 template <typename T
>
1770 bool PreAllocateableGCArray
<T
>::allocateWith(T init
, size_t length
) {
1771 MOZ_ASSERT(empty());
1780 elems_
= reinterpret_cast<T
*>(js_malloc(sizeof(T
) * length_
));
1785 std::fill(elems_
, elems_
+ length_
, init
);
1789 template <typename T
>
1790 void PreAllocateableGCArray
<T
>::steal(Preallocated
&& buffer
) {
1791 MOZ_ASSERT(empty());
1793 length_
= buffer
.length_
;
1797 inlineElem_
= nullptr;
1801 elems_
= reinterpret_cast<T
*>(buffer
.elems_
);
1802 buffer
.elems_
= nullptr;
1805 for (size_t i
= 0; i
< length_
; i
++) {
1806 MOZ_ASSERT(elems_
[i
] == nullptr);
1811 template <typename T
>
1812 void PreAllocateableGCArray
<T
>::trace(JSTracer
* trc
) {
1818 TraceNullableRoot(trc
, &inlineElem_
, "PreAllocateableGCArray::inlineElem_");
1822 for (size_t i
= 0; i
< length_
; i
++) {
1823 TraceNullableRoot(trc
, &elems_
[i
], "PreAllocateableGCArray::elems_");
1827 template <typename T
>
1828 PreAllocateableGCArray
<T
>::Preallocated::~Preallocated() {
1835 template <typename T
>
1836 bool PreAllocateableGCArray
<T
>::Preallocated::allocate(size_t length
) {
1837 MOZ_ASSERT(empty());
1845 elems_
= reinterpret_cast<uintptr_t*>(js_calloc(sizeof(uintptr_t) * length_
));
1853 template struct js::frontend::PreAllocateableGCArray
<JSFunction
*>;
1854 template struct js::frontend::PreAllocateableGCArray
<js::Scope
*>;
1856 void CompilationAtomCache::trace(JSTracer
* trc
) { atoms_
.trace(trc
); }
1858 void CompilationGCOutput::trace(JSTracer
* trc
) {
1859 TraceNullableRoot(trc
, &script
, "compilation-gc-output-script");
1860 TraceNullableRoot(trc
, &module
, "compilation-gc-output-module");
1861 TraceNullableRoot(trc
, &sourceObject
, "compilation-gc-output-source");
1862 functions
.trace(trc
);
1866 RegExpObject
* RegExpStencil::createRegExp(
1867 JSContext
* cx
, const CompilationAtomCache
& atomCache
) const {
1868 Rooted
<JSAtom
*> atom(cx
, atomCache
.getExistingAtomAt(cx
, atom_
));
1869 return RegExpObject::createSyntaxChecked(cx
, atom
, flags(), TenuredObject
);
1872 RegExpObject
* RegExpStencil::createRegExpAndEnsureAtom(
1873 JSContext
* cx
, FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
,
1874 CompilationAtomCache
& atomCache
) const {
1875 Rooted
<JSAtom
*> atom(cx
, parserAtoms
.toJSAtom(cx
, fc
, atom_
, atomCache
));
1879 return RegExpObject::createSyntaxChecked(cx
, atom
, flags(), TenuredObject
);
1882 AbstractScopePtr
ScopeStencil::enclosing(
1883 CompilationState
& compilationState
) const {
1884 if (hasEnclosing()) {
1885 return AbstractScopePtr(compilationState
, enclosing());
1888 return AbstractScopePtr::compilationEnclosingScope(compilationState
);
1891 Scope
* ScopeStencil::enclosingExistingScope(
1892 const CompilationInput
& input
, const CompilationGCOutput
& gcOutput
) const {
1893 if (hasEnclosing()) {
1894 Scope
* result
= gcOutput
.getScopeNoBaseIndex(enclosing());
1895 MOZ_ASSERT(result
, "Scope must already exist to use this method");
1899 // When creating a scope based on the input and a gc-output, we assume that
1900 // the scope stencil that we are looking at has not been merged into another
1901 // stencil, and thus that we still have the compilation input of the stencil.
1903 // Otherwise, if this was in the case of an input generated from a Stencil
1904 // instead of live-gc values, we would not know its associated gcOutput as it
1905 // might not even have one yet.
1906 return input
.enclosingScope
.variant().as
<Scope
*>();
1909 Scope
* ScopeStencil::createScope(JSContext
* cx
, CompilationInput
& input
,
1910 CompilationGCOutput
& gcOutput
,
1911 BaseParserScopeData
* baseScopeData
) const {
1912 Rooted
<Scope
*> enclosingScope(cx
, enclosingExistingScope(input
, gcOutput
));
1913 return createScope(cx
, input
.atomCache
, enclosingScope
, baseScopeData
);
1916 Scope
* ScopeStencil::createScope(JSContext
* cx
, CompilationAtomCache
& atomCache
,
1917 Handle
<Scope
*> enclosingScope
,
1918 BaseParserScopeData
* baseScopeData
) const {
1920 case ScopeKind::Function
: {
1921 using ScopeType
= FunctionScope
;
1922 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1923 return createSpecificScope
<ScopeType
, CallObject
>(
1924 cx
, atomCache
, enclosingScope
, baseScopeData
);
1926 case ScopeKind::Lexical
:
1927 case ScopeKind::SimpleCatch
:
1928 case ScopeKind::Catch
:
1929 case ScopeKind::NamedLambda
:
1930 case ScopeKind::StrictNamedLambda
:
1931 case ScopeKind::FunctionLexical
: {
1932 using ScopeType
= LexicalScope
;
1933 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1934 return createSpecificScope
<ScopeType
, BlockLexicalEnvironmentObject
>(
1935 cx
, atomCache
, enclosingScope
, baseScopeData
);
1937 case ScopeKind::ClassBody
: {
1938 using ScopeType
= ClassBodyScope
;
1939 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1940 return createSpecificScope
<ScopeType
, BlockLexicalEnvironmentObject
>(
1941 cx
, atomCache
, enclosingScope
, baseScopeData
);
1943 case ScopeKind::FunctionBodyVar
: {
1944 using ScopeType
= VarScope
;
1945 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1946 return createSpecificScope
<ScopeType
, VarEnvironmentObject
>(
1947 cx
, atomCache
, enclosingScope
, baseScopeData
);
1949 case ScopeKind::Global
:
1950 case ScopeKind::NonSyntactic
: {
1951 using ScopeType
= GlobalScope
;
1952 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1953 return createSpecificScope
<ScopeType
, std::nullptr_t
>(
1954 cx
, atomCache
, enclosingScope
, baseScopeData
);
1956 case ScopeKind::Eval
:
1957 case ScopeKind::StrictEval
: {
1958 using ScopeType
= EvalScope
;
1959 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1960 return createSpecificScope
<ScopeType
, VarEnvironmentObject
>(
1961 cx
, atomCache
, enclosingScope
, baseScopeData
);
1963 case ScopeKind::Module
: {
1964 using ScopeType
= ModuleScope
;
1965 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1966 return createSpecificScope
<ScopeType
, ModuleEnvironmentObject
>(
1967 cx
, atomCache
, enclosingScope
, baseScopeData
);
1969 case ScopeKind::With
: {
1970 using ScopeType
= WithScope
;
1971 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1972 return createSpecificScope
<ScopeType
, std::nullptr_t
>(
1973 cx
, atomCache
, enclosingScope
, baseScopeData
);
1975 case ScopeKind::WasmFunction
:
1976 case ScopeKind::WasmInstance
: {
1977 // ScopeStencil does not support WASM
1984 bool CompilationState::prepareSharedDataStorage(FrontendContext
* fc
) {
1985 size_t allScriptCount
= scriptData
.length();
1986 size_t nonLazyScriptCount
= nonLazyFunctionCount
;
1987 if (!scriptData
[0].isFunction()) {
1988 nonLazyScriptCount
++;
1990 return sharedData
.prepareStorageFor(fc
, nonLazyScriptCount
, allScriptCount
);
1993 static bool CreateLazyScript(JSContext
* cx
,
1994 const CompilationAtomCache
& atomCache
,
1995 const CompilationStencil
& stencil
,
1996 CompilationGCOutput
& gcOutput
,
1997 const ScriptStencil
& script
,
1998 const ScriptStencilExtra
& scriptExtra
,
1999 ScriptIndex scriptIndex
, HandleFunction function
) {
2000 Rooted
<ScriptSourceObject
*> sourceObject(cx
, gcOutput
.sourceObject
);
2002 size_t ngcthings
= script
.gcThingsLength
;
2004 Rooted
<BaseScript
*> lazy(
2005 cx
, BaseScript::CreateRawLazy(cx
, ngcthings
, function
, sourceObject
,
2007 scriptExtra
.immutableFlags
));
2013 if (!EmitScriptThingsVector(cx
, atomCache
, stencil
, gcOutput
,
2014 script
.gcthings(stencil
),
2015 lazy
->gcthingsForInit())) {
2020 if (scriptExtra
.useMemberInitializers()) {
2021 lazy
->setMemberInitializers(scriptExtra
.memberInitializers());
2024 function
->initScript(lazy
);
2029 // Parser-generated functions with the same prototype will share the same shape.
2030 // By computing the correct values up front, we can save a lot of time in the
2031 // Object creation code. For simplicity, we focus only on plain synchronous
2032 // functions which are by far the most common.
2034 // NOTE: Keep this in sync with `js::NewFunctionWithProto`.
2035 static JSFunction
* CreateFunctionFast(JSContext
* cx
,
2036 CompilationAtomCache
& atomCache
,
2037 Handle
<SharedShape
*> shape
,
2038 const ScriptStencil
& script
,
2039 const ScriptStencilExtra
& scriptExtra
) {
2041 !scriptExtra
.immutableFlags
.hasFlag(ImmutableScriptFlagsEnum::IsAsync
));
2042 MOZ_ASSERT(!scriptExtra
.immutableFlags
.hasFlag(
2043 ImmutableScriptFlagsEnum::IsGenerator
));
2044 MOZ_ASSERT(!script
.functionFlags
.isAsmJSNative());
2046 FunctionFlags flags
= script
.functionFlags
;
2047 gc::AllocKind allocKind
= flags
.isExtended()
2048 ? gc::AllocKind::FUNCTION_EXTENDED
2049 : gc::AllocKind::FUNCTION
;
2051 JSFunction
* fun
= JSFunction::create(cx
, allocKind
, gc::Heap::Tenured
, shape
);
2056 fun
->setArgCount(scriptExtra
.nargs
);
2057 fun
->setFlags(flags
);
2059 fun
->initScript(nullptr);
2060 fun
->initEnvironment(nullptr);
2062 if (script
.functionAtom
) {
2063 JSAtom
* atom
= atomCache
.getExistingAtomAt(cx
, script
.functionAtom
);
2065 fun
->initAtom(atom
);
2069 fun
->assertFunctionKindIntegrity();
2075 static JSFunction
* CreateFunction(JSContext
* cx
,
2076 CompilationAtomCache
& atomCache
,
2077 const CompilationStencil
& stencil
,
2078 const ScriptStencil
& script
,
2079 const ScriptStencilExtra
& scriptExtra
,
2080 ScriptIndex functionIndex
) {
2081 GeneratorKind generatorKind
=
2082 scriptExtra
.immutableFlags
.hasFlag(ImmutableScriptFlagsEnum::IsGenerator
)
2083 ? GeneratorKind::Generator
2084 : GeneratorKind::NotGenerator
;
2085 FunctionAsyncKind asyncKind
=
2086 scriptExtra
.immutableFlags
.hasFlag(ImmutableScriptFlagsEnum::IsAsync
)
2087 ? FunctionAsyncKind::AsyncFunction
2088 : FunctionAsyncKind::SyncFunction
;
2090 // Determine the new function's proto. This must be done for singleton
2092 RootedObject
proto(cx
);
2093 if (!GetFunctionPrototype(cx
, generatorKind
, asyncKind
, &proto
)) {
2097 gc::AllocKind allocKind
= script
.functionFlags
.isExtended()
2098 ? gc::AllocKind::FUNCTION_EXTENDED
2099 : gc::AllocKind::FUNCTION
;
2100 bool isAsmJS
= script
.functionFlags
.isAsmJSNative();
2102 JSNative maybeNative
= isAsmJS
? InstantiateAsmJS
: nullptr;
2104 Rooted
<JSAtom
*> displayAtom(cx
);
2105 if (script
.functionAtom
) {
2106 displayAtom
.set(atomCache
.getExistingAtomAt(cx
, script
.functionAtom
));
2107 MOZ_ASSERT(displayAtom
);
2110 cx
, NewFunctionWithProto(cx
, maybeNative
, scriptExtra
.nargs
,
2111 script
.functionFlags
, nullptr, displayAtom
,
2112 proto
, allocKind
, TenuredObject
));
2118 RefPtr
<const JS::WasmModule
> asmJS
=
2119 stencil
.asmJS
->moduleMap
.lookup(functionIndex
)->value();
2121 JSObject
* moduleObj
= asmJS
->createObjectForAsmJS(cx
);
2126 fun
->setExtendedSlot(FunctionExtended::ASMJS_MODULE_SLOT
,
2127 ObjectValue(*moduleObj
));
2133 static bool InstantiateAtoms(JSContext
* cx
, FrontendContext
* fc
,
2134 CompilationAtomCache
& atomCache
,
2135 const CompilationStencil
& stencil
) {
2136 return InstantiateMarkedAtoms(cx
, fc
, stencil
.parserAtomData
, atomCache
);
2139 static bool InstantiateScriptSourceObject(JSContext
* cx
,
2140 const JS::InstantiateOptions
& options
,
2141 const CompilationStencil
& stencil
,
2142 CompilationGCOutput
& gcOutput
) {
2143 MOZ_ASSERT(stencil
.source
);
2145 gcOutput
.sourceObject
= ScriptSourceObject::create(cx
, stencil
.source
.get());
2146 if (!gcOutput
.sourceObject
) {
2150 Rooted
<ScriptSourceObject
*> sourceObject(cx
, gcOutput
.sourceObject
);
2151 if (!ScriptSourceObject::initFromOptions(cx
, sourceObject
, options
)) {
2158 // Instantiate ModuleObject. Further initialization is done after the associated
2159 // BaseScript is instantiated in InstantiateTopLevel.
2160 static bool InstantiateModuleObject(JSContext
* cx
, FrontendContext
* fc
,
2161 CompilationAtomCache
& atomCache
,
2162 const CompilationStencil
& stencil
,
2163 CompilationGCOutput
& gcOutput
) {
2164 MOZ_ASSERT(stencil
.isModule());
2166 gcOutput
.module
= ModuleObject::create(cx
);
2167 if (!gcOutput
.module
) {
2171 Rooted
<ModuleObject
*> module(cx
, gcOutput
.module
);
2172 return stencil
.moduleMetadata
->initModule(cx
, fc
, atomCache
, module
);
2175 // Instantiate JSFunctions for each FunctionBox.
2176 static bool InstantiateFunctions(JSContext
* cx
, FrontendContext
* fc
,
2177 CompilationAtomCache
& atomCache
,
2178 const CompilationStencil
& stencil
,
2179 CompilationGCOutput
& gcOutput
) {
2180 using ImmutableFlags
= ImmutableScriptFlagsEnum
;
2182 MOZ_ASSERT(gcOutput
.functions
.length() == stencil
.scriptData
.size());
2184 // Most JSFunctions will be have the same Shape so we can compute it now to
2185 // allow fast object creation. Generators / Async will use the slow path
2187 Rooted
<SharedShape
*> functionShape(
2188 cx
, GlobalObject::getFunctionShapeWithDefaultProto(
2189 cx
, /* extended = */ false));
2190 if (!functionShape
) {
2194 Rooted
<SharedShape
*> extendedShape(
2195 cx
, GlobalObject::getFunctionShapeWithDefaultProto(
2196 cx
, /* extended = */ true));
2197 if (!extendedShape
) {
2202 CompilationStencil::functionScriptStencils(stencil
, gcOutput
)) {
2203 const auto& scriptStencil
= item
.script
;
2204 const auto& scriptExtra
= (*item
.scriptExtra
);
2205 auto index
= item
.index
;
2207 MOZ_ASSERT(!item
.function
);
2209 // Plain functions can use a fast path.
2211 !scriptExtra
.immutableFlags
.hasFlag(ImmutableFlags::IsAsync
) &&
2212 !scriptExtra
.immutableFlags
.hasFlag(ImmutableFlags::IsGenerator
) &&
2213 !scriptStencil
.functionFlags
.isAsmJSNative();
2217 Handle
<SharedShape
*> shape
= scriptStencil
.functionFlags
.isExtended()
2221 CreateFunctionFast(cx
, atomCache
, shape
, scriptStencil
, scriptExtra
);
2223 fun
= CreateFunction(cx
, atomCache
, stencil
, scriptStencil
, scriptExtra
,
2231 // Self-hosted functions may have a canonical name to use when instantiating
2232 // into other realms.
2233 if (scriptStencil
.hasSelfHostedCanonicalName()) {
2234 JSAtom
* canonicalName
= atomCache
.getExistingAtomAt(
2235 cx
, scriptStencil
.selfHostedCanonicalName());
2236 fun
->setAtom(canonicalName
);
2239 gcOutput
.getFunctionNoBaseIndex(index
) = fun
;
2245 // Instantiate Scope for each ScopeStencil.
2247 // This should be called after InstantiateFunctions, given FunctionScope needs
2248 // associated JSFunction pointer, and also should be called before
2249 // InstantiateScriptStencils, given JSScript needs Scope pointer in gc things.
2250 static bool InstantiateScopes(JSContext
* cx
, CompilationInput
& input
,
2251 const CompilationStencil
& stencil
,
2252 CompilationGCOutput
& gcOutput
) {
2253 // While allocating Scope object from ScopeStencil, Scope object for the
2254 // enclosing Scope should already be allocated.
2256 // Enclosing scope of ScopeStencil can be either ScopeStencil or Scope*
2259 // If the enclosing scope is ScopeStencil, it's guaranteed to be earlier
2260 // element in stencil.scopeData, because enclosing_ field holds
2261 // index into it, and newly created ScopeStencil is pushed back to the array.
2263 // If the enclosing scope is Scope*, it's CompilationInput.enclosingScope.
2265 MOZ_ASSERT(stencil
.scopeData
.size() == stencil
.scopeNames
.size());
2266 size_t scopeCount
= stencil
.scopeData
.size();
2267 for (size_t i
= 0; i
< scopeCount
; i
++) {
2268 Scope
* scope
= stencil
.scopeData
[i
].createScope(cx
, input
, gcOutput
,
2269 stencil
.scopeNames
[i
]);
2273 gcOutput
.scopes
[i
] = scope
;
2279 // Instantiate js::BaseScripts from ScriptStencils for inner functions of the
2280 // compilation. Note that standalone functions and functions being delazified
2281 // are handled below with other top-levels.
2282 static bool InstantiateScriptStencils(JSContext
* cx
,
2283 CompilationAtomCache
& atomCache
,
2284 const CompilationStencil
& stencil
,
2285 CompilationGCOutput
& gcOutput
) {
2286 MOZ_ASSERT(stencil
.isInitialStencil());
2288 Rooted
<JSFunction
*> fun(cx
);
2290 CompilationStencil::functionScriptStencils(stencil
, gcOutput
)) {
2291 auto& scriptStencil
= item
.script
;
2292 auto* scriptExtra
= item
.scriptExtra
;
2293 fun
= item
.function
;
2294 auto index
= item
.index
;
2295 if (scriptStencil
.hasSharedData()) {
2296 // If the function was not referenced by enclosing script's bytecode, we
2297 // do not generate a BaseScript for it. For example, `(function(){});`.
2299 // `wasEmittedByEnclosingScript` is false also for standalone
2300 // functions. They are handled in InstantiateTopLevel.
2301 if (!scriptStencil
.wasEmittedByEnclosingScript()) {
2305 RootedScript
script(
2306 cx
, JSScript::fromStencil(cx
, atomCache
, stencil
, gcOutput
, index
));
2311 if (scriptStencil
.allowRelazify()) {
2312 MOZ_ASSERT(script
->isRelazifiable());
2313 script
->setAllowRelazify();
2315 } else if (scriptStencil
.functionFlags
.isAsmJSNative()) {
2316 MOZ_ASSERT(fun
->isAsmJSNative());
2318 MOZ_ASSERT(fun
->isIncomplete());
2319 if (!CreateLazyScript(cx
, atomCache
, stencil
, gcOutput
, scriptStencil
,
2320 *scriptExtra
, index
, fun
)) {
2329 // Instantiate the Stencil for the top-level script of the compilation. This
2330 // includes standalone functions and functions being delazified.
2331 static bool InstantiateTopLevel(JSContext
* cx
, CompilationInput
& input
,
2332 const CompilationStencil
& stencil
,
2333 CompilationGCOutput
& gcOutput
) {
2334 const ScriptStencil
& scriptStencil
=
2335 stencil
.scriptData
[CompilationStencil::TopLevelIndex
];
2337 // Top-level asm.js does not generate a JSScript.
2338 if (scriptStencil
.functionFlags
.isAsmJSNative()) {
2342 MOZ_ASSERT(scriptStencil
.hasSharedData());
2343 MOZ_ASSERT(stencil
.sharedData
.get(CompilationStencil::TopLevelIndex
));
2345 if (!stencil
.isInitialStencil()) {
2346 MOZ_ASSERT(input
.lazyOuterBaseScript());
2347 RootedScript
script(cx
,
2348 JSScript::CastFromLazy(input
.lazyOuterBaseScript()));
2349 if (!JSScript::fullyInitFromStencil(cx
, input
.atomCache
, stencil
, gcOutput
,
2351 CompilationStencil::TopLevelIndex
)) {
2355 if (scriptStencil
.allowRelazify()) {
2356 MOZ_ASSERT(script
->isRelazifiable());
2357 script
->setAllowRelazify();
2360 gcOutput
.script
= script
;
2365 JSScript::fromStencil(cx
, input
.atomCache
, stencil
, gcOutput
,
2366 CompilationStencil::TopLevelIndex
);
2367 if (!gcOutput
.script
) {
2371 if (scriptStencil
.allowRelazify()) {
2372 MOZ_ASSERT(gcOutput
.script
->isRelazifiable());
2373 gcOutput
.script
->setAllowRelazify();
2376 const ScriptStencilExtra
& scriptExtra
=
2377 stencil
.scriptExtra
[CompilationStencil::TopLevelIndex
];
2379 // Finish initializing the ModuleObject if needed.
2380 if (scriptExtra
.isModule()) {
2381 RootedScript
script(cx
, gcOutput
.script
);
2382 Rooted
<ModuleObject
*> module(cx
, gcOutput
.module
);
2384 script
->outermostScope()->as
<ModuleScope
>().initModule(module
);
2386 module
->initScriptSlots(script
);
2388 if (!ModuleObject::createEnvironment(cx
, module
)) {
2392 if (!ModuleObject::Freeze(cx
, module
)) {
2400 // When a function is first referenced by enclosing script's bytecode, we need
2401 // to update it with information determined by the BytecodeEmitter. This applies
2402 // to both initial and delazification parses. The functions being update may or
2403 // may not have bytecode at this point.
2404 static void UpdateEmittedInnerFunctions(JSContext
* cx
,
2405 CompilationAtomCache
& atomCache
,
2406 const CompilationStencil
& stencil
,
2407 CompilationGCOutput
& gcOutput
) {
2409 CompilationStencil::functionScriptStencils(stencil
, gcOutput
)) {
2410 auto& scriptStencil
= item
.script
;
2411 auto& fun
= item
.function
;
2412 if (!scriptStencil
.wasEmittedByEnclosingScript()) {
2416 if (scriptStencil
.functionFlags
.isAsmJSNative() ||
2417 fun
->baseScript()->hasBytecode()) {
2418 // Non-lazy inner functions don't use the enclosingScope_ field.
2419 MOZ_ASSERT(!scriptStencil
.hasLazyFunctionEnclosingScopeIndex());
2421 // Apply updates from FunctionEmitter::emitLazy().
2422 BaseScript
* script
= fun
->baseScript();
2424 ScopeIndex index
= scriptStencil
.lazyFunctionEnclosingScopeIndex();
2425 Scope
* scope
= gcOutput
.getScopeNoBaseIndex(index
);
2426 script
->setEnclosingScope(scope
);
2428 // Inferred and Guessed names are computed by BytecodeEmitter and so may
2429 // need to be applied to existing JSFunctions during delazification.
2430 if (fun
->fullDisplayAtom() == nullptr) {
2431 JSAtom
* funcAtom
= nullptr;
2432 if (scriptStencil
.functionFlags
.hasInferredName() ||
2433 scriptStencil
.functionFlags
.hasGuessedAtom()) {
2435 atomCache
.getExistingAtomAt(cx
, scriptStencil
.functionAtom
);
2436 MOZ_ASSERT(funcAtom
);
2438 if (scriptStencil
.functionFlags
.hasInferredName()) {
2439 fun
->setInferredName(funcAtom
);
2441 if (scriptStencil
.functionFlags
.hasGuessedAtom()) {
2442 fun
->setGuessedAtom(funcAtom
);
2449 // During initial parse we must link lazy-functions-inside-lazy-functions to
2450 // their enclosing script.
2451 static void LinkEnclosingLazyScript(const CompilationStencil
& stencil
,
2452 CompilationGCOutput
& gcOutput
) {
2454 CompilationStencil::functionScriptStencils(stencil
, gcOutput
)) {
2455 auto& scriptStencil
= item
.script
;
2456 auto& fun
= item
.function
;
2457 if (!scriptStencil
.functionFlags
.hasBaseScript()) {
2461 if (!fun
->baseScript()) {
2465 if (fun
->baseScript()->hasBytecode()) {
2469 BaseScript
* script
= fun
->baseScript();
2470 MOZ_ASSERT(!script
->hasBytecode());
2472 for (auto inner
: script
->gcthings()) {
2473 if (!inner
.is
<JSObject
>()) {
2476 JSFunction
* innerFun
= &inner
.as
<JSObject
>().as
<JSFunction
>();
2478 MOZ_ASSERT(innerFun
->hasBaseScript(),
2479 "inner function should have base script");
2480 if (!innerFun
->hasBaseScript()) {
2484 // Check for the case that the inner function has the base script flag,
2485 // but still doesn't have the actual base script pointer.
2486 // `baseScript` method asserts the pointer itself, so no extra MOZ_ASSERT
2488 if (!innerFun
->baseScript()) {
2492 innerFun
->setEnclosingLazyScript(script
);
2498 // Some fields aren't used in delazification, given the target functions and
2499 // scripts are already instantiated, but they still should match.
2500 static void AssertDelazificationFieldsMatch(const CompilationStencil
& stencil
,
2501 CompilationGCOutput
& gcOutput
) {
2503 CompilationStencil::functionScriptStencils(stencil
, gcOutput
)) {
2504 auto& scriptStencil
= item
.script
;
2505 auto* scriptExtra
= item
.scriptExtra
;
2506 auto& fun
= item
.function
;
2508 MOZ_ASSERT(scriptExtra
== nullptr);
2510 // Names are updated by UpdateInnerFunctions.
2511 constexpr uint16_t HAS_INFERRED_NAME
=
2512 uint16_t(FunctionFlags::Flags::HAS_INFERRED_NAME
);
2513 constexpr uint16_t HAS_GUESSED_ATOM
=
2514 uint16_t(FunctionFlags::Flags::HAS_GUESSED_ATOM
);
2515 constexpr uint16_t MUTABLE_FLAGS
=
2516 uint16_t(FunctionFlags::Flags::MUTABLE_FLAGS
);
2517 constexpr uint16_t acceptableDifferenceForFunction
=
2518 HAS_INFERRED_NAME
| HAS_GUESSED_ATOM
| MUTABLE_FLAGS
;
2520 MOZ_ASSERT((fun
->flags().toRaw() | acceptableDifferenceForFunction
) ==
2521 (scriptStencil
.functionFlags
.toRaw() |
2522 acceptableDifferenceForFunction
));
2524 // Delazification shouldn't delazify inner scripts.
2525 MOZ_ASSERT_IF(item
.index
== CompilationStencil::TopLevelIndex
,
2526 scriptStencil
.hasSharedData());
2527 MOZ_ASSERT_IF(item
.index
> CompilationStencil::TopLevelIndex
,
2528 !scriptStencil
.hasSharedData());
2533 // When delazifying, use the existing JSFunctions. The initial and delazifying
2534 // parse are required to generate the same sequence of functions for lazy
2535 // parsing to work at all.
2536 static void FunctionsFromExistingLazy(CompilationInput
& input
,
2537 CompilationGCOutput
& gcOutput
) {
2538 MOZ_ASSERT(!gcOutput
.functions
[0]);
2540 size_t instantiatedFunIndex
= 0;
2541 gcOutput
.functions
[instantiatedFunIndex
++] = input
.function();
2543 for (JS::GCCellPtr elem
: input
.lazyOuterBaseScript()->gcthings()) {
2544 if (!elem
.is
<JSObject
>()) {
2547 JSFunction
* fun
= &elem
.as
<JSObject
>().as
<JSFunction
>();
2548 gcOutput
.functions
[instantiatedFunIndex
++] = fun
;
2552 void CompilationStencil::borrowFromExtensibleCompilationStencil(
2553 ExtensibleCompilationStencil
& extensibleStencil
) {
2554 canLazilyParse
= extensibleStencil
.canLazilyParse
;
2555 functionKey
= extensibleStencil
.functionKey
;
2557 // Borrow the vector content as span.
2558 scriptData
= extensibleStencil
.scriptData
;
2559 scriptExtra
= extensibleStencil
.scriptExtra
;
2561 gcThingData
= extensibleStencil
.gcThingData
;
2563 scopeData
= extensibleStencil
.scopeData
;
2564 scopeNames
= extensibleStencil
.scopeNames
;
2566 regExpData
= extensibleStencil
.regExpData
;
2567 bigIntData
= extensibleStencil
.bigIntData
;
2568 objLiteralData
= extensibleStencil
.objLiteralData
;
2570 // Borrow the parser atoms as span.
2571 parserAtomData
= extensibleStencil
.parserAtoms
.entries_
;
2573 // Borrow container.
2574 sharedData
.setBorrow(&extensibleStencil
.sharedData
);
2576 // Share ref-counted data.
2577 source
= extensibleStencil
.source
;
2578 asmJS
= extensibleStencil
.asmJS
;
2579 moduleMetadata
= extensibleStencil
.moduleMetadata
;
2583 void CompilationStencil::assertBorrowingFromExtensibleCompilationStencil(
2584 const ExtensibleCompilationStencil
& extensibleStencil
) const {
2585 MOZ_ASSERT(canLazilyParse
== extensibleStencil
.canLazilyParse
);
2586 MOZ_ASSERT(functionKey
== extensibleStencil
.functionKey
);
2588 AssertBorrowingSpan(scriptData
, extensibleStencil
.scriptData
);
2589 AssertBorrowingSpan(scriptExtra
, extensibleStencil
.scriptExtra
);
2591 AssertBorrowingSpan(gcThingData
, extensibleStencil
.gcThingData
);
2593 AssertBorrowingSpan(scopeData
, extensibleStencil
.scopeData
);
2594 AssertBorrowingSpan(scopeNames
, extensibleStencil
.scopeNames
);
2596 AssertBorrowingSpan(regExpData
, extensibleStencil
.regExpData
);
2597 AssertBorrowingSpan(bigIntData
, extensibleStencil
.bigIntData
);
2598 AssertBorrowingSpan(objLiteralData
, extensibleStencil
.objLiteralData
);
2600 AssertBorrowingSpan(parserAtomData
, extensibleStencil
.parserAtoms
.entries_
);
2602 MOZ_ASSERT(sharedData
.isBorrow());
2603 MOZ_ASSERT(sharedData
.asBorrow() == &extensibleStencil
.sharedData
);
2605 MOZ_ASSERT(source
== extensibleStencil
.source
);
2606 MOZ_ASSERT(asmJS
== extensibleStencil
.asmJS
);
2607 MOZ_ASSERT(moduleMetadata
== extensibleStencil
.moduleMetadata
);
2611 CompilationStencil::CompilationStencil(
2612 UniquePtr
<ExtensibleCompilationStencil
>&& extensibleStencil
)
2613 : alloc(LifoAllocChunkSize
) {
2614 ownedBorrowStencil
= std::move(extensibleStencil
);
2616 storageType
= StorageType::OwnedExtensible
;
2618 borrowFromExtensibleCompilationStencil(*ownedBorrowStencil
);
2621 assertNoExternalDependency();
2626 bool CompilationStencil::instantiateStencils(JSContext
* cx
,
2627 CompilationInput
& input
,
2628 const CompilationStencil
& stencil
,
2629 CompilationGCOutput
& gcOutput
) {
2630 AutoReportFrontendContext
fc(cx
);
2631 if (!prepareForInstantiate(&fc
, input
.atomCache
, stencil
, gcOutput
)) {
2635 return instantiateStencilAfterPreparation(cx
, input
, stencil
, gcOutput
);
2639 bool CompilationStencil::instantiateStencilAfterPreparation(
2640 JSContext
* cx
, CompilationInput
& input
, const CompilationStencil
& stencil
,
2641 CompilationGCOutput
& gcOutput
) {
2642 // Distinguish between the initial (possibly lazy) compile and any subsequent
2643 // delazification compiles. Delazification will update existing GC things.
2644 bool isInitialParse
= stencil
.isInitialStencil();
2645 MOZ_ASSERT(stencil
.isInitialStencil() == input
.isInitialStencil());
2647 // Assert the consistency between the compile option and the target global.
2648 MOZ_ASSERT_IF(cx
->realm()->behaviors().discardSource(),
2649 !stencil
.canLazilyParse
);
2651 CompilationAtomCache
& atomCache
= input
.atomCache
;
2652 const JS::InstantiateOptions
options(input
.options
);
2654 // Phase 1: Instantiate JSAtom/JSStrings.
2655 AutoReportFrontendContext
fc(cx
);
2656 if (!InstantiateAtoms(cx
, &fc
, atomCache
, stencil
)) {
2660 // Phase 2: Instantiate ScriptSourceObject, ModuleObject, JSFunctions.
2661 if (isInitialParse
) {
2662 if (!InstantiateScriptSourceObject(cx
, options
, stencil
, gcOutput
)) {
2666 if (stencil
.moduleMetadata
) {
2667 // The enclosing script of a module is always the global scope. Fetch the
2668 // scope of the current global and update input data.
2669 MOZ_ASSERT(input
.enclosingScope
.isNull());
2670 input
.enclosingScope
= InputScope(&cx
->global()->emptyGlobalScope());
2671 MOZ_ASSERT(input
.enclosingScope
.environmentChainLength() ==
2672 ModuleScope::EnclosingEnvironmentChainLength
);
2674 if (!InstantiateModuleObject(cx
, &fc
, atomCache
, stencil
, gcOutput
)) {
2679 if (!InstantiateFunctions(cx
, &fc
, atomCache
, stencil
, gcOutput
)) {
2684 stencil
.scriptData
[CompilationStencil::TopLevelIndex
].isFunction());
2686 // FunctionKey is used when caching to map a delazification stencil to a
2687 // specific lazy script. It is not used by instantiation, but we should
2688 // ensure it is correctly defined.
2689 MOZ_ASSERT(stencil
.functionKey
== input
.extent().toFunctionKey());
2691 FunctionsFromExistingLazy(input
, gcOutput
);
2692 MOZ_ASSERT(gcOutput
.functions
.length() == stencil
.scriptData
.size());
2695 AssertDelazificationFieldsMatch(stencil
, gcOutput
);
2699 // Phase 3: Instantiate js::Scopes.
2700 if (!InstantiateScopes(cx
, input
, stencil
, gcOutput
)) {
2704 // Phase 4: Instantiate (inner) BaseScripts.
2705 if (isInitialParse
) {
2706 if (!InstantiateScriptStencils(cx
, atomCache
, stencil
, gcOutput
)) {
2711 // Phase 5: Finish top-level handling
2712 if (!InstantiateTopLevel(cx
, input
, stencil
, gcOutput
)) {
2716 // !! Must be infallible from here forward !!
2718 // Phase 6: Update lazy scripts.
2719 if (stencil
.canLazilyParse
) {
2720 UpdateEmittedInnerFunctions(cx
, atomCache
, stencil
, gcOutput
);
2722 if (isInitialParse
) {
2723 LinkEnclosingLazyScript(stencil
, gcOutput
);
2730 // The top-level self-hosted script is created and executed in each realm that
2731 // needs it. While the stencil has a gcthings list for the various top-level
2732 // functions, we use special machinery to create them on demand. So instead we
2733 // use a placeholder JSFunction that should never be called.
2734 static bool SelfHostedDummyFunction(JSContext
* cx
, unsigned argc
,
2736 MOZ_CRASH("Self-hosting top-level should not use functions directly");
2739 bool CompilationStencil::instantiateSelfHostedAtoms(
2740 JSContext
* cx
, AtomSet
& atomSet
, CompilationAtomCache
& atomCache
) const {
2741 MOZ_ASSERT(isInitialStencil());
2743 // We must instantiate atoms during startup so they can be made permanent
2744 // across multiple runtimes.
2745 AutoReportFrontendContext
fc(cx
);
2746 return InstantiateMarkedAtomsAsPermanent(cx
, &fc
, atomSet
, parserAtomData
,
2750 JSScript
* CompilationStencil::instantiateSelfHostedTopLevelForRealm(
2751 JSContext
* cx
, CompilationInput
& input
) {
2752 MOZ_ASSERT(isInitialStencil());
2754 Rooted
<CompilationGCOutput
> gcOutput(cx
);
2756 gcOutput
.get().sourceObject
= SelfHostingScriptSourceObject(cx
);
2757 if (!gcOutput
.get().sourceObject
) {
2761 // The top-level script has ScriptIndex references in its gcthings list, but
2762 // we do not want to instantiate those functions here since they are instead
2763 // created on demand from the stencil. Create a dummy function and populate
2764 // the functions array of the CompilationGCOutput with references to it.
2765 RootedFunction
dummy(
2766 cx
, NewNativeFunction(cx
, SelfHostedDummyFunction
, 0, nullptr));
2771 if (!gcOutput
.get().functions
.allocateWith(dummy
, scriptData
.size())) {
2772 ReportOutOfMemory(cx
);
2776 if (!InstantiateTopLevel(cx
, input
, *this, gcOutput
.get())) {
2780 return gcOutput
.get().script
;
2783 JSFunction
* CompilationStencil::instantiateSelfHostedLazyFunction(
2784 JSContext
* cx
, CompilationAtomCache
& atomCache
, ScriptIndex index
,
2785 Handle
<JSAtom
*> name
) {
2786 GeneratorKind generatorKind
= scriptExtra
[index
].immutableFlags
.hasFlag(
2787 ImmutableScriptFlagsEnum::IsGenerator
)
2788 ? GeneratorKind::Generator
2789 : GeneratorKind::NotGenerator
;
2790 FunctionAsyncKind asyncKind
= scriptExtra
[index
].immutableFlags
.hasFlag(
2791 ImmutableScriptFlagsEnum::IsAsync
)
2792 ? FunctionAsyncKind::AsyncFunction
2793 : FunctionAsyncKind::SyncFunction
;
2795 Rooted
<JSAtom
*> funName(cx
);
2796 if (scriptData
[index
].hasSelfHostedCanonicalName()) {
2797 // SetCanonicalName was used to override the name.
2798 funName
= atomCache
.getExistingAtomAt(
2799 cx
, scriptData
[index
].selfHostedCanonicalName());
2801 // Our caller has a name it wants to use.
2804 MOZ_ASSERT(scriptData
[index
].functionAtom
);
2805 funName
= atomCache
.getExistingAtomAt(cx
, scriptData
[index
].functionAtom
);
2808 RootedObject
proto(cx
);
2809 if (!GetFunctionPrototype(cx
, generatorKind
, asyncKind
, &proto
)) {
2813 RootedObject
env(cx
, &cx
->global()->lexicalEnvironment());
2817 NewFunctionWithProto(cx
, nullptr, scriptExtra
[index
].nargs
,
2818 scriptData
[index
].functionFlags
, env
, funName
, proto
,
2819 gc::AllocKind::FUNCTION_EXTENDED
, TenuredObject
));
2824 fun
->initSelfHostedLazyScript(&cx
->runtime()->selfHostedLazyScript
.ref());
2826 JSAtom
* selfHostedName
=
2827 atomCache
.getExistingAtomAt(cx
, scriptData
[index
].functionAtom
);
2828 SetClonedSelfHostedFunctionName(fun
, selfHostedName
->asPropertyName());
2833 bool CompilationStencil::delazifySelfHostedFunction(
2834 JSContext
* cx
, CompilationAtomCache
& atomCache
, ScriptIndexRange range
,
2835 HandleFunction fun
) {
2836 // Determine the equivalent ScopeIndex range by looking at the outermost scope
2837 // of the scripts defining the range. Take special care if this is the last
2838 // script in the list.
2839 auto getOutermostScope
= [this](ScriptIndex scriptIndex
) -> ScopeIndex
{
2840 MOZ_ASSERT(scriptData
[scriptIndex
].hasSharedData());
2841 auto gcthings
= scriptData
[scriptIndex
].gcthings(*this);
2842 return gcthings
[GCThingIndex::outermostScopeIndex()].toScope();
2844 ScopeIndex scopeIndex
= getOutermostScope(range
.start
);
2845 ScopeIndex scopeLimit
= (range
.limit
< scriptData
.size())
2846 ? getOutermostScope(range
.limit
)
2847 : ScopeIndex(scopeData
.size());
2849 // Prepare to instantiate by allocating the output arrays. We also set a base
2850 // index to avoid allocations in most cases.
2851 AutoReportFrontendContext
fc(cx
);
2852 Rooted
<CompilationGCOutput
> gcOutput(cx
);
2853 if (!gcOutput
.get().ensureAllocatedWithBaseIndex(
2854 &fc
, range
.start
, range
.limit
, scopeIndex
, scopeLimit
)) {
2858 // Phase 1: Instantiate JSAtoms.
2859 // NOTE: The self-hosted atoms are all "permanent" and the
2860 // CompilationAtomCache is already stored on the JSRuntime.
2862 // Phase 2: Instantiate ScriptSourceObject, ModuleObject, JSFunctions.
2864 // Get the corresponding ScriptSourceObject to use in current realm.
2865 gcOutput
.get().sourceObject
= SelfHostingScriptSourceObject(cx
);
2866 if (!gcOutput
.get().sourceObject
) {
2870 size_t instantiatedFunIndex
= 0;
2872 // Delazification target function.
2873 gcOutput
.get().functions
[instantiatedFunIndex
++] = fun
;
2875 // Allocate inner functions. Self-hosted functions do not allocate these with
2876 // the initial function.
2877 for (size_t i
= range
.start
+ 1; i
< range
.limit
; i
++) {
2878 JSFunction
* innerFun
= CreateFunction(cx
, atomCache
, *this, scriptData
[i
],
2879 scriptExtra
[i
], ScriptIndex(i
));
2883 gcOutput
.get().functions
[instantiatedFunIndex
++] = innerFun
;
2886 // Phase 3: Instantiate js::Scopes.
2887 // NOTE: When the enclosing scope is not a stencil, directly use the
2888 // `emptyGlobalScope` instead of reading from CompilationInput. This is
2889 // a special case for self-hosted delazification that allows us to reuse
2890 // the CompilationInput between different realms.
2891 size_t instantiatedScopeIndex
= 0;
2892 for (size_t i
= scopeIndex
; i
< scopeLimit
; i
++) {
2893 ScopeStencil
& data
= scopeData
[i
];
2894 Rooted
<Scope
*> enclosingScope(
2895 cx
, data
.hasEnclosing() ? gcOutput
.get().getScope(data
.enclosing())
2896 : &cx
->global()->emptyGlobalScope());
2899 data
.createScope(cx
, atomCache
, enclosingScope
, scopeNames
[i
]);
2903 gcOutput
.get().scopes
[instantiatedScopeIndex
++] = scope
;
2906 // Phase 4: Instantiate (inner) BaseScripts.
2907 ScriptIndex
innerStart(range
.start
+ 1);
2908 for (size_t i
= innerStart
; i
< range
.limit
; i
++) {
2909 if (!JSScript::fromStencil(cx
, atomCache
, *this, gcOutput
.get(),
2915 // Phase 5: Finish top-level handling
2916 // NOTE: We do not have a `CompilationInput` handy here, so avoid using the
2917 // `InstantiateTopLevel` helper and directly create the JSScript. Our
2918 // caller also handles the `AllowRelazify` flag for us since self-hosted
2919 // delazification is a special case.
2920 if (!JSScript::fromStencil(cx
, atomCache
, *this, gcOutput
.get(),
2925 // Phase 6: Update lazy scripts.
2926 // NOTE: Self-hosting is always fully parsed so there is nothing to do here.
2932 bool CompilationStencil::prepareForInstantiate(
2933 FrontendContext
* fc
, CompilationAtomCache
& atomCache
,
2934 const CompilationStencil
& stencil
, CompilationGCOutput
& gcOutput
) {
2935 // Allocate the `gcOutput` arrays.
2936 if (!gcOutput
.ensureAllocated(fc
, stencil
.scriptData
.size(),
2937 stencil
.scopeData
.size())) {
2941 return atomCache
.allocate(fc
, stencil
.parserAtomData
.size());
2945 bool CompilationStencil::prepareForInstantiate(
2946 FrontendContext
* fc
, const CompilationStencil
& stencil
,
2947 PreallocatedCompilationGCOutput
& gcOutput
) {
2948 return gcOutput
.allocate(fc
, stencil
.scriptData
.size(),
2949 stencil
.scopeData
.size());
2952 bool CompilationStencil::serializeStencils(JSContext
* cx
,
2953 CompilationInput
& input
,
2954 JS::TranscodeBuffer
& buf
,
2955 bool* succeededOut
) const {
2957 *succeededOut
= false;
2959 AutoReportFrontendContext
fc(cx
);
2960 XDRStencilEncoder
encoder(&fc
, buf
);
2962 XDRResult res
= encoder
.codeStencil(*this);
2964 if (JS::IsTranscodeFailureResult(res
.unwrapErr())) {
2968 MOZ_ASSERT(res
.unwrapErr() == JS::TranscodeResult::Throw
);
2974 *succeededOut
= true;
2979 bool CompilationStencil::deserializeStencils(
2980 FrontendContext
* fc
, const JS::ReadOnlyCompileOptions
& compileOptions
,
2981 const JS::TranscodeRange
& range
, bool* succeededOut
) {
2983 *succeededOut
= false;
2985 MOZ_ASSERT(parserAtomData
.empty());
2986 XDRStencilDecoder
decoder(fc
, range
);
2987 JS::DecodeOptions
options(compileOptions
);
2989 XDRResult res
= decoder
.codeStencil(options
, *this);
2991 if (JS::IsTranscodeFailureResult(res
.unwrapErr())) {
2994 MOZ_ASSERT(res
.unwrapErr() == JS::TranscodeResult::Throw
);
3000 *succeededOut
= true;
3005 ExtensibleCompilationStencil::ExtensibleCompilationStencil(ScriptSource
* source
)
3006 : alloc(CompilationStencil::LifoAllocChunkSize
),
3008 parserAtoms(alloc
) {}
3010 ExtensibleCompilationStencil::ExtensibleCompilationStencil(
3011 CompilationInput
& input
)
3012 : canLazilyParse(CanLazilyParse(input
.options
)),
3013 alloc(CompilationStencil::LifoAllocChunkSize
),
3014 source(input
.source
),
3015 parserAtoms(alloc
) {}
3017 ExtensibleCompilationStencil::ExtensibleCompilationStencil(
3018 const JS::ReadOnlyCompileOptions
& options
, RefPtr
<ScriptSource
> source
)
3019 : canLazilyParse(CanLazilyParse(options
)),
3020 alloc(CompilationStencil::LifoAllocChunkSize
),
3021 source(std::move(source
)),
3022 parserAtoms(alloc
) {}
3024 CompilationState::CompilationState(FrontendContext
* fc
,
3025 LifoAllocScope
& parserAllocScope
,
3026 CompilationInput
& input
)
3027 : ExtensibleCompilationStencil(input
),
3028 directives(input
.options
.forceStrictMode()),
3030 parserAllocScope(parserAllocScope
),
3033 BorrowingCompilationStencil::BorrowingCompilationStencil(
3034 ExtensibleCompilationStencil
& extensibleStencil
)
3035 : CompilationStencil(extensibleStencil
.source
) {
3036 storageType
= StorageType::Borrowed
;
3038 borrowFromExtensibleCompilationStencil(extensibleStencil
);
3041 SharedDataContainer::~SharedDataContainer() {
3044 } else if (isSingle()) {
3045 asSingle()->Release();
3046 } else if (isVector()) {
3047 js_delete(asVector());
3048 } else if (isMap()) {
3051 MOZ_ASSERT(isBorrow());
3056 bool SharedDataContainer::initVector(FrontendContext
* fc
) {
3057 MOZ_ASSERT(isEmpty());
3059 auto* vec
= js_new
<SharedDataVector
>();
3061 ReportOutOfMemory(fc
);
3064 data_
= uintptr_t(vec
) | VectorTag
;
3068 bool SharedDataContainer::initMap(FrontendContext
* fc
) {
3069 MOZ_ASSERT(isEmpty());
3071 auto* map
= js_new
<SharedDataMap
>();
3073 ReportOutOfMemory(fc
);
3076 data_
= uintptr_t(map
) | MapTag
;
3080 bool SharedDataContainer::prepareStorageFor(FrontendContext
* fc
,
3081 size_t nonLazyScriptCount
,
3082 size_t allScriptCount
) {
3083 MOZ_ASSERT(isEmpty());
3085 if (nonLazyScriptCount
<= 1) {
3086 MOZ_ASSERT(isSingle());
3090 // If the ratio of scripts with bytecode is small, allocating the Vector
3091 // storage with the number of all scripts isn't space-efficient.
3092 // In that case use HashMap instead.
3094 // In general, we expect either all scripts to contain bytecode (priviledge
3095 // and self-hosted), or almost none to (eg standard lazy parsing output).
3096 constexpr size_t thresholdRatio
= 8;
3097 bool useHashMap
= nonLazyScriptCount
< allScriptCount
/ thresholdRatio
;
3102 if (!asMap()->reserve(nonLazyScriptCount
)) {
3103 ReportOutOfMemory(fc
);
3107 if (!initVector(fc
)) {
3110 if (!asVector()->resize(allScriptCount
)) {
3111 ReportOutOfMemory(fc
);
3119 bool SharedDataContainer::cloneFrom(FrontendContext
* fc
,
3120 const SharedDataContainer
& other
) {
3121 MOZ_ASSERT(isEmpty());
3123 if (other
.isBorrow()) {
3124 return cloneFrom(fc
, *other
.asBorrow());
3127 if (other
.isSingle()) {
3128 // As we clone, we add an extra reference.
3129 RefPtr
<SharedImmutableScriptData
> ref(other
.asSingle());
3130 setSingle(ref
.forget());
3131 } else if (other
.isVector()) {
3132 if (!initVector(fc
)) {
3135 if (!asVector()->appendAll(*other
.asVector())) {
3136 ReportOutOfMemory(fc
);
3139 } else if (other
.isMap()) {
3143 auto& otherMap
= *other
.asMap();
3144 if (!asMap()->reserve(otherMap
.count())) {
3145 ReportOutOfMemory(fc
);
3148 auto& map
= *asMap();
3149 for (auto iter
= otherMap
.iter(); !iter
.done(); iter
.next()) {
3150 auto& entry
= iter
.get();
3151 map
.putNewInfallible(entry
.key(), entry
.value());
3157 js::SharedImmutableScriptData
* SharedDataContainer::get(
3158 ScriptIndex index
) const {
3160 if (index
== CompilationStencil::TopLevelIndex
) {
3167 auto& vec
= *asVector();
3168 if (index
.index
< vec
.length()) {
3175 auto& map
= *asMap();
3176 auto p
= map
.lookup(index
);
3183 MOZ_ASSERT(isBorrow());
3184 return asBorrow()->get(index
);
3187 bool SharedDataContainer::convertFromSingleToMap(FrontendContext
* fc
) {
3188 MOZ_ASSERT(isSingle());
3190 // Use a temporary container so that on OOM we do not break the stencil.
3191 SharedDataContainer other
;
3192 if (!other
.initMap(fc
)) {
3196 if (!other
.asMap()->putNew(CompilationStencil::TopLevelIndex
, asSingle())) {
3197 ReportOutOfMemory(fc
);
3201 std::swap(data_
, other
.data_
);
3205 bool SharedDataContainer::addAndShare(FrontendContext
* fc
, ScriptIndex index
,
3206 js::SharedImmutableScriptData
* data
) {
3207 MOZ_ASSERT(!isBorrow());
3210 MOZ_ASSERT(index
== CompilationStencil::TopLevelIndex
);
3211 RefPtr
<SharedImmutableScriptData
> ref(data
);
3212 if (!SharedImmutableScriptData::shareScriptData(fc
, ref
)) {
3215 setSingle(ref
.forget());
3220 auto& vec
= *asVector();
3221 // Resized by SharedDataContainer::prepareStorageFor.
3223 return SharedImmutableScriptData::shareScriptData(fc
, vec
[index
]);
3226 MOZ_ASSERT(isMap());
3227 auto& map
= *asMap();
3228 // Reserved by SharedDataContainer::prepareStorageFor.
3229 map
.putNewInfallible(index
, data
);
3230 auto p
= map
.lookup(index
);
3232 return SharedImmutableScriptData::shareScriptData(fc
, p
->value());
3235 bool SharedDataContainer::addExtraWithoutShare(
3236 FrontendContext
* fc
, ScriptIndex index
,
3237 js::SharedImmutableScriptData
* data
) {
3238 MOZ_ASSERT(!isEmpty());
3241 if (!convertFromSingleToMap(fc
)) {
3247 // SharedDataContainer::prepareStorageFor allocates space for all scripts.
3248 (*asVector())[index
] = data
;
3252 MOZ_ASSERT(isMap());
3253 // SharedDataContainer::prepareStorageFor doesn't allocate space for
3254 // delazification, and this can fail.
3255 if (!asMap()->putNew(index
, data
)) {
3256 ReportOutOfMemory(fc
);
3263 void CompilationStencil::assertNoExternalDependency() const {
3264 if (ownedBorrowStencil
) {
3265 ownedBorrowStencil
->assertNoExternalDependency();
3267 assertBorrowingFromExtensibleCompilationStencil(*ownedBorrowStencil
);
3271 MOZ_ASSERT_IF(!scriptData
.empty(), alloc
.contains(scriptData
.data()));
3272 MOZ_ASSERT_IF(!scriptExtra
.empty(), alloc
.contains(scriptExtra
.data()));
3274 MOZ_ASSERT_IF(!scopeData
.empty(), alloc
.contains(scopeData
.data()));
3275 MOZ_ASSERT_IF(!scopeNames
.empty(), alloc
.contains(scopeNames
.data()));
3276 for (const auto* data
: scopeNames
) {
3277 MOZ_ASSERT_IF(data
, alloc
.contains(data
));
3280 MOZ_ASSERT_IF(!regExpData
.empty(), alloc
.contains(regExpData
.data()));
3282 MOZ_ASSERT_IF(!bigIntData
.empty(), alloc
.contains(bigIntData
.data()));
3283 for (const auto& data
: bigIntData
) {
3284 MOZ_ASSERT(data
.isContainedIn(alloc
));
3287 MOZ_ASSERT_IF(!objLiteralData
.empty(), alloc
.contains(objLiteralData
.data()));
3288 for (const auto& data
: objLiteralData
) {
3289 MOZ_ASSERT(data
.isContainedIn(alloc
));
3292 MOZ_ASSERT_IF(!parserAtomData
.empty(), alloc
.contains(parserAtomData
.data()));
3293 for (const auto* data
: parserAtomData
) {
3294 MOZ_ASSERT_IF(data
, alloc
.contains(data
));
3297 MOZ_ASSERT(!sharedData
.isBorrow());
3300 void ExtensibleCompilationStencil::assertNoExternalDependency() const {
3301 for (const auto& data
: bigIntData
) {
3302 MOZ_ASSERT(data
.isContainedIn(alloc
));
3305 for (const auto& data
: objLiteralData
) {
3306 MOZ_ASSERT(data
.isContainedIn(alloc
));
3309 for (const auto* data
: scopeNames
) {
3310 MOZ_ASSERT_IF(data
, alloc
.contains(data
));
3313 for (const auto* data
: parserAtoms
.entries()) {
3314 MOZ_ASSERT_IF(data
, alloc
.contains(data
));
3317 MOZ_ASSERT(!sharedData
.isBorrow());
3321 template <typename T
, typename VectorT
>
3322 [[nodiscard
]] bool CopySpanToVector(FrontendContext
* fc
, VectorT
& vec
,
3323 mozilla::Span
<T
>& span
) {
3324 auto len
= span
.size();
3329 if (!vec
.append(span
.data(), len
)) {
3330 js::ReportOutOfMemory(fc
);
3336 template <typename T
, typename IntoSpanT
, size_t Inline
, typename AllocPolicy
>
3337 [[nodiscard
]] bool CopyToVector(FrontendContext
* fc
,
3338 mozilla::Vector
<T
, Inline
, AllocPolicy
>& vec
,
3339 const IntoSpanT
& source
) {
3340 mozilla::Span
<const T
> span
= source
;
3341 return CopySpanToVector(fc
, vec
, span
);
3344 // Span and Vector do not share the same method names.
3345 template <typename T
, size_t Inline
, typename AllocPolicy
>
3346 size_t GetLength(const mozilla::Vector
<T
, Inline
, AllocPolicy
>& vec
) {
3347 return vec
.length();
3349 template <typename T
>
3350 size_t GetLength(const mozilla::Span
<T
>& span
) {
3351 return span
.Length();
3354 // Copy scope names from `src` into `alloc`, and returns the allocated data.
3355 BaseParserScopeData
* CopyScopeData(FrontendContext
* fc
, LifoAlloc
& alloc
,
3357 const BaseParserScopeData
* src
) {
3358 MOZ_ASSERT(kind
!= ScopeKind::With
);
3360 size_t dataSize
= SizeOfParserScopeData(kind
, src
->length
);
3362 auto* dest
= static_cast<BaseParserScopeData
*>(alloc
.alloc(dataSize
));
3364 js::ReportOutOfMemory(fc
);
3367 memcpy(dest
, src
, dataSize
);
3372 template <typename Stencil
>
3373 bool ExtensibleCompilationStencil::cloneFromImpl(FrontendContext
* fc
,
3374 const Stencil
& other
) {
3375 MOZ_ASSERT(alloc
.isEmpty());
3377 canLazilyParse
= other
.canLazilyParse
;
3378 functionKey
= other
.functionKey
;
3380 if (!CopyToVector(fc
, scriptData
, other
.scriptData
)) {
3384 if (!CopyToVector(fc
, scriptExtra
, other
.scriptExtra
)) {
3388 if (!CopyToVector(fc
, gcThingData
, other
.gcThingData
)) {
3392 size_t scopeSize
= GetLength(other
.scopeData
);
3393 if (!CopyToVector(fc
, scopeData
, other
.scopeData
)) {
3396 if (!scopeNames
.reserve(scopeSize
)) {
3397 js::ReportOutOfMemory(fc
);
3400 for (size_t i
= 0; i
< scopeSize
; i
++) {
3401 if (other
.scopeNames
[i
]) {
3402 BaseParserScopeData
* data
= CopyScopeData(
3403 fc
, alloc
, other
.scopeData
[i
].kind(), other
.scopeNames
[i
]);
3407 scopeNames
.infallibleEmplaceBack(data
);
3409 scopeNames
.infallibleEmplaceBack(nullptr);
3413 if (!CopyToVector(fc
, regExpData
, other
.regExpData
)) {
3417 // If CompilationStencil has external dependency, peform deep copy.
3419 size_t bigIntSize
= GetLength(other
.bigIntData
);
3420 if (!bigIntData
.resize(bigIntSize
)) {
3421 js::ReportOutOfMemory(fc
);
3424 for (size_t i
= 0; i
< bigIntSize
; i
++) {
3425 if (!bigIntData
[i
].init(fc
, alloc
, other
.bigIntData
[i
].source())) {
3430 size_t objLiteralSize
= GetLength(other
.objLiteralData
);
3431 if (!objLiteralData
.reserve(objLiteralSize
)) {
3432 js::ReportOutOfMemory(fc
);
3435 for (const auto& data
: other
.objLiteralData
) {
3436 size_t length
= data
.code().size();
3437 auto* code
= alloc
.newArrayUninitialized
<uint8_t>(length
);
3439 js::ReportOutOfMemory(fc
);
3442 memcpy(code
, data
.code().data(), length
);
3443 objLiteralData
.infallibleEmplaceBack(code
, length
, data
.kind(),
3444 data
.flags(), data
.propertyCount());
3447 // Regardless of whether CompilationStencil has external dependency or not,
3448 // ParserAtoms should be interned, to populate internal HashMap.
3449 for (const auto* entry
: other
.parserAtomsSpan()) {
3451 if (!parserAtoms
.addPlaceholder(fc
)) {
3457 auto index
= parserAtoms
.internExternalParserAtom(fc
, entry
);
3463 // We copy the stencil and increment the reference count of each
3464 // SharedImmutableScriptData.
3465 if (!sharedData
.cloneFrom(fc
, other
.sharedData
)) {
3469 // Note: moduleMetadata and asmJS are known after the first parse, and are
3470 // not mutated by any delazifications later on. Thus we can safely increment
3471 // the reference counter and keep these as-is.
3472 moduleMetadata
= other
.moduleMetadata
;
3473 asmJS
= other
.asmJS
;
3476 assertNoExternalDependency();
3482 bool ExtensibleCompilationStencil::cloneFrom(FrontendContext
* fc
,
3483 const CompilationStencil
& other
) {
3484 return cloneFromImpl(fc
, other
);
3486 bool ExtensibleCompilationStencil::cloneFrom(
3487 FrontendContext
* fc
, const ExtensibleCompilationStencil
& other
) {
3488 return cloneFromImpl(fc
, other
);
3491 bool ExtensibleCompilationStencil::steal(FrontendContext
* fc
,
3492 RefPtr
<CompilationStencil
>&& other
) {
3493 MOZ_ASSERT(alloc
.isEmpty());
3494 using StorageType
= CompilationStencil::StorageType
;
3495 StorageType storageType
= other
->storageType
;
3496 if (other
->refCount
> 1) {
3497 storageType
= StorageType::Borrowed
;
3500 if (storageType
== StorageType::OwnedExtensible
) {
3501 auto& otherExtensible
= other
->ownedBorrowStencil
;
3503 canLazilyParse
= otherExtensible
->canLazilyParse
;
3504 functionKey
= otherExtensible
->functionKey
;
3506 alloc
.steal(&otherExtensible
->alloc
);
3508 source
= std::move(otherExtensible
->source
);
3510 scriptData
= std::move(otherExtensible
->scriptData
);
3511 scriptExtra
= std::move(otherExtensible
->scriptExtra
);
3512 gcThingData
= std::move(otherExtensible
->gcThingData
);
3513 scopeData
= std::move(otherExtensible
->scopeData
);
3514 scopeNames
= std::move(otherExtensible
->scopeNames
);
3515 regExpData
= std::move(otherExtensible
->regExpData
);
3516 bigIntData
= std::move(otherExtensible
->bigIntData
);
3517 objLiteralData
= std::move(otherExtensible
->objLiteralData
);
3519 parserAtoms
= std::move(otherExtensible
->parserAtoms
);
3520 parserAtoms
.fixupAlloc(alloc
);
3522 sharedData
= std::move(otherExtensible
->sharedData
);
3523 moduleMetadata
= std::move(otherExtensible
->moduleMetadata
);
3524 asmJS
= std::move(otherExtensible
->asmJS
);
3527 assertNoExternalDependency();
3533 if (storageType
== StorageType::Borrowed
) {
3534 return cloneFrom(fc
, *other
);
3537 MOZ_ASSERT(storageType
== StorageType::Owned
);
3539 canLazilyParse
= other
->canLazilyParse
;
3540 functionKey
= other
->functionKey
;
3543 other
->assertNoExternalDependency();
3544 MOZ_ASSERT(other
->refCount
== 1);
3547 // If CompilationStencil has no external dependency,
3548 // steal LifoAlloc and perform shallow copy.
3549 alloc
.steal(&other
->alloc
);
3551 if (!CopySpanToVector(fc
, scriptData
, other
->scriptData
)) {
3555 if (!CopySpanToVector(fc
, scriptExtra
, other
->scriptExtra
)) {
3559 if (!CopySpanToVector(fc
, gcThingData
, other
->gcThingData
)) {
3563 if (!CopySpanToVector(fc
, scopeData
, other
->scopeData
)) {
3566 if (!CopySpanToVector(fc
, scopeNames
, other
->scopeNames
)) {
3570 if (!CopySpanToVector(fc
, regExpData
, other
->regExpData
)) {
3574 if (!CopySpanToVector(fc
, bigIntData
, other
->bigIntData
)) {
3578 if (!CopySpanToVector(fc
, objLiteralData
, other
->objLiteralData
)) {
3582 // Regardless of whether CompilationStencil has external dependency or not,
3583 // ParserAtoms should be interned, to populate internal HashMap.
3584 for (const auto* entry
: other
->parserAtomData
) {
3586 if (!parserAtoms
.addPlaceholder(fc
)) {
3592 auto index
= parserAtoms
.internExternalParserAtom(fc
, entry
);
3598 sharedData
= std::move(other
->sharedData
);
3599 moduleMetadata
= std::move(other
->moduleMetadata
);
3600 asmJS
= std::move(other
->asmJS
);
3603 assertNoExternalDependency();
3609 bool CompilationStencil::isModule() const {
3610 return scriptExtra
[CompilationStencil::TopLevelIndex
].isModule();
3613 bool ExtensibleCompilationStencil::isModule() const {
3614 return scriptExtra
[CompilationStencil::TopLevelIndex
].isModule();
3617 mozilla::Span
<TaggedScriptThingIndex
> ScriptStencil::gcthings(
3618 const CompilationStencil
& stencil
) const {
3619 return stencil
.gcThingData
.Subspan(gcThingsOffset
, gcThingsLength
);
3622 bool BigIntStencil::init(FrontendContext
* fc
, LifoAlloc
& alloc
,
3623 const mozilla::Span
<const char16_t
> buf
) {
3625 // Assert we have no separators; if we have a separator then the algorithm
3626 // used in BigInt::literalIsZero will be incorrect.
3627 for (char16_t c
: buf
) {
3628 MOZ_ASSERT(c
!= '_');
3631 size_t length
= buf
.size();
3632 char16_t
* p
= alloc
.template newArrayUninitialized
<char16_t
>(length
);
3634 ReportOutOfMemory(fc
);
3637 mozilla::PodCopy(p
, buf
.data(), length
);
3638 source_
= mozilla::Span(p
, length
);
3642 BigInt
* BigIntStencil::createBigInt(JSContext
* cx
) const {
3643 mozilla::Range
<const char16_t
> source(source_
.data(), source_
.size());
3644 return js::ParseBigIntLiteral(cx
, source
);
3647 bool BigIntStencil::isZero() const {
3648 mozilla::Range
<const char16_t
> source(source_
.data(), source_
.size());
3649 return js::BigIntLiteralIsZero(source
);
3653 bool BigIntStencil::isContainedIn(const LifoAlloc
& alloc
) const {
3654 return alloc
.contains(source_
.data());
3658 #if defined(DEBUG) || defined(JS_JITSPEW)
3660 void frontend::DumpTaggedParserAtomIndex(js::JSONPrinter
& json
,
3661 TaggedParserAtomIndex taggedIndex
,
3662 const CompilationStencil
* stencil
) {
3663 if (taggedIndex
.isParserAtomIndex()) {
3664 json
.property("tag", "AtomIndex");
3665 auto index
= taggedIndex
.toParserAtomIndex();
3666 if (stencil
&& stencil
->parserAtomData
[index
]) {
3667 GenericPrinter
& out
= json
.beginStringProperty("atom");
3668 stencil
->parserAtomData
[index
]->dumpCharsNoQuote(out
);
3671 json
.property("index", size_t(index
));
3676 if (taggedIndex
.isWellKnownAtomId()) {
3677 json
.property("tag", "WellKnown");
3678 auto index
= taggedIndex
.toWellKnownAtomId();
3680 case WellKnownAtomId::empty_
:
3681 json
.property("atom", "");
3684 # define CASE_(name, _) case WellKnownAtomId::name:
3685 FOR_EACH_NONTINY_COMMON_PROPERTYNAME(CASE_
)
3688 # define CASE_(name, _) case WellKnownAtomId::name:
3689 JS_FOR_EACH_PROTOTYPE(CASE_
)
3692 # define CASE_(name) case WellKnownAtomId::name:
3693 JS_FOR_EACH_WELL_KNOWN_SYMBOL(CASE_
)
3697 GenericPrinter
& out
= json
.beginStringProperty("atom");
3698 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3704 // This includes tiny WellKnownAtomId atoms, which is invalid.
3705 json
.property("index", size_t(index
));
3711 if (taggedIndex
.isLength1StaticParserString()) {
3712 json
.property("tag", "Length1Static");
3713 auto index
= taggedIndex
.toLength1StaticParserString();
3714 GenericPrinter
& out
= json
.beginStringProperty("atom");
3715 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3720 if (taggedIndex
.isLength2StaticParserString()) {
3721 json
.property("tag", "Length2Static");
3722 auto index
= taggedIndex
.toLength2StaticParserString();
3723 GenericPrinter
& out
= json
.beginStringProperty("atom");
3724 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3729 if (taggedIndex
.isLength3StaticParserString()) {
3730 json
.property("tag", "Length3Static");
3731 auto index
= taggedIndex
.toLength3StaticParserString();
3732 GenericPrinter
& out
= json
.beginStringProperty("atom");
3733 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3738 MOZ_ASSERT(taggedIndex
.isNull());
3739 json
.property("tag", "null");
3742 void frontend::DumpTaggedParserAtomIndexNoQuote(
3743 GenericPrinter
& out
, TaggedParserAtomIndex taggedIndex
,
3744 const CompilationStencil
* stencil
) {
3745 if (taggedIndex
.isParserAtomIndex()) {
3746 auto index
= taggedIndex
.toParserAtomIndex();
3747 if (stencil
&& stencil
->parserAtomData
[index
]) {
3748 stencil
->parserAtomData
[index
]->dumpCharsNoQuote(out
);
3750 out
.printf("AtomIndex#%zu", size_t(index
));
3755 if (taggedIndex
.isWellKnownAtomId()) {
3756 auto index
= taggedIndex
.toWellKnownAtomId();
3758 case WellKnownAtomId::empty_
:
3759 out
.put("#<zero-length name>");
3762 # define CASE_(name, _) case WellKnownAtomId::name:
3763 FOR_EACH_NONTINY_COMMON_PROPERTYNAME(CASE_
)
3766 # define CASE_(name, _) case WellKnownAtomId::name:
3767 JS_FOR_EACH_PROTOTYPE(CASE_
)
3770 # define CASE_(name) case WellKnownAtomId::name:
3771 JS_FOR_EACH_WELL_KNOWN_SYMBOL(CASE_
)
3775 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3780 // This includes tiny WellKnownAtomId atoms, which is invalid.
3781 out
.printf("WellKnown#%zu", size_t(index
));
3787 if (taggedIndex
.isLength1StaticParserString()) {
3788 auto index
= taggedIndex
.toLength1StaticParserString();
3789 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3793 if (taggedIndex
.isLength2StaticParserString()) {
3794 auto index
= taggedIndex
.toLength2StaticParserString();
3795 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3799 if (taggedIndex
.isLength3StaticParserString()) {
3800 auto index
= taggedIndex
.toLength3StaticParserString();
3801 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3805 MOZ_ASSERT(taggedIndex
.isNull());
3806 out
.put("#<null name>");
3809 void RegExpStencil::dump() const {
3810 js::Fprinter
out(stderr
);
3811 js::JSONPrinter
json(out
);
3812 dump(json
, nullptr);
3815 void RegExpStencil::dump(js::JSONPrinter
& json
,
3816 const CompilationStencil
* stencil
) const {
3818 dumpFields(json
, stencil
);
3822 void RegExpStencil::dumpFields(js::JSONPrinter
& json
,
3823 const CompilationStencil
* stencil
) const {
3824 json
.beginObjectProperty("pattern");
3825 DumpTaggedParserAtomIndex(json
, atom_
, stencil
);
3828 GenericPrinter
& out
= json
.beginStringProperty("flags");
3830 if (flags().global()) {
3833 if (flags().ignoreCase()) {
3836 if (flags().multiline()) {
3839 if (flags().dotAll()) {
3842 if (flags().unicode()) {
3845 if (flags().sticky()) {
3849 json
.endStringProperty();
3852 void BigIntStencil::dump() const {
3853 js::Fprinter
out(stderr
);
3854 js::JSONPrinter
json(out
);
3858 void BigIntStencil::dump(js::JSONPrinter
& json
) const {
3859 GenericPrinter
& out
= json
.beginString();
3860 dumpCharsNoQuote(out
);
3864 void BigIntStencil::dumpCharsNoQuote(GenericPrinter
& out
) const {
3865 for (char16_t c
: source_
) {
3866 out
.putChar(char(c
));
3870 void ScopeStencil::dump() const {
3871 js::Fprinter
out(stderr
);
3872 js::JSONPrinter
json(out
);
3873 dump(json
, nullptr, nullptr);
3876 void ScopeStencil::dump(js::JSONPrinter
& json
,
3877 const BaseParserScopeData
* baseScopeData
,
3878 const CompilationStencil
* stencil
) const {
3880 dumpFields(json
, baseScopeData
, stencil
);
3884 void ScopeStencil::dumpFields(js::JSONPrinter
& json
,
3885 const BaseParserScopeData
* baseScopeData
,
3886 const CompilationStencil
* stencil
) const {
3887 json
.property("kind", ScopeKindString(kind_
));
3889 if (hasEnclosing()) {
3890 json
.formatProperty("enclosing", "ScopeIndex(%zu)", size_t(enclosing()));
3893 json
.property("firstFrameSlot", firstFrameSlot_
);
3895 if (hasEnvironmentShape()) {
3896 json
.formatProperty("numEnvironmentSlots", "%zu",
3897 size_t(numEnvironmentSlots_
));
3901 json
.formatProperty("functionIndex", "ScriptIndex(%zu)",
3902 size_t(functionIndex_
));
3905 json
.beginListProperty("flags");
3906 if (flags_
& HasEnclosing
) {
3907 json
.value("HasEnclosing");
3909 if (flags_
& HasEnvironmentShape
) {
3910 json
.value("HasEnvironmentShape");
3912 if (flags_
& IsArrow
) {
3913 json
.value("IsArrow");
3917 if (!baseScopeData
) {
3921 json
.beginObjectProperty("data");
3923 mozilla::Span
<const ParserBindingName
> trailingNames
;
3925 case ScopeKind::Function
: {
3927 static_cast<const FunctionScope::ParserData
*>(baseScopeData
);
3928 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3929 json
.property("hasParameterExprs", data
->slotInfo
.hasParameterExprs());
3930 json
.property("nonPositionalFormalStart",
3931 data
->slotInfo
.nonPositionalFormalStart
);
3932 json
.property("varStart", data
->slotInfo
.varStart
);
3934 trailingNames
= GetScopeDataTrailingNames(data
);
3938 case ScopeKind::FunctionBodyVar
: {
3940 static_cast<const VarScope::ParserData
*>(baseScopeData
);
3941 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3943 trailingNames
= GetScopeDataTrailingNames(data
);
3947 case ScopeKind::Lexical
:
3948 case ScopeKind::SimpleCatch
:
3949 case ScopeKind::Catch
:
3950 case ScopeKind::NamedLambda
:
3951 case ScopeKind::StrictNamedLambda
:
3952 case ScopeKind::FunctionLexical
: {
3954 static_cast<const LexicalScope::ParserData
*>(baseScopeData
);
3955 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3956 json
.property("constStart", data
->slotInfo
.constStart
);
3958 trailingNames
= GetScopeDataTrailingNames(data
);
3962 case ScopeKind::ClassBody
: {
3964 static_cast<const ClassBodyScope::ParserData
*>(baseScopeData
);
3965 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3966 json
.property("privateMethodStart", data
->slotInfo
.privateMethodStart
);
3968 trailingNames
= GetScopeDataTrailingNames(data
);
3972 case ScopeKind::With
: {
3976 case ScopeKind::Eval
:
3977 case ScopeKind::StrictEval
: {
3979 static_cast<const EvalScope::ParserData
*>(baseScopeData
);
3980 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3982 trailingNames
= GetScopeDataTrailingNames(data
);
3986 case ScopeKind::Global
:
3987 case ScopeKind::NonSyntactic
: {
3989 static_cast<const GlobalScope::ParserData
*>(baseScopeData
);
3990 json
.property("letStart", data
->slotInfo
.letStart
);
3991 json
.property("constStart", data
->slotInfo
.constStart
);
3993 trailingNames
= GetScopeDataTrailingNames(data
);
3997 case ScopeKind::Module
: {
3999 static_cast<const ModuleScope::ParserData
*>(baseScopeData
);
4000 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
4001 json
.property("varStart", data
->slotInfo
.varStart
);
4002 json
.property("letStart", data
->slotInfo
.letStart
);
4003 json
.property("constStart", data
->slotInfo
.constStart
);
4005 trailingNames
= GetScopeDataTrailingNames(data
);
4009 case ScopeKind::WasmInstance
: {
4011 static_cast<const WasmInstanceScope::ParserData
*>(baseScopeData
);
4012 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
4013 json
.property("globalsStart", data
->slotInfo
.globalsStart
);
4015 trailingNames
= GetScopeDataTrailingNames(data
);
4019 case ScopeKind::WasmFunction
: {
4021 static_cast<const WasmFunctionScope::ParserData
*>(baseScopeData
);
4022 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
4024 trailingNames
= GetScopeDataTrailingNames(data
);
4029 MOZ_CRASH("Unexpected ScopeKind");
4034 if (!trailingNames
.empty()) {
4036 json
.beginObjectProperty("trailingNames");
4037 for (size_t i
= 0; i
< trailingNames
.size(); i
++) {
4038 const auto& name
= trailingNames
[i
];
4039 SprintfLiteral(index
, "%zu", i
);
4040 json
.beginObjectProperty(index
);
4042 json
.boolProperty("closedOver", name
.closedOver());
4044 json
.boolProperty("isTopLevelFunction", name
.isTopLevelFunction());
4046 json
.beginObjectProperty("name");
4047 DumpTaggedParserAtomIndex(json
, name
.name(), stencil
);
4058 static void DumpModuleRequestVectorItems(
4059 js::JSONPrinter
& json
, const StencilModuleMetadata::RequestVector
& requests
,
4060 const CompilationStencil
* stencil
) {
4061 for (const auto& request
: requests
) {
4063 if (request
.specifier
) {
4064 json
.beginObjectProperty("specifier");
4065 DumpTaggedParserAtomIndex(json
, request
.specifier
, stencil
);
4072 static void DumpModuleEntryVectorItems(
4073 js::JSONPrinter
& json
, const StencilModuleMetadata::EntryVector
& entries
,
4074 const CompilationStencil
* stencil
) {
4075 for (const auto& entry
: entries
) {
4077 if (entry
.moduleRequest
) {
4078 json
.property("moduleRequest", entry
.moduleRequest
.value());
4080 if (entry
.localName
) {
4081 json
.beginObjectProperty("localName");
4082 DumpTaggedParserAtomIndex(json
, entry
.localName
, stencil
);
4085 if (entry
.importName
) {
4086 json
.beginObjectProperty("importName");
4087 DumpTaggedParserAtomIndex(json
, entry
.importName
, stencil
);
4090 if (entry
.exportName
) {
4091 json
.beginObjectProperty("exportName");
4092 DumpTaggedParserAtomIndex(json
, entry
.exportName
, stencil
);
4095 // TODO: Dump assertions.
4100 void StencilModuleMetadata::dump() const {
4101 js::Fprinter
out(stderr
);
4102 js::JSONPrinter
json(out
);
4103 dump(json
, nullptr);
4106 void StencilModuleMetadata::dump(js::JSONPrinter
& json
,
4107 const CompilationStencil
* stencil
) const {
4109 dumpFields(json
, stencil
);
4113 void StencilModuleMetadata::dumpFields(
4114 js::JSONPrinter
& json
, const CompilationStencil
* stencil
) const {
4115 json
.beginListProperty("moduleRequests");
4116 DumpModuleRequestVectorItems(json
, moduleRequests
, stencil
);
4119 json
.beginListProperty("requestedModules");
4120 DumpModuleEntryVectorItems(json
, requestedModules
, stencil
);
4123 json
.beginListProperty("importEntries");
4124 DumpModuleEntryVectorItems(json
, importEntries
, stencil
);
4127 json
.beginListProperty("localExportEntries");
4128 DumpModuleEntryVectorItems(json
, localExportEntries
, stencil
);
4131 json
.beginListProperty("indirectExportEntries");
4132 DumpModuleEntryVectorItems(json
, indirectExportEntries
, stencil
);
4135 json
.beginListProperty("starExportEntries");
4136 DumpModuleEntryVectorItems(json
, starExportEntries
, stencil
);
4139 json
.beginListProperty("functionDecls");
4140 for (const auto& index
: functionDecls
) {
4141 json
.value("ScriptIndex(%zu)", size_t(index
));
4145 json
.boolProperty("isAsync", isAsync
);
4148 void js::DumpImmutableScriptFlags(js::JSONPrinter
& json
,
4149 ImmutableScriptFlags immutableFlags
) {
4150 for (uint32_t i
= 1; i
; i
= i
<< 1) {
4151 if (uint32_t(immutableFlags
) & i
) {
4152 switch (ImmutableScriptFlagsEnum(i
)) {
4153 case ImmutableScriptFlagsEnum::IsForEval
:
4154 json
.value("IsForEval");
4156 case ImmutableScriptFlagsEnum::IsModule
:
4157 json
.value("IsModule");
4159 case ImmutableScriptFlagsEnum::IsFunction
:
4160 json
.value("IsFunction");
4162 case ImmutableScriptFlagsEnum::SelfHosted
:
4163 json
.value("SelfHosted");
4165 case ImmutableScriptFlagsEnum::ForceStrict
:
4166 json
.value("ForceStrict");
4168 case ImmutableScriptFlagsEnum::HasNonSyntacticScope
:
4169 json
.value("HasNonSyntacticScope");
4171 case ImmutableScriptFlagsEnum::NoScriptRval
:
4172 json
.value("NoScriptRval");
4174 case ImmutableScriptFlagsEnum::TreatAsRunOnce
:
4175 json
.value("TreatAsRunOnce");
4177 case ImmutableScriptFlagsEnum::Strict
:
4178 json
.value("Strict");
4180 case ImmutableScriptFlagsEnum::HasModuleGoal
:
4181 json
.value("HasModuleGoal");
4183 case ImmutableScriptFlagsEnum::HasInnerFunctions
:
4184 json
.value("HasInnerFunctions");
4186 case ImmutableScriptFlagsEnum::HasDirectEval
:
4187 json
.value("HasDirectEval");
4189 case ImmutableScriptFlagsEnum::BindingsAccessedDynamically
:
4190 json
.value("BindingsAccessedDynamically");
4192 case ImmutableScriptFlagsEnum::HasCallSiteObj
:
4193 json
.value("HasCallSiteObj");
4195 case ImmutableScriptFlagsEnum::IsAsync
:
4196 json
.value("IsAsync");
4198 case ImmutableScriptFlagsEnum::IsGenerator
:
4199 json
.value("IsGenerator");
4201 case ImmutableScriptFlagsEnum::FunHasExtensibleScope
:
4202 json
.value("FunHasExtensibleScope");
4204 case ImmutableScriptFlagsEnum::FunctionHasThisBinding
:
4205 json
.value("FunctionHasThisBinding");
4207 case ImmutableScriptFlagsEnum::NeedsHomeObject
:
4208 json
.value("NeedsHomeObject");
4210 case ImmutableScriptFlagsEnum::IsDerivedClassConstructor
:
4211 json
.value("IsDerivedClassConstructor");
4213 case ImmutableScriptFlagsEnum::IsSyntheticFunction
:
4214 json
.value("IsSyntheticFunction");
4216 case ImmutableScriptFlagsEnum::UseMemberInitializers
:
4217 json
.value("UseMemberInitializers");
4219 case ImmutableScriptFlagsEnum::HasRest
:
4220 json
.value("HasRest");
4222 case ImmutableScriptFlagsEnum::NeedsFunctionEnvironmentObjects
:
4223 json
.value("NeedsFunctionEnvironmentObjects");
4225 case ImmutableScriptFlagsEnum::FunctionHasExtraBodyVarScope
:
4226 json
.value("FunctionHasExtraBodyVarScope");
4228 case ImmutableScriptFlagsEnum::ShouldDeclareArguments
:
4229 json
.value("ShouldDeclareArguments");
4231 case ImmutableScriptFlagsEnum::NeedsArgsObj
:
4232 json
.value("NeedsArgsObj");
4234 case ImmutableScriptFlagsEnum::HasMappedArgsObj
:
4235 json
.value("HasMappedArgsObj");
4237 case ImmutableScriptFlagsEnum::IsInlinableLargeFunction
:
4238 json
.value("IsInlinableLargeFunction");
4240 case ImmutableScriptFlagsEnum::FunctionHasNewTargetBinding
:
4241 json
.value("FunctionHasNewTargetBinding");
4243 case ImmutableScriptFlagsEnum::UsesArgumentsIntrinsics
:
4244 json
.value("UsesArgumentsIntrinsics");
4247 json
.value("Unknown(%x)", i
);
4254 void js::DumpFunctionFlagsItems(js::JSONPrinter
& json
,
4255 FunctionFlags functionFlags
) {
4256 switch (functionFlags
.kind()) {
4257 case FunctionFlags::FunctionKind::NormalFunction
:
4258 json
.value("NORMAL_KIND");
4260 case FunctionFlags::FunctionKind::AsmJS
:
4261 json
.value("ASMJS_KIND");
4263 case FunctionFlags::FunctionKind::Wasm
:
4264 json
.value("WASM_KIND");
4266 case FunctionFlags::FunctionKind::Arrow
:
4267 json
.value("ARROW_KIND");
4269 case FunctionFlags::FunctionKind::Method
:
4270 json
.value("METHOD_KIND");
4272 case FunctionFlags::FunctionKind::ClassConstructor
:
4273 json
.value("CLASSCONSTRUCTOR_KIND");
4275 case FunctionFlags::FunctionKind::Getter
:
4276 json
.value("GETTER_KIND");
4278 case FunctionFlags::FunctionKind::Setter
:
4279 json
.value("SETTER_KIND");
4282 json
.value("Unknown(%x)", uint8_t(functionFlags
.kind()));
4286 static_assert(FunctionFlags::FUNCTION_KIND_MASK
== 0x0007,
4287 "FunctionKind should use the lowest 3 bits");
4288 for (uint16_t i
= 1 << 3; i
; i
= i
<< 1) {
4289 if (functionFlags
.toRaw() & i
) {
4290 switch (FunctionFlags::Flags(i
)) {
4291 case FunctionFlags::Flags::EXTENDED
:
4292 json
.value("EXTENDED");
4294 case FunctionFlags::Flags::SELF_HOSTED
:
4295 json
.value("SELF_HOSTED");
4297 case FunctionFlags::Flags::BASESCRIPT
:
4298 json
.value("BASESCRIPT");
4300 case FunctionFlags::Flags::SELFHOSTLAZY
:
4301 json
.value("SELFHOSTLAZY");
4303 case FunctionFlags::Flags::CONSTRUCTOR
:
4304 json
.value("CONSTRUCTOR");
4306 case FunctionFlags::Flags::LAZY_ACCESSOR_NAME
:
4307 json
.value("LAZY_ACCESSOR_NAME");
4309 case FunctionFlags::Flags::LAMBDA
:
4310 json
.value("LAMBDA");
4312 case FunctionFlags::Flags::NATIVE_JIT_ENTRY
:
4313 json
.value("NATIVE_JIT_ENTRY");
4315 case FunctionFlags::Flags::HAS_INFERRED_NAME
:
4316 json
.value("HAS_INFERRED_NAME");
4318 case FunctionFlags::Flags::HAS_GUESSED_ATOM
:
4319 json
.value("HAS_GUESSED_ATOM");
4321 case FunctionFlags::Flags::RESOLVED_NAME
:
4322 json
.value("RESOLVED_NAME");
4324 case FunctionFlags::Flags::RESOLVED_LENGTH
:
4325 json
.value("RESOLVED_LENGTH");
4327 case FunctionFlags::Flags::GHOST_FUNCTION
:
4328 json
.value("GHOST_FUNCTION");
4331 json
.value("Unknown(%x)", i
);
4338 static void DumpScriptThing(js::JSONPrinter
& json
,
4339 const CompilationStencil
* stencil
,
4340 TaggedScriptThingIndex thing
) {
4341 switch (thing
.tag()) {
4342 case TaggedScriptThingIndex::Kind::ParserAtomIndex
:
4343 case TaggedScriptThingIndex::Kind::WellKnown
:
4345 json
.property("type", "Atom");
4346 DumpTaggedParserAtomIndex(json
, thing
.toAtom(), stencil
);
4349 case TaggedScriptThingIndex::Kind::Null
:
4352 case TaggedScriptThingIndex::Kind::BigInt
:
4353 json
.value("BigIntIndex(%zu)", size_t(thing
.toBigInt()));
4355 case TaggedScriptThingIndex::Kind::ObjLiteral
:
4356 json
.value("ObjLiteralIndex(%zu)", size_t(thing
.toObjLiteral()));
4358 case TaggedScriptThingIndex::Kind::RegExp
:
4359 json
.value("RegExpIndex(%zu)", size_t(thing
.toRegExp()));
4361 case TaggedScriptThingIndex::Kind::Scope
:
4362 json
.value("ScopeIndex(%zu)", size_t(thing
.toScope()));
4364 case TaggedScriptThingIndex::Kind::Function
:
4365 json
.value("ScriptIndex(%zu)", size_t(thing
.toFunction()));
4367 case TaggedScriptThingIndex::Kind::EmptyGlobalScope
:
4368 json
.value("EmptyGlobalScope");
4373 void ScriptStencil::dump() const {
4374 js::Fprinter
out(stderr
);
4375 js::JSONPrinter
json(out
);
4376 dump(json
, nullptr);
4379 void ScriptStencil::dump(js::JSONPrinter
& json
,
4380 const CompilationStencil
* stencil
) const {
4382 dumpFields(json
, stencil
);
4386 void ScriptStencil::dumpFields(js::JSONPrinter
& json
,
4387 const CompilationStencil
* stencil
) const {
4388 json
.formatProperty("gcThingsOffset", "CompilationGCThingIndex(%u)",
4389 gcThingsOffset
.index
);
4390 json
.property("gcThingsLength", gcThingsLength
);
4393 json
.beginListProperty("gcThings");
4394 for (const auto& thing
: gcthings(*stencil
)) {
4395 DumpScriptThing(json
, stencil
, thing
);
4400 json
.beginListProperty("flags");
4401 if (flags_
& WasEmittedByEnclosingScriptFlag
) {
4402 json
.value("WasEmittedByEnclosingScriptFlag");
4404 if (flags_
& AllowRelazifyFlag
) {
4405 json
.value("AllowRelazifyFlag");
4407 if (flags_
& HasSharedDataFlag
) {
4408 json
.value("HasSharedDataFlag");
4410 if (flags_
& HasLazyFunctionEnclosingScopeIndexFlag
) {
4411 json
.value("HasLazyFunctionEnclosingScopeIndexFlag");
4416 json
.beginObjectProperty("functionAtom");
4417 DumpTaggedParserAtomIndex(json
, functionAtom
, stencil
);
4420 json
.beginListProperty("functionFlags");
4421 DumpFunctionFlagsItems(json
, functionFlags
);
4424 if (hasLazyFunctionEnclosingScopeIndex()) {
4425 json
.formatProperty("lazyFunctionEnclosingScopeIndex", "ScopeIndex(%zu)",
4426 size_t(lazyFunctionEnclosingScopeIndex()));
4429 if (hasSelfHostedCanonicalName()) {
4430 json
.beginObjectProperty("selfHostCanonicalName");
4431 DumpTaggedParserAtomIndex(json
, selfHostedCanonicalName(), stencil
);
4437 void ScriptStencilExtra::dump() const {
4438 js::Fprinter
out(stderr
);
4439 js::JSONPrinter
json(out
);
4443 void ScriptStencilExtra::dump(js::JSONPrinter
& json
) const {
4449 void ScriptStencilExtra::dumpFields(js::JSONPrinter
& json
) const {
4450 json
.beginListProperty("immutableFlags");
4451 DumpImmutableScriptFlags(json
, immutableFlags
);
4454 json
.beginObjectProperty("extent");
4455 json
.property("sourceStart", extent
.sourceStart
);
4456 json
.property("sourceEnd", extent
.sourceEnd
);
4457 json
.property("toStringStart", extent
.toStringStart
);
4458 json
.property("toStringEnd", extent
.toStringEnd
);
4459 json
.property("lineno", extent
.lineno
);
4460 json
.property("column", extent
.column
.oneOriginValue());
4463 json
.property("memberInitializers", memberInitializers_
);
4465 json
.property("nargs", nargs
);
4468 void SharedDataContainer::dump() const {
4469 js::Fprinter
out(stderr
);
4470 js::JSONPrinter
json(out
);
4474 void SharedDataContainer::dump(js::JSONPrinter
& json
) const {
4480 void SharedDataContainer::dumpFields(js::JSONPrinter
& json
) const {
4482 json
.nullProperty("ScriptIndex(0)");
4487 json
.formatProperty("ScriptIndex(0)", "u8[%zu]",
4488 asSingle()->immutableDataLength());
4493 auto& vec
= *asVector();
4496 for (size_t i
= 0; i
< vec
.length(); i
++) {
4497 SprintfLiteral(index
, "ScriptIndex(%zu)", i
);
4499 json
.formatProperty(index
, "u8[%zu]", vec
[i
]->immutableDataLength());
4501 json
.nullProperty(index
);
4508 auto& map
= *asMap();
4511 for (auto iter
= map
.iter(); !iter
.done(); iter
.next()) {
4512 SprintfLiteral(index
, "ScriptIndex(%u)", iter
.get().key().index
);
4513 json
.formatProperty(index
, "u8[%zu]",
4514 iter
.get().value()->immutableDataLength());
4519 MOZ_ASSERT(isBorrow());
4520 asBorrow()->dumpFields(json
);
4523 struct DumpOptionsFields
{
4524 js::JSONPrinter
& json
;
4526 void operator()(const char* name
, JS::AsmJSOption value
) {
4527 const char* valueStr
= nullptr;
4529 case JS::AsmJSOption::Enabled
:
4530 valueStr
= "JS::AsmJSOption::Enabled";
4532 case JS::AsmJSOption::DisabledByAsmJSPref
:
4533 valueStr
= "JS::AsmJSOption::DisabledByAsmJSPref";
4535 case JS::AsmJSOption::DisabledByLinker
:
4536 valueStr
= "JS::AsmJSOption::DisabledByLinker";
4538 case JS::AsmJSOption::DisabledByNoWasmCompiler
:
4539 valueStr
= "JS::AsmJSOption::DisabledByNoWasmCompiler";
4541 case JS::AsmJSOption::DisabledByDebugger
:
4542 valueStr
= "JS::AsmJSOption::DisabledByDebugger";
4545 json
.property(name
, valueStr
);
4548 void operator()(const char* name
, JS::DelazificationOption value
) {
4549 const char* valueStr
= nullptr;
4551 # define SelectValueStr_(Strategy) \
4552 case JS::DelazificationOption::Strategy: \
4553 valueStr = "JS::DelazificationOption::" #Strategy; \
4556 FOREACH_DELAZIFICATION_STRATEGY(SelectValueStr_
)
4557 # undef SelectValueStr_
4559 json
.property(name
, valueStr
);
4562 void operator()(const char* name
, char16_t
* value
) {}
4564 void operator()(const char* name
, bool value
) { json
.property(name
, value
); }
4566 void operator()(const char* name
, uint32_t value
) {
4567 json
.property(name
, value
);
4570 void operator()(const char* name
, uint64_t value
) {
4571 json
.property(name
, value
);
4574 void operator()(const char* name
, const char* value
) {
4576 json
.property(name
, value
);
4579 json
.nullProperty(name
);
4582 void operator()(const char* name
, JS::ConstUTF8CharsZ value
) {
4584 json
.property(name
, value
.c_str());
4587 json
.nullProperty(name
);
4591 static void DumpOptionsFields(js::JSONPrinter
& json
,
4592 const JS::ReadOnlyCompileOptions
& options
) {
4593 struct DumpOptionsFields printer
{
4596 options
.dumpWith(printer
);
4599 static void DumpInputScopeFields(js::JSONPrinter
& json
,
4600 const InputScope
& scope
) {
4601 json
.property("kind", ScopeKindString(scope
.kind()));
4603 InputScope enclosing
= scope
.enclosing();
4604 if (enclosing
.isNull()) {
4605 json
.nullProperty("enclosing");
4607 json
.beginObjectProperty("enclosing");
4608 DumpInputScopeFields(json
, enclosing
);
4613 static void DumpInputScriptFields(js::JSONPrinter
& json
,
4614 const InputScript
& script
) {
4615 json
.beginObjectProperty("extent");
4617 SourceExtent extent
= script
.extent();
4618 json
.property("sourceStart", extent
.sourceStart
);
4619 json
.property("sourceEnd", extent
.sourceEnd
);
4620 json
.property("toStringStart", extent
.toStringStart
);
4621 json
.property("toStringEnd", extent
.toStringEnd
);
4622 json
.property("lineno", extent
.lineno
);
4623 json
.property("column", extent
.column
.oneOriginValue());
4627 json
.beginListProperty("immutableFlags");
4628 DumpImmutableScriptFlags(json
, script
.immutableFlags());
4631 json
.beginListProperty("functionFlags");
4632 DumpFunctionFlagsItems(json
, script
.functionFlags());
4635 json
.property("hasPrivateScriptData", script
.hasPrivateScriptData());
4637 InputScope scope
= script
.enclosingScope();
4638 if (scope
.isNull()) {
4639 json
.nullProperty("enclosingScope");
4641 json
.beginObjectProperty("enclosingScope");
4642 DumpInputScopeFields(json
, scope
);
4646 if (script
.useMemberInitializers()) {
4647 json
.property("memberInitializers",
4648 script
.getMemberInitializers().serialize());
4652 void CompilationInput::dump() const {
4653 js::Fprinter
out(stderr
);
4654 js::JSONPrinter
json(out
);
4659 void CompilationInput::dump(js::JSONPrinter
& json
) const {
4665 void CompilationInput::dumpFields(js::JSONPrinter
& json
) const {
4666 const char* targetStr
= nullptr;
4668 case CompilationTarget::Global
:
4669 targetStr
= "CompilationTarget::Global";
4671 case CompilationTarget::SelfHosting
:
4672 targetStr
= "CompilationTarget::SelfHosting";
4674 case CompilationTarget::StandaloneFunction
:
4675 targetStr
= "CompilationTarget::StandaloneFunction";
4677 case CompilationTarget::StandaloneFunctionInNonSyntacticScope
:
4678 targetStr
= "CompilationTarget::StandaloneFunctionInNonSyntacticScope";
4680 case CompilationTarget::Eval
:
4681 targetStr
= "CompilationTarget::Eval";
4683 case CompilationTarget::Module
:
4684 targetStr
= "CompilationTarget::Module";
4686 case CompilationTarget::Delazification
:
4687 targetStr
= "CompilationTarget::Delazification";
4690 json
.property("target", targetStr
);
4692 json
.beginObjectProperty("options");
4693 DumpOptionsFields(json
, options
);
4696 if (lazy_
.isNull()) {
4697 json
.nullProperty("lazy_");
4699 json
.beginObjectProperty("lazy_");
4700 DumpInputScriptFields(json
, lazy_
);
4704 if (enclosingScope
.isNull()) {
4705 json
.nullProperty("enclosingScope");
4707 json
.beginObjectProperty("enclosingScope");
4708 DumpInputScopeFields(json
, enclosingScope
);
4712 // TODO: Support printing the atomCache and the source fields.
4715 void CompilationStencil::dump() const {
4716 js::Fprinter
out(stderr
);
4717 js::JSONPrinter
json(out
);
4722 void CompilationStencil::dump(js::JSONPrinter
& json
) const {
4728 void CompilationStencil::dumpFields(js::JSONPrinter
& json
) const {
4731 json
.beginObjectProperty("scriptData");
4732 for (size_t i
= 0; i
< scriptData
.size(); i
++) {
4733 SprintfLiteral(index
, "ScriptIndex(%zu)", i
);
4734 json
.beginObjectProperty(index
);
4735 scriptData
[i
].dumpFields(json
, this);
4740 json
.beginObjectProperty("scriptExtra");
4741 for (size_t i
= 0; i
< scriptExtra
.size(); i
++) {
4742 SprintfLiteral(index
, "ScriptIndex(%zu)", i
);
4743 json
.beginObjectProperty(index
);
4744 scriptExtra
[i
].dumpFields(json
);
4749 json
.beginObjectProperty("scopeData");
4750 MOZ_ASSERT(scopeData
.size() == scopeNames
.size());
4751 for (size_t i
= 0; i
< scopeData
.size(); i
++) {
4752 SprintfLiteral(index
, "ScopeIndex(%zu)", i
);
4753 json
.beginObjectProperty(index
);
4754 scopeData
[i
].dumpFields(json
, scopeNames
[i
], this);
4759 json
.beginObjectProperty("sharedData");
4760 sharedData
.dumpFields(json
);
4763 json
.beginObjectProperty("regExpData");
4764 for (size_t i
= 0; i
< regExpData
.size(); i
++) {
4765 SprintfLiteral(index
, "RegExpIndex(%zu)", i
);
4766 json
.beginObjectProperty(index
);
4767 regExpData
[i
].dumpFields(json
, this);
4772 json
.beginObjectProperty("bigIntData");
4773 for (size_t i
= 0; i
< bigIntData
.size(); i
++) {
4774 SprintfLiteral(index
, "BigIntIndex(%zu)", i
);
4775 GenericPrinter
& out
= json
.beginStringProperty(index
);
4776 bigIntData
[i
].dumpCharsNoQuote(out
);
4777 json
.endStringProperty();
4781 json
.beginObjectProperty("objLiteralData");
4782 for (size_t i
= 0; i
< objLiteralData
.size(); i
++) {
4783 SprintfLiteral(index
, "ObjLiteralIndex(%zu)", i
);
4784 json
.beginObjectProperty(index
);
4785 objLiteralData
[i
].dumpFields(json
, this);
4790 if (moduleMetadata
) {
4791 json
.beginObjectProperty("moduleMetadata");
4792 moduleMetadata
->dumpFields(json
, this);
4796 json
.beginObjectProperty("asmJS");
4798 for (auto iter
= asmJS
->moduleMap
.iter(); !iter
.done(); iter
.next()) {
4799 SprintfLiteral(index
, "ScriptIndex(%u)", iter
.get().key().index
);
4800 json
.formatProperty(index
, "asm.js");
4806 void CompilationStencil::dumpAtom(TaggedParserAtomIndex index
) const {
4807 js::Fprinter
out(stderr
);
4808 js::JSONPrinter
json(out
);
4810 DumpTaggedParserAtomIndex(json
, index
, this);
4814 void ExtensibleCompilationStencil::dump() {
4815 frontend::BorrowingCompilationStencil
borrowingStencil(*this);
4816 borrowingStencil
.dump();
4819 void ExtensibleCompilationStencil::dump(js::JSONPrinter
& json
) {
4820 frontend::BorrowingCompilationStencil
borrowingStencil(*this);
4821 borrowingStencil
.dump(json
);
4824 void ExtensibleCompilationStencil::dumpFields(js::JSONPrinter
& json
) {
4825 frontend::BorrowingCompilationStencil
borrowingStencil(*this);
4826 borrowingStencil
.dumpFields(json
);
4829 void ExtensibleCompilationStencil::dumpAtom(TaggedParserAtomIndex index
) {
4830 frontend::BorrowingCompilationStencil
borrowingStencil(*this);
4831 borrowingStencil
.dumpAtom(index
);
4834 #endif // defined(DEBUG) || defined(JS_JITSPEW)
4836 JSString
* CompilationAtomCache::getExistingStringAt(
4837 ParserAtomIndex index
) const {
4838 MOZ_RELEASE_ASSERT(atoms_
.length() >= index
);
4839 return atoms_
[index
];
4842 JSString
* CompilationAtomCache::getExistingStringAt(
4843 JSContext
* cx
, TaggedParserAtomIndex taggedIndex
) const {
4844 if (taggedIndex
.isParserAtomIndex()) {
4845 auto index
= taggedIndex
.toParserAtomIndex();
4846 return getExistingStringAt(index
);
4849 if (taggedIndex
.isWellKnownAtomId()) {
4850 auto index
= taggedIndex
.toWellKnownAtomId();
4851 return GetWellKnownAtom(cx
, index
);
4854 if (taggedIndex
.isLength1StaticParserString()) {
4855 auto index
= taggedIndex
.toLength1StaticParserString();
4856 return cx
->staticStrings().getUnit(char16_t(index
));
4859 if (taggedIndex
.isLength2StaticParserString()) {
4860 auto index
= taggedIndex
.toLength2StaticParserString();
4861 return cx
->staticStrings().getLength2FromIndex(size_t(index
));
4864 MOZ_ASSERT(taggedIndex
.isLength3StaticParserString());
4865 auto index
= taggedIndex
.toLength3StaticParserString();
4866 return cx
->staticStrings().getUint(uint32_t(index
));
4869 JSString
* CompilationAtomCache::getStringAt(ParserAtomIndex index
) const {
4870 if (size_t(index
) >= atoms_
.length()) {
4873 return atoms_
[index
];
4876 JSAtom
* CompilationAtomCache::getExistingAtomAt(ParserAtomIndex index
) const {
4877 return &getExistingStringAt(index
)->asAtom();
4880 JSAtom
* CompilationAtomCache::getExistingAtomAt(
4881 JSContext
* cx
, TaggedParserAtomIndex taggedIndex
) const {
4882 return &getExistingStringAt(cx
, taggedIndex
)->asAtom();
4885 JSAtom
* CompilationAtomCache::getAtomAt(ParserAtomIndex index
) const {
4886 if (size_t(index
) >= atoms_
.length()) {
4889 if (!atoms_
[index
]) {
4892 return &atoms_
[index
]->asAtom();
4895 bool CompilationAtomCache::hasAtomAt(ParserAtomIndex index
) const {
4896 if (size_t(index
) >= atoms_
.length()) {
4899 return !!atoms_
[index
];
4902 bool CompilationAtomCache::setAtomAt(FrontendContext
* fc
, ParserAtomIndex index
,
4904 if (size_t(index
) < atoms_
.length()) {
4905 atoms_
[index
] = atom
;
4909 if (!atoms_
.resize(size_t(index
) + 1)) {
4910 ReportOutOfMemory(fc
);
4914 atoms_
[index
] = atom
;
4918 bool CompilationAtomCache::allocate(FrontendContext
* fc
, size_t length
) {
4919 MOZ_ASSERT(length
>= atoms_
.length());
4920 if (length
== atoms_
.length()) {
4924 if (!atoms_
.resize(length
)) {
4925 ReportOutOfMemory(fc
);
4932 void CompilationAtomCache::stealBuffer(AtomCacheVector
& atoms
) {
4933 atoms_
= std::move(atoms
);
4934 // Destroy elements, without unreserving.
4938 void CompilationAtomCache::releaseBuffer(AtomCacheVector
& atoms
) {
4939 atoms
= std::move(atoms_
);
4942 bool CompilationState::allocateGCThingsUninitialized(
4943 FrontendContext
* fc
, ScriptIndex scriptIndex
, size_t length
,
4944 TaggedScriptThingIndex
** cursor
) {
4945 MOZ_ASSERT(gcThingData
.length() <= UINT32_MAX
);
4947 auto gcThingsOffset
= CompilationGCThingIndex(gcThingData
.length());
4949 if (length
> INDEX_LIMIT
) {
4950 ReportAllocationOverflow(fc
);
4953 uint32_t gcThingsLength
= length
;
4955 if (!gcThingData
.growByUninitialized(length
)) {
4956 js::ReportOutOfMemory(fc
);
4960 if (gcThingData
.length() > UINT32_MAX
) {
4961 ReportAllocationOverflow(fc
);
4965 ScriptStencil
& script
= scriptData
[scriptIndex
];
4966 script
.gcThingsOffset
= gcThingsOffset
;
4967 script
.gcThingsLength
= gcThingsLength
;
4969 *cursor
= gcThingData
.begin() + gcThingsOffset
;
4973 bool CompilationState::appendScriptStencilAndData(FrontendContext
* fc
) {
4974 if (!scriptData
.emplaceBack()) {
4975 js::ReportOutOfMemory(fc
);
4979 if (isInitialStencil()) {
4980 if (!scriptExtra
.emplaceBack()) {
4981 scriptData
.popBack();
4982 MOZ_ASSERT(scriptData
.length() == scriptExtra
.length());
4984 js::ReportOutOfMemory(fc
);
4992 bool CompilationState::appendGCThings(
4993 FrontendContext
* fc
, ScriptIndex scriptIndex
,
4994 mozilla::Span
<const TaggedScriptThingIndex
> things
) {
4995 MOZ_ASSERT(gcThingData
.length() <= UINT32_MAX
);
4997 auto gcThingsOffset
= CompilationGCThingIndex(gcThingData
.length());
4999 if (things
.size() > INDEX_LIMIT
) {
5000 ReportAllocationOverflow(fc
);
5003 uint32_t gcThingsLength
= uint32_t(things
.size());
5005 if (!gcThingData
.append(things
.data(), things
.size())) {
5006 js::ReportOutOfMemory(fc
);
5010 if (gcThingData
.length() > UINT32_MAX
) {
5011 ReportAllocationOverflow(fc
);
5015 ScriptStencil
& script
= scriptData
[scriptIndex
];
5016 script
.gcThingsOffset
= gcThingsOffset
;
5017 script
.gcThingsLength
= gcThingsLength
;
5021 CompilationState::CompilationStatePosition
CompilationState::getPosition() {
5022 return CompilationStatePosition
{scriptData
.length(),
5023 asmJS
? asmJS
->moduleMap
.count() : 0};
5026 void CompilationState::rewind(
5027 const CompilationState::CompilationStatePosition
& pos
) {
5028 if (asmJS
&& asmJS
->moduleMap
.count() != pos
.asmJSCount
) {
5029 for (size_t i
= pos
.scriptDataLength
; i
< scriptData
.length(); i
++) {
5030 asmJS
->moduleMap
.remove(ScriptIndex(i
));
5032 MOZ_ASSERT(asmJS
->moduleMap
.count() == pos
.asmJSCount
);
5034 // scriptExtra is empty for delazification.
5035 if (scriptExtra
.length()) {
5036 MOZ_ASSERT(scriptExtra
.length() == scriptData
.length());
5037 scriptExtra
.shrinkTo(pos
.scriptDataLength
);
5039 scriptData
.shrinkTo(pos
.scriptDataLength
);
5042 void CompilationState::markGhost(
5043 const CompilationState::CompilationStatePosition
& pos
) {
5044 for (size_t i
= pos
.scriptDataLength
; i
< scriptData
.length(); i
++) {
5045 scriptData
[i
].setIsGhost();
5049 bool CompilationStencilMerger::buildFunctionKeyToIndex(FrontendContext
* fc
) {
5050 if (!functionKeyToInitialScriptIndex_
.reserve(initial_
->scriptExtra
.length() -
5052 ReportOutOfMemory(fc
);
5056 for (size_t i
= 1; i
< initial_
->scriptExtra
.length(); i
++) {
5057 const auto& extra
= initial_
->scriptExtra
[i
];
5058 auto key
= extra
.extent
.toFunctionKey();
5060 // There can be multiple ScriptStencilExtra with same extent if
5061 // the function is parsed multiple times because of rewind for
5062 // arrow function, and in that case the last one's index should be used.
5063 // Overwrite with the last one.
5065 // Already reserved above, but OOMTest can hit failure mode in
5067 if (!functionKeyToInitialScriptIndex_
.put(key
, ScriptIndex(i
))) {
5068 ReportOutOfMemory(fc
);
5076 ScriptIndex
CompilationStencilMerger::getInitialScriptIndexFor(
5077 const CompilationStencil
& delazification
) const {
5078 auto p
= functionKeyToInitialScriptIndex_
.lookup(delazification
.functionKey
);
5083 bool CompilationStencilMerger::buildAtomIndexMap(
5084 FrontendContext
* fc
, const CompilationStencil
& delazification
,
5085 AtomIndexMap
& atomIndexMap
) {
5086 uint32_t atomCount
= delazification
.parserAtomData
.size();
5087 if (!atomIndexMap
.reserve(atomCount
)) {
5088 ReportOutOfMemory(fc
);
5091 for (const auto& atom
: delazification
.parserAtomData
) {
5092 auto mappedIndex
= initial_
->parserAtoms
.internExternalParserAtom(fc
, atom
);
5096 atomIndexMap
.infallibleAppend(mappedIndex
);
5101 bool CompilationStencilMerger::setInitial(
5102 FrontendContext
* fc
, UniquePtr
<ExtensibleCompilationStencil
>&& initial
) {
5103 MOZ_ASSERT(!initial_
);
5105 initial_
= std::move(initial
);
5107 return buildFunctionKeyToIndex(fc
);
5110 template <typename GCThingIndexMapFunc
, typename AtomIndexMapFunc
,
5111 typename ScopeIndexMapFunc
>
5112 static void MergeScriptStencil(ScriptStencil
& dest
, const ScriptStencil
& src
,
5113 GCThingIndexMapFunc mapGCThingIndex
,
5114 AtomIndexMapFunc mapAtomIndex
,
5115 ScopeIndexMapFunc mapScopeIndex
,
5117 // If this function was lazy, all inner functions should have been lazy.
5118 MOZ_ASSERT(!dest
.hasSharedData());
5120 // If the inner lazy function is skipped, gcThingsLength is empty.
5121 if (src
.gcThingsLength
) {
5122 dest
.gcThingsOffset
= mapGCThingIndex(src
.gcThingsOffset
);
5123 dest
.gcThingsLength
= src
.gcThingsLength
;
5126 if (src
.functionAtom
) {
5127 dest
.functionAtom
= mapAtomIndex(src
.functionAtom
);
5130 if (!dest
.hasLazyFunctionEnclosingScopeIndex() &&
5131 src
.hasLazyFunctionEnclosingScopeIndex()) {
5132 // Both enclosing function and this function were lazy, and
5133 // now enclosing function is non-lazy and this function is still lazy.
5134 dest
.setLazyFunctionEnclosingScopeIndex(
5135 mapScopeIndex(src
.lazyFunctionEnclosingScopeIndex()));
5136 } else if (dest
.hasLazyFunctionEnclosingScopeIndex() &&
5137 !src
.hasLazyFunctionEnclosingScopeIndex()) {
5138 // The enclosing function was non-lazy and this function was lazy, and
5139 // now this function is non-lazy.
5140 dest
.resetHasLazyFunctionEnclosingScopeIndexAfterStencilMerge();
5142 // The enclosing function is still lazy.
5143 MOZ_ASSERT(!dest
.hasLazyFunctionEnclosingScopeIndex());
5144 MOZ_ASSERT(!src
.hasLazyFunctionEnclosingScopeIndex());
5148 uint16_t BASESCRIPT
= uint16_t(FunctionFlags::Flags::BASESCRIPT
);
5149 uint16_t HAS_INFERRED_NAME
=
5150 uint16_t(FunctionFlags::Flags::HAS_INFERRED_NAME
);
5151 uint16_t HAS_GUESSED_ATOM
= uint16_t(FunctionFlags::Flags::HAS_GUESSED_ATOM
);
5152 uint16_t acceptableDifferenceForLazy
= HAS_INFERRED_NAME
| HAS_GUESSED_ATOM
;
5153 uint16_t acceptableDifferenceForNonLazy
=
5154 BASESCRIPT
| HAS_INFERRED_NAME
| HAS_GUESSED_ATOM
;
5158 (dest
.functionFlags
.toRaw() | acceptableDifferenceForNonLazy
) ==
5159 (src
.functionFlags
.toRaw() | acceptableDifferenceForNonLazy
));
5161 // NOTE: Currently we don't delazify inner functions.
5162 MOZ_ASSERT_IF(!isTopLevel
,
5163 (dest
.functionFlags
.toRaw() | acceptableDifferenceForLazy
) ==
5164 (src
.functionFlags
.toRaw() | acceptableDifferenceForLazy
));
5166 dest
.functionFlags
= src
.functionFlags
;
5170 if (src
.wasEmittedByEnclosingScript()) {
5171 // NOTE: the top-level function of the delazification have
5172 // src.wasEmittedByEnclosingScript() == false, and that shouldn't
5174 dest
.setWasEmittedByEnclosingScript();
5177 if (src
.allowRelazify()) {
5178 dest
.setAllowRelazify();
5181 if (src
.hasSharedData()) {
5182 dest
.setHasSharedData();
5186 bool CompilationStencilMerger::addDelazification(
5187 FrontendContext
* fc
, const CompilationStencil
& delazification
) {
5188 MOZ_ASSERT(initial_
);
5190 auto delazifiedFunctionIndex
= getInitialScriptIndexFor(delazification
);
5191 auto& destFun
= initial_
->scriptData
[delazifiedFunctionIndex
];
5193 if (destFun
.hasSharedData()) {
5194 // If the function was already non-lazy, it means the following happened:
5195 // A. delazified twice within single incremental encoding
5196 // 1. this function is lazily parsed
5197 // 2. incremental encoding is started
5198 // 3. this function is delazified, encoded, and merged
5199 // 4. this function is relazified
5200 // 5. this function is delazified, encoded, and merged
5202 // B. delazified twice across decode
5203 // 1. this function is lazily parsed
5204 // 2. incremental encoding is started
5205 // 3. this function is delazified, encoded, and merged
5206 // 4. incremental encoding is finished
5208 // 6. incremental encoding is started
5209 // here, this function is non-lazy
5210 // 7. this function is relazified
5211 // 8. this function is delazified, encoded, and merged
5213 // A can happen with public API.
5215 // B cannot happen with public API, but can happen if incremental
5216 // encoding at step B.6 is explicitly started by internal function.
5217 // See Evaluate and StartIncrementalEncoding in js/src/shell/js.cpp.
5221 // If any failure happens, the initial stencil is left in the broken state.
5222 // Immediately discard it.
5223 auto failureCase
= mozilla::MakeScopeExit([&] { initial_
.reset(); });
5225 mozilla::Maybe
<ScopeIndex
> functionEnclosingScope
;
5226 if (destFun
.hasLazyFunctionEnclosingScopeIndex()) {
5227 // lazyFunctionEnclosingScopeIndex_ can be Nothing if this is
5228 // top-level function.
5229 functionEnclosingScope
=
5230 mozilla::Some(destFun
.lazyFunctionEnclosingScopeIndex());
5233 // A map from ParserAtomIndex in delazification to TaggedParserAtomIndex
5235 AtomIndexMap atomIndexMap
;
5236 if (!buildAtomIndexMap(fc
, delazification
, atomIndexMap
)) {
5239 auto mapAtomIndex
= [&](TaggedParserAtomIndex index
) {
5240 if (index
.isParserAtomIndex()) {
5241 return atomIndexMap
[index
.toParserAtomIndex()];
5247 size_t gcThingOffset
= initial_
->gcThingData
.length();
5248 size_t regExpOffset
= initial_
->regExpData
.length();
5249 size_t bigIntOffset
= initial_
->bigIntData
.length();
5250 size_t objLiteralOffset
= initial_
->objLiteralData
.length();
5251 size_t scopeOffset
= initial_
->scopeData
.length();
5253 // Map delazification's ScriptIndex to initial's ScriptIndex.
5255 // The lazy function's gcthings list stores inner function's ScriptIndex.
5256 // The n-th gcthing holds the ScriptIndex of the (n+1)-th script in
5259 // NOTE: Currently we don't delazify inner functions.
5260 auto lazyFunctionGCThingsOffset
= destFun
.gcThingsOffset
;
5261 auto mapScriptIndex
= [&](ScriptIndex index
) {
5262 if (index
== CompilationStencil::TopLevelIndex
) {
5263 return delazifiedFunctionIndex
;
5266 return initial_
->gcThingData
[lazyFunctionGCThingsOffset
+ index
.index
- 1]
5270 // Map other delazification's indices into initial's indices.
5271 auto mapGCThingIndex
= [&](CompilationGCThingIndex offset
) {
5272 return CompilationGCThingIndex(gcThingOffset
+ offset
.index
);
5274 auto mapRegExpIndex
= [&](RegExpIndex index
) {
5275 return RegExpIndex(regExpOffset
+ index
.index
);
5277 auto mapBigIntIndex
= [&](BigIntIndex index
) {
5278 return BigIntIndex(bigIntOffset
+ index
.index
);
5280 auto mapObjLiteralIndex
= [&](ObjLiteralIndex index
) {
5281 return ObjLiteralIndex(objLiteralOffset
+ index
.index
);
5283 auto mapScopeIndex
= [&](ScopeIndex index
) {
5284 return ScopeIndex(scopeOffset
+ index
.index
);
5287 // Append gcThingData, with mapping TaggedScriptThingIndex.
5288 if (!initial_
->gcThingData
.append(delazification
.gcThingData
.data(),
5289 delazification
.gcThingData
.size())) {
5290 js::ReportOutOfMemory(fc
);
5293 for (size_t i
= gcThingOffset
; i
< initial_
->gcThingData
.length(); i
++) {
5294 auto& index
= initial_
->gcThingData
[i
];
5295 if (index
.isNull()) {
5297 } else if (index
.isAtom()) {
5298 index
= TaggedScriptThingIndex(mapAtomIndex(index
.toAtom()));
5299 } else if (index
.isBigInt()) {
5300 index
= TaggedScriptThingIndex(mapBigIntIndex(index
.toBigInt()));
5301 } else if (index
.isObjLiteral()) {
5302 index
= TaggedScriptThingIndex(mapObjLiteralIndex(index
.toObjLiteral()));
5303 } else if (index
.isRegExp()) {
5304 index
= TaggedScriptThingIndex(mapRegExpIndex(index
.toRegExp()));
5305 } else if (index
.isScope()) {
5306 index
= TaggedScriptThingIndex(mapScopeIndex(index
.toScope()));
5307 } else if (index
.isFunction()) {
5308 index
= TaggedScriptThingIndex(mapScriptIndex(index
.toFunction()));
5310 MOZ_ASSERT(index
.isEmptyGlobalScope());
5315 // Append regExpData, with mapping RegExpStencil.atom_.
5316 if (!initial_
->regExpData
.append(delazification
.regExpData
.data(),
5317 delazification
.regExpData
.size())) {
5318 js::ReportOutOfMemory(fc
);
5321 for (size_t i
= regExpOffset
; i
< initial_
->regExpData
.length(); i
++) {
5322 auto& data
= initial_
->regExpData
[i
];
5323 data
.atom_
= mapAtomIndex(data
.atom_
);
5326 // Append bigIntData, with copying BigIntStencil.source_.
5327 if (!initial_
->bigIntData
.reserve(bigIntOffset
+
5328 delazification
.bigIntData
.size())) {
5329 js::ReportOutOfMemory(fc
);
5332 for (const auto& data
: delazification
.bigIntData
) {
5333 initial_
->bigIntData
.infallibleEmplaceBack();
5334 if (!initial_
->bigIntData
.back().init(fc
, initial_
->alloc
, data
.source())) {
5339 // Append objLiteralData, with copying ObjLiteralStencil.code_, and mapping
5340 // TaggedParserAtomIndex in it.
5341 if (!initial_
->objLiteralData
.reserve(objLiteralOffset
+
5342 delazification
.objLiteralData
.size())) {
5343 js::ReportOutOfMemory(fc
);
5346 for (const auto& data
: delazification
.objLiteralData
) {
5347 size_t length
= data
.code().size();
5348 auto* code
= initial_
->alloc
.newArrayUninitialized
<uint8_t>(length
);
5350 js::ReportOutOfMemory(fc
);
5353 memcpy(code
, data
.code().data(), length
);
5355 ObjLiteralModifier
modifier(mozilla::Span(code
, length
));
5356 modifier
.mapAtom(mapAtomIndex
);
5358 initial_
->objLiteralData
.infallibleEmplaceBack(
5359 code
, length
, data
.kind(), data
.flags(), data
.propertyCount());
5362 // Append scopeData, with mapping indices in ScopeStencil fields.
5363 // And append scopeNames, with copying the entire data, and mapping
5365 if (!initial_
->scopeData
.reserve(scopeOffset
+
5366 delazification
.scopeData
.size())) {
5367 js::ReportOutOfMemory(fc
);
5370 if (!initial_
->scopeNames
.reserve(scopeOffset
+
5371 delazification
.scopeNames
.size())) {
5372 js::ReportOutOfMemory(fc
);
5375 for (size_t i
= 0; i
< delazification
.scopeData
.size(); i
++) {
5376 const auto& srcData
= delazification
.scopeData
[i
];
5377 const auto* srcNames
= delazification
.scopeNames
[i
];
5379 mozilla::Maybe
<ScriptIndex
> functionIndex
= mozilla::Nothing();
5380 if (srcData
.isFunction()) {
5381 // Inner functions should be in the same order as initial, beginning from
5382 // the delazification's index.
5383 functionIndex
= mozilla::Some(mapScriptIndex(srcData
.functionIndex()));
5386 BaseParserScopeData
* destNames
= nullptr;
5388 destNames
= CopyScopeData(fc
, initial_
->alloc
, srcData
.kind(), srcNames
);
5392 auto trailingNames
=
5393 GetParserScopeDataTrailingNames(srcData
.kind(), destNames
);
5394 for (auto& name
: trailingNames
) {
5396 name
.updateNameAfterStencilMerge(mapAtomIndex(name
.name()));
5401 initial_
->scopeData
.infallibleEmplaceBack(
5403 srcData
.hasEnclosing()
5404 ? mozilla::Some(mapScopeIndex(srcData
.enclosing()))
5405 : functionEnclosingScope
,
5406 srcData
.firstFrameSlot(),
5407 srcData
.hasEnvironmentShape()
5408 ? mozilla::Some(srcData
.numEnvironmentSlots())
5409 : mozilla::Nothing(),
5410 functionIndex
, srcData
.isArrow());
5412 initial_
->scopeNames
.infallibleEmplaceBack(destNames
);
5415 // Add delazified function's shared data.
5417 // NOTE: Currently we don't delazify inner functions.
5418 if (!initial_
->sharedData
.addExtraWithoutShare(
5419 fc
, delazifiedFunctionIndex
,
5420 delazification
.sharedData
.get(CompilationStencil::TopLevelIndex
))) {
5424 // Update scriptData, with mapping indices in ScriptStencil fields.
5425 for (uint32_t i
= 0; i
< delazification
.scriptData
.size(); i
++) {
5426 auto destIndex
= mapScriptIndex(ScriptIndex(i
));
5427 MergeScriptStencil(initial_
->scriptData
[destIndex
],
5428 delazification
.scriptData
[i
], mapGCThingIndex
,
5429 mapAtomIndex
, mapScopeIndex
,
5430 i
== CompilationStencil::TopLevelIndex
);
5433 // WARNING: moduleMetadata and asmJS fields are known at script/module
5434 // top-level parsing, any mutation made in this function should be reflected
5435 // to ExtensibleCompilationStencil::steal and CompilationStencil::clone.
5437 // Function shouldn't be a module.
5438 MOZ_ASSERT(!delazification
.moduleMetadata
);
5440 // asm.js shouldn't appear inside delazification, given asm.js forces
5442 MOZ_ASSERT(!delazification
.asmJS
);
5444 failureCase
.release();
5448 void JS::StencilAddRef(JS::Stencil
* stencil
) { stencil
->refCount
++; }
5449 void JS::StencilRelease(JS::Stencil
* stencil
) {
5450 MOZ_RELEASE_ASSERT(stencil
->refCount
> 0);
5451 if (--stencil
->refCount
== 0) {
5456 template <typename CharT
>
5457 static already_AddRefed
<JS::Stencil
> CompileGlobalScriptToStencilImpl(
5458 JSContext
* cx
, const JS::ReadOnlyCompileOptions
& options
,
5459 JS::SourceText
<CharT
>& srcBuf
) {
5460 ScopeKind scopeKind
=
5461 options
.nonSyntacticScope
? ScopeKind::NonSyntactic
: ScopeKind::Global
;
5463 AutoReportFrontendContext
fc(cx
);
5464 NoScopeBindingCache scopeCache
;
5465 Rooted
<CompilationInput
> input(cx
, CompilationInput(options
));
5466 RefPtr
<JS::Stencil
> stencil
= js::frontend::CompileGlobalScriptToStencil(
5467 cx
, &fc
, cx
->tempLifoAlloc(), input
.get(), &scopeCache
, srcBuf
,
5473 // Convert the UniquePtr to a RefPtr and increment the count (to 1).
5474 return stencil
.forget();
5477 already_AddRefed
<JS::Stencil
> JS::CompileGlobalScriptToStencil(
5478 JSContext
* cx
, const JS::ReadOnlyCompileOptions
& options
,
5479 JS::SourceText
<mozilla::Utf8Unit
>& srcBuf
) {
5480 return CompileGlobalScriptToStencilImpl(cx
, options
, srcBuf
);
5483 already_AddRefed
<JS::Stencil
> JS::CompileGlobalScriptToStencil(
5484 JSContext
* cx
, const JS::ReadOnlyCompileOptions
& options
,
5485 JS::SourceText
<char16_t
>& srcBuf
) {
5486 return CompileGlobalScriptToStencilImpl(cx
, options
, srcBuf
);
5489 template <typename CharT
>
5490 static already_AddRefed
<JS::Stencil
> CompileModuleScriptToStencilImpl(
5491 JSContext
* cx
, const JS::ReadOnlyCompileOptions
& optionsInput
,
5492 JS::SourceText
<CharT
>& srcBuf
) {
5493 JS::CompileOptions
options(cx
, optionsInput
);
5494 options
.setModule();
5496 AutoReportFrontendContext
fc(cx
);
5497 NoScopeBindingCache scopeCache
;
5498 Rooted
<CompilationInput
> input(cx
, CompilationInput(options
));
5499 RefPtr
<JS::Stencil
> stencil
= js::frontend::ParseModuleToStencil(
5500 cx
, &fc
, cx
->tempLifoAlloc(), input
.get(), &scopeCache
, srcBuf
);
5505 // Convert the UniquePtr to a RefPtr and increment the count (to 1).
5506 return stencil
.forget();
5509 already_AddRefed
<JS::Stencil
> JS::CompileModuleScriptToStencil(
5510 JSContext
* cx
, const JS::ReadOnlyCompileOptions
& options
,
5511 JS::SourceText
<mozilla::Utf8Unit
>& srcBuf
) {
5512 return CompileModuleScriptToStencilImpl(cx
, options
, srcBuf
);
5515 already_AddRefed
<JS::Stencil
> JS::CompileModuleScriptToStencil(
5516 JSContext
* cx
, const JS::ReadOnlyCompileOptions
& options
,
5517 JS::SourceText
<char16_t
>& srcBuf
) {
5518 return CompileModuleScriptToStencilImpl(cx
, options
, srcBuf
);
5521 JS_PUBLIC_API JSScript
* JS::InstantiateGlobalStencil(
5522 JSContext
* cx
, const JS::InstantiateOptions
& options
, JS::Stencil
* stencil
,
5523 JS::InstantiationStorage
* storage
) {
5524 MOZ_ASSERT_IF(storage
, storage
->isValid());
5526 CompileOptions
compileOptions(cx
);
5527 options
.copyTo(compileOptions
);
5528 Rooted
<CompilationInput
> input(cx
, CompilationInput(compileOptions
));
5529 Rooted
<CompilationGCOutput
> gcOutput(cx
);
5531 gcOutput
.get().steal(std::move(*storage
->gcOutput_
));
5534 if (!InstantiateStencils(cx
, input
.get(), *stencil
, gcOutput
.get())) {
5537 return gcOutput
.get().script
;
5540 JS_PUBLIC_API
bool JS::StencilIsBorrowed(Stencil
* stencil
) {
5541 return stencil
->storageType
== CompilationStencil::StorageType::Borrowed
;
5544 JS_PUBLIC_API JSObject
* JS::InstantiateModuleStencil(
5545 JSContext
* cx
, const JS::InstantiateOptions
& options
, JS::Stencil
* stencil
,
5546 JS::InstantiationStorage
* storage
) {
5547 MOZ_ASSERT_IF(storage
, storage
->isValid());
5549 CompileOptions
compileOptions(cx
);
5550 options
.copyTo(compileOptions
);
5551 compileOptions
.setModule();
5552 Rooted
<CompilationInput
> input(cx
, CompilationInput(compileOptions
));
5553 Rooted
<CompilationGCOutput
> gcOutput(cx
);
5555 gcOutput
.get().steal(std::move(*storage
->gcOutput_
));
5558 if (!InstantiateStencils(cx
, input
.get(), *stencil
, gcOutput
.get())) {
5561 return gcOutput
.get().module
;
5564 JS::TranscodeResult
JS::EncodeStencil(JSContext
* cx
, JS::Stencil
* stencil
,
5565 TranscodeBuffer
& buffer
) {
5566 AutoReportFrontendContext
fc(cx
);
5567 XDRStencilEncoder
encoder(&fc
, buffer
);
5568 XDRResult res
= encoder
.codeStencil(*stencil
);
5570 return res
.unwrapErr();
5572 return TranscodeResult::Ok
;
5575 JS::TranscodeResult
JS::DecodeStencil(JSContext
* cx
,
5576 const JS::ReadOnlyDecodeOptions
& options
,
5577 const JS::TranscodeRange
& range
,
5578 JS::Stencil
** stencilOut
) {
5579 AutoReportFrontendContext
fc(cx
);
5580 return JS::DecodeStencil(&fc
, options
, range
, stencilOut
);
5583 JS::TranscodeResult
JS::DecodeStencil(JS::FrontendContext
* fc
,
5584 const JS::ReadOnlyDecodeOptions
& options
,
5585 const JS::TranscodeRange
& range
,
5586 JS::Stencil
** stencilOut
) {
5587 RefPtr
<ScriptSource
> source
= fc
->getAllocator()->new_
<ScriptSource
>();
5589 return TranscodeResult::Throw
;
5591 RefPtr
<JS::Stencil
> stencil(
5592 fc
->getAllocator()->new_
<CompilationStencil
>(source
));
5594 return TranscodeResult::Throw
;
5596 XDRStencilDecoder
decoder(fc
, range
);
5597 XDRResult res
= decoder
.codeStencil(options
, *stencil
);
5599 return res
.unwrapErr();
5601 *stencilOut
= stencil
.forget().take();
5602 return TranscodeResult::Ok
;
5605 JS_PUBLIC_API
size_t JS::SizeOfStencil(Stencil
* stencil
,
5606 mozilla::MallocSizeOf mallocSizeOf
) {
5607 return stencil
->sizeOfIncludingThis(mallocSizeOf
);
5610 JS::InstantiationStorage::~InstantiationStorage() {
5612 js_delete(gcOutput_
);
5613 gcOutput_
= nullptr;