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/RootingAPI.h" // Rooted
40 #include "js/Transcoding.h" // JS::TranscodeBuffer
41 #include "js/Utility.h" // js_malloc, js_calloc, js_free
42 #include "js/Value.h" // ObjectValue
43 #include "js/WasmModule.h" // JS::WasmModule
44 #include "vm/BigIntType.h" // ParseBigIntLiteral, BigIntLiteralIsZero
45 #include "vm/BindingKind.h" // BindingKind
46 #include "vm/EnvironmentObject.h"
47 #include "vm/GeneratorAndAsyncKind.h" // GeneratorKind, FunctionAsyncKind
48 #include "vm/JSContext.h" // JSContext
49 #include "vm/JSFunction.h" // JSFunction, GetFunctionPrototype, NewFunctionWithProto
50 #include "vm/JSObject.h" // JSObject, TenuredObject
51 #include "vm/JSONPrinter.h" // js::JSONPrinter
52 #include "vm/JSScript.h" // BaseScript, JSScript
53 #include "vm/RegExpObject.h" // js::RegExpObject
54 #include "vm/Scope.h" // Scope, *Scope, ScopeKind::*, ScopeKindString, ScopeIter, ScopeKindIsCatch, BindingIter, GetScopeDataTrailingNames, SizeOfParserScopeData
55 #include "vm/ScopeKind.h" // ScopeKind
56 #include "vm/SelfHosting.h" // SetClonedSelfHostedFunctionName
57 #include "vm/StaticStrings.h"
58 #include "vm/StencilEnums.h" // ImmutableScriptFlagsEnum
59 #include "vm/StringType.h" // JSAtom, js::CopyChars
60 #include "wasm/AsmJS.h" // InstantiateAsmJS
62 #include "vm/EnvironmentObject-inl.h" // JSObject::enclosingEnvironment
63 #include "vm/JSFunction-inl.h" // JSFunction::create
66 using namespace js::frontend
;
68 // These 2 functions are used to write the same code with lambda using auto
69 // arguments. The auto argument type is set by the Variant.match function of the
70 // InputScope variant. Thus dispatching to either a Scope* or to a
71 // ScopeStencilRef. This function can then be used as a way to specialize the
72 // code within the lambda without duplicating the code.
74 // Identically, an InputName is constructed using the scope type and the
75 // matching binding name type. This way, functions which are called by this
76 // lambda can manipulate an InputName and do not have to be duplicated.
78 // for (InputScopeIter si(...); si; si++) {
79 // si.scope().match([](auto& scope) {
80 // for (auto bi = InputBindingIter(scope); bi; bi++) {
81 // InputName name(scope, bi.name());
85 static js::BindingIter
InputBindingIter(Scope
* ptr
) {
86 return js::BindingIter(ptr
);
89 static ParserBindingIter
InputBindingIter(const ScopeStencilRef
& ref
) {
90 return ParserBindingIter(ref
);
93 static ParserBindingIter
InputBindingIter(const FakeStencilGlobalScope
&) {
94 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No bindings on empty global.");
97 InputName
InputScript::displayAtom() const {
100 return InputName(ptr
, ptr
->function()->fullDisplayAtom());
102 [](const ScriptStencilRef
& ref
) {
103 return InputName(ref
, ref
.scriptData().functionAtom
);
107 TaggedParserAtomIndex
InputName::internInto(FrontendContext
* fc
,
108 ParserAtomsTable
& parserAtoms
,
109 CompilationAtomCache
& atomCache
) {
110 return variant_
.match(
111 [&](JSAtom
* ptr
) -> TaggedParserAtomIndex
{
112 return parserAtoms
.internJSAtom(fc
, atomCache
, ptr
);
114 [&](NameStencilRef
& ref
) -> TaggedParserAtomIndex
{
115 return parserAtoms
.internExternalParserAtomIndex(fc
, ref
.context_
,
120 bool InputName::isEqualTo(FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
,
121 CompilationAtomCache
& atomCache
,
122 TaggedParserAtomIndex other
,
123 JSAtom
** otherCached
) const {
124 return variant_
.match(
125 [&](const JSAtom
* ptr
) -> bool {
126 if (ptr
->hash() != parserAtoms
.hash(other
)) {
130 // JSAtom variant is used only on the main thread delazification,
131 // where JSContext is always available.
132 JSContext
* cx
= fc
->maybeCurrentJSContext();
137 // Here, we convert our name into a JSAtom*, and hard-crash on failure
138 // to allocate. This conversion should not be required as we should be
139 // able to iterate up snapshotted scope chains that use parser atoms.
141 // This will be fixed when the enclosing scopes are snapshotted.
144 AutoEnterOOMUnsafeRegion oomUnsafe
;
145 *otherCached
= parserAtoms
.toJSAtom(cx
, fc
, other
, atomCache
);
147 oomUnsafe
.crash("InputName::isEqualTo");
150 MOZ_ASSERT(atomCache
.getExistingAtomAt(cx
, other
) == *otherCached
);
152 return ptr
== *otherCached
;
154 [&](const NameStencilRef
& ref
) -> bool {
155 return parserAtoms
.isEqualToExternalParserAtomIndex(other
, ref
.context_
,
160 GenericAtom::GenericAtom(FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
,
161 CompilationAtomCache
& atomCache
,
162 TaggedParserAtomIndex index
)
163 : ref(EmitterName(fc
, parserAtoms
, atomCache
, index
)) {
164 hash
= parserAtoms
.hash(index
);
167 GenericAtom::GenericAtom(const CompilationStencil
& context
,
168 TaggedParserAtomIndex index
)
169 : ref(StencilName
{context
, index
}) {
170 if (index
.isParserAtomIndex()) {
171 ParserAtom
* atom
= context
.parserAtomData
[index
.toParserAtomIndex()];
174 hash
= index
.staticOrWellKnownHash();
178 GenericAtom::GenericAtom(ScopeStencilRef
& scope
, TaggedParserAtomIndex index
)
179 : GenericAtom(scope
.context_
, index
) {}
181 BindingHasher
<TaggedParserAtomIndex
>::Lookup::Lookup(ScopeStencilRef
& scope_ref
,
182 const GenericAtom
& other
)
183 : keyStencil(scope_ref
.context_
), other(other
) {}
185 bool GenericAtom::operator==(const GenericAtom
& other
) const {
187 [&other
](const EmitterName
& name
) -> bool {
188 return other
.ref
.match(
189 [&name
](const EmitterName
& other
) -> bool {
190 // We never have multiple Emitter context at the same time.
191 MOZ_ASSERT(name
.fc
== other
.fc
);
192 MOZ_ASSERT(&name
.parserAtoms
== &other
.parserAtoms
);
193 MOZ_ASSERT(&name
.atomCache
== &other
.atomCache
);
194 return name
.index
== other
.index
;
196 [&name
](const StencilName
& other
) -> bool {
197 return name
.parserAtoms
.isEqualToExternalParserAtomIndex(
198 name
.index
, other
.stencil
, other
.index
);
200 [&name
](JSAtom
* other
) -> bool {
201 // JSAtom variant is used only on the main thread delazification,
202 // where JSContext is always available.
203 JSContext
* cx
= name
.fc
->maybeCurrentJSContext();
205 AutoEnterOOMUnsafeRegion oomUnsafe
;
206 JSAtom
* namePtr
= name
.parserAtoms
.toJSAtom(
207 cx
, name
.fc
, name
.index
, name
.atomCache
);
209 oomUnsafe
.crash("GenericAtom(EmitterName == JSAtom*)");
211 return namePtr
== other
;
214 [&other
](const StencilName
& name
) -> bool {
215 return other
.ref
.match(
216 [&name
](const EmitterName
& other
) -> bool {
217 return other
.parserAtoms
.isEqualToExternalParserAtomIndex(
218 other
.index
, name
.stencil
, name
.index
);
220 [&name
](const StencilName
& other
) -> bool {
221 // Technically it is possible to have multiple stencils, but in
222 // this particular case let's assume we never encounter a case
223 // where we are comparing names from different stencils.
225 // The reason this assumption is safe today is that we are only
226 // using this in the context of a stencil-delazification, where
227 // the only StencilNames are coming from the CompilationStencil
228 // provided to CompilationInput::initFromStencil.
229 MOZ_ASSERT(&name
.stencil
== &other
.stencil
);
230 return name
.index
== other
.index
;
232 [](JSAtom
* other
) -> bool {
233 MOZ_CRASH("Never used.");
237 [&other
](JSAtom
* name
) -> bool {
238 return other
.ref
.match(
239 [&name
](const EmitterName
& other
) -> bool {
240 // JSAtom variant is used only on the main thread delazification,
241 // where JSContext is always available.
242 JSContext
* cx
= other
.fc
->maybeCurrentJSContext();
244 AutoEnterOOMUnsafeRegion oomUnsafe
;
245 JSAtom
* otherPtr
= other
.parserAtoms
.toJSAtom(
246 cx
, other
.fc
, other
.index
, other
.atomCache
);
248 oomUnsafe
.crash("GenericAtom(JSAtom* == EmitterName)");
250 return name
== otherPtr
;
252 [](const StencilName
& other
) -> bool {
253 MOZ_CRASH("Never used.");
256 [&name
](JSAtom
* other
) -> bool { return name
== other
; });
261 template <typename SpanT
, typename VecT
>
262 void AssertBorrowingSpan(const SpanT
& span
, const VecT
& vec
) {
263 MOZ_ASSERT(span
.size() == vec
.length());
264 MOZ_ASSERT(span
.data() == vec
.begin());
268 bool ScopeBindingCache::canCacheFor(Scope
* ptr
) {
269 MOZ_CRASH("Unexpected scope chain type: Scope*");
272 bool ScopeBindingCache::canCacheFor(ScopeStencilRef ref
) {
273 MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef");
276 bool ScopeBindingCache::canCacheFor(const FakeStencilGlobalScope
& ref
) {
277 MOZ_CRASH("Unexpected scope chain type: FakeStencilGlobalScope");
280 BindingMap
<JSAtom
*>* ScopeBindingCache::createCacheFor(Scope
* ptr
) {
281 MOZ_CRASH("Unexpected scope chain type: Scope*");
284 BindingMap
<JSAtom
*>* ScopeBindingCache::lookupScope(Scope
* ptr
,
285 CacheGeneration gen
) {
286 MOZ_CRASH("Unexpected scope chain type: Scope*");
289 BindingMap
<TaggedParserAtomIndex
>* ScopeBindingCache::createCacheFor(
290 ScopeStencilRef ref
) {
291 MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef");
294 BindingMap
<TaggedParserAtomIndex
>* ScopeBindingCache::lookupScope(
295 ScopeStencilRef ref
, CacheGeneration gen
) {
296 MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef");
299 BindingMap
<TaggedParserAtomIndex
>* ScopeBindingCache::createCacheFor(
300 const FakeStencilGlobalScope
& ref
) {
301 MOZ_CRASH("Unexpected scope chain type: FakeStencilGlobalScope");
304 BindingMap
<TaggedParserAtomIndex
>* ScopeBindingCache::lookupScope(
305 const FakeStencilGlobalScope
& ref
, CacheGeneration gen
) {
306 MOZ_CRASH("Unexpected scope chain type: FakeStencilGlobalScope");
309 bool NoScopeBindingCache::canCacheFor(Scope
* ptr
) { return false; }
311 bool NoScopeBindingCache::canCacheFor(ScopeStencilRef ref
) { return false; }
313 bool NoScopeBindingCache::canCacheFor(const FakeStencilGlobalScope
& ref
) {
317 bool RuntimeScopeBindingCache::canCacheFor(Scope
* ptr
) { return true; }
319 BindingMap
<JSAtom
*>* RuntimeScopeBindingCache::createCacheFor(Scope
* ptr
) {
320 BaseScopeData
* dataPtr
= ptr
->rawData();
321 BindingMap
<JSAtom
*> bindingCache
;
322 if (!scopeMap
.putNew(dataPtr
, std::move(bindingCache
))) {
326 return lookupScope(ptr
, cacheGeneration
);
329 BindingMap
<JSAtom
*>* RuntimeScopeBindingCache::lookupScope(
330 Scope
* ptr
, CacheGeneration gen
) {
331 MOZ_ASSERT(gen
== cacheGeneration
);
332 BaseScopeData
* dataPtr
= ptr
->rawData();
333 auto valuePtr
= scopeMap
.lookup(dataPtr
);
337 return &valuePtr
->value();
340 bool StencilScopeBindingCache::canCacheFor(ScopeStencilRef ref
) { return true; }
342 BindingMap
<TaggedParserAtomIndex
>* StencilScopeBindingCache::createCacheFor(
343 ScopeStencilRef ref
) {
345 AssertBorrowingSpan(ref
.context_
.scopeNames
, merger_
.getResult().scopeNames
);
347 auto* dataPtr
= ref
.context_
.scopeNames
[ref
.scopeIndex_
];
348 BindingMap
<TaggedParserAtomIndex
> bindingCache
;
349 if (!scopeMap
.putNew(dataPtr
, std::move(bindingCache
))) {
353 return lookupScope(ref
, 1);
356 BindingMap
<TaggedParserAtomIndex
>* StencilScopeBindingCache::lookupScope(
357 ScopeStencilRef ref
, CacheGeneration gen
) {
359 AssertBorrowingSpan(ref
.context_
.scopeNames
, merger_
.getResult().scopeNames
);
361 auto* dataPtr
= ref
.context_
.scopeNames
[ref
.scopeIndex_
];
362 auto ptr
= scopeMap
.lookup(dataPtr
);
366 return &ptr
->value();
369 static AbstractBaseScopeData
<TaggedParserAtomIndex
>
370 moduleGlobalAbstractScopeData
;
372 bool StencilScopeBindingCache::canCacheFor(const FakeStencilGlobalScope
& ref
) {
376 BindingMap
<TaggedParserAtomIndex
>* StencilScopeBindingCache::createCacheFor(
377 const FakeStencilGlobalScope
& ref
) {
378 auto* dataPtr
= &moduleGlobalAbstractScopeData
;
379 BindingMap
<TaggedParserAtomIndex
> bindingCache
;
380 if (!scopeMap
.putNew(dataPtr
, std::move(bindingCache
))) {
384 return lookupScope(ref
, 1);
387 BindingMap
<TaggedParserAtomIndex
>* StencilScopeBindingCache::lookupScope(
388 const FakeStencilGlobalScope
& ref
, CacheGeneration gen
) {
389 auto* dataPtr
= &moduleGlobalAbstractScopeData
;
390 auto ptr
= scopeMap
.lookup(dataPtr
);
394 return &ptr
->value();
397 bool ScopeContext::init(FrontendContext
* fc
, CompilationInput
& input
,
398 ParserAtomsTable
& parserAtoms
,
399 ScopeBindingCache
* scopeCache
, InheritThis inheritThis
,
400 JSObject
* enclosingEnv
) {
401 // Record the scopeCache to be used while looking up NameLocation bindings.
402 this->scopeCache
= scopeCache
;
403 scopeCacheGen
= scopeCache
->getCurrentGeneration();
405 InputScope
maybeNonDefaultEnclosingScope(
406 input
.maybeNonDefaultEnclosingScope());
408 // If this eval is in response to Debugger.Frame.eval, we may have an
409 // incomplete scope chain. In order to provide a better debugging experience,
410 // we inspect the (optional) environment chain to determine it's enclosing
411 // FunctionScope if there is one. If there is no such scope, we use the
412 // orignal scope provided.
414 // NOTE: This is used to compute the ThisBinding kind and to allow access to
415 // private fields and methods, while other contextual information only
416 // uses the actual scope passed to the compile.
417 auto effectiveScope
=
418 determineEffectiveScope(maybeNonDefaultEnclosingScope
, enclosingEnv
);
420 if (inheritThis
== InheritThis::Yes
) {
421 computeThisBinding(effectiveScope
);
422 computeThisEnvironment(maybeNonDefaultEnclosingScope
);
424 computeInScope(maybeNonDefaultEnclosingScope
);
426 cacheEnclosingScope(input
.enclosingScope
);
428 if (input
.target
== CompilationInput::CompilationTarget::Eval
) {
429 if (!cacheEnclosingScopeBindingForEval(fc
, input
, parserAtoms
)) {
432 if (!cachePrivateFieldsForEval(fc
, input
, enclosingEnv
, effectiveScope
,
441 void ScopeContext::computeThisEnvironment(const InputScope
& enclosingScope
) {
442 uint32_t envCount
= 0;
443 for (InputScopeIter
si(enclosingScope
); si
; si
++) {
444 if (si
.kind() == ScopeKind::Function
) {
445 // Arrow function inherit the "this" environment of the enclosing script,
446 // so continue ignore them.
447 if (!si
.scope().isArrow()) {
448 allowNewTarget
= true;
450 if (si
.scope().allowSuperProperty()) {
451 allowSuperProperty
= true;
452 enclosingThisEnvironmentHops
= envCount
;
455 if (si
.scope().isClassConstructor()) {
457 si
.scope().useMemberInitializers()
458 ? mozilla::Some(si
.scope().getMemberInitializers())
459 : mozilla::Some(MemberInitializers::Empty());
460 MOZ_ASSERT(memberInitializers
->valid
);
462 if (si
.scope().isSyntheticFunction()) {
463 allowArguments
= false;
467 if (si
.scope().isDerivedClassConstructor()) {
468 allowSuperCall
= true;
471 // Found the effective "this" environment, so stop.
476 if (si
.scope().hasEnvironment()) {
482 void ScopeContext::computeThisBinding(const InputScope
& scope
) {
483 // Inspect the scope-chain.
484 for (InputScopeIter
si(scope
); si
; si
++) {
485 if (si
.kind() == ScopeKind::Module
) {
486 thisBinding
= ThisBinding::Module
;
490 if (si
.kind() == ScopeKind::Function
) {
491 // Arrow functions don't have their own `this` binding.
492 if (si
.scope().isArrow()) {
496 // Derived class constructors (and their nested arrow functions and evals)
497 // use ThisBinding::DerivedConstructor, which ensures TDZ checks happen
498 // when accessing |this|.
499 if (si
.scope().isDerivedClassConstructor()) {
500 thisBinding
= ThisBinding::DerivedConstructor
;
502 thisBinding
= ThisBinding::Function
;
509 thisBinding
= ThisBinding::Global
;
512 void ScopeContext::computeInScope(const InputScope
& enclosingScope
) {
513 for (InputScopeIter
si(enclosingScope
); si
; si
++) {
514 if (si
.kind() == ScopeKind::ClassBody
) {
518 if (si
.kind() == ScopeKind::With
) {
524 void ScopeContext::cacheEnclosingScope(const InputScope
& enclosingScope
) {
525 if (enclosingScope
.isNull()) {
529 enclosingScopeEnvironmentChainLength
=
530 enclosingScope
.environmentChainLength();
531 enclosingScopeKind
= enclosingScope
.kind();
533 if (enclosingScopeKind
== ScopeKind::Function
) {
534 enclosingScopeIsArrow
= enclosingScope
.isArrow();
537 enclosingScopeHasEnvironment
= enclosingScope
.hasEnvironment();
540 hasNonSyntacticScopeOnChain
=
541 enclosingScope
.hasOnChain(ScopeKind::NonSyntactic
);
543 // This computes a general answer for the query "does the enclosing scope
544 // have a function scope that needs a home object?", but it's only asserted
545 // if the parser parses eval body that contains `super` that needs a home
547 for (InputScopeIter
si(enclosingScope
); si
; si
++) {
548 if (si
.kind() == ScopeKind::Function
) {
549 if (si
.scope().isArrow()) {
552 if (si
.scope().allowSuperProperty() && si
.scope().needsHomeObject()) {
553 hasFunctionNeedsHomeObjectOnChain
= true;
560 // Pre-fill the scope cache by iterating over all the names. Stop iterating
561 // as soon as we find a scope which already has a filled scope cache.
562 AutoEnterOOMUnsafeRegion oomUnsafe
;
563 for (InputScopeIter
si(enclosingScope
); si
; si
++) {
564 // If the current scope already exists, then there is no need to go deeper
565 // as the scope which are encoded after this one should already be present
567 bool hasScopeCache
= si
.scope().match([&](auto& scope_ref
) -> bool {
568 MOZ_ASSERT(scopeCache
->canCacheFor(scope_ref
));
569 return scopeCache
->lookupScope(scope_ref
, scopeCacheGen
);
575 bool hasEnv
= si
.hasSyntacticEnvironment();
576 auto setCacthAll
= [&](NameLocation loc
) {
577 return si
.scope().match([&](auto& scope_ref
) {
578 using BindingMapPtr
= decltype(scopeCache
->createCacheFor(scope_ref
));
579 BindingMapPtr bindingMapPtr
= scopeCache
->createCacheFor(scope_ref
);
580 if (!bindingMapPtr
) {
582 "ScopeContext::cacheEnclosingScope: scopeCache->createCacheFor");
586 bindingMapPtr
->catchAll
.emplace(loc
);
589 auto createEmpty
= [&]() {
590 return si
.scope().match([&](auto& scope_ref
) {
591 using BindingMapPtr
= decltype(scopeCache
->createCacheFor(scope_ref
));
592 BindingMapPtr bindingMapPtr
= scopeCache
->createCacheFor(scope_ref
);
593 if (!bindingMapPtr
) {
595 "ScopeContext::cacheEnclosingScope: scopeCache->createCacheFor");
602 case ScopeKind::Function
:
604 if (si
.scope().funHasExtensibleScope()) {
605 setCacthAll(NameLocation::Dynamic());
609 si
.scope().match([&](auto& scope_ref
) {
610 using BindingMapPtr
=
611 decltype(scopeCache
->createCacheFor(scope_ref
));
613 typename
std::remove_pointer_t
<BindingMapPtr
>::Lookup
;
614 BindingMapPtr bindingMapPtr
= scopeCache
->createCacheFor(scope_ref
);
615 if (!bindingMapPtr
) {
617 "ScopeContext::cacheEnclosingScope: "
618 "scopeCache->createCacheFor");
622 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
623 NameLocation loc
= bi
.nameLocation();
624 if (loc
.kind() != NameLocation::Kind::EnvironmentCoordinate
) {
627 auto ctxFreeKey
= bi
.name();
628 GenericAtom
ctxKey(scope_ref
, ctxFreeKey
);
629 Lookup
ctxLookup(scope_ref
, ctxKey
);
630 if (!bindingMapPtr
->hashMap
.put(ctxLookup
, ctxFreeKey
, loc
)) {
632 "ScopeContext::cacheEnclosingScope: bindingMapPtr->put");
642 case ScopeKind::StrictEval
:
643 case ScopeKind::FunctionBodyVar
:
644 case ScopeKind::Lexical
:
645 case ScopeKind::NamedLambda
:
646 case ScopeKind::StrictNamedLambda
:
647 case ScopeKind::SimpleCatch
:
648 case ScopeKind::Catch
:
649 case ScopeKind::FunctionLexical
:
650 case ScopeKind::ClassBody
:
652 si
.scope().match([&](auto& scope_ref
) {
653 using BindingMapPtr
=
654 decltype(scopeCache
->createCacheFor(scope_ref
));
656 typename
std::remove_pointer_t
<BindingMapPtr
>::Lookup
;
657 BindingMapPtr bindingMapPtr
= scopeCache
->createCacheFor(scope_ref
);
658 if (!bindingMapPtr
) {
660 "ScopeContext::cacheEnclosingScope: "
661 "scopeCache->createCacheFor");
665 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
666 NameLocation loc
= bi
.nameLocation();
667 if (loc
.kind() != NameLocation::Kind::EnvironmentCoordinate
) {
670 auto ctxFreeKey
= bi
.name();
671 GenericAtom
ctxKey(scope_ref
, ctxFreeKey
);
672 Lookup
ctxLookup(scope_ref
, ctxKey
);
673 if (!bindingMapPtr
->hashMap
.putNew(ctxLookup
, ctxFreeKey
, loc
)) {
675 "ScopeContext::cacheEnclosingScope: bindingMapPtr->put");
685 case ScopeKind::Module
:
686 // This case is used only when delazifying a function inside
688 // Initial compilation of module doesn't have enlcosing scope.
690 si
.scope().match([&](auto& scope_ref
) {
691 using BindingMapPtr
=
692 decltype(scopeCache
->createCacheFor(scope_ref
));
694 typename
std::remove_pointer_t
<BindingMapPtr
>::Lookup
;
695 BindingMapPtr bindingMapPtr
= scopeCache
->createCacheFor(scope_ref
);
696 if (!bindingMapPtr
) {
698 "ScopeContext::cacheEnclosingScope: "
699 "scopeCache->createCacheFor");
703 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
704 // Imports are on the environment but are indirect
705 // bindings and must be accessed dynamically instead of
706 // using an EnvironmentCoordinate.
707 NameLocation loc
= bi
.nameLocation();
708 if (loc
.kind() != NameLocation::Kind::EnvironmentCoordinate
&&
709 loc
.kind() != NameLocation::Kind::Import
) {
712 auto ctxFreeKey
= bi
.name();
713 GenericAtom
ctxKey(scope_ref
, ctxFreeKey
);
714 Lookup
ctxLookup(scope_ref
, ctxKey
);
715 if (!bindingMapPtr
->hashMap
.putNew(ctxLookup
, ctxFreeKey
, loc
)) {
717 "ScopeContext::cacheEnclosingScope: bindingMapPtr->put");
727 case ScopeKind::Eval
:
728 // As an optimization, if the eval doesn't have its own var
729 // environment and its immediate enclosing scope is a global
730 // scope, all accesses are global.
732 ScopeKind kind
= si
.scope().enclosing().kind();
733 if (kind
== ScopeKind::Global
|| kind
== ScopeKind::NonSyntactic
) {
734 setCacthAll(NameLocation::Global(BindingKind::Var
));
739 setCacthAll(NameLocation::Dynamic());
742 case ScopeKind::Global
:
743 setCacthAll(NameLocation::Global(BindingKind::Var
));
746 case ScopeKind::With
:
747 case ScopeKind::NonSyntactic
:
748 setCacthAll(NameLocation::Dynamic());
751 case ScopeKind::WasmInstance
:
752 case ScopeKind::WasmFunction
:
753 MOZ_CRASH("No direct eval inside wasm functions");
757 MOZ_CRASH("Malformed scope chain");
760 InputScope
ScopeContext::determineEffectiveScope(InputScope
& scope
,
761 JSObject
* environment
) {
762 MOZ_ASSERT(effectiveScopeHops
== 0);
763 // If the scope-chain is non-syntactic, we may still determine a more precise
764 // effective-scope to use instead.
765 if (environment
&& scope
.hasOnChain(ScopeKind::NonSyntactic
)) {
766 JSObject
* env
= environment
;
768 // Look at target of any DebugEnvironmentProxy, but be sure to use
769 // enclosingEnvironment() of the proxy itself.
770 JSObject
* unwrapped
= env
;
771 if (env
->is
<DebugEnvironmentProxy
>()) {
772 unwrapped
= &env
->as
<DebugEnvironmentProxy
>().environment();
774 enclosingEnvironmentIsDebugProxy_
= true;
778 if (unwrapped
->is
<CallObject
>()) {
779 JSFunction
* callee
= &unwrapped
->as
<CallObject
>().callee();
780 return InputScope(callee
->nonLazyScript()->bodyScope());
783 env
= env
->enclosingEnvironment();
784 effectiveScopeHops
++;
791 static uint32_t DepthOfNearestVarScopeForDirectEval(const InputScope
& scope
) {
793 if (scope
.isNull()) {
796 for (InputScopeIter
si(scope
); si
; si
++) {
798 switch (si
.scope().kind()) {
799 case ScopeKind::Function
:
800 case ScopeKind::FunctionBodyVar
:
801 case ScopeKind::Global
:
802 case ScopeKind::NonSyntactic
:
811 bool ScopeContext::cacheEnclosingScopeBindingForEval(
812 FrontendContext
* fc
, CompilationInput
& input
,
813 ParserAtomsTable
& parserAtoms
) {
814 enclosingLexicalBindingCache_
.emplace();
816 uint32_t varScopeDepth
=
817 DepthOfNearestVarScopeForDirectEval(input
.enclosingScope
);
819 for (InputScopeIter
si(input
.enclosingScope
); si
; si
++) {
820 bool success
= si
.scope().match([&](auto& scope_ref
) {
821 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
823 case BindingKind::Let
: {
824 // Annex B.3.5 allows redeclaring simple (non-destructured)
825 // catch parameters with var declarations.
826 bool annexB35Allowance
= si
.kind() == ScopeKind::SimpleCatch
;
827 if (!annexB35Allowance
) {
828 auto kind
= ScopeKindIsCatch(si
.kind())
829 ? EnclosingLexicalBindingKind::CatchParameter
830 : EnclosingLexicalBindingKind::Let
;
831 InputName
binding(scope_ref
, bi
.name());
832 if (!addToEnclosingLexicalBindingCache(
833 fc
, parserAtoms
, input
.atomCache
, binding
, kind
)) {
840 case BindingKind::Const
: {
841 InputName
binding(scope_ref
, bi
.name());
842 if (!addToEnclosingLexicalBindingCache(
843 fc
, parserAtoms
, input
.atomCache
, binding
,
844 EnclosingLexicalBindingKind::Const
)) {
850 case BindingKind::Synthetic
: {
851 InputName
binding(scope_ref
, bi
.name());
852 if (!addToEnclosingLexicalBindingCache(
853 fc
, parserAtoms
, input
.atomCache
, binding
,
854 EnclosingLexicalBindingKind::Synthetic
)) {
860 case BindingKind::PrivateMethod
: {
861 InputName
binding(scope_ref
, bi
.name());
862 if (!addToEnclosingLexicalBindingCache(
863 fc
, parserAtoms
, input
.atomCache
, binding
,
864 EnclosingLexicalBindingKind::PrivateMethod
)) {
870 case BindingKind::Import
:
871 case BindingKind::FormalParameter
:
872 case BindingKind::Var
:
873 case BindingKind::NamedLambdaCallee
:
883 if (++depth
== varScopeDepth
) {
891 bool ScopeContext::addToEnclosingLexicalBindingCache(
892 FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
,
893 CompilationAtomCache
& atomCache
, InputName
& name
,
894 EnclosingLexicalBindingKind kind
) {
895 TaggedParserAtomIndex parserName
=
896 name
.internInto(fc
, parserAtoms
, atomCache
);
901 // Same lexical binding can appear multiple times across scopes.
903 // enclosingLexicalBindingCache_ map is used for detecting conflicting
904 // `var` binding, and inner binding should be reported in the error.
906 // cacheEnclosingScopeBindingForEval iterates from inner scope, and
907 // inner-most binding is added to the map first.
909 // Do not overwrite the value with outer bindings.
910 auto p
= enclosingLexicalBindingCache_
->lookupForAdd(parserName
);
912 if (!enclosingLexicalBindingCache_
->add(p
, parserName
, kind
)) {
913 ReportOutOfMemory(fc
);
921 static bool IsPrivateField(Scope
*, JSAtom
* atom
) {
922 MOZ_ASSERT(atom
->length() > 0);
924 JS::AutoCheckCannotGC nogc
;
925 if (atom
->hasLatin1Chars()) {
926 return atom
->latin1Chars(nogc
)[0] == '#';
929 return atom
->twoByteChars(nogc
)[0] == '#';
932 static bool IsPrivateField(ScopeStencilRef
& scope
, TaggedParserAtomIndex atom
) {
933 if (atom
.isParserAtomIndex()) {
934 const CompilationStencil
& context
= scope
.context_
;
935 ParserAtom
* parserAtom
= context
.parserAtomData
[atom
.toParserAtomIndex()];
936 return parserAtom
->isPrivateName();
940 if (atom
.isWellKnownAtomId()) {
941 const auto& info
= GetWellKnownAtomInfo(atom
.toWellKnownAtomId());
942 // #constructor is a well-known term, but it is invalid private name.
943 MOZ_ASSERT(!(info
.length
> 1 && info
.content
[0] == '#'));
944 } else if (atom
.isLength2StaticParserString()) {
946 ParserAtomsTable::getLength2Content(atom
.toLength2StaticParserString(),
948 // # character is not part of the allowed character of static strings.
949 MOZ_ASSERT(content
[0] != '#');
956 static bool IsPrivateField(const FakeStencilGlobalScope
&,
957 TaggedParserAtomIndex
) {
958 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No private fields on empty global.");
961 bool ScopeContext::cachePrivateFieldsForEval(FrontendContext
* fc
,
962 CompilationInput
& input
,
963 JSObject
* enclosingEnvironment
,
964 const InputScope
& effectiveScope
,
965 ParserAtomsTable
& parserAtoms
) {
966 effectiveScopePrivateFieldCache_
.emplace();
968 // We compute an environment coordinate relative to the effective scope
969 // environment. In order to safely consume these environment coordinates,
970 // we re-map them to include the hops to get the to the effective scope:
971 // see EmitterScope::lookupPrivate
972 uint32_t hops
= effectiveScopeHops
;
973 for (InputScopeIter
si(effectiveScope
); si
; si
++) {
974 if (si
.scope().kind() == ScopeKind::ClassBody
) {
976 bool success
= si
.scope().match([&](auto& scope_ref
) {
977 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
978 if (bi
.kind() == BindingKind::PrivateMethod
||
979 (bi
.kind() == BindingKind::Synthetic
&&
980 IsPrivateField(scope_ref
, bi
.name()))) {
981 InputName
binding(scope_ref
, bi
.name());
983 binding
.internInto(fc
, parserAtoms
, input
.atomCache
);
988 NameLocation loc
= NameLocation::DebugEnvironmentCoordinate(
989 bi
.kind(), hops
, slots
);
991 if (!effectiveScopePrivateFieldCache_
->put(parserName
, loc
)) {
992 ReportOutOfMemory(fc
);
1005 // Hops is only consumed by GetAliasedDebugVar, which uses this to
1006 // traverse the debug environment chain. See the [SMDOC] for Debug
1007 // Environment Chain, which explains why we don't check for
1008 // isEnvironment when computing hops here (basically, debug proxies
1009 // pretend all scopes have environments, even if they were actually
1018 static bool NameIsOnEnvironment(FrontendContext
* fc
,
1019 ParserAtomsTable
& parserAtoms
,
1020 CompilationAtomCache
& atomCache
,
1021 InputScope
& scope
, TaggedParserAtomIndex name
) {
1022 JSAtom
* jsname
= nullptr;
1023 return scope
.match([&](auto& scope_ref
) {
1024 if (std::is_same_v
<decltype(scope_ref
), FakeStencilGlobalScope
&>) {
1025 // This condition is added to handle the FakeStencilGlobalScope which is
1026 // used to emulate the global object when delazifying while executing, and
1027 // which is not provided by the Stencil.
1030 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
1031 // If found, the name must already be on the environment or an import,
1032 // or else there is a bug in the closed-over name analysis in the
1034 InputName
binding(scope_ref
, bi
.name());
1035 if (binding
.isEqualTo(fc
, parserAtoms
, atomCache
, name
, &jsname
)) {
1036 BindingLocation::Kind kind
= bi
.location().kind();
1038 if (bi
.hasArgumentSlot()) {
1039 // The following is equivalent to
1040 // functionScope.script()->functionAllowsParameterRedeclaration()
1041 if (scope
.hasMappedArgsObj()) {
1042 // Check for duplicate positional formal parameters.
1043 using InputBindingIter
= decltype(bi
);
1044 for (InputBindingIter
bi2(bi
); bi2
&& bi2
.hasArgumentSlot();
1046 InputName
binding2(scope_ref
, bi2
.name());
1047 if (binding2
.isEqualTo(fc
, parserAtoms
, atomCache
, name
,
1049 kind
= bi2
.location().kind();
1055 return kind
== BindingLocation::Kind::Global
||
1056 kind
== BindingLocation::Kind::Environment
||
1057 kind
== BindingLocation::Kind::Import
;
1061 // If not found, assume it's on the global or dynamically accessed.
1067 NameLocation
ScopeContext::searchInEnclosingScope(FrontendContext
* fc
,
1068 CompilationInput
& input
,
1069 ParserAtomsTable
& parserAtoms
,
1070 TaggedParserAtomIndex name
) {
1071 MOZ_ASSERT(input
.target
==
1072 CompilationInput::CompilationTarget::Delazification
||
1073 input
.target
== CompilationInput::CompilationTarget::Eval
);
1075 MOZ_ASSERT(scopeCache
);
1076 if (scopeCacheGen
!= scopeCache
->getCurrentGeneration()) {
1077 return searchInEnclosingScopeNoCache(fc
, input
, parserAtoms
, name
);
1081 // Catch assertion failures in the NoCache variant before looking at the
1083 NameLocation expect
=
1084 searchInEnclosingScopeNoCache(fc
, input
, parserAtoms
, name
);
1087 NameLocation found
=
1088 searchInEnclosingScopeWithCache(fc
, input
, parserAtoms
, name
);
1089 MOZ_ASSERT(expect
== found
);
1093 NameLocation
ScopeContext::searchInEnclosingScopeWithCache(
1094 FrontendContext
* fc
, CompilationInput
& input
, ParserAtomsTable
& parserAtoms
,
1095 TaggedParserAtomIndex name
) {
1096 MOZ_ASSERT(input
.target
==
1097 CompilationInput::CompilationTarget::Delazification
||
1098 input
.target
== CompilationInput::CompilationTarget::Eval
);
1100 // Generic atom of the looked up name.
1101 GenericAtom
genName(fc
, parserAtoms
, input
.atomCache
, name
);
1102 mozilla::Maybe
<NameLocation
> found
;
1104 // Number of enclosing scope we walked over.
1107 for (InputScopeIter
si(input
.enclosingScope
); si
; si
++) {
1108 MOZ_ASSERT(NameIsOnEnvironment(fc
, parserAtoms
, input
.atomCache
, si
.scope(),
1111 // If the result happens to be in the cached content of the scope that we
1112 // are iterating over, then return it.
1113 si
.scope().match([&](auto& scope_ref
) {
1114 using BindingMapPtr
=
1115 decltype(scopeCache
->lookupScope(scope_ref
, scopeCacheGen
));
1116 BindingMapPtr bindingMapPtr
=
1117 scopeCache
->lookupScope(scope_ref
, scopeCacheGen
);
1118 MOZ_ASSERT(bindingMapPtr
);
1120 auto& bindingMap
= *bindingMapPtr
;
1121 if (bindingMap
.catchAll
.isSome()) {
1122 found
= bindingMap
.catchAll
;
1126 // The scope_ref is given as argument to know where to lookup the key
1127 // index of the hash table if the names have to be compared.
1128 using Lookup
= typename
std::remove_pointer_t
<BindingMapPtr
>::Lookup
;
1129 Lookup
ctxName(scope_ref
, genName
);
1130 auto ptr
= bindingMap
.hashMap
.lookup(ctxName
);
1135 found
.emplace(ptr
->value());
1138 if (found
.isSome()) {
1139 // Cached entries do not store the number of hops, as it might be reused
1140 // by multiple inner functions, which might different number of hops.
1141 found
= found
.map([&hops
](NameLocation loc
) {
1142 if (loc
.kind() != NameLocation::Kind::EnvironmentCoordinate
) {
1145 return loc
.addHops(hops
);
1147 return found
.value();
1150 bool hasEnv
= si
.hasSyntacticEnvironment();
1153 MOZ_ASSERT(hops
< ENVCOORD_HOPS_LIMIT
- 1);
1158 MOZ_CRASH("Malformed scope chain");
1161 NameLocation
ScopeContext::searchInEnclosingScopeNoCache(
1162 FrontendContext
* fc
, CompilationInput
& input
, ParserAtomsTable
& parserAtoms
,
1163 TaggedParserAtomIndex name
) {
1164 MOZ_ASSERT(input
.target
==
1165 CompilationInput::CompilationTarget::Delazification
||
1166 input
.target
== CompilationInput::CompilationTarget::Eval
);
1168 // Cached JSAtom equivalent of the TaggedParserAtomIndex `name` argument.
1169 JSAtom
* jsname
= nullptr;
1171 // NameLocation which contains relative locations to access `name`.
1172 mozilla::Maybe
<NameLocation
> result
;
1174 // Number of enclosing scoep we walked over.
1177 for (InputScopeIter
si(input
.enclosingScope
); si
; si
++) {
1178 MOZ_ASSERT(NameIsOnEnvironment(fc
, parserAtoms
, input
.atomCache
, si
.scope(),
1181 bool hasEnv
= si
.hasSyntacticEnvironment();
1182 switch (si
.kind()) {
1183 case ScopeKind::Function
:
1185 if (si
.scope().funHasExtensibleScope()) {
1186 return NameLocation::Dynamic();
1189 si
.scope().match([&](auto& scope_ref
) {
1190 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
1191 InputName
binding(scope_ref
, bi
.name());
1192 if (!binding
.isEqualTo(fc
, parserAtoms
, input
.atomCache
, name
,
1197 BindingLocation bindLoc
= bi
.location();
1198 // hasMappedArgsObj == script.functionAllowsParameterRedeclaration
1199 if (bi
.hasArgumentSlot() && si
.scope().hasMappedArgsObj()) {
1200 // Check for duplicate positional formal parameters.
1201 using InputBindingIter
= decltype(bi
);
1202 for (InputBindingIter
bi2(bi
); bi2
&& bi2
.hasArgumentSlot();
1204 if (bi
.name() == bi2
.name()) {
1205 bindLoc
= bi2
.location();
1210 MOZ_ASSERT(bindLoc
.kind() == BindingLocation::Kind::Environment
);
1211 result
.emplace(NameLocation::EnvironmentCoordinate(
1212 bi
.kind(), hops
, bindLoc
.slot()));
1219 case ScopeKind::StrictEval
:
1220 case ScopeKind::FunctionBodyVar
:
1221 case ScopeKind::Lexical
:
1222 case ScopeKind::NamedLambda
:
1223 case ScopeKind::StrictNamedLambda
:
1224 case ScopeKind::SimpleCatch
:
1225 case ScopeKind::Catch
:
1226 case ScopeKind::FunctionLexical
:
1227 case ScopeKind::ClassBody
:
1229 si
.scope().match([&](auto& scope_ref
) {
1230 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
1231 InputName
binding(scope_ref
, bi
.name());
1232 if (!binding
.isEqualTo(fc
, parserAtoms
, input
.atomCache
, name
,
1237 // The name must already have been marked as closed
1238 // over. If this assertion is hit, there is a bug in the
1240 BindingLocation bindLoc
= bi
.location();
1241 MOZ_ASSERT(bindLoc
.kind() == BindingLocation::Kind::Environment
);
1242 result
.emplace(NameLocation::EnvironmentCoordinate(
1243 bi
.kind(), hops
, bindLoc
.slot()));
1250 case ScopeKind::Module
:
1251 // This case is used only when delazifying a function inside
1253 // Initial compilation of module doesn't have enlcosing scope.
1255 si
.scope().match([&](auto& scope_ref
) {
1256 for (auto bi
= InputBindingIter(scope_ref
); bi
; bi
++) {
1257 InputName
binding(scope_ref
, bi
.name());
1258 if (!binding
.isEqualTo(fc
, parserAtoms
, input
.atomCache
, name
,
1263 BindingLocation bindLoc
= bi
.location();
1265 // Imports are on the environment but are indirect
1266 // bindings and must be accessed dynamically instead of
1267 // using an EnvironmentCoordinate.
1268 if (bindLoc
.kind() == BindingLocation::Kind::Import
) {
1269 MOZ_ASSERT(si
.kind() == ScopeKind::Module
);
1270 result
.emplace(NameLocation::Import());
1274 MOZ_ASSERT(bindLoc
.kind() == BindingLocation::Kind::Environment
);
1275 result
.emplace(NameLocation::EnvironmentCoordinate(
1276 bi
.kind(), hops
, bindLoc
.slot()));
1283 case ScopeKind::Eval
:
1284 // As an optimization, if the eval doesn't have its own var
1285 // environment and its immediate enclosing scope is a global
1286 // scope, all accesses are global.
1288 ScopeKind kind
= si
.scope().enclosing().kind();
1289 if (kind
== ScopeKind::Global
|| kind
== ScopeKind::NonSyntactic
) {
1290 return NameLocation::Global(BindingKind::Var
);
1293 return NameLocation::Dynamic();
1295 case ScopeKind::Global
:
1296 return NameLocation::Global(BindingKind::Var
);
1298 case ScopeKind::With
:
1299 case ScopeKind::NonSyntactic
:
1300 return NameLocation::Dynamic();
1302 case ScopeKind::WasmInstance
:
1303 case ScopeKind::WasmFunction
:
1304 MOZ_CRASH("No direct eval inside wasm functions");
1307 if (result
.isSome()) {
1308 return result
.value();
1312 MOZ_ASSERT(hops
< ENVCOORD_HOPS_LIMIT
- 1);
1317 MOZ_CRASH("Malformed scope chain");
1320 mozilla::Maybe
<ScopeContext::EnclosingLexicalBindingKind
>
1321 ScopeContext::lookupLexicalBindingInEnclosingScope(TaggedParserAtomIndex name
) {
1322 auto p
= enclosingLexicalBindingCache_
->lookup(name
);
1324 return mozilla::Nothing();
1327 return mozilla::Some(p
->value());
1330 bool ScopeContext::effectiveScopePrivateFieldCacheHas(
1331 TaggedParserAtomIndex name
) {
1332 return effectiveScopePrivateFieldCache_
->has(name
);
1335 mozilla::Maybe
<NameLocation
> ScopeContext::getPrivateFieldLocation(
1336 TaggedParserAtomIndex name
) {
1337 // The locations returned by this method are only valid for
1338 // traversing debug environments.
1340 // See the comment in cachePrivateFieldsForEval
1341 MOZ_ASSERT(enclosingEnvironmentIsDebugProxy_
);
1342 auto p
= effectiveScopePrivateFieldCache_
->lookup(name
);
1344 return mozilla::Nothing();
1346 return mozilla::Some(p
->value());
1349 bool CompilationInput::initScriptSource(FrontendContext
* fc
) {
1350 source
= do_AddRef(fc
->getAllocator()->new_
<ScriptSource
>());
1355 return source
->initFromOptions(fc
, options
);
1358 bool CompilationInput::initForStandaloneFunctionInNonSyntacticScope(
1359 FrontendContext
* fc
, Handle
<Scope
*> functionEnclosingScope
) {
1360 MOZ_ASSERT(!functionEnclosingScope
->as
<GlobalScope
>().isSyntactic());
1362 target
= CompilationTarget::StandaloneFunctionInNonSyntacticScope
;
1363 if (!initScriptSource(fc
)) {
1366 enclosingScope
= InputScope(functionEnclosingScope
);
1370 FunctionSyntaxKind
CompilationInput::functionSyntaxKind() const {
1371 if (functionFlags().isClassConstructor()) {
1372 if (functionFlags().hasBaseScript() && isDerivedClassConstructor()) {
1373 return FunctionSyntaxKind::DerivedClassConstructor
;
1375 return FunctionSyntaxKind::ClassConstructor
;
1377 if (functionFlags().isMethod()) {
1378 if (functionFlags().hasBaseScript() && isSyntheticFunction()) {
1379 // return FunctionSyntaxKind::FieldInitializer;
1380 MOZ_ASSERT_UNREACHABLE(
1381 "Lazy parsing of class field initializers not supported (yet)");
1383 return FunctionSyntaxKind::Method
;
1385 if (functionFlags().isGetter()) {
1386 return FunctionSyntaxKind::Getter
;
1388 if (functionFlags().isSetter()) {
1389 return FunctionSyntaxKind::Setter
;
1391 if (functionFlags().isArrow()) {
1392 return FunctionSyntaxKind::Arrow
;
1394 return FunctionSyntaxKind::Statement
;
1397 bool CompilationInput::internExtraBindings(FrontendContext
* fc
,
1398 ParserAtomsTable
& parserAtoms
) {
1399 MOZ_ASSERT(hasExtraBindings());
1401 for (auto& bindingInfo
: *maybeExtraBindings_
) {
1402 if (bindingInfo
.isShadowed
) {
1406 const char* chars
= bindingInfo
.nameChars
.get();
1407 auto index
= parserAtoms
.internUtf8(
1408 fc
, reinterpret_cast<const mozilla::Utf8Unit
*>(chars
), strlen(chars
));
1413 bindingInfo
.nameIndex
= index
;
1419 void InputScope::trace(JSTracer
* trc
) {
1420 using ScopePtr
= Scope
*;
1421 if (scope_
.is
<ScopePtr
>()) {
1422 ScopePtr
* ptrAddr
= &scope_
.as
<ScopePtr
>();
1423 TraceNullableRoot(trc
, ptrAddr
, "compilation-input-scope");
1427 void InputScript::trace(JSTracer
* trc
) {
1428 using ScriptPtr
= BaseScript
*;
1429 if (script_
.is
<ScriptPtr
>()) {
1430 ScriptPtr
* ptrAddr
= &script_
.as
<ScriptPtr
>();
1431 TraceNullableRoot(trc
, ptrAddr
, "compilation-input-lazy");
1435 void CompilationInput::trace(JSTracer
* trc
) {
1436 atomCache
.trace(trc
);
1438 enclosingScope
.trace(trc
);
1441 bool CompilationSyntaxParseCache::init(FrontendContext
* fc
, LifoAlloc
& alloc
,
1442 ParserAtomsTable
& parseAtoms
,
1443 CompilationAtomCache
& atomCache
,
1444 const InputScript
& lazy
) {
1445 if (!copyFunctionInfo(fc
, parseAtoms
, atomCache
, lazy
)) {
1448 bool success
= lazy
.raw().match([&](auto& ref
) {
1449 if (!copyScriptInfo(fc
, alloc
, parseAtoms
, atomCache
, ref
)) {
1452 if (!copyClosedOverBindings(fc
, alloc
, parseAtoms
, atomCache
, ref
)) {
1461 isInitialized
= true;
1466 bool CompilationSyntaxParseCache::copyFunctionInfo(
1467 FrontendContext
* fc
, ParserAtomsTable
& parseAtoms
,
1468 CompilationAtomCache
& atomCache
, const InputScript
& lazy
) {
1469 InputName name
= lazy
.displayAtom();
1470 if (!name
.isNull()) {
1471 displayAtom_
= name
.internInto(fc
, parseAtoms
, atomCache
);
1472 if (!displayAtom_
) {
1477 funExtra_
.immutableFlags
= lazy
.immutableFlags();
1478 funExtra_
.extent
= lazy
.extent();
1479 if (funExtra_
.useMemberInitializers()) {
1480 funExtra_
.setMemberInitializers(lazy
.getMemberInitializers());
1486 bool CompilationSyntaxParseCache::copyScriptInfo(
1487 FrontendContext
* fc
, LifoAlloc
& alloc
, ParserAtomsTable
& parseAtoms
,
1488 CompilationAtomCache
& atomCache
, BaseScript
* lazy
) {
1489 using GCThingsSpan
= mozilla::Span
<TaggedScriptThingIndex
>;
1490 using ScriptDataSpan
= mozilla::Span
<ScriptStencil
>;
1491 using ScriptExtraSpan
= mozilla::Span
<ScriptStencilExtra
>;
1492 cachedGCThings_
= GCThingsSpan(nullptr);
1493 cachedScriptData_
= ScriptDataSpan(nullptr);
1494 cachedScriptExtra_
= ScriptExtraSpan(nullptr);
1496 auto gcthings
= lazy
->gcthings();
1497 size_t length
= gcthings
.Length();
1502 // Reduce the length to the first element which is not a function.
1503 for (size_t i
= 0; i
< length
; i
++) {
1504 gc::Cell
* cell
= gcthings
[i
].asCell();
1505 if (!cell
|| !cell
->is
<JSObject
>()) {
1509 MOZ_ASSERT(cell
->as
<JSObject
>()->is
<JSFunction
>());
1512 TaggedScriptThingIndex
* gcThingsData
=
1513 alloc
.newArrayUninitialized
<TaggedScriptThingIndex
>(length
);
1514 ScriptStencil
* scriptData
=
1515 alloc
.newArrayUninitialized
<ScriptStencil
>(length
);
1516 ScriptStencilExtra
* scriptExtra
=
1517 alloc
.newArrayUninitialized
<ScriptStencilExtra
>(length
);
1518 if (!gcThingsData
|| !scriptData
|| !scriptExtra
) {
1519 ReportOutOfMemory(fc
);
1523 for (size_t i
= 0; i
< length
; i
++) {
1524 gc::Cell
* cell
= gcthings
[i
].asCell();
1525 JSFunction
* fun
= &cell
->as
<JSObject
>()->as
<JSFunction
>();
1526 gcThingsData
[i
] = TaggedScriptThingIndex(ScriptIndex(i
));
1527 new (mozilla::KnownNotNull
, &scriptData
[i
]) ScriptStencil();
1528 ScriptStencil
& data
= scriptData
[i
];
1529 new (mozilla::KnownNotNull
, &scriptExtra
[i
]) ScriptStencilExtra();
1530 ScriptStencilExtra
& extra
= scriptExtra
[i
];
1532 if (fun
->fullDisplayAtom()) {
1533 TaggedParserAtomIndex displayAtom
=
1534 parseAtoms
.internJSAtom(fc
, atomCache
, fun
->fullDisplayAtom());
1538 data
.functionAtom
= displayAtom
;
1540 data
.functionFlags
= fun
->flags();
1542 BaseScript
* lazy
= fun
->baseScript();
1543 extra
.immutableFlags
= lazy
->immutableFlags();
1544 extra
.extent
= lazy
->extent();
1546 // Info derived from parent compilation should not be set yet for our inner
1547 // lazy functions. Instead that info will be updated when we finish our
1549 MOZ_ASSERT(lazy
->hasEnclosingScript());
1552 cachedGCThings_
= GCThingsSpan(gcThingsData
, length
);
1553 cachedScriptData_
= ScriptDataSpan(scriptData
, length
);
1554 cachedScriptExtra_
= ScriptExtraSpan(scriptExtra
, length
);
1558 bool CompilationSyntaxParseCache::copyScriptInfo(
1559 FrontendContext
* fc
, LifoAlloc
& alloc
, ParserAtomsTable
& parseAtoms
,
1560 CompilationAtomCache
& atomCache
, const ScriptStencilRef
& lazy
) {
1561 using GCThingsSpan
= mozilla::Span
<TaggedScriptThingIndex
>;
1562 using ScriptDataSpan
= mozilla::Span
<ScriptStencil
>;
1563 using ScriptExtraSpan
= mozilla::Span
<ScriptStencilExtra
>;
1564 cachedGCThings_
= GCThingsSpan(nullptr);
1565 cachedScriptData_
= ScriptDataSpan(nullptr);
1566 cachedScriptExtra_
= ScriptExtraSpan(nullptr);
1568 size_t offset
= lazy
.scriptData().gcThingsOffset
.index
;
1569 size_t length
= lazy
.scriptData().gcThingsLength
;
1574 // Reduce the length to the first element which is not a function.
1575 for (size_t i
= offset
; i
< offset
+ length
; i
++) {
1576 if (!lazy
.context_
.gcThingData
[i
].isFunction()) {
1577 length
= i
- offset
;
1582 TaggedScriptThingIndex
* gcThingsData
=
1583 alloc
.newArrayUninitialized
<TaggedScriptThingIndex
>(length
);
1584 ScriptStencil
* scriptData
=
1585 alloc
.newArrayUninitialized
<ScriptStencil
>(length
);
1586 ScriptStencilExtra
* scriptExtra
=
1587 alloc
.newArrayUninitialized
<ScriptStencilExtra
>(length
);
1588 if (!gcThingsData
|| !scriptData
|| !scriptExtra
) {
1589 ReportOutOfMemory(fc
);
1593 for (size_t i
= 0; i
< length
; i
++) {
1594 ScriptStencilRef inner
{lazy
.context_
,
1595 lazy
.context_
.gcThingData
[i
+ offset
].toFunction()};
1596 gcThingsData
[i
] = TaggedScriptThingIndex(ScriptIndex(i
));
1597 new (mozilla::KnownNotNull
, &scriptData
[i
]) ScriptStencil();
1598 ScriptStencil
& data
= scriptData
[i
];
1599 ScriptStencilExtra
& extra
= scriptExtra
[i
];
1601 InputName name
{inner
, inner
.scriptData().functionAtom
};
1602 if (!name
.isNull()) {
1603 auto displayAtom
= name
.internInto(fc
, parseAtoms
, atomCache
);
1607 data
.functionAtom
= displayAtom
;
1609 data
.functionFlags
= inner
.scriptData().functionFlags
;
1611 extra
= inner
.scriptExtra();
1614 cachedGCThings_
= GCThingsSpan(gcThingsData
, length
);
1615 cachedScriptData_
= ScriptDataSpan(scriptData
, length
);
1616 cachedScriptExtra_
= ScriptExtraSpan(scriptExtra
, length
);
1620 bool CompilationSyntaxParseCache::copyClosedOverBindings(
1621 FrontendContext
* fc
, LifoAlloc
& alloc
, ParserAtomsTable
& parseAtoms
,
1622 CompilationAtomCache
& atomCache
, BaseScript
* lazy
) {
1623 using ClosedOverBindingsSpan
= mozilla::Span
<TaggedParserAtomIndex
>;
1624 closedOverBindings_
= ClosedOverBindingsSpan(nullptr);
1626 // The gcthings() array contains the inner function list followed by the
1627 // closed-over bindings data. Skip the inner function list, as it is already
1628 // cached in cachedGCThings_. See also: BaseScript::CreateLazy.
1629 size_t start
= cachedGCThings_
.Length();
1630 auto gcthings
= lazy
->gcthings();
1631 size_t length
= gcthings
.Length();
1632 MOZ_ASSERT(start
<= length
);
1633 if (length
- start
== 0) {
1637 TaggedParserAtomIndex
* closedOverBindings
=
1638 alloc
.newArrayUninitialized
<TaggedParserAtomIndex
>(length
- start
);
1639 if (!closedOverBindings
) {
1640 ReportOutOfMemory(fc
);
1644 for (size_t i
= start
; i
< length
; i
++) {
1645 gc::Cell
* cell
= gcthings
[i
].asCell();
1647 closedOverBindings
[i
- start
] = TaggedParserAtomIndex::null();
1651 MOZ_ASSERT(cell
->as
<JSString
>()->isAtom());
1653 auto name
= static_cast<JSAtom
*>(cell
);
1654 auto parserAtom
= parseAtoms
.internJSAtom(fc
, atomCache
, name
);
1659 closedOverBindings
[i
- start
] = parserAtom
;
1662 closedOverBindings_
=
1663 ClosedOverBindingsSpan(closedOverBindings
, length
- start
);
1667 bool CompilationSyntaxParseCache::copyClosedOverBindings(
1668 FrontendContext
* fc
, LifoAlloc
& alloc
, ParserAtomsTable
& parseAtoms
,
1669 CompilationAtomCache
& atomCache
, const ScriptStencilRef
& lazy
) {
1670 using ClosedOverBindingsSpan
= mozilla::Span
<TaggedParserAtomIndex
>;
1671 closedOverBindings_
= ClosedOverBindingsSpan(nullptr);
1673 // The gcthings array contains the inner function list followed by the
1674 // closed-over bindings data. Skip the inner function list, as it is already
1675 // cached in cachedGCThings_. See also: BaseScript::CreateLazy.
1676 size_t offset
= lazy
.scriptData().gcThingsOffset
.index
;
1677 size_t length
= lazy
.scriptData().gcThingsLength
;
1678 size_t start
= cachedGCThings_
.Length();
1679 MOZ_ASSERT(start
<= length
);
1680 if (length
- start
== 0) {
1686 // Atoms from the lazy.context (CompilationStencil) are not registered in the
1687 // the parseAtoms table. Thus we create a new span which will contain all the
1689 TaggedParserAtomIndex
* closedOverBindings
=
1690 alloc
.newArrayUninitialized
<TaggedParserAtomIndex
>(length
);
1691 if (!closedOverBindings
) {
1692 ReportOutOfMemory(fc
);
1696 for (size_t i
= 0; i
< length
; i
++) {
1697 auto gcThing
= lazy
.context_
.gcThingData
[i
+ start
];
1698 if (gcThing
.isNull()) {
1699 closedOverBindings
[i
] = TaggedParserAtomIndex::null();
1703 MOZ_ASSERT(gcThing
.isAtom());
1704 InputName
name(lazy
, gcThing
.toAtom());
1705 auto parserAtom
= name
.internInto(fc
, parseAtoms
, atomCache
);
1710 closedOverBindings
[i
] = parserAtom
;
1713 closedOverBindings_
= ClosedOverBindingsSpan(closedOverBindings
, length
);
1717 template <typename T
>
1718 PreAllocateableGCArray
<T
>::~PreAllocateableGCArray() {
1725 template <typename T
>
1726 bool PreAllocateableGCArray
<T
>::allocate(size_t length
) {
1727 MOZ_ASSERT(empty());
1732 inlineElem_
= nullptr;
1736 elems_
= reinterpret_cast<T
*>(js_calloc(sizeof(T
) * length_
));
1744 template <typename T
>
1745 bool PreAllocateableGCArray
<T
>::allocateWith(T init
, size_t length
) {
1746 MOZ_ASSERT(empty());
1755 elems_
= reinterpret_cast<T
*>(js_malloc(sizeof(T
) * length_
));
1760 std::fill(elems_
, elems_
+ length_
, init
);
1764 template <typename T
>
1765 void PreAllocateableGCArray
<T
>::steal(Preallocated
&& buffer
) {
1766 MOZ_ASSERT(empty());
1768 length_
= buffer
.length_
;
1772 inlineElem_
= nullptr;
1776 elems_
= reinterpret_cast<T
*>(buffer
.elems_
);
1777 buffer
.elems_
= nullptr;
1780 for (size_t i
= 0; i
< length_
; i
++) {
1781 MOZ_ASSERT(elems_
[i
] == nullptr);
1786 template <typename T
>
1787 void PreAllocateableGCArray
<T
>::trace(JSTracer
* trc
) {
1793 TraceNullableRoot(trc
, &inlineElem_
, "PreAllocateableGCArray::inlineElem_");
1797 for (size_t i
= 0; i
< length_
; i
++) {
1798 TraceNullableRoot(trc
, &elems_
[i
], "PreAllocateableGCArray::elems_");
1802 template <typename T
>
1803 PreAllocateableGCArray
<T
>::Preallocated::~Preallocated() {
1810 template <typename T
>
1811 bool PreAllocateableGCArray
<T
>::Preallocated::allocate(size_t length
) {
1812 MOZ_ASSERT(empty());
1820 elems_
= reinterpret_cast<uintptr_t*>(js_calloc(sizeof(uintptr_t) * length_
));
1828 template struct js::frontend::PreAllocateableGCArray
<JSFunction
*>;
1829 template struct js::frontend::PreAllocateableGCArray
<js::Scope
*>;
1831 void CompilationAtomCache::trace(JSTracer
* trc
) { atoms_
.trace(trc
); }
1833 void CompilationGCOutput::trace(JSTracer
* trc
) {
1834 TraceNullableRoot(trc
, &script
, "compilation-gc-output-script");
1835 TraceNullableRoot(trc
, &module
, "compilation-gc-output-module");
1836 TraceNullableRoot(trc
, &sourceObject
, "compilation-gc-output-source");
1837 functions
.trace(trc
);
1841 RegExpObject
* RegExpStencil::createRegExp(
1842 JSContext
* cx
, const CompilationAtomCache
& atomCache
) const {
1843 Rooted
<JSAtom
*> atom(cx
, atomCache
.getExistingAtomAt(cx
, atom_
));
1844 return RegExpObject::createSyntaxChecked(cx
, atom
, flags(), TenuredObject
);
1847 RegExpObject
* RegExpStencil::createRegExpAndEnsureAtom(
1848 JSContext
* cx
, FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
,
1849 CompilationAtomCache
& atomCache
) const {
1850 Rooted
<JSAtom
*> atom(cx
, parserAtoms
.toJSAtom(cx
, fc
, atom_
, atomCache
));
1854 return RegExpObject::createSyntaxChecked(cx
, atom
, flags(), TenuredObject
);
1857 AbstractScopePtr
ScopeStencil::enclosing(
1858 CompilationState
& compilationState
) const {
1859 if (hasEnclosing()) {
1860 return AbstractScopePtr(compilationState
, enclosing());
1863 return AbstractScopePtr::compilationEnclosingScope(compilationState
);
1866 Scope
* ScopeStencil::enclosingExistingScope(
1867 const CompilationInput
& input
, const CompilationGCOutput
& gcOutput
) const {
1868 if (hasEnclosing()) {
1869 Scope
* result
= gcOutput
.getScopeNoBaseIndex(enclosing());
1870 MOZ_ASSERT(result
, "Scope must already exist to use this method");
1874 // When creating a scope based on the input and a gc-output, we assume that
1875 // the scope stencil that we are looking at has not been merged into another
1876 // stencil, and thus that we still have the compilation input of the stencil.
1878 // Otherwise, if this was in the case of an input generated from a Stencil
1879 // instead of live-gc values, we would not know its associated gcOutput as it
1880 // might not even have one yet.
1881 return input
.enclosingScope
.variant().as
<Scope
*>();
1884 Scope
* ScopeStencil::createScope(JSContext
* cx
, CompilationInput
& input
,
1885 CompilationGCOutput
& gcOutput
,
1886 BaseParserScopeData
* baseScopeData
) const {
1887 Rooted
<Scope
*> enclosingScope(cx
, enclosingExistingScope(input
, gcOutput
));
1888 return createScope(cx
, input
.atomCache
, enclosingScope
, baseScopeData
);
1891 Scope
* ScopeStencil::createScope(JSContext
* cx
, CompilationAtomCache
& atomCache
,
1892 Handle
<Scope
*> enclosingScope
,
1893 BaseParserScopeData
* baseScopeData
) const {
1895 case ScopeKind::Function
: {
1896 using ScopeType
= FunctionScope
;
1897 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1898 return createSpecificScope
<ScopeType
, CallObject
>(
1899 cx
, atomCache
, enclosingScope
, baseScopeData
);
1901 case ScopeKind::Lexical
:
1902 case ScopeKind::SimpleCatch
:
1903 case ScopeKind::Catch
:
1904 case ScopeKind::NamedLambda
:
1905 case ScopeKind::StrictNamedLambda
:
1906 case ScopeKind::FunctionLexical
: {
1907 using ScopeType
= LexicalScope
;
1908 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1909 return createSpecificScope
<ScopeType
, BlockLexicalEnvironmentObject
>(
1910 cx
, atomCache
, enclosingScope
, baseScopeData
);
1912 case ScopeKind::ClassBody
: {
1913 using ScopeType
= ClassBodyScope
;
1914 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1915 return createSpecificScope
<ScopeType
, BlockLexicalEnvironmentObject
>(
1916 cx
, atomCache
, enclosingScope
, baseScopeData
);
1918 case ScopeKind::FunctionBodyVar
: {
1919 using ScopeType
= VarScope
;
1920 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1921 return createSpecificScope
<ScopeType
, VarEnvironmentObject
>(
1922 cx
, atomCache
, enclosingScope
, baseScopeData
);
1924 case ScopeKind::Global
:
1925 case ScopeKind::NonSyntactic
: {
1926 using ScopeType
= GlobalScope
;
1927 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1928 return createSpecificScope
<ScopeType
, std::nullptr_t
>(
1929 cx
, atomCache
, enclosingScope
, baseScopeData
);
1931 case ScopeKind::Eval
:
1932 case ScopeKind::StrictEval
: {
1933 using ScopeType
= EvalScope
;
1934 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1935 return createSpecificScope
<ScopeType
, VarEnvironmentObject
>(
1936 cx
, atomCache
, enclosingScope
, baseScopeData
);
1938 case ScopeKind::Module
: {
1939 using ScopeType
= ModuleScope
;
1940 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1941 return createSpecificScope
<ScopeType
, ModuleEnvironmentObject
>(
1942 cx
, atomCache
, enclosingScope
, baseScopeData
);
1944 case ScopeKind::With
: {
1945 using ScopeType
= WithScope
;
1946 MOZ_ASSERT(matchScopeKind
<ScopeType
>(kind()));
1947 return createSpecificScope
<ScopeType
, std::nullptr_t
>(
1948 cx
, atomCache
, enclosingScope
, baseScopeData
);
1950 case ScopeKind::WasmFunction
:
1951 case ScopeKind::WasmInstance
: {
1952 // ScopeStencil does not support WASM
1959 bool CompilationState::prepareSharedDataStorage(FrontendContext
* fc
) {
1960 size_t allScriptCount
= scriptData
.length();
1961 size_t nonLazyScriptCount
= nonLazyFunctionCount
;
1962 if (!scriptData
[0].isFunction()) {
1963 nonLazyScriptCount
++;
1965 return sharedData
.prepareStorageFor(fc
, nonLazyScriptCount
, allScriptCount
);
1968 static bool CreateLazyScript(JSContext
* cx
,
1969 const CompilationAtomCache
& atomCache
,
1970 const CompilationStencil
& stencil
,
1971 CompilationGCOutput
& gcOutput
,
1972 const ScriptStencil
& script
,
1973 const ScriptStencilExtra
& scriptExtra
,
1974 ScriptIndex scriptIndex
, HandleFunction function
) {
1975 Rooted
<ScriptSourceObject
*> sourceObject(cx
, gcOutput
.sourceObject
);
1977 size_t ngcthings
= script
.gcThingsLength
;
1979 Rooted
<BaseScript
*> lazy(
1980 cx
, BaseScript::CreateRawLazy(cx
, ngcthings
, function
, sourceObject
,
1982 scriptExtra
.immutableFlags
));
1988 if (!EmitScriptThingsVector(cx
, atomCache
, stencil
, gcOutput
,
1989 script
.gcthings(stencil
),
1990 lazy
->gcthingsForInit())) {
1995 if (scriptExtra
.useMemberInitializers()) {
1996 lazy
->setMemberInitializers(scriptExtra
.memberInitializers());
1999 function
->initScript(lazy
);
2004 // Parser-generated functions with the same prototype will share the same shape.
2005 // By computing the correct values up front, we can save a lot of time in the
2006 // Object creation code. For simplicity, we focus only on plain synchronous
2007 // functions which are by far the most common.
2009 // NOTE: Keep this in sync with `js::NewFunctionWithProto`.
2010 static JSFunction
* CreateFunctionFast(JSContext
* cx
,
2011 CompilationAtomCache
& atomCache
,
2012 Handle
<SharedShape
*> shape
,
2013 const ScriptStencil
& script
,
2014 const ScriptStencilExtra
& scriptExtra
) {
2016 !scriptExtra
.immutableFlags
.hasFlag(ImmutableScriptFlagsEnum::IsAsync
));
2017 MOZ_ASSERT(!scriptExtra
.immutableFlags
.hasFlag(
2018 ImmutableScriptFlagsEnum::IsGenerator
));
2019 MOZ_ASSERT(!script
.functionFlags
.isAsmJSNative());
2021 FunctionFlags flags
= script
.functionFlags
;
2022 gc::AllocKind allocKind
= flags
.isExtended()
2023 ? gc::AllocKind::FUNCTION_EXTENDED
2024 : gc::AllocKind::FUNCTION
;
2026 JSFunction
* fun
= JSFunction::create(cx
, allocKind
, gc::Heap::Tenured
, shape
);
2031 fun
->setArgCount(scriptExtra
.nargs
);
2032 fun
->setFlags(flags
);
2034 fun
->initScript(nullptr);
2035 fun
->initEnvironment(nullptr);
2037 if (script
.functionAtom
) {
2038 JSAtom
* atom
= atomCache
.getExistingAtomAt(cx
, script
.functionAtom
);
2040 fun
->initAtom(atom
);
2044 fun
->assertFunctionKindIntegrity();
2050 static JSFunction
* CreateFunction(JSContext
* cx
,
2051 CompilationAtomCache
& atomCache
,
2052 const CompilationStencil
& stencil
,
2053 const ScriptStencil
& script
,
2054 const ScriptStencilExtra
& scriptExtra
,
2055 ScriptIndex functionIndex
) {
2056 GeneratorKind generatorKind
=
2057 scriptExtra
.immutableFlags
.hasFlag(ImmutableScriptFlagsEnum::IsGenerator
)
2058 ? GeneratorKind::Generator
2059 : GeneratorKind::NotGenerator
;
2060 FunctionAsyncKind asyncKind
=
2061 scriptExtra
.immutableFlags
.hasFlag(ImmutableScriptFlagsEnum::IsAsync
)
2062 ? FunctionAsyncKind::AsyncFunction
2063 : FunctionAsyncKind::SyncFunction
;
2065 // Determine the new function's proto. This must be done for singleton
2067 RootedObject
proto(cx
);
2068 if (!GetFunctionPrototype(cx
, generatorKind
, asyncKind
, &proto
)) {
2072 gc::AllocKind allocKind
= script
.functionFlags
.isExtended()
2073 ? gc::AllocKind::FUNCTION_EXTENDED
2074 : gc::AllocKind::FUNCTION
;
2075 bool isAsmJS
= script
.functionFlags
.isAsmJSNative();
2077 JSNative maybeNative
= isAsmJS
? InstantiateAsmJS
: nullptr;
2079 Rooted
<JSAtom
*> displayAtom(cx
);
2080 if (script
.functionAtom
) {
2081 displayAtom
.set(atomCache
.getExistingAtomAt(cx
, script
.functionAtom
));
2082 MOZ_ASSERT(displayAtom
);
2085 cx
, NewFunctionWithProto(cx
, maybeNative
, scriptExtra
.nargs
,
2086 script
.functionFlags
, nullptr, displayAtom
,
2087 proto
, allocKind
, TenuredObject
));
2093 RefPtr
<const JS::WasmModule
> asmJS
=
2094 stencil
.asmJS
->moduleMap
.lookup(functionIndex
)->value();
2096 JSObject
* moduleObj
= asmJS
->createObjectForAsmJS(cx
);
2101 fun
->setExtendedSlot(FunctionExtended::ASMJS_MODULE_SLOT
,
2102 ObjectValue(*moduleObj
));
2108 static bool InstantiateAtoms(JSContext
* cx
, FrontendContext
* fc
,
2109 CompilationAtomCache
& atomCache
,
2110 const CompilationStencil
& stencil
) {
2111 return InstantiateMarkedAtoms(cx
, fc
, stencil
.parserAtomData
, atomCache
);
2114 static bool InstantiateScriptSourceObject(JSContext
* cx
,
2115 const JS::InstantiateOptions
& options
,
2116 const CompilationStencil
& stencil
,
2117 CompilationGCOutput
& gcOutput
) {
2118 MOZ_ASSERT(stencil
.source
);
2120 gcOutput
.sourceObject
= ScriptSourceObject::create(cx
, stencil
.source
.get());
2121 if (!gcOutput
.sourceObject
) {
2125 Rooted
<ScriptSourceObject
*> sourceObject(cx
, gcOutput
.sourceObject
);
2126 if (!ScriptSourceObject::initFromOptions(cx
, sourceObject
, options
)) {
2133 // Instantiate ModuleObject. Further initialization is done after the associated
2134 // BaseScript is instantiated in InstantiateTopLevel.
2135 static bool InstantiateModuleObject(JSContext
* cx
, FrontendContext
* fc
,
2136 CompilationAtomCache
& atomCache
,
2137 const CompilationStencil
& stencil
,
2138 CompilationGCOutput
& gcOutput
) {
2139 MOZ_ASSERT(stencil
.isModule());
2141 gcOutput
.module
= ModuleObject::create(cx
);
2142 if (!gcOutput
.module
) {
2146 Rooted
<ModuleObject
*> module(cx
, gcOutput
.module
);
2147 return stencil
.moduleMetadata
->initModule(cx
, fc
, atomCache
, module
);
2150 // Instantiate JSFunctions for each FunctionBox.
2151 static bool InstantiateFunctions(JSContext
* cx
, FrontendContext
* fc
,
2152 CompilationAtomCache
& atomCache
,
2153 const CompilationStencil
& stencil
,
2154 CompilationGCOutput
& gcOutput
) {
2155 using ImmutableFlags
= ImmutableScriptFlagsEnum
;
2157 MOZ_ASSERT(gcOutput
.functions
.length() == stencil
.scriptData
.size());
2159 // Most JSFunctions will be have the same Shape so we can compute it now to
2160 // allow fast object creation. Generators / Async will use the slow path
2162 Rooted
<SharedShape
*> functionShape(
2163 cx
, GlobalObject::getFunctionShapeWithDefaultProto(
2164 cx
, /* extended = */ false));
2165 if (!functionShape
) {
2169 Rooted
<SharedShape
*> extendedShape(
2170 cx
, GlobalObject::getFunctionShapeWithDefaultProto(
2171 cx
, /* extended = */ true));
2172 if (!extendedShape
) {
2177 CompilationStencil::functionScriptStencils(stencil
, gcOutput
)) {
2178 const auto& scriptStencil
= item
.script
;
2179 const auto& scriptExtra
= (*item
.scriptExtra
);
2180 auto index
= item
.index
;
2182 MOZ_ASSERT(!item
.function
);
2184 // Plain functions can use a fast path.
2186 !scriptExtra
.immutableFlags
.hasFlag(ImmutableFlags::IsAsync
) &&
2187 !scriptExtra
.immutableFlags
.hasFlag(ImmutableFlags::IsGenerator
) &&
2188 !scriptStencil
.functionFlags
.isAsmJSNative();
2192 Handle
<SharedShape
*> shape
= scriptStencil
.functionFlags
.isExtended()
2196 CreateFunctionFast(cx
, atomCache
, shape
, scriptStencil
, scriptExtra
);
2198 fun
= CreateFunction(cx
, atomCache
, stencil
, scriptStencil
, scriptExtra
,
2206 // Self-hosted functions may have a canonical name to use when instantiating
2207 // into other realms.
2208 if (scriptStencil
.hasSelfHostedCanonicalName()) {
2209 JSAtom
* canonicalName
= atomCache
.getExistingAtomAt(
2210 cx
, scriptStencil
.selfHostedCanonicalName());
2211 fun
->setAtom(canonicalName
);
2214 gcOutput
.getFunctionNoBaseIndex(index
) = fun
;
2220 // Instantiate Scope for each ScopeStencil.
2222 // This should be called after InstantiateFunctions, given FunctionScope needs
2223 // associated JSFunction pointer, and also should be called before
2224 // InstantiateScriptStencils, given JSScript needs Scope pointer in gc things.
2225 static bool InstantiateScopes(JSContext
* cx
, CompilationInput
& input
,
2226 const CompilationStencil
& stencil
,
2227 CompilationGCOutput
& gcOutput
) {
2228 // While allocating Scope object from ScopeStencil, Scope object for the
2229 // enclosing Scope should already be allocated.
2231 // Enclosing scope of ScopeStencil can be either ScopeStencil or Scope*
2234 // If the enclosing scope is ScopeStencil, it's guaranteed to be earlier
2235 // element in stencil.scopeData, because enclosing_ field holds
2236 // index into it, and newly created ScopeStencil is pushed back to the array.
2238 // If the enclosing scope is Scope*, it's CompilationInput.enclosingScope.
2240 MOZ_ASSERT(stencil
.scopeData
.size() == stencil
.scopeNames
.size());
2241 size_t scopeCount
= stencil
.scopeData
.size();
2242 for (size_t i
= 0; i
< scopeCount
; i
++) {
2243 Scope
* scope
= stencil
.scopeData
[i
].createScope(cx
, input
, gcOutput
,
2244 stencil
.scopeNames
[i
]);
2248 gcOutput
.scopes
[i
] = scope
;
2254 // Instantiate js::BaseScripts from ScriptStencils for inner functions of the
2255 // compilation. Note that standalone functions and functions being delazified
2256 // are handled below with other top-levels.
2257 static bool InstantiateScriptStencils(JSContext
* cx
,
2258 CompilationAtomCache
& atomCache
,
2259 const CompilationStencil
& stencil
,
2260 CompilationGCOutput
& gcOutput
) {
2261 MOZ_ASSERT(stencil
.isInitialStencil());
2263 Rooted
<JSFunction
*> fun(cx
);
2265 CompilationStencil::functionScriptStencils(stencil
, gcOutput
)) {
2266 auto& scriptStencil
= item
.script
;
2267 auto* scriptExtra
= item
.scriptExtra
;
2268 fun
= item
.function
;
2269 auto index
= item
.index
;
2270 if (scriptStencil
.hasSharedData()) {
2271 // If the function was not referenced by enclosing script's bytecode, we
2272 // do not generate a BaseScript for it. For example, `(function(){});`.
2274 // `wasEmittedByEnclosingScript` is false also for standalone
2275 // functions. They are handled in InstantiateTopLevel.
2276 if (!scriptStencil
.wasEmittedByEnclosingScript()) {
2280 RootedScript
script(
2281 cx
, JSScript::fromStencil(cx
, atomCache
, stencil
, gcOutput
, index
));
2286 if (scriptStencil
.allowRelazify()) {
2287 MOZ_ASSERT(script
->isRelazifiable());
2288 script
->setAllowRelazify();
2290 } else if (scriptStencil
.functionFlags
.isAsmJSNative()) {
2291 MOZ_ASSERT(fun
->isAsmJSNative());
2293 MOZ_ASSERT(fun
->isIncomplete());
2294 if (!CreateLazyScript(cx
, atomCache
, stencil
, gcOutput
, scriptStencil
,
2295 *scriptExtra
, index
, fun
)) {
2304 // Instantiate the Stencil for the top-level script of the compilation. This
2305 // includes standalone functions and functions being delazified.
2306 static bool InstantiateTopLevel(JSContext
* cx
, CompilationInput
& input
,
2307 const CompilationStencil
& stencil
,
2308 CompilationGCOutput
& gcOutput
) {
2309 const ScriptStencil
& scriptStencil
=
2310 stencil
.scriptData
[CompilationStencil::TopLevelIndex
];
2312 // Top-level asm.js does not generate a JSScript.
2313 if (scriptStencil
.functionFlags
.isAsmJSNative()) {
2317 MOZ_ASSERT(scriptStencil
.hasSharedData());
2318 MOZ_ASSERT(stencil
.sharedData
.get(CompilationStencil::TopLevelIndex
));
2320 if (!stencil
.isInitialStencil()) {
2321 MOZ_ASSERT(input
.lazyOuterBaseScript());
2322 RootedScript
script(cx
,
2323 JSScript::CastFromLazy(input
.lazyOuterBaseScript()));
2324 if (!JSScript::fullyInitFromStencil(cx
, input
.atomCache
, stencil
, gcOutput
,
2326 CompilationStencil::TopLevelIndex
)) {
2330 if (scriptStencil
.allowRelazify()) {
2331 MOZ_ASSERT(script
->isRelazifiable());
2332 script
->setAllowRelazify();
2335 gcOutput
.script
= script
;
2340 JSScript::fromStencil(cx
, input
.atomCache
, stencil
, gcOutput
,
2341 CompilationStencil::TopLevelIndex
);
2342 if (!gcOutput
.script
) {
2346 if (scriptStencil
.allowRelazify()) {
2347 MOZ_ASSERT(gcOutput
.script
->isRelazifiable());
2348 gcOutput
.script
->setAllowRelazify();
2351 const ScriptStencilExtra
& scriptExtra
=
2352 stencil
.scriptExtra
[CompilationStencil::TopLevelIndex
];
2354 // Finish initializing the ModuleObject if needed.
2355 if (scriptExtra
.isModule()) {
2356 RootedScript
script(cx
, gcOutput
.script
);
2357 Rooted
<ModuleObject
*> module(cx
, gcOutput
.module
);
2359 script
->outermostScope()->as
<ModuleScope
>().initModule(module
);
2361 module
->initScriptSlots(script
);
2363 if (!ModuleObject::createEnvironment(cx
, module
)) {
2367 if (!ModuleObject::Freeze(cx
, module
)) {
2375 // When a function is first referenced by enclosing script's bytecode, we need
2376 // to update it with information determined by the BytecodeEmitter. This applies
2377 // to both initial and delazification parses. The functions being update may or
2378 // may not have bytecode at this point.
2379 static void UpdateEmittedInnerFunctions(JSContext
* cx
,
2380 CompilationAtomCache
& atomCache
,
2381 const CompilationStencil
& stencil
,
2382 CompilationGCOutput
& gcOutput
) {
2384 CompilationStencil::functionScriptStencils(stencil
, gcOutput
)) {
2385 auto& scriptStencil
= item
.script
;
2386 auto& fun
= item
.function
;
2387 if (!scriptStencil
.wasEmittedByEnclosingScript()) {
2391 if (scriptStencil
.functionFlags
.isAsmJSNative() ||
2392 fun
->baseScript()->hasBytecode()) {
2393 // Non-lazy inner functions don't use the enclosingScope_ field.
2394 MOZ_ASSERT(!scriptStencil
.hasLazyFunctionEnclosingScopeIndex());
2396 // Apply updates from FunctionEmitter::emitLazy().
2397 BaseScript
* script
= fun
->baseScript();
2399 ScopeIndex index
= scriptStencil
.lazyFunctionEnclosingScopeIndex();
2400 Scope
* scope
= gcOutput
.getScopeNoBaseIndex(index
);
2401 script
->setEnclosingScope(scope
);
2403 // Inferred and Guessed names are computed by BytecodeEmitter and so may
2404 // need to be applied to existing JSFunctions during delazification.
2405 if (fun
->fullDisplayAtom() == nullptr) {
2406 JSAtom
* funcAtom
= nullptr;
2407 if (scriptStencil
.functionFlags
.hasInferredName() ||
2408 scriptStencil
.functionFlags
.hasGuessedAtom()) {
2410 atomCache
.getExistingAtomAt(cx
, scriptStencil
.functionAtom
);
2411 MOZ_ASSERT(funcAtom
);
2413 if (scriptStencil
.functionFlags
.hasInferredName()) {
2414 fun
->setInferredName(funcAtom
);
2416 if (scriptStencil
.functionFlags
.hasGuessedAtom()) {
2417 fun
->setGuessedAtom(funcAtom
);
2424 // During initial parse we must link lazy-functions-inside-lazy-functions to
2425 // their enclosing script.
2426 static void LinkEnclosingLazyScript(const CompilationStencil
& stencil
,
2427 CompilationGCOutput
& gcOutput
) {
2429 CompilationStencil::functionScriptStencils(stencil
, gcOutput
)) {
2430 auto& scriptStencil
= item
.script
;
2431 auto& fun
= item
.function
;
2432 if (!scriptStencil
.functionFlags
.hasBaseScript()) {
2436 if (!fun
->baseScript()) {
2440 if (fun
->baseScript()->hasBytecode()) {
2444 BaseScript
* script
= fun
->baseScript();
2445 MOZ_ASSERT(!script
->hasBytecode());
2447 for (auto inner
: script
->gcthings()) {
2448 if (!inner
.is
<JSObject
>()) {
2451 JSFunction
* innerFun
= &inner
.as
<JSObject
>().as
<JSFunction
>();
2453 MOZ_ASSERT(innerFun
->hasBaseScript(),
2454 "inner function should have base script");
2455 if (!innerFun
->hasBaseScript()) {
2459 // Check for the case that the inner function has the base script flag,
2460 // but still doesn't have the actual base script pointer.
2461 // `baseScript` method asserts the pointer itself, so no extra MOZ_ASSERT
2463 if (!innerFun
->baseScript()) {
2467 innerFun
->setEnclosingLazyScript(script
);
2473 // Some fields aren't used in delazification, given the target functions and
2474 // scripts are already instantiated, but they still should match.
2475 static void AssertDelazificationFieldsMatch(const CompilationStencil
& stencil
,
2476 CompilationGCOutput
& gcOutput
) {
2478 CompilationStencil::functionScriptStencils(stencil
, gcOutput
)) {
2479 auto& scriptStencil
= item
.script
;
2480 auto* scriptExtra
= item
.scriptExtra
;
2481 auto& fun
= item
.function
;
2483 MOZ_ASSERT(scriptExtra
== nullptr);
2485 // Names are updated by UpdateInnerFunctions.
2486 constexpr uint16_t HAS_INFERRED_NAME
=
2487 uint16_t(FunctionFlags::Flags::HAS_INFERRED_NAME
);
2488 constexpr uint16_t HAS_GUESSED_ATOM
=
2489 uint16_t(FunctionFlags::Flags::HAS_GUESSED_ATOM
);
2490 constexpr uint16_t MUTABLE_FLAGS
=
2491 uint16_t(FunctionFlags::Flags::MUTABLE_FLAGS
);
2492 constexpr uint16_t acceptableDifferenceForFunction
=
2493 HAS_INFERRED_NAME
| HAS_GUESSED_ATOM
| MUTABLE_FLAGS
;
2495 MOZ_ASSERT((fun
->flags().toRaw() | acceptableDifferenceForFunction
) ==
2496 (scriptStencil
.functionFlags
.toRaw() |
2497 acceptableDifferenceForFunction
));
2499 // Delazification shouldn't delazify inner scripts.
2500 MOZ_ASSERT_IF(item
.index
== CompilationStencil::TopLevelIndex
,
2501 scriptStencil
.hasSharedData());
2502 MOZ_ASSERT_IF(item
.index
> CompilationStencil::TopLevelIndex
,
2503 !scriptStencil
.hasSharedData());
2508 // When delazifying, use the existing JSFunctions. The initial and delazifying
2509 // parse are required to generate the same sequence of functions for lazy
2510 // parsing to work at all.
2511 static void FunctionsFromExistingLazy(CompilationInput
& input
,
2512 CompilationGCOutput
& gcOutput
) {
2513 MOZ_ASSERT(!gcOutput
.functions
[0]);
2515 size_t instantiatedFunIndex
= 0;
2516 gcOutput
.functions
[instantiatedFunIndex
++] = input
.function();
2518 for (JS::GCCellPtr elem
: input
.lazyOuterBaseScript()->gcthings()) {
2519 if (!elem
.is
<JSObject
>()) {
2522 JSFunction
* fun
= &elem
.as
<JSObject
>().as
<JSFunction
>();
2523 gcOutput
.functions
[instantiatedFunIndex
++] = fun
;
2527 void CompilationStencil::borrowFromExtensibleCompilationStencil(
2528 ExtensibleCompilationStencil
& extensibleStencil
) {
2529 canLazilyParse
= extensibleStencil
.canLazilyParse
;
2530 functionKey
= extensibleStencil
.functionKey
;
2532 // Borrow the vector content as span.
2533 scriptData
= extensibleStencil
.scriptData
;
2534 scriptExtra
= extensibleStencil
.scriptExtra
;
2536 gcThingData
= extensibleStencil
.gcThingData
;
2538 scopeData
= extensibleStencil
.scopeData
;
2539 scopeNames
= extensibleStencil
.scopeNames
;
2541 regExpData
= extensibleStencil
.regExpData
;
2542 bigIntData
= extensibleStencil
.bigIntData
;
2543 objLiteralData
= extensibleStencil
.objLiteralData
;
2545 // Borrow the parser atoms as span.
2546 parserAtomData
= extensibleStencil
.parserAtoms
.entries_
;
2548 // Borrow container.
2549 sharedData
.setBorrow(&extensibleStencil
.sharedData
);
2551 // Share ref-counted data.
2552 source
= extensibleStencil
.source
;
2553 asmJS
= extensibleStencil
.asmJS
;
2554 moduleMetadata
= extensibleStencil
.moduleMetadata
;
2558 void CompilationStencil::assertBorrowingFromExtensibleCompilationStencil(
2559 const ExtensibleCompilationStencil
& extensibleStencil
) const {
2560 MOZ_ASSERT(canLazilyParse
== extensibleStencil
.canLazilyParse
);
2561 MOZ_ASSERT(functionKey
== extensibleStencil
.functionKey
);
2563 AssertBorrowingSpan(scriptData
, extensibleStencil
.scriptData
);
2564 AssertBorrowingSpan(scriptExtra
, extensibleStencil
.scriptExtra
);
2566 AssertBorrowingSpan(gcThingData
, extensibleStencil
.gcThingData
);
2568 AssertBorrowingSpan(scopeData
, extensibleStencil
.scopeData
);
2569 AssertBorrowingSpan(scopeNames
, extensibleStencil
.scopeNames
);
2571 AssertBorrowingSpan(regExpData
, extensibleStencil
.regExpData
);
2572 AssertBorrowingSpan(bigIntData
, extensibleStencil
.bigIntData
);
2573 AssertBorrowingSpan(objLiteralData
, extensibleStencil
.objLiteralData
);
2575 AssertBorrowingSpan(parserAtomData
, extensibleStencil
.parserAtoms
.entries_
);
2577 MOZ_ASSERT(sharedData
.isBorrow());
2578 MOZ_ASSERT(sharedData
.asBorrow() == &extensibleStencil
.sharedData
);
2580 MOZ_ASSERT(source
== extensibleStencil
.source
);
2581 MOZ_ASSERT(asmJS
== extensibleStencil
.asmJS
);
2582 MOZ_ASSERT(moduleMetadata
== extensibleStencil
.moduleMetadata
);
2586 CompilationStencil::CompilationStencil(
2587 UniquePtr
<ExtensibleCompilationStencil
>&& extensibleStencil
)
2588 : alloc(LifoAllocChunkSize
) {
2589 ownedBorrowStencil
= std::move(extensibleStencil
);
2591 storageType
= StorageType::OwnedExtensible
;
2593 borrowFromExtensibleCompilationStencil(*ownedBorrowStencil
);
2596 assertNoExternalDependency();
2601 bool CompilationStencil::instantiateStencils(JSContext
* cx
,
2602 CompilationInput
& input
,
2603 const CompilationStencil
& stencil
,
2604 CompilationGCOutput
& gcOutput
) {
2605 AutoReportFrontendContext
fc(cx
);
2606 if (!prepareForInstantiate(&fc
, input
.atomCache
, stencil
, gcOutput
)) {
2610 return instantiateStencilAfterPreparation(cx
, input
, stencil
, gcOutput
);
2614 bool CompilationStencil::instantiateStencilAfterPreparation(
2615 JSContext
* cx
, CompilationInput
& input
, const CompilationStencil
& stencil
,
2616 CompilationGCOutput
& gcOutput
) {
2617 // Distinguish between the initial (possibly lazy) compile and any subsequent
2618 // delazification compiles. Delazification will update existing GC things.
2619 bool isInitialParse
= stencil
.isInitialStencil();
2620 MOZ_ASSERT(stencil
.isInitialStencil() == input
.isInitialStencil());
2622 CompilationAtomCache
& atomCache
= input
.atomCache
;
2623 const JS::InstantiateOptions
options(input
.options
);
2625 // Phase 1: Instantiate JSAtom/JSStrings.
2626 AutoReportFrontendContext
fc(cx
);
2627 if (!InstantiateAtoms(cx
, &fc
, atomCache
, stencil
)) {
2631 // Phase 2: Instantiate ScriptSourceObject, ModuleObject, JSFunctions.
2632 if (isInitialParse
) {
2633 if (!InstantiateScriptSourceObject(cx
, options
, stencil
, gcOutput
)) {
2637 if (stencil
.moduleMetadata
) {
2638 // The enclosing script of a module is always the global scope. Fetch the
2639 // scope of the current global and update input data.
2640 MOZ_ASSERT(input
.enclosingScope
.isNull());
2641 input
.enclosingScope
= InputScope(&cx
->global()->emptyGlobalScope());
2642 MOZ_ASSERT(input
.enclosingScope
.environmentChainLength() ==
2643 ModuleScope::EnclosingEnvironmentChainLength
);
2645 if (!InstantiateModuleObject(cx
, &fc
, atomCache
, stencil
, gcOutput
)) {
2650 if (!InstantiateFunctions(cx
, &fc
, atomCache
, stencil
, gcOutput
)) {
2655 stencil
.scriptData
[CompilationStencil::TopLevelIndex
].isFunction());
2657 // FunctionKey is used when caching to map a delazification stencil to a
2658 // specific lazy script. It is not used by instantiation, but we should
2659 // ensure it is correctly defined.
2660 MOZ_ASSERT(stencil
.functionKey
== input
.extent().toFunctionKey());
2662 FunctionsFromExistingLazy(input
, gcOutput
);
2663 MOZ_ASSERT(gcOutput
.functions
.length() == stencil
.scriptData
.size());
2666 AssertDelazificationFieldsMatch(stencil
, gcOutput
);
2670 // Phase 3: Instantiate js::Scopes.
2671 if (!InstantiateScopes(cx
, input
, stencil
, gcOutput
)) {
2675 // Phase 4: Instantiate (inner) BaseScripts.
2676 if (isInitialParse
) {
2677 if (!InstantiateScriptStencils(cx
, atomCache
, stencil
, gcOutput
)) {
2682 // Phase 5: Finish top-level handling
2683 if (!InstantiateTopLevel(cx
, input
, stencil
, gcOutput
)) {
2687 // !! Must be infallible from here forward !!
2689 // Phase 6: Update lazy scripts.
2690 if (stencil
.canLazilyParse
) {
2691 UpdateEmittedInnerFunctions(cx
, atomCache
, stencil
, gcOutput
);
2693 if (isInitialParse
) {
2694 LinkEnclosingLazyScript(stencil
, gcOutput
);
2701 // The top-level self-hosted script is created and executed in each realm that
2702 // needs it. While the stencil has a gcthings list for the various top-level
2703 // functions, we use special machinery to create them on demand. So instead we
2704 // use a placeholder JSFunction that should never be called.
2705 static bool SelfHostedDummyFunction(JSContext
* cx
, unsigned argc
,
2707 MOZ_CRASH("Self-hosting top-level should not use functions directly");
2710 bool CompilationStencil::instantiateSelfHostedAtoms(
2711 JSContext
* cx
, AtomSet
& atomSet
, CompilationAtomCache
& atomCache
) const {
2712 MOZ_ASSERT(isInitialStencil());
2714 // We must instantiate atoms during startup so they can be made permanent
2715 // across multiple runtimes.
2716 AutoReportFrontendContext
fc(cx
);
2717 return InstantiateMarkedAtomsAsPermanent(cx
, &fc
, atomSet
, parserAtomData
,
2721 JSScript
* CompilationStencil::instantiateSelfHostedTopLevelForRealm(
2722 JSContext
* cx
, CompilationInput
& input
) {
2723 MOZ_ASSERT(isInitialStencil());
2725 Rooted
<CompilationGCOutput
> gcOutput(cx
);
2727 gcOutput
.get().sourceObject
= SelfHostingScriptSourceObject(cx
);
2728 if (!gcOutput
.get().sourceObject
) {
2732 // The top-level script has ScriptIndex references in its gcthings list, but
2733 // we do not want to instantiate those functions here since they are instead
2734 // created on demand from the stencil. Create a dummy function and populate
2735 // the functions array of the CompilationGCOutput with references to it.
2736 RootedFunction
dummy(
2737 cx
, NewNativeFunction(cx
, SelfHostedDummyFunction
, 0, nullptr));
2742 if (!gcOutput
.get().functions
.allocateWith(dummy
, scriptData
.size())) {
2743 ReportOutOfMemory(cx
);
2747 if (!InstantiateTopLevel(cx
, input
, *this, gcOutput
.get())) {
2751 return gcOutput
.get().script
;
2754 JSFunction
* CompilationStencil::instantiateSelfHostedLazyFunction(
2755 JSContext
* cx
, CompilationAtomCache
& atomCache
, ScriptIndex index
,
2756 Handle
<JSAtom
*> name
) {
2757 GeneratorKind generatorKind
= scriptExtra
[index
].immutableFlags
.hasFlag(
2758 ImmutableScriptFlagsEnum::IsGenerator
)
2759 ? GeneratorKind::Generator
2760 : GeneratorKind::NotGenerator
;
2761 FunctionAsyncKind asyncKind
= scriptExtra
[index
].immutableFlags
.hasFlag(
2762 ImmutableScriptFlagsEnum::IsAsync
)
2763 ? FunctionAsyncKind::AsyncFunction
2764 : FunctionAsyncKind::SyncFunction
;
2766 Rooted
<JSAtom
*> funName(cx
);
2767 if (scriptData
[index
].hasSelfHostedCanonicalName()) {
2768 // SetCanonicalName was used to override the name.
2769 funName
= atomCache
.getExistingAtomAt(
2770 cx
, scriptData
[index
].selfHostedCanonicalName());
2772 // Our caller has a name it wants to use.
2775 MOZ_ASSERT(scriptData
[index
].functionAtom
);
2776 funName
= atomCache
.getExistingAtomAt(cx
, scriptData
[index
].functionAtom
);
2779 RootedObject
proto(cx
);
2780 if (!GetFunctionPrototype(cx
, generatorKind
, asyncKind
, &proto
)) {
2784 RootedObject
env(cx
, &cx
->global()->lexicalEnvironment());
2788 NewFunctionWithProto(cx
, nullptr, scriptExtra
[index
].nargs
,
2789 scriptData
[index
].functionFlags
, env
, funName
, proto
,
2790 gc::AllocKind::FUNCTION_EXTENDED
, TenuredObject
));
2795 fun
->initSelfHostedLazyScript(&cx
->runtime()->selfHostedLazyScript
.ref());
2797 JSAtom
* selfHostedName
=
2798 atomCache
.getExistingAtomAt(cx
, scriptData
[index
].functionAtom
);
2799 SetClonedSelfHostedFunctionName(fun
, selfHostedName
->asPropertyName());
2804 bool CompilationStencil::delazifySelfHostedFunction(
2805 JSContext
* cx
, CompilationAtomCache
& atomCache
, ScriptIndexRange range
,
2806 HandleFunction fun
) {
2807 // Determine the equivalent ScopeIndex range by looking at the outermost scope
2808 // of the scripts defining the range. Take special care if this is the last
2809 // script in the list.
2810 auto getOutermostScope
= [this](ScriptIndex scriptIndex
) -> ScopeIndex
{
2811 MOZ_ASSERT(scriptData
[scriptIndex
].hasSharedData());
2812 auto gcthings
= scriptData
[scriptIndex
].gcthings(*this);
2813 return gcthings
[GCThingIndex::outermostScopeIndex()].toScope();
2815 ScopeIndex scopeIndex
= getOutermostScope(range
.start
);
2816 ScopeIndex scopeLimit
= (range
.limit
< scriptData
.size())
2817 ? getOutermostScope(range
.limit
)
2818 : ScopeIndex(scopeData
.size());
2820 // Prepare to instantiate by allocating the output arrays. We also set a base
2821 // index to avoid allocations in most cases.
2822 AutoReportFrontendContext
fc(cx
);
2823 Rooted
<CompilationGCOutput
> gcOutput(cx
);
2824 if (!gcOutput
.get().ensureAllocatedWithBaseIndex(
2825 &fc
, range
.start
, range
.limit
, scopeIndex
, scopeLimit
)) {
2829 // Phase 1: Instantiate JSAtoms.
2830 // NOTE: The self-hosted atoms are all "permanent" and the
2831 // CompilationAtomCache is already stored on the JSRuntime.
2833 // Phase 2: Instantiate ScriptSourceObject, ModuleObject, JSFunctions.
2835 // Get the corresponding ScriptSourceObject to use in current realm.
2836 gcOutput
.get().sourceObject
= SelfHostingScriptSourceObject(cx
);
2837 if (!gcOutput
.get().sourceObject
) {
2841 size_t instantiatedFunIndex
= 0;
2843 // Delazification target function.
2844 gcOutput
.get().functions
[instantiatedFunIndex
++] = fun
;
2846 // Allocate inner functions. Self-hosted functions do not allocate these with
2847 // the initial function.
2848 for (size_t i
= range
.start
+ 1; i
< range
.limit
; i
++) {
2849 JSFunction
* innerFun
= CreateFunction(cx
, atomCache
, *this, scriptData
[i
],
2850 scriptExtra
[i
], ScriptIndex(i
));
2854 gcOutput
.get().functions
[instantiatedFunIndex
++] = innerFun
;
2857 // Phase 3: Instantiate js::Scopes.
2858 // NOTE: When the enclosing scope is not a stencil, directly use the
2859 // `emptyGlobalScope` instead of reading from CompilationInput. This is
2860 // a special case for self-hosted delazification that allows us to reuse
2861 // the CompilationInput between different realms.
2862 size_t instantiatedScopeIndex
= 0;
2863 for (size_t i
= scopeIndex
; i
< scopeLimit
; i
++) {
2864 ScopeStencil
& data
= scopeData
[i
];
2865 Rooted
<Scope
*> enclosingScope(
2866 cx
, data
.hasEnclosing() ? gcOutput
.get().getScope(data
.enclosing())
2867 : &cx
->global()->emptyGlobalScope());
2870 data
.createScope(cx
, atomCache
, enclosingScope
, scopeNames
[i
]);
2874 gcOutput
.get().scopes
[instantiatedScopeIndex
++] = scope
;
2877 // Phase 4: Instantiate (inner) BaseScripts.
2878 ScriptIndex
innerStart(range
.start
+ 1);
2879 for (size_t i
= innerStart
; i
< range
.limit
; i
++) {
2880 if (!JSScript::fromStencil(cx
, atomCache
, *this, gcOutput
.get(),
2886 // Phase 5: Finish top-level handling
2887 // NOTE: We do not have a `CompilationInput` handy here, so avoid using the
2888 // `InstantiateTopLevel` helper and directly create the JSScript. Our
2889 // caller also handles the `AllowRelazify` flag for us since self-hosted
2890 // delazification is a special case.
2891 if (!JSScript::fromStencil(cx
, atomCache
, *this, gcOutput
.get(),
2896 // Phase 6: Update lazy scripts.
2897 // NOTE: Self-hosting is always fully parsed so there is nothing to do here.
2903 bool CompilationStencil::prepareForInstantiate(
2904 FrontendContext
* fc
, CompilationAtomCache
& atomCache
,
2905 const CompilationStencil
& stencil
, CompilationGCOutput
& gcOutput
) {
2906 // Allocate the `gcOutput` arrays.
2907 if (!gcOutput
.ensureAllocated(fc
, stencil
.scriptData
.size(),
2908 stencil
.scopeData
.size())) {
2912 return atomCache
.allocate(fc
, stencil
.parserAtomData
.size());
2916 bool CompilationStencil::prepareForInstantiate(
2917 FrontendContext
* fc
, const CompilationStencil
& stencil
,
2918 PreallocatedCompilationGCOutput
& gcOutput
) {
2919 return gcOutput
.allocate(fc
, stencil
.scriptData
.size(),
2920 stencil
.scopeData
.size());
2923 bool CompilationStencil::serializeStencils(JSContext
* cx
,
2924 CompilationInput
& input
,
2925 JS::TranscodeBuffer
& buf
,
2926 bool* succeededOut
) const {
2928 *succeededOut
= false;
2930 AutoReportFrontendContext
fc(cx
);
2931 XDRStencilEncoder
encoder(&fc
, buf
);
2933 XDRResult res
= encoder
.codeStencil(*this);
2935 if (JS::IsTranscodeFailureResult(res
.unwrapErr())) {
2939 MOZ_ASSERT(res
.unwrapErr() == JS::TranscodeResult::Throw
);
2945 *succeededOut
= true;
2950 bool CompilationStencil::deserializeStencils(
2951 FrontendContext
* fc
, const JS::ReadOnlyCompileOptions
& compileOptions
,
2952 const JS::TranscodeRange
& range
, bool* succeededOut
) {
2954 *succeededOut
= false;
2956 MOZ_ASSERT(parserAtomData
.empty());
2957 XDRStencilDecoder
decoder(fc
, range
);
2958 JS::DecodeOptions
options(compileOptions
);
2960 XDRResult res
= decoder
.codeStencil(options
, *this);
2962 if (JS::IsTranscodeFailureResult(res
.unwrapErr())) {
2965 MOZ_ASSERT(res
.unwrapErr() == JS::TranscodeResult::Throw
);
2971 *succeededOut
= true;
2976 ExtensibleCompilationStencil::ExtensibleCompilationStencil(ScriptSource
* source
)
2977 : alloc(CompilationStencil::LifoAllocChunkSize
),
2979 parserAtoms(alloc
) {}
2981 ExtensibleCompilationStencil::ExtensibleCompilationStencil(
2982 CompilationInput
& input
)
2983 : canLazilyParse(CanLazilyParse(input
.options
)),
2984 alloc(CompilationStencil::LifoAllocChunkSize
),
2985 source(input
.source
),
2986 parserAtoms(alloc
) {}
2988 ExtensibleCompilationStencil::ExtensibleCompilationStencil(
2989 const JS::ReadOnlyCompileOptions
& options
, RefPtr
<ScriptSource
> source
)
2990 : canLazilyParse(CanLazilyParse(options
)),
2991 alloc(CompilationStencil::LifoAllocChunkSize
),
2992 source(std::move(source
)),
2993 parserAtoms(alloc
) {}
2995 CompilationState::CompilationState(FrontendContext
* fc
,
2996 LifoAllocScope
& parserAllocScope
,
2997 CompilationInput
& input
)
2998 : ExtensibleCompilationStencil(input
),
2999 directives(input
.options
.forceStrictMode()),
3001 parserAllocScope(parserAllocScope
),
3004 BorrowingCompilationStencil::BorrowingCompilationStencil(
3005 ExtensibleCompilationStencil
& extensibleStencil
)
3006 : CompilationStencil(extensibleStencil
.source
) {
3007 storageType
= StorageType::Borrowed
;
3009 borrowFromExtensibleCompilationStencil(extensibleStencil
);
3012 SharedDataContainer::~SharedDataContainer() {
3015 } else if (isSingle()) {
3016 asSingle()->Release();
3017 } else if (isVector()) {
3018 js_delete(asVector());
3019 } else if (isMap()) {
3022 MOZ_ASSERT(isBorrow());
3027 bool SharedDataContainer::initVector(FrontendContext
* fc
) {
3028 MOZ_ASSERT(isEmpty());
3030 auto* vec
= js_new
<SharedDataVector
>();
3032 ReportOutOfMemory(fc
);
3035 data_
= uintptr_t(vec
) | VectorTag
;
3039 bool SharedDataContainer::initMap(FrontendContext
* fc
) {
3040 MOZ_ASSERT(isEmpty());
3042 auto* map
= js_new
<SharedDataMap
>();
3044 ReportOutOfMemory(fc
);
3047 data_
= uintptr_t(map
) | MapTag
;
3051 bool SharedDataContainer::prepareStorageFor(FrontendContext
* fc
,
3052 size_t nonLazyScriptCount
,
3053 size_t allScriptCount
) {
3054 MOZ_ASSERT(isEmpty());
3056 if (nonLazyScriptCount
<= 1) {
3057 MOZ_ASSERT(isSingle());
3061 // If the ratio of scripts with bytecode is small, allocating the Vector
3062 // storage with the number of all scripts isn't space-efficient.
3063 // In that case use HashMap instead.
3065 // In general, we expect either all scripts to contain bytecode (priviledge
3066 // and self-hosted), or almost none to (eg standard lazy parsing output).
3067 constexpr size_t thresholdRatio
= 8;
3068 bool useHashMap
= nonLazyScriptCount
< allScriptCount
/ thresholdRatio
;
3073 if (!asMap()->reserve(nonLazyScriptCount
)) {
3074 ReportOutOfMemory(fc
);
3078 if (!initVector(fc
)) {
3081 if (!asVector()->resize(allScriptCount
)) {
3082 ReportOutOfMemory(fc
);
3090 bool SharedDataContainer::cloneFrom(FrontendContext
* fc
,
3091 const SharedDataContainer
& other
) {
3092 MOZ_ASSERT(isEmpty());
3094 if (other
.isBorrow()) {
3095 return cloneFrom(fc
, *other
.asBorrow());
3098 if (other
.isSingle()) {
3099 // As we clone, we add an extra reference.
3100 RefPtr
<SharedImmutableScriptData
> ref(other
.asSingle());
3101 setSingle(ref
.forget());
3102 } else if (other
.isVector()) {
3103 if (!initVector(fc
)) {
3106 if (!asVector()->appendAll(*other
.asVector())) {
3107 ReportOutOfMemory(fc
);
3110 } else if (other
.isMap()) {
3114 auto& otherMap
= *other
.asMap();
3115 if (!asMap()->reserve(otherMap
.count())) {
3116 ReportOutOfMemory(fc
);
3119 auto& map
= *asMap();
3120 for (auto iter
= otherMap
.iter(); !iter
.done(); iter
.next()) {
3121 auto& entry
= iter
.get();
3122 map
.putNewInfallible(entry
.key(), entry
.value());
3128 js::SharedImmutableScriptData
* SharedDataContainer::get(
3129 ScriptIndex index
) const {
3131 if (index
== CompilationStencil::TopLevelIndex
) {
3138 auto& vec
= *asVector();
3139 if (index
.index
< vec
.length()) {
3146 auto& map
= *asMap();
3147 auto p
= map
.lookup(index
);
3154 MOZ_ASSERT(isBorrow());
3155 return asBorrow()->get(index
);
3158 bool SharedDataContainer::convertFromSingleToMap(FrontendContext
* fc
) {
3159 MOZ_ASSERT(isSingle());
3161 // Use a temporary container so that on OOM we do not break the stencil.
3162 SharedDataContainer other
;
3163 if (!other
.initMap(fc
)) {
3167 if (!other
.asMap()->putNew(CompilationStencil::TopLevelIndex
, asSingle())) {
3168 ReportOutOfMemory(fc
);
3172 std::swap(data_
, other
.data_
);
3176 bool SharedDataContainer::addAndShare(FrontendContext
* fc
, ScriptIndex index
,
3177 js::SharedImmutableScriptData
* data
) {
3178 MOZ_ASSERT(!isBorrow());
3181 MOZ_ASSERT(index
== CompilationStencil::TopLevelIndex
);
3182 RefPtr
<SharedImmutableScriptData
> ref(data
);
3183 if (!SharedImmutableScriptData::shareScriptData(fc
, ref
)) {
3186 setSingle(ref
.forget());
3191 auto& vec
= *asVector();
3192 // Resized by SharedDataContainer::prepareStorageFor.
3194 return SharedImmutableScriptData::shareScriptData(fc
, vec
[index
]);
3197 MOZ_ASSERT(isMap());
3198 auto& map
= *asMap();
3199 // Reserved by SharedDataContainer::prepareStorageFor.
3200 map
.putNewInfallible(index
, data
);
3201 auto p
= map
.lookup(index
);
3203 return SharedImmutableScriptData::shareScriptData(fc
, p
->value());
3206 bool SharedDataContainer::addExtraWithoutShare(
3207 FrontendContext
* fc
, ScriptIndex index
,
3208 js::SharedImmutableScriptData
* data
) {
3209 MOZ_ASSERT(!isEmpty());
3212 if (!convertFromSingleToMap(fc
)) {
3218 // SharedDataContainer::prepareStorageFor allocates space for all scripts.
3219 (*asVector())[index
] = data
;
3223 MOZ_ASSERT(isMap());
3224 // SharedDataContainer::prepareStorageFor doesn't allocate space for
3225 // delazification, and this can fail.
3226 if (!asMap()->putNew(index
, data
)) {
3227 ReportOutOfMemory(fc
);
3234 void CompilationStencil::assertNoExternalDependency() const {
3235 if (ownedBorrowStencil
) {
3236 ownedBorrowStencil
->assertNoExternalDependency();
3238 assertBorrowingFromExtensibleCompilationStencil(*ownedBorrowStencil
);
3242 MOZ_ASSERT_IF(!scriptData
.empty(), alloc
.contains(scriptData
.data()));
3243 MOZ_ASSERT_IF(!scriptExtra
.empty(), alloc
.contains(scriptExtra
.data()));
3245 MOZ_ASSERT_IF(!scopeData
.empty(), alloc
.contains(scopeData
.data()));
3246 MOZ_ASSERT_IF(!scopeNames
.empty(), alloc
.contains(scopeNames
.data()));
3247 for (const auto* data
: scopeNames
) {
3248 MOZ_ASSERT_IF(data
, alloc
.contains(data
));
3251 MOZ_ASSERT_IF(!regExpData
.empty(), alloc
.contains(regExpData
.data()));
3253 MOZ_ASSERT_IF(!bigIntData
.empty(), alloc
.contains(bigIntData
.data()));
3254 for (const auto& data
: bigIntData
) {
3255 MOZ_ASSERT(data
.isContainedIn(alloc
));
3258 MOZ_ASSERT_IF(!objLiteralData
.empty(), alloc
.contains(objLiteralData
.data()));
3259 for (const auto& data
: objLiteralData
) {
3260 MOZ_ASSERT(data
.isContainedIn(alloc
));
3263 MOZ_ASSERT_IF(!parserAtomData
.empty(), alloc
.contains(parserAtomData
.data()));
3264 for (const auto* data
: parserAtomData
) {
3265 MOZ_ASSERT_IF(data
, alloc
.contains(data
));
3268 MOZ_ASSERT(!sharedData
.isBorrow());
3271 void ExtensibleCompilationStencil::assertNoExternalDependency() const {
3272 for (const auto& data
: bigIntData
) {
3273 MOZ_ASSERT(data
.isContainedIn(alloc
));
3276 for (const auto& data
: objLiteralData
) {
3277 MOZ_ASSERT(data
.isContainedIn(alloc
));
3280 for (const auto* data
: scopeNames
) {
3281 MOZ_ASSERT_IF(data
, alloc
.contains(data
));
3284 for (const auto* data
: parserAtoms
.entries()) {
3285 MOZ_ASSERT_IF(data
, alloc
.contains(data
));
3288 MOZ_ASSERT(!sharedData
.isBorrow());
3292 template <typename T
, typename VectorT
>
3293 [[nodiscard
]] bool CopySpanToVector(FrontendContext
* fc
, VectorT
& vec
,
3294 mozilla::Span
<T
>& span
) {
3295 auto len
= span
.size();
3300 if (!vec
.append(span
.data(), len
)) {
3301 js::ReportOutOfMemory(fc
);
3307 template <typename T
, typename IntoSpanT
, size_t Inline
, typename AllocPolicy
>
3308 [[nodiscard
]] bool CopyToVector(FrontendContext
* fc
,
3309 mozilla::Vector
<T
, Inline
, AllocPolicy
>& vec
,
3310 const IntoSpanT
& source
) {
3311 mozilla::Span
<const T
> span
= source
;
3312 return CopySpanToVector(fc
, vec
, span
);
3315 // Span and Vector do not share the same method names.
3316 template <typename T
, size_t Inline
, typename AllocPolicy
>
3317 size_t GetLength(const mozilla::Vector
<T
, Inline
, AllocPolicy
>& vec
) {
3318 return vec
.length();
3320 template <typename T
>
3321 size_t GetLength(const mozilla::Span
<T
>& span
) {
3322 return span
.Length();
3325 // Copy scope names from `src` into `alloc`, and returns the allocated data.
3326 BaseParserScopeData
* CopyScopeData(FrontendContext
* fc
, LifoAlloc
& alloc
,
3328 const BaseParserScopeData
* src
) {
3329 MOZ_ASSERT(kind
!= ScopeKind::With
);
3331 size_t dataSize
= SizeOfParserScopeData(kind
, src
->length
);
3333 auto* dest
= static_cast<BaseParserScopeData
*>(alloc
.alloc(dataSize
));
3335 js::ReportOutOfMemory(fc
);
3338 memcpy(dest
, src
, dataSize
);
3343 template <typename Stencil
>
3344 bool ExtensibleCompilationStencil::cloneFromImpl(FrontendContext
* fc
,
3345 const Stencil
& other
) {
3346 MOZ_ASSERT(alloc
.isEmpty());
3348 canLazilyParse
= other
.canLazilyParse
;
3349 functionKey
= other
.functionKey
;
3351 if (!CopyToVector(fc
, scriptData
, other
.scriptData
)) {
3355 if (!CopyToVector(fc
, scriptExtra
, other
.scriptExtra
)) {
3359 if (!CopyToVector(fc
, gcThingData
, other
.gcThingData
)) {
3363 size_t scopeSize
= GetLength(other
.scopeData
);
3364 if (!CopyToVector(fc
, scopeData
, other
.scopeData
)) {
3367 if (!scopeNames
.reserve(scopeSize
)) {
3368 js::ReportOutOfMemory(fc
);
3371 for (size_t i
= 0; i
< scopeSize
; i
++) {
3372 if (other
.scopeNames
[i
]) {
3373 BaseParserScopeData
* data
= CopyScopeData(
3374 fc
, alloc
, other
.scopeData
[i
].kind(), other
.scopeNames
[i
]);
3378 scopeNames
.infallibleEmplaceBack(data
);
3380 scopeNames
.infallibleEmplaceBack(nullptr);
3384 if (!CopyToVector(fc
, regExpData
, other
.regExpData
)) {
3388 // If CompilationStencil has external dependency, peform deep copy.
3390 size_t bigIntSize
= GetLength(other
.bigIntData
);
3391 if (!bigIntData
.resize(bigIntSize
)) {
3392 js::ReportOutOfMemory(fc
);
3395 for (size_t i
= 0; i
< bigIntSize
; i
++) {
3396 if (!bigIntData
[i
].init(fc
, alloc
, other
.bigIntData
[i
].source())) {
3401 size_t objLiteralSize
= GetLength(other
.objLiteralData
);
3402 if (!objLiteralData
.reserve(objLiteralSize
)) {
3403 js::ReportOutOfMemory(fc
);
3406 for (const auto& data
: other
.objLiteralData
) {
3407 size_t length
= data
.code().size();
3408 auto* code
= alloc
.newArrayUninitialized
<uint8_t>(length
);
3410 js::ReportOutOfMemory(fc
);
3413 memcpy(code
, data
.code().data(), length
);
3414 objLiteralData
.infallibleEmplaceBack(code
, length
, data
.kind(),
3415 data
.flags(), data
.propertyCount());
3418 // Regardless of whether CompilationStencil has external dependency or not,
3419 // ParserAtoms should be interned, to populate internal HashMap.
3420 for (const auto* entry
: other
.parserAtomsSpan()) {
3422 if (!parserAtoms
.addPlaceholder(fc
)) {
3428 auto index
= parserAtoms
.internExternalParserAtom(fc
, entry
);
3434 // We copy the stencil and increment the reference count of each
3435 // SharedImmutableScriptData.
3436 if (!sharedData
.cloneFrom(fc
, other
.sharedData
)) {
3440 // Note: moduleMetadata and asmJS are known after the first parse, and are
3441 // not mutated by any delazifications later on. Thus we can safely increment
3442 // the reference counter and keep these as-is.
3443 moduleMetadata
= other
.moduleMetadata
;
3444 asmJS
= other
.asmJS
;
3447 assertNoExternalDependency();
3453 bool ExtensibleCompilationStencil::cloneFrom(FrontendContext
* fc
,
3454 const CompilationStencil
& other
) {
3455 return cloneFromImpl(fc
, other
);
3457 bool ExtensibleCompilationStencil::cloneFrom(
3458 FrontendContext
* fc
, const ExtensibleCompilationStencil
& other
) {
3459 return cloneFromImpl(fc
, other
);
3462 bool ExtensibleCompilationStencil::steal(FrontendContext
* fc
,
3463 RefPtr
<CompilationStencil
>&& other
) {
3464 MOZ_ASSERT(alloc
.isEmpty());
3465 using StorageType
= CompilationStencil::StorageType
;
3466 StorageType storageType
= other
->storageType
;
3467 if (other
->refCount
> 1) {
3468 storageType
= StorageType::Borrowed
;
3471 if (storageType
== StorageType::OwnedExtensible
) {
3472 auto& otherExtensible
= other
->ownedBorrowStencil
;
3474 canLazilyParse
= otherExtensible
->canLazilyParse
;
3475 functionKey
= otherExtensible
->functionKey
;
3477 alloc
.steal(&otherExtensible
->alloc
);
3479 source
= std::move(otherExtensible
->source
);
3481 scriptData
= std::move(otherExtensible
->scriptData
);
3482 scriptExtra
= std::move(otherExtensible
->scriptExtra
);
3483 gcThingData
= std::move(otherExtensible
->gcThingData
);
3484 scopeData
= std::move(otherExtensible
->scopeData
);
3485 scopeNames
= std::move(otherExtensible
->scopeNames
);
3486 regExpData
= std::move(otherExtensible
->regExpData
);
3487 bigIntData
= std::move(otherExtensible
->bigIntData
);
3488 objLiteralData
= std::move(otherExtensible
->objLiteralData
);
3490 parserAtoms
= std::move(otherExtensible
->parserAtoms
);
3491 parserAtoms
.fixupAlloc(alloc
);
3493 sharedData
= std::move(otherExtensible
->sharedData
);
3494 moduleMetadata
= std::move(otherExtensible
->moduleMetadata
);
3495 asmJS
= std::move(otherExtensible
->asmJS
);
3498 assertNoExternalDependency();
3504 if (storageType
== StorageType::Borrowed
) {
3505 return cloneFrom(fc
, *other
);
3508 MOZ_ASSERT(storageType
== StorageType::Owned
);
3510 canLazilyParse
= other
->canLazilyParse
;
3511 functionKey
= other
->functionKey
;
3514 other
->assertNoExternalDependency();
3515 MOZ_ASSERT(other
->refCount
== 1);
3518 // If CompilationStencil has no external dependency,
3519 // steal LifoAlloc and perform shallow copy.
3520 alloc
.steal(&other
->alloc
);
3522 if (!CopySpanToVector(fc
, scriptData
, other
->scriptData
)) {
3526 if (!CopySpanToVector(fc
, scriptExtra
, other
->scriptExtra
)) {
3530 if (!CopySpanToVector(fc
, gcThingData
, other
->gcThingData
)) {
3534 if (!CopySpanToVector(fc
, scopeData
, other
->scopeData
)) {
3537 if (!CopySpanToVector(fc
, scopeNames
, other
->scopeNames
)) {
3541 if (!CopySpanToVector(fc
, regExpData
, other
->regExpData
)) {
3545 if (!CopySpanToVector(fc
, bigIntData
, other
->bigIntData
)) {
3549 if (!CopySpanToVector(fc
, objLiteralData
, other
->objLiteralData
)) {
3553 // Regardless of whether CompilationStencil has external dependency or not,
3554 // ParserAtoms should be interned, to populate internal HashMap.
3555 for (const auto* entry
: other
->parserAtomData
) {
3557 if (!parserAtoms
.addPlaceholder(fc
)) {
3563 auto index
= parserAtoms
.internExternalParserAtom(fc
, entry
);
3569 sharedData
= std::move(other
->sharedData
);
3570 moduleMetadata
= std::move(other
->moduleMetadata
);
3571 asmJS
= std::move(other
->asmJS
);
3574 assertNoExternalDependency();
3580 bool CompilationStencil::isModule() const {
3581 return scriptExtra
[CompilationStencil::TopLevelIndex
].isModule();
3584 bool ExtensibleCompilationStencil::isModule() const {
3585 return scriptExtra
[CompilationStencil::TopLevelIndex
].isModule();
3588 mozilla::Span
<TaggedScriptThingIndex
> ScriptStencil::gcthings(
3589 const CompilationStencil
& stencil
) const {
3590 return stencil
.gcThingData
.Subspan(gcThingsOffset
, gcThingsLength
);
3593 bool BigIntStencil::init(FrontendContext
* fc
, LifoAlloc
& alloc
,
3594 const mozilla::Span
<const char16_t
> buf
) {
3596 // Assert we have no separators; if we have a separator then the algorithm
3597 // used in BigInt::literalIsZero will be incorrect.
3598 for (char16_t c
: buf
) {
3599 MOZ_ASSERT(c
!= '_');
3602 size_t length
= buf
.size();
3603 char16_t
* p
= alloc
.template newArrayUninitialized
<char16_t
>(length
);
3605 ReportOutOfMemory(fc
);
3608 mozilla::PodCopy(p
, buf
.data(), length
);
3609 source_
= mozilla::Span(p
, length
);
3613 BigInt
* BigIntStencil::createBigInt(JSContext
* cx
) const {
3614 mozilla::Range
<const char16_t
> source(source_
.data(), source_
.size());
3615 return js::ParseBigIntLiteral(cx
, source
);
3618 bool BigIntStencil::isZero() const {
3619 mozilla::Range
<const char16_t
> source(source_
.data(), source_
.size());
3620 return js::BigIntLiteralIsZero(source
);
3624 bool BigIntStencil::isContainedIn(const LifoAlloc
& alloc
) const {
3625 return alloc
.contains(source_
.data());
3629 #if defined(DEBUG) || defined(JS_JITSPEW)
3631 void frontend::DumpTaggedParserAtomIndex(js::JSONPrinter
& json
,
3632 TaggedParserAtomIndex taggedIndex
,
3633 const CompilationStencil
* stencil
) {
3634 if (taggedIndex
.isParserAtomIndex()) {
3635 json
.property("tag", "AtomIndex");
3636 auto index
= taggedIndex
.toParserAtomIndex();
3637 if (stencil
&& stencil
->parserAtomData
[index
]) {
3638 GenericPrinter
& out
= json
.beginStringProperty("atom");
3639 stencil
->parserAtomData
[index
]->dumpCharsNoQuote(out
);
3642 json
.property("index", size_t(index
));
3647 if (taggedIndex
.isWellKnownAtomId()) {
3648 json
.property("tag", "WellKnown");
3649 auto index
= taggedIndex
.toWellKnownAtomId();
3651 case WellKnownAtomId::empty_
:
3652 json
.property("atom", "");
3655 # define CASE_(name, _) case WellKnownAtomId::name:
3656 FOR_EACH_NONTINY_COMMON_PROPERTYNAME(CASE_
)
3659 # define CASE_(name, _) case WellKnownAtomId::name:
3660 JS_FOR_EACH_PROTOTYPE(CASE_
)
3663 # define CASE_(name) case WellKnownAtomId::name:
3664 JS_FOR_EACH_WELL_KNOWN_SYMBOL(CASE_
)
3668 GenericPrinter
& out
= json
.beginStringProperty("atom");
3669 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3675 // This includes tiny WellKnownAtomId atoms, which is invalid.
3676 json
.property("index", size_t(index
));
3682 if (taggedIndex
.isLength1StaticParserString()) {
3683 json
.property("tag", "Length1Static");
3684 auto index
= taggedIndex
.toLength1StaticParserString();
3685 GenericPrinter
& out
= json
.beginStringProperty("atom");
3686 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3691 if (taggedIndex
.isLength2StaticParserString()) {
3692 json
.property("tag", "Length2Static");
3693 auto index
= taggedIndex
.toLength2StaticParserString();
3694 GenericPrinter
& out
= json
.beginStringProperty("atom");
3695 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3700 if (taggedIndex
.isLength3StaticParserString()) {
3701 json
.property("tag", "Length3Static");
3702 auto index
= taggedIndex
.toLength3StaticParserString();
3703 GenericPrinter
& out
= json
.beginStringProperty("atom");
3704 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3709 MOZ_ASSERT(taggedIndex
.isNull());
3710 json
.property("tag", "null");
3713 void frontend::DumpTaggedParserAtomIndexNoQuote(
3714 GenericPrinter
& out
, TaggedParserAtomIndex taggedIndex
,
3715 const CompilationStencil
* stencil
) {
3716 if (taggedIndex
.isParserAtomIndex()) {
3717 auto index
= taggedIndex
.toParserAtomIndex();
3718 if (stencil
&& stencil
->parserAtomData
[index
]) {
3719 stencil
->parserAtomData
[index
]->dumpCharsNoQuote(out
);
3721 out
.printf("AtomIndex#%zu", size_t(index
));
3726 if (taggedIndex
.isWellKnownAtomId()) {
3727 auto index
= taggedIndex
.toWellKnownAtomId();
3729 case WellKnownAtomId::empty_
:
3730 out
.put("#<zero-length name>");
3733 # define CASE_(name, _) case WellKnownAtomId::name:
3734 FOR_EACH_NONTINY_COMMON_PROPERTYNAME(CASE_
)
3737 # define CASE_(name, _) case WellKnownAtomId::name:
3738 JS_FOR_EACH_PROTOTYPE(CASE_
)
3741 # define CASE_(name) case WellKnownAtomId::name:
3742 JS_FOR_EACH_WELL_KNOWN_SYMBOL(CASE_
)
3746 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3751 // This includes tiny WellKnownAtomId atoms, which is invalid.
3752 out
.printf("WellKnown#%zu", size_t(index
));
3758 if (taggedIndex
.isLength1StaticParserString()) {
3759 auto index
= taggedIndex
.toLength1StaticParserString();
3760 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3764 if (taggedIndex
.isLength2StaticParserString()) {
3765 auto index
= taggedIndex
.toLength2StaticParserString();
3766 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3770 if (taggedIndex
.isLength3StaticParserString()) {
3771 auto index
= taggedIndex
.toLength3StaticParserString();
3772 ParserAtomsTable::dumpCharsNoQuote(out
, index
);
3776 MOZ_ASSERT(taggedIndex
.isNull());
3777 out
.put("#<null name>");
3780 void RegExpStencil::dump() const {
3781 js::Fprinter
out(stderr
);
3782 js::JSONPrinter
json(out
);
3783 dump(json
, nullptr);
3786 void RegExpStencil::dump(js::JSONPrinter
& json
,
3787 const CompilationStencil
* stencil
) const {
3789 dumpFields(json
, stencil
);
3793 void RegExpStencil::dumpFields(js::JSONPrinter
& json
,
3794 const CompilationStencil
* stencil
) const {
3795 json
.beginObjectProperty("pattern");
3796 DumpTaggedParserAtomIndex(json
, atom_
, stencil
);
3799 GenericPrinter
& out
= json
.beginStringProperty("flags");
3801 if (flags().global()) {
3804 if (flags().ignoreCase()) {
3807 if (flags().multiline()) {
3810 if (flags().dotAll()) {
3813 if (flags().unicode()) {
3816 if (flags().sticky()) {
3820 json
.endStringProperty();
3823 void BigIntStencil::dump() const {
3824 js::Fprinter
out(stderr
);
3825 js::JSONPrinter
json(out
);
3829 void BigIntStencil::dump(js::JSONPrinter
& json
) const {
3830 GenericPrinter
& out
= json
.beginString();
3831 dumpCharsNoQuote(out
);
3835 void BigIntStencil::dumpCharsNoQuote(GenericPrinter
& out
) const {
3836 for (char16_t c
: source_
) {
3837 out
.putChar(char(c
));
3841 void ScopeStencil::dump() const {
3842 js::Fprinter
out(stderr
);
3843 js::JSONPrinter
json(out
);
3844 dump(json
, nullptr, nullptr);
3847 void ScopeStencil::dump(js::JSONPrinter
& json
,
3848 const BaseParserScopeData
* baseScopeData
,
3849 const CompilationStencil
* stencil
) const {
3851 dumpFields(json
, baseScopeData
, stencil
);
3855 void ScopeStencil::dumpFields(js::JSONPrinter
& json
,
3856 const BaseParserScopeData
* baseScopeData
,
3857 const CompilationStencil
* stencil
) const {
3858 json
.property("kind", ScopeKindString(kind_
));
3860 if (hasEnclosing()) {
3861 json
.formatProperty("enclosing", "ScopeIndex(%zu)", size_t(enclosing()));
3864 json
.property("firstFrameSlot", firstFrameSlot_
);
3866 if (hasEnvironmentShape()) {
3867 json
.formatProperty("numEnvironmentSlots", "%zu",
3868 size_t(numEnvironmentSlots_
));
3872 json
.formatProperty("functionIndex", "ScriptIndex(%zu)",
3873 size_t(functionIndex_
));
3876 json
.beginListProperty("flags");
3877 if (flags_
& HasEnclosing
) {
3878 json
.value("HasEnclosing");
3880 if (flags_
& HasEnvironmentShape
) {
3881 json
.value("HasEnvironmentShape");
3883 if (flags_
& IsArrow
) {
3884 json
.value("IsArrow");
3888 if (!baseScopeData
) {
3892 json
.beginObjectProperty("data");
3894 mozilla::Span
<const ParserBindingName
> trailingNames
;
3896 case ScopeKind::Function
: {
3898 static_cast<const FunctionScope::ParserData
*>(baseScopeData
);
3899 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3900 json
.property("hasParameterExprs", data
->slotInfo
.hasParameterExprs());
3901 json
.property("nonPositionalFormalStart",
3902 data
->slotInfo
.nonPositionalFormalStart
);
3903 json
.property("varStart", data
->slotInfo
.varStart
);
3905 trailingNames
= GetScopeDataTrailingNames(data
);
3909 case ScopeKind::FunctionBodyVar
: {
3911 static_cast<const VarScope::ParserData
*>(baseScopeData
);
3912 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3914 trailingNames
= GetScopeDataTrailingNames(data
);
3918 case ScopeKind::Lexical
:
3919 case ScopeKind::SimpleCatch
:
3920 case ScopeKind::Catch
:
3921 case ScopeKind::NamedLambda
:
3922 case ScopeKind::StrictNamedLambda
:
3923 case ScopeKind::FunctionLexical
: {
3925 static_cast<const LexicalScope::ParserData
*>(baseScopeData
);
3926 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3927 json
.property("constStart", data
->slotInfo
.constStart
);
3929 trailingNames
= GetScopeDataTrailingNames(data
);
3933 case ScopeKind::ClassBody
: {
3935 static_cast<const ClassBodyScope::ParserData
*>(baseScopeData
);
3936 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3937 json
.property("privateMethodStart", data
->slotInfo
.privateMethodStart
);
3939 trailingNames
= GetScopeDataTrailingNames(data
);
3943 case ScopeKind::With
: {
3947 case ScopeKind::Eval
:
3948 case ScopeKind::StrictEval
: {
3950 static_cast<const EvalScope::ParserData
*>(baseScopeData
);
3951 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3953 trailingNames
= GetScopeDataTrailingNames(data
);
3957 case ScopeKind::Global
:
3958 case ScopeKind::NonSyntactic
: {
3960 static_cast<const GlobalScope::ParserData
*>(baseScopeData
);
3961 json
.property("letStart", data
->slotInfo
.letStart
);
3962 json
.property("constStart", data
->slotInfo
.constStart
);
3964 trailingNames
= GetScopeDataTrailingNames(data
);
3968 case ScopeKind::Module
: {
3970 static_cast<const ModuleScope::ParserData
*>(baseScopeData
);
3971 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3972 json
.property("varStart", data
->slotInfo
.varStart
);
3973 json
.property("letStart", data
->slotInfo
.letStart
);
3974 json
.property("constStart", data
->slotInfo
.constStart
);
3976 trailingNames
= GetScopeDataTrailingNames(data
);
3980 case ScopeKind::WasmInstance
: {
3982 static_cast<const WasmInstanceScope::ParserData
*>(baseScopeData
);
3983 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3984 json
.property("globalsStart", data
->slotInfo
.globalsStart
);
3986 trailingNames
= GetScopeDataTrailingNames(data
);
3990 case ScopeKind::WasmFunction
: {
3992 static_cast<const WasmFunctionScope::ParserData
*>(baseScopeData
);
3993 json
.property("nextFrameSlot", data
->slotInfo
.nextFrameSlot
);
3995 trailingNames
= GetScopeDataTrailingNames(data
);
4000 MOZ_CRASH("Unexpected ScopeKind");
4005 if (!trailingNames
.empty()) {
4007 json
.beginObjectProperty("trailingNames");
4008 for (size_t i
= 0; i
< trailingNames
.size(); i
++) {
4009 const auto& name
= trailingNames
[i
];
4010 SprintfLiteral(index
, "%zu", i
);
4011 json
.beginObjectProperty(index
);
4013 json
.boolProperty("closedOver", name
.closedOver());
4015 json
.boolProperty("isTopLevelFunction", name
.isTopLevelFunction());
4017 json
.beginObjectProperty("name");
4018 DumpTaggedParserAtomIndex(json
, name
.name(), stencil
);
4029 static void DumpModuleRequestVectorItems(
4030 js::JSONPrinter
& json
, const StencilModuleMetadata::RequestVector
& requests
,
4031 const CompilationStencil
* stencil
) {
4032 for (const auto& request
: requests
) {
4034 if (request
.specifier
) {
4035 json
.beginObjectProperty("specifier");
4036 DumpTaggedParserAtomIndex(json
, request
.specifier
, stencil
);
4043 static void DumpModuleEntryVectorItems(
4044 js::JSONPrinter
& json
, const StencilModuleMetadata::EntryVector
& entries
,
4045 const CompilationStencil
* stencil
) {
4046 for (const auto& entry
: entries
) {
4048 if (entry
.moduleRequest
) {
4049 json
.property("moduleRequest", entry
.moduleRequest
.value());
4051 if (entry
.localName
) {
4052 json
.beginObjectProperty("localName");
4053 DumpTaggedParserAtomIndex(json
, entry
.localName
, stencil
);
4056 if (entry
.importName
) {
4057 json
.beginObjectProperty("importName");
4058 DumpTaggedParserAtomIndex(json
, entry
.importName
, stencil
);
4061 if (entry
.exportName
) {
4062 json
.beginObjectProperty("exportName");
4063 DumpTaggedParserAtomIndex(json
, entry
.exportName
, stencil
);
4066 // TODO: Dump assertions.
4071 void StencilModuleMetadata::dump() const {
4072 js::Fprinter
out(stderr
);
4073 js::JSONPrinter
json(out
);
4074 dump(json
, nullptr);
4077 void StencilModuleMetadata::dump(js::JSONPrinter
& json
,
4078 const CompilationStencil
* stencil
) const {
4080 dumpFields(json
, stencil
);
4084 void StencilModuleMetadata::dumpFields(
4085 js::JSONPrinter
& json
, const CompilationStencil
* stencil
) const {
4086 json
.beginListProperty("moduleRequests");
4087 DumpModuleRequestVectorItems(json
, moduleRequests
, stencil
);
4090 json
.beginListProperty("requestedModules");
4091 DumpModuleEntryVectorItems(json
, requestedModules
, stencil
);
4094 json
.beginListProperty("importEntries");
4095 DumpModuleEntryVectorItems(json
, importEntries
, stencil
);
4098 json
.beginListProperty("localExportEntries");
4099 DumpModuleEntryVectorItems(json
, localExportEntries
, stencil
);
4102 json
.beginListProperty("indirectExportEntries");
4103 DumpModuleEntryVectorItems(json
, indirectExportEntries
, stencil
);
4106 json
.beginListProperty("starExportEntries");
4107 DumpModuleEntryVectorItems(json
, starExportEntries
, stencil
);
4110 json
.beginListProperty("functionDecls");
4111 for (const auto& index
: functionDecls
) {
4112 json
.value("ScriptIndex(%zu)", size_t(index
));
4116 json
.boolProperty("isAsync", isAsync
);
4119 void js::DumpImmutableScriptFlags(js::JSONPrinter
& json
,
4120 ImmutableScriptFlags immutableFlags
) {
4121 for (uint32_t i
= 1; i
; i
= i
<< 1) {
4122 if (uint32_t(immutableFlags
) & i
) {
4123 switch (ImmutableScriptFlagsEnum(i
)) {
4124 case ImmutableScriptFlagsEnum::IsForEval
:
4125 json
.value("IsForEval");
4127 case ImmutableScriptFlagsEnum::IsModule
:
4128 json
.value("IsModule");
4130 case ImmutableScriptFlagsEnum::IsFunction
:
4131 json
.value("IsFunction");
4133 case ImmutableScriptFlagsEnum::SelfHosted
:
4134 json
.value("SelfHosted");
4136 case ImmutableScriptFlagsEnum::ForceStrict
:
4137 json
.value("ForceStrict");
4139 case ImmutableScriptFlagsEnum::HasNonSyntacticScope
:
4140 json
.value("HasNonSyntacticScope");
4142 case ImmutableScriptFlagsEnum::NoScriptRval
:
4143 json
.value("NoScriptRval");
4145 case ImmutableScriptFlagsEnum::TreatAsRunOnce
:
4146 json
.value("TreatAsRunOnce");
4148 case ImmutableScriptFlagsEnum::Strict
:
4149 json
.value("Strict");
4151 case ImmutableScriptFlagsEnum::HasModuleGoal
:
4152 json
.value("HasModuleGoal");
4154 case ImmutableScriptFlagsEnum::HasInnerFunctions
:
4155 json
.value("HasInnerFunctions");
4157 case ImmutableScriptFlagsEnum::HasDirectEval
:
4158 json
.value("HasDirectEval");
4160 case ImmutableScriptFlagsEnum::BindingsAccessedDynamically
:
4161 json
.value("BindingsAccessedDynamically");
4163 case ImmutableScriptFlagsEnum::HasCallSiteObj
:
4164 json
.value("HasCallSiteObj");
4166 case ImmutableScriptFlagsEnum::IsAsync
:
4167 json
.value("IsAsync");
4169 case ImmutableScriptFlagsEnum::IsGenerator
:
4170 json
.value("IsGenerator");
4172 case ImmutableScriptFlagsEnum::FunHasExtensibleScope
:
4173 json
.value("FunHasExtensibleScope");
4175 case ImmutableScriptFlagsEnum::FunctionHasThisBinding
:
4176 json
.value("FunctionHasThisBinding");
4178 case ImmutableScriptFlagsEnum::NeedsHomeObject
:
4179 json
.value("NeedsHomeObject");
4181 case ImmutableScriptFlagsEnum::IsDerivedClassConstructor
:
4182 json
.value("IsDerivedClassConstructor");
4184 case ImmutableScriptFlagsEnum::IsSyntheticFunction
:
4185 json
.value("IsSyntheticFunction");
4187 case ImmutableScriptFlagsEnum::UseMemberInitializers
:
4188 json
.value("UseMemberInitializers");
4190 case ImmutableScriptFlagsEnum::HasRest
:
4191 json
.value("HasRest");
4193 case ImmutableScriptFlagsEnum::NeedsFunctionEnvironmentObjects
:
4194 json
.value("NeedsFunctionEnvironmentObjects");
4196 case ImmutableScriptFlagsEnum::FunctionHasExtraBodyVarScope
:
4197 json
.value("FunctionHasExtraBodyVarScope");
4199 case ImmutableScriptFlagsEnum::ShouldDeclareArguments
:
4200 json
.value("ShouldDeclareArguments");
4202 case ImmutableScriptFlagsEnum::NeedsArgsObj
:
4203 json
.value("NeedsArgsObj");
4205 case ImmutableScriptFlagsEnum::HasMappedArgsObj
:
4206 json
.value("HasMappedArgsObj");
4208 case ImmutableScriptFlagsEnum::IsInlinableLargeFunction
:
4209 json
.value("IsInlinableLargeFunction");
4211 case ImmutableScriptFlagsEnum::FunctionHasNewTargetBinding
:
4212 json
.value("FunctionHasNewTargetBinding");
4214 case ImmutableScriptFlagsEnum::UsesArgumentsIntrinsics
:
4215 json
.value("UsesArgumentsIntrinsics");
4218 json
.value("Unknown(%x)", i
);
4225 void js::DumpFunctionFlagsItems(js::JSONPrinter
& json
,
4226 FunctionFlags functionFlags
) {
4227 switch (functionFlags
.kind()) {
4228 case FunctionFlags::FunctionKind::NormalFunction
:
4229 json
.value("NORMAL_KIND");
4231 case FunctionFlags::FunctionKind::AsmJS
:
4232 json
.value("ASMJS_KIND");
4234 case FunctionFlags::FunctionKind::Wasm
:
4235 json
.value("WASM_KIND");
4237 case FunctionFlags::FunctionKind::Arrow
:
4238 json
.value("ARROW_KIND");
4240 case FunctionFlags::FunctionKind::Method
:
4241 json
.value("METHOD_KIND");
4243 case FunctionFlags::FunctionKind::ClassConstructor
:
4244 json
.value("CLASSCONSTRUCTOR_KIND");
4246 case FunctionFlags::FunctionKind::Getter
:
4247 json
.value("GETTER_KIND");
4249 case FunctionFlags::FunctionKind::Setter
:
4250 json
.value("SETTER_KIND");
4253 json
.value("Unknown(%x)", uint8_t(functionFlags
.kind()));
4257 static_assert(FunctionFlags::FUNCTION_KIND_MASK
== 0x0007,
4258 "FunctionKind should use the lowest 3 bits");
4259 for (uint16_t i
= 1 << 3; i
; i
= i
<< 1) {
4260 if (functionFlags
.toRaw() & i
) {
4261 switch (FunctionFlags::Flags(i
)) {
4262 case FunctionFlags::Flags::EXTENDED
:
4263 json
.value("EXTENDED");
4265 case FunctionFlags::Flags::SELF_HOSTED
:
4266 json
.value("SELF_HOSTED");
4268 case FunctionFlags::Flags::BASESCRIPT
:
4269 json
.value("BASESCRIPT");
4271 case FunctionFlags::Flags::SELFHOSTLAZY
:
4272 json
.value("SELFHOSTLAZY");
4274 case FunctionFlags::Flags::CONSTRUCTOR
:
4275 json
.value("CONSTRUCTOR");
4277 case FunctionFlags::Flags::LAZY_ACCESSOR_NAME
:
4278 json
.value("LAZY_ACCESSOR_NAME");
4280 case FunctionFlags::Flags::LAMBDA
:
4281 json
.value("LAMBDA");
4283 case FunctionFlags::Flags::WASM_JIT_ENTRY
:
4284 json
.value("WASM_JIT_ENTRY");
4286 case FunctionFlags::Flags::HAS_INFERRED_NAME
:
4287 json
.value("HAS_INFERRED_NAME");
4289 case FunctionFlags::Flags::HAS_GUESSED_ATOM
:
4290 json
.value("HAS_GUESSED_ATOM");
4292 case FunctionFlags::Flags::RESOLVED_NAME
:
4293 json
.value("RESOLVED_NAME");
4295 case FunctionFlags::Flags::RESOLVED_LENGTH
:
4296 json
.value("RESOLVED_LENGTH");
4298 case FunctionFlags::Flags::GHOST_FUNCTION
:
4299 json
.value("GHOST_FUNCTION");
4302 json
.value("Unknown(%x)", i
);
4309 static void DumpScriptThing(js::JSONPrinter
& json
,
4310 const CompilationStencil
* stencil
,
4311 TaggedScriptThingIndex thing
) {
4312 switch (thing
.tag()) {
4313 case TaggedScriptThingIndex::Kind::ParserAtomIndex
:
4314 case TaggedScriptThingIndex::Kind::WellKnown
:
4316 json
.property("type", "Atom");
4317 DumpTaggedParserAtomIndex(json
, thing
.toAtom(), stencil
);
4320 case TaggedScriptThingIndex::Kind::Null
:
4323 case TaggedScriptThingIndex::Kind::BigInt
:
4324 json
.value("BigIntIndex(%zu)", size_t(thing
.toBigInt()));
4326 case TaggedScriptThingIndex::Kind::ObjLiteral
:
4327 json
.value("ObjLiteralIndex(%zu)", size_t(thing
.toObjLiteral()));
4329 case TaggedScriptThingIndex::Kind::RegExp
:
4330 json
.value("RegExpIndex(%zu)", size_t(thing
.toRegExp()));
4332 case TaggedScriptThingIndex::Kind::Scope
:
4333 json
.value("ScopeIndex(%zu)", size_t(thing
.toScope()));
4335 case TaggedScriptThingIndex::Kind::Function
:
4336 json
.value("ScriptIndex(%zu)", size_t(thing
.toFunction()));
4338 case TaggedScriptThingIndex::Kind::EmptyGlobalScope
:
4339 json
.value("EmptyGlobalScope");
4344 void ScriptStencil::dump() const {
4345 js::Fprinter
out(stderr
);
4346 js::JSONPrinter
json(out
);
4347 dump(json
, nullptr);
4350 void ScriptStencil::dump(js::JSONPrinter
& json
,
4351 const CompilationStencil
* stencil
) const {
4353 dumpFields(json
, stencil
);
4357 void ScriptStencil::dumpFields(js::JSONPrinter
& json
,
4358 const CompilationStencil
* stencil
) const {
4359 json
.formatProperty("gcThingsOffset", "CompilationGCThingIndex(%u)",
4360 gcThingsOffset
.index
);
4361 json
.property("gcThingsLength", gcThingsLength
);
4364 json
.beginListProperty("gcThings");
4365 for (const auto& thing
: gcthings(*stencil
)) {
4366 DumpScriptThing(json
, stencil
, thing
);
4371 json
.beginListProperty("flags");
4372 if (flags_
& WasEmittedByEnclosingScriptFlag
) {
4373 json
.value("WasEmittedByEnclosingScriptFlag");
4375 if (flags_
& AllowRelazifyFlag
) {
4376 json
.value("AllowRelazifyFlag");
4378 if (flags_
& HasSharedDataFlag
) {
4379 json
.value("HasSharedDataFlag");
4381 if (flags_
& HasLazyFunctionEnclosingScopeIndexFlag
) {
4382 json
.value("HasLazyFunctionEnclosingScopeIndexFlag");
4387 json
.beginObjectProperty("functionAtom");
4388 DumpTaggedParserAtomIndex(json
, functionAtom
, stencil
);
4391 json
.beginListProperty("functionFlags");
4392 DumpFunctionFlagsItems(json
, functionFlags
);
4395 if (hasLazyFunctionEnclosingScopeIndex()) {
4396 json
.formatProperty("lazyFunctionEnclosingScopeIndex", "ScopeIndex(%zu)",
4397 size_t(lazyFunctionEnclosingScopeIndex()));
4400 if (hasSelfHostedCanonicalName()) {
4401 json
.beginObjectProperty("selfHostCanonicalName");
4402 DumpTaggedParserAtomIndex(json
, selfHostedCanonicalName(), stencil
);
4408 void ScriptStencilExtra::dump() const {
4409 js::Fprinter
out(stderr
);
4410 js::JSONPrinter
json(out
);
4414 void ScriptStencilExtra::dump(js::JSONPrinter
& json
) const {
4420 void ScriptStencilExtra::dumpFields(js::JSONPrinter
& json
) const {
4421 json
.beginListProperty("immutableFlags");
4422 DumpImmutableScriptFlags(json
, immutableFlags
);
4425 json
.beginObjectProperty("extent");
4426 json
.property("sourceStart", extent
.sourceStart
);
4427 json
.property("sourceEnd", extent
.sourceEnd
);
4428 json
.property("toStringStart", extent
.toStringStart
);
4429 json
.property("toStringEnd", extent
.toStringEnd
);
4430 json
.property("lineno", extent
.lineno
);
4431 json
.property("column", extent
.column
.zeroOriginValue());
4434 json
.property("memberInitializers", memberInitializers_
);
4436 json
.property("nargs", nargs
);
4439 void SharedDataContainer::dump() const {
4440 js::Fprinter
out(stderr
);
4441 js::JSONPrinter
json(out
);
4445 void SharedDataContainer::dump(js::JSONPrinter
& json
) const {
4451 void SharedDataContainer::dumpFields(js::JSONPrinter
& json
) const {
4453 json
.nullProperty("ScriptIndex(0)");
4458 json
.formatProperty("ScriptIndex(0)", "u8[%zu]",
4459 asSingle()->immutableDataLength());
4464 auto& vec
= *asVector();
4467 for (size_t i
= 0; i
< vec
.length(); i
++) {
4468 SprintfLiteral(index
, "ScriptIndex(%zu)", i
);
4470 json
.formatProperty(index
, "u8[%zu]", vec
[i
]->immutableDataLength());
4472 json
.nullProperty(index
);
4479 auto& map
= *asMap();
4482 for (auto iter
= map
.iter(); !iter
.done(); iter
.next()) {
4483 SprintfLiteral(index
, "ScriptIndex(%u)", iter
.get().key().index
);
4484 json
.formatProperty(index
, "u8[%zu]",
4485 iter
.get().value()->immutableDataLength());
4490 MOZ_ASSERT(isBorrow());
4491 asBorrow()->dumpFields(json
);
4494 struct DumpOptionsFields
{
4495 js::JSONPrinter
& json
;
4497 void operator()(const char* name
, JS::AsmJSOption value
) {
4498 const char* valueStr
= nullptr;
4500 case JS::AsmJSOption::Enabled
:
4501 valueStr
= "JS::AsmJSOption::Enabled";
4503 case JS::AsmJSOption::DisabledByAsmJSPref
:
4504 valueStr
= "JS::AsmJSOption::DisabledByAsmJSPref";
4506 case JS::AsmJSOption::DisabledByLinker
:
4507 valueStr
= "JS::AsmJSOption::DisabledByLinker";
4509 case JS::AsmJSOption::DisabledByNoWasmCompiler
:
4510 valueStr
= "JS::AsmJSOption::DisabledByNoWasmCompiler";
4512 case JS::AsmJSOption::DisabledByDebugger
:
4513 valueStr
= "JS::AsmJSOption::DisabledByDebugger";
4516 json
.property(name
, valueStr
);
4519 void operator()(const char* name
, JS::DelazificationOption value
) {
4520 const char* valueStr
= nullptr;
4522 # define SelectValueStr_(Strategy) \
4523 case JS::DelazificationOption::Strategy: \
4524 valueStr = "JS::DelazificationOption::" #Strategy; \
4527 FOREACH_DELAZIFICATION_STRATEGY(SelectValueStr_
)
4528 # undef SelectValueStr_
4530 json
.property(name
, valueStr
);
4533 void operator()(const char* name
, char16_t
* value
) {}
4535 void operator()(const char* name
, bool value
) { json
.property(name
, value
); }
4537 void operator()(const char* name
, uint32_t value
) {
4538 json
.property(name
, value
);
4541 void operator()(const char* name
, uint64_t value
) {
4542 json
.property(name
, value
);
4545 void operator()(const char* name
, const char* value
) {
4547 json
.property(name
, value
);
4550 json
.nullProperty(name
);
4553 void operator()(const char* name
, JS::ConstUTF8CharsZ value
) {
4555 json
.property(name
, value
.c_str());
4558 json
.nullProperty(name
);
4562 static void DumpOptionsFields(js::JSONPrinter
& json
,
4563 const JS::ReadOnlyCompileOptions
& options
) {
4564 struct DumpOptionsFields printer
{
4567 options
.dumpWith(printer
);
4570 static void DumpInputScopeFields(js::JSONPrinter
& json
,
4571 const InputScope
& scope
) {
4572 json
.property("kind", ScopeKindString(scope
.kind()));
4574 InputScope enclosing
= scope
.enclosing();
4575 if (enclosing
.isNull()) {
4576 json
.nullProperty("enclosing");
4578 json
.beginObjectProperty("enclosing");
4579 DumpInputScopeFields(json
, enclosing
);
4584 static void DumpInputScriptFields(js::JSONPrinter
& json
,
4585 const InputScript
& script
) {
4586 json
.beginObjectProperty("extent");
4588 SourceExtent extent
= script
.extent();
4589 json
.property("sourceStart", extent
.sourceStart
);
4590 json
.property("sourceEnd", extent
.sourceEnd
);
4591 json
.property("toStringStart", extent
.toStringStart
);
4592 json
.property("toStringEnd", extent
.toStringEnd
);
4593 json
.property("lineno", extent
.lineno
);
4594 json
.property("column", extent
.column
.zeroOriginValue());
4598 json
.beginListProperty("immutableFlags");
4599 DumpImmutableScriptFlags(json
, script
.immutableFlags());
4602 json
.beginListProperty("functionFlags");
4603 DumpFunctionFlagsItems(json
, script
.functionFlags());
4606 json
.property("hasPrivateScriptData", script
.hasPrivateScriptData());
4608 InputScope scope
= script
.enclosingScope();
4609 if (scope
.isNull()) {
4610 json
.nullProperty("enclosingScope");
4612 json
.beginObjectProperty("enclosingScope");
4613 DumpInputScopeFields(json
, scope
);
4617 if (script
.useMemberInitializers()) {
4618 json
.property("memberInitializers",
4619 script
.getMemberInitializers().serialize());
4623 void CompilationInput::dump() const {
4624 js::Fprinter
out(stderr
);
4625 js::JSONPrinter
json(out
);
4630 void CompilationInput::dump(js::JSONPrinter
& json
) const {
4636 void CompilationInput::dumpFields(js::JSONPrinter
& json
) const {
4637 const char* targetStr
= nullptr;
4639 case CompilationTarget::Global
:
4640 targetStr
= "CompilationTarget::Global";
4642 case CompilationTarget::SelfHosting
:
4643 targetStr
= "CompilationTarget::SelfHosting";
4645 case CompilationTarget::StandaloneFunction
:
4646 targetStr
= "CompilationTarget::StandaloneFunction";
4648 case CompilationTarget::StandaloneFunctionInNonSyntacticScope
:
4649 targetStr
= "CompilationTarget::StandaloneFunctionInNonSyntacticScope";
4651 case CompilationTarget::Eval
:
4652 targetStr
= "CompilationTarget::Eval";
4654 case CompilationTarget::Module
:
4655 targetStr
= "CompilationTarget::Module";
4657 case CompilationTarget::Delazification
:
4658 targetStr
= "CompilationTarget::Delazification";
4661 json
.property("target", targetStr
);
4663 json
.beginObjectProperty("options");
4664 DumpOptionsFields(json
, options
);
4667 if (lazy_
.isNull()) {
4668 json
.nullProperty("lazy_");
4670 json
.beginObjectProperty("lazy_");
4671 DumpInputScriptFields(json
, lazy_
);
4675 if (enclosingScope
.isNull()) {
4676 json
.nullProperty("enclosingScope");
4678 json
.beginObjectProperty("enclosingScope");
4679 DumpInputScopeFields(json
, enclosingScope
);
4683 // TODO: Support printing the atomCache and the source fields.
4686 void CompilationStencil::dump() const {
4687 js::Fprinter
out(stderr
);
4688 js::JSONPrinter
json(out
);
4693 void CompilationStencil::dump(js::JSONPrinter
& json
) const {
4699 void CompilationStencil::dumpFields(js::JSONPrinter
& json
) const {
4702 json
.beginObjectProperty("scriptData");
4703 for (size_t i
= 0; i
< scriptData
.size(); i
++) {
4704 SprintfLiteral(index
, "ScriptIndex(%zu)", i
);
4705 json
.beginObjectProperty(index
);
4706 scriptData
[i
].dumpFields(json
, this);
4711 json
.beginObjectProperty("scriptExtra");
4712 for (size_t i
= 0; i
< scriptExtra
.size(); i
++) {
4713 SprintfLiteral(index
, "ScriptIndex(%zu)", i
);
4714 json
.beginObjectProperty(index
);
4715 scriptExtra
[i
].dumpFields(json
);
4720 json
.beginObjectProperty("scopeData");
4721 MOZ_ASSERT(scopeData
.size() == scopeNames
.size());
4722 for (size_t i
= 0; i
< scopeData
.size(); i
++) {
4723 SprintfLiteral(index
, "ScopeIndex(%zu)", i
);
4724 json
.beginObjectProperty(index
);
4725 scopeData
[i
].dumpFields(json
, scopeNames
[i
], this);
4730 json
.beginObjectProperty("sharedData");
4731 sharedData
.dumpFields(json
);
4734 json
.beginObjectProperty("regExpData");
4735 for (size_t i
= 0; i
< regExpData
.size(); i
++) {
4736 SprintfLiteral(index
, "RegExpIndex(%zu)", i
);
4737 json
.beginObjectProperty(index
);
4738 regExpData
[i
].dumpFields(json
, this);
4743 json
.beginObjectProperty("bigIntData");
4744 for (size_t i
= 0; i
< bigIntData
.size(); i
++) {
4745 SprintfLiteral(index
, "BigIntIndex(%zu)", i
);
4746 GenericPrinter
& out
= json
.beginStringProperty(index
);
4747 bigIntData
[i
].dumpCharsNoQuote(out
);
4748 json
.endStringProperty();
4752 json
.beginObjectProperty("objLiteralData");
4753 for (size_t i
= 0; i
< objLiteralData
.size(); i
++) {
4754 SprintfLiteral(index
, "ObjLiteralIndex(%zu)", i
);
4755 json
.beginObjectProperty(index
);
4756 objLiteralData
[i
].dumpFields(json
, this);
4761 if (moduleMetadata
) {
4762 json
.beginObjectProperty("moduleMetadata");
4763 moduleMetadata
->dumpFields(json
, this);
4767 json
.beginObjectProperty("asmJS");
4769 for (auto iter
= asmJS
->moduleMap
.iter(); !iter
.done(); iter
.next()) {
4770 SprintfLiteral(index
, "ScriptIndex(%u)", iter
.get().key().index
);
4771 json
.formatProperty(index
, "asm.js");
4777 void CompilationStencil::dumpAtom(TaggedParserAtomIndex index
) const {
4778 js::Fprinter
out(stderr
);
4779 js::JSONPrinter
json(out
);
4781 DumpTaggedParserAtomIndex(json
, index
, this);
4785 void ExtensibleCompilationStencil::dump() {
4786 frontend::BorrowingCompilationStencil
borrowingStencil(*this);
4787 borrowingStencil
.dump();
4790 void ExtensibleCompilationStencil::dump(js::JSONPrinter
& json
) {
4791 frontend::BorrowingCompilationStencil
borrowingStencil(*this);
4792 borrowingStencil
.dump(json
);
4795 void ExtensibleCompilationStencil::dumpFields(js::JSONPrinter
& json
) {
4796 frontend::BorrowingCompilationStencil
borrowingStencil(*this);
4797 borrowingStencil
.dumpFields(json
);
4800 void ExtensibleCompilationStencil::dumpAtom(TaggedParserAtomIndex index
) {
4801 frontend::BorrowingCompilationStencil
borrowingStencil(*this);
4802 borrowingStencil
.dumpAtom(index
);
4805 #endif // defined(DEBUG) || defined(JS_JITSPEW)
4807 JSString
* CompilationAtomCache::getExistingStringAt(
4808 ParserAtomIndex index
) const {
4809 MOZ_RELEASE_ASSERT(atoms_
.length() >= index
);
4810 return atoms_
[index
];
4813 JSString
* CompilationAtomCache::getExistingStringAt(
4814 JSContext
* cx
, TaggedParserAtomIndex taggedIndex
) const {
4815 if (taggedIndex
.isParserAtomIndex()) {
4816 auto index
= taggedIndex
.toParserAtomIndex();
4817 return getExistingStringAt(index
);
4820 if (taggedIndex
.isWellKnownAtomId()) {
4821 auto index
= taggedIndex
.toWellKnownAtomId();
4822 return GetWellKnownAtom(cx
, index
);
4825 if (taggedIndex
.isLength1StaticParserString()) {
4826 auto index
= taggedIndex
.toLength1StaticParserString();
4827 return cx
->staticStrings().getUnit(char16_t(index
));
4830 if (taggedIndex
.isLength2StaticParserString()) {
4831 auto index
= taggedIndex
.toLength2StaticParserString();
4832 return cx
->staticStrings().getLength2FromIndex(size_t(index
));
4835 MOZ_ASSERT(taggedIndex
.isLength3StaticParserString());
4836 auto index
= taggedIndex
.toLength3StaticParserString();
4837 return cx
->staticStrings().getUint(uint32_t(index
));
4840 JSString
* CompilationAtomCache::getStringAt(ParserAtomIndex index
) const {
4841 if (size_t(index
) >= atoms_
.length()) {
4844 return atoms_
[index
];
4847 JSAtom
* CompilationAtomCache::getExistingAtomAt(ParserAtomIndex index
) const {
4848 return &getExistingStringAt(index
)->asAtom();
4851 JSAtom
* CompilationAtomCache::getExistingAtomAt(
4852 JSContext
* cx
, TaggedParserAtomIndex taggedIndex
) const {
4853 return &getExistingStringAt(cx
, taggedIndex
)->asAtom();
4856 JSAtom
* CompilationAtomCache::getAtomAt(ParserAtomIndex index
) const {
4857 if (size_t(index
) >= atoms_
.length()) {
4860 if (!atoms_
[index
]) {
4863 return &atoms_
[index
]->asAtom();
4866 bool CompilationAtomCache::hasAtomAt(ParserAtomIndex index
) const {
4867 if (size_t(index
) >= atoms_
.length()) {
4870 return !!atoms_
[index
];
4873 bool CompilationAtomCache::setAtomAt(FrontendContext
* fc
, ParserAtomIndex index
,
4875 if (size_t(index
) < atoms_
.length()) {
4876 atoms_
[index
] = atom
;
4880 if (!atoms_
.resize(size_t(index
) + 1)) {
4881 ReportOutOfMemory(fc
);
4885 atoms_
[index
] = atom
;
4889 bool CompilationAtomCache::allocate(FrontendContext
* fc
, size_t length
) {
4890 MOZ_ASSERT(length
>= atoms_
.length());
4891 if (length
== atoms_
.length()) {
4895 if (!atoms_
.resize(length
)) {
4896 ReportOutOfMemory(fc
);
4903 void CompilationAtomCache::stealBuffer(AtomCacheVector
& atoms
) {
4904 atoms_
= std::move(atoms
);
4905 // Destroy elements, without unreserving.
4909 void CompilationAtomCache::releaseBuffer(AtomCacheVector
& atoms
) {
4910 atoms
= std::move(atoms_
);
4913 bool CompilationState::allocateGCThingsUninitialized(
4914 FrontendContext
* fc
, ScriptIndex scriptIndex
, size_t length
,
4915 TaggedScriptThingIndex
** cursor
) {
4916 MOZ_ASSERT(gcThingData
.length() <= UINT32_MAX
);
4918 auto gcThingsOffset
= CompilationGCThingIndex(gcThingData
.length());
4920 if (length
> INDEX_LIMIT
) {
4921 ReportAllocationOverflow(fc
);
4924 uint32_t gcThingsLength
= length
;
4926 if (!gcThingData
.growByUninitialized(length
)) {
4927 js::ReportOutOfMemory(fc
);
4931 if (gcThingData
.length() > UINT32_MAX
) {
4932 ReportAllocationOverflow(fc
);
4936 ScriptStencil
& script
= scriptData
[scriptIndex
];
4937 script
.gcThingsOffset
= gcThingsOffset
;
4938 script
.gcThingsLength
= gcThingsLength
;
4940 *cursor
= gcThingData
.begin() + gcThingsOffset
;
4944 bool CompilationState::appendScriptStencilAndData(FrontendContext
* fc
) {
4945 if (!scriptData
.emplaceBack()) {
4946 js::ReportOutOfMemory(fc
);
4950 if (isInitialStencil()) {
4951 if (!scriptExtra
.emplaceBack()) {
4952 scriptData
.popBack();
4953 MOZ_ASSERT(scriptData
.length() == scriptExtra
.length());
4955 js::ReportOutOfMemory(fc
);
4963 bool CompilationState::appendGCThings(
4964 FrontendContext
* fc
, ScriptIndex scriptIndex
,
4965 mozilla::Span
<const TaggedScriptThingIndex
> things
) {
4966 MOZ_ASSERT(gcThingData
.length() <= UINT32_MAX
);
4968 auto gcThingsOffset
= CompilationGCThingIndex(gcThingData
.length());
4970 if (things
.size() > INDEX_LIMIT
) {
4971 ReportAllocationOverflow(fc
);
4974 uint32_t gcThingsLength
= uint32_t(things
.size());
4976 if (!gcThingData
.append(things
.data(), things
.size())) {
4977 js::ReportOutOfMemory(fc
);
4981 if (gcThingData
.length() > UINT32_MAX
) {
4982 ReportAllocationOverflow(fc
);
4986 ScriptStencil
& script
= scriptData
[scriptIndex
];
4987 script
.gcThingsOffset
= gcThingsOffset
;
4988 script
.gcThingsLength
= gcThingsLength
;
4992 CompilationState::CompilationStatePosition
CompilationState::getPosition() {
4993 return CompilationStatePosition
{scriptData
.length(),
4994 asmJS
? asmJS
->moduleMap
.count() : 0};
4997 void CompilationState::rewind(
4998 const CompilationState::CompilationStatePosition
& pos
) {
4999 if (asmJS
&& asmJS
->moduleMap
.count() != pos
.asmJSCount
) {
5000 for (size_t i
= pos
.scriptDataLength
; i
< scriptData
.length(); i
++) {
5001 asmJS
->moduleMap
.remove(ScriptIndex(i
));
5003 MOZ_ASSERT(asmJS
->moduleMap
.count() == pos
.asmJSCount
);
5005 // scriptExtra is empty for delazification.
5006 if (scriptExtra
.length()) {
5007 MOZ_ASSERT(scriptExtra
.length() == scriptData
.length());
5008 scriptExtra
.shrinkTo(pos
.scriptDataLength
);
5010 scriptData
.shrinkTo(pos
.scriptDataLength
);
5013 void CompilationState::markGhost(
5014 const CompilationState::CompilationStatePosition
& pos
) {
5015 for (size_t i
= pos
.scriptDataLength
; i
< scriptData
.length(); i
++) {
5016 scriptData
[i
].setIsGhost();
5020 bool CompilationStencilMerger::buildFunctionKeyToIndex(FrontendContext
* fc
) {
5021 if (!functionKeyToInitialScriptIndex_
.reserve(initial_
->scriptExtra
.length() -
5023 ReportOutOfMemory(fc
);
5027 for (size_t i
= 1; i
< initial_
->scriptExtra
.length(); i
++) {
5028 const auto& extra
= initial_
->scriptExtra
[i
];
5029 auto key
= extra
.extent
.toFunctionKey();
5031 // There can be multiple ScriptStencilExtra with same extent if
5032 // the function is parsed multiple times because of rewind for
5033 // arrow function, and in that case the last one's index should be used.
5034 // Overwrite with the last one.
5036 // Already reserved above, but OOMTest can hit failure mode in
5038 if (!functionKeyToInitialScriptIndex_
.put(key
, ScriptIndex(i
))) {
5039 ReportOutOfMemory(fc
);
5047 ScriptIndex
CompilationStencilMerger::getInitialScriptIndexFor(
5048 const CompilationStencil
& delazification
) const {
5049 auto p
= functionKeyToInitialScriptIndex_
.lookup(delazification
.functionKey
);
5054 bool CompilationStencilMerger::buildAtomIndexMap(
5055 FrontendContext
* fc
, const CompilationStencil
& delazification
,
5056 AtomIndexMap
& atomIndexMap
) {
5057 uint32_t atomCount
= delazification
.parserAtomData
.size();
5058 if (!atomIndexMap
.reserve(atomCount
)) {
5059 ReportOutOfMemory(fc
);
5062 for (const auto& atom
: delazification
.parserAtomData
) {
5063 auto mappedIndex
= initial_
->parserAtoms
.internExternalParserAtom(fc
, atom
);
5067 atomIndexMap
.infallibleAppend(mappedIndex
);
5072 bool CompilationStencilMerger::setInitial(
5073 FrontendContext
* fc
, UniquePtr
<ExtensibleCompilationStencil
>&& initial
) {
5074 MOZ_ASSERT(!initial_
);
5076 initial_
= std::move(initial
);
5078 return buildFunctionKeyToIndex(fc
);
5081 template <typename GCThingIndexMapFunc
, typename AtomIndexMapFunc
,
5082 typename ScopeIndexMapFunc
>
5083 static void MergeScriptStencil(ScriptStencil
& dest
, const ScriptStencil
& src
,
5084 GCThingIndexMapFunc mapGCThingIndex
,
5085 AtomIndexMapFunc mapAtomIndex
,
5086 ScopeIndexMapFunc mapScopeIndex
,
5088 // If this function was lazy, all inner functions should have been lazy.
5089 MOZ_ASSERT(!dest
.hasSharedData());
5091 // If the inner lazy function is skipped, gcThingsLength is empty.
5092 if (src
.gcThingsLength
) {
5093 dest
.gcThingsOffset
= mapGCThingIndex(src
.gcThingsOffset
);
5094 dest
.gcThingsLength
= src
.gcThingsLength
;
5097 if (src
.functionAtom
) {
5098 dest
.functionAtom
= mapAtomIndex(src
.functionAtom
);
5101 if (!dest
.hasLazyFunctionEnclosingScopeIndex() &&
5102 src
.hasLazyFunctionEnclosingScopeIndex()) {
5103 // Both enclosing function and this function were lazy, and
5104 // now enclosing function is non-lazy and this function is still lazy.
5105 dest
.setLazyFunctionEnclosingScopeIndex(
5106 mapScopeIndex(src
.lazyFunctionEnclosingScopeIndex()));
5107 } else if (dest
.hasLazyFunctionEnclosingScopeIndex() &&
5108 !src
.hasLazyFunctionEnclosingScopeIndex()) {
5109 // The enclosing function was non-lazy and this function was lazy, and
5110 // now this function is non-lazy.
5111 dest
.resetHasLazyFunctionEnclosingScopeIndexAfterStencilMerge();
5113 // The enclosing function is still lazy.
5114 MOZ_ASSERT(!dest
.hasLazyFunctionEnclosingScopeIndex());
5115 MOZ_ASSERT(!src
.hasLazyFunctionEnclosingScopeIndex());
5119 uint16_t BASESCRIPT
= uint16_t(FunctionFlags::Flags::BASESCRIPT
);
5120 uint16_t HAS_INFERRED_NAME
=
5121 uint16_t(FunctionFlags::Flags::HAS_INFERRED_NAME
);
5122 uint16_t HAS_GUESSED_ATOM
= uint16_t(FunctionFlags::Flags::HAS_GUESSED_ATOM
);
5123 uint16_t acceptableDifferenceForLazy
= HAS_INFERRED_NAME
| HAS_GUESSED_ATOM
;
5124 uint16_t acceptableDifferenceForNonLazy
=
5125 BASESCRIPT
| HAS_INFERRED_NAME
| HAS_GUESSED_ATOM
;
5129 (dest
.functionFlags
.toRaw() | acceptableDifferenceForNonLazy
) ==
5130 (src
.functionFlags
.toRaw() | acceptableDifferenceForNonLazy
));
5132 // NOTE: Currently we don't delazify inner functions.
5133 MOZ_ASSERT_IF(!isTopLevel
,
5134 (dest
.functionFlags
.toRaw() | acceptableDifferenceForLazy
) ==
5135 (src
.functionFlags
.toRaw() | acceptableDifferenceForLazy
));
5137 dest
.functionFlags
= src
.functionFlags
;
5141 if (src
.wasEmittedByEnclosingScript()) {
5142 // NOTE: the top-level function of the delazification have
5143 // src.wasEmittedByEnclosingScript() == false, and that shouldn't
5145 dest
.setWasEmittedByEnclosingScript();
5148 if (src
.allowRelazify()) {
5149 dest
.setAllowRelazify();
5152 if (src
.hasSharedData()) {
5153 dest
.setHasSharedData();
5157 bool CompilationStencilMerger::addDelazification(
5158 FrontendContext
* fc
, const CompilationStencil
& delazification
) {
5159 MOZ_ASSERT(initial_
);
5161 auto delazifiedFunctionIndex
= getInitialScriptIndexFor(delazification
);
5162 auto& destFun
= initial_
->scriptData
[delazifiedFunctionIndex
];
5164 if (destFun
.hasSharedData()) {
5165 // If the function was already non-lazy, it means the following happened:
5166 // A. delazified twice within single incremental encoding
5167 // 1. this function is lazily parsed
5168 // 2. incremental encoding is started
5169 // 3. this function is delazified, encoded, and merged
5170 // 4. this function is relazified
5171 // 5. this function is delazified, encoded, and merged
5173 // B. delazified twice across decode
5174 // 1. this function is lazily parsed
5175 // 2. incremental encoding is started
5176 // 3. this function is delazified, encoded, and merged
5177 // 4. incremental encoding is finished
5179 // 6. incremental encoding is started
5180 // here, this function is non-lazy
5181 // 7. this function is relazified
5182 // 8. this function is delazified, encoded, and merged
5184 // A can happen with public API.
5186 // B cannot happen with public API, but can happen if incremental
5187 // encoding at step B.6 is explicitly started by internal function.
5188 // See Evaluate and StartIncrementalEncoding in js/src/shell/js.cpp.
5192 // If any failure happens, the initial stencil is left in the broken state.
5193 // Immediately discard it.
5194 auto failureCase
= mozilla::MakeScopeExit([&] { initial_
.reset(); });
5196 mozilla::Maybe
<ScopeIndex
> functionEnclosingScope
;
5197 if (destFun
.hasLazyFunctionEnclosingScopeIndex()) {
5198 // lazyFunctionEnclosingScopeIndex_ can be Nothing if this is
5199 // top-level function.
5200 functionEnclosingScope
=
5201 mozilla::Some(destFun
.lazyFunctionEnclosingScopeIndex());
5204 // A map from ParserAtomIndex in delazification to TaggedParserAtomIndex
5206 AtomIndexMap atomIndexMap
;
5207 if (!buildAtomIndexMap(fc
, delazification
, atomIndexMap
)) {
5210 auto mapAtomIndex
= [&](TaggedParserAtomIndex index
) {
5211 if (index
.isParserAtomIndex()) {
5212 return atomIndexMap
[index
.toParserAtomIndex()];
5218 size_t gcThingOffset
= initial_
->gcThingData
.length();
5219 size_t regExpOffset
= initial_
->regExpData
.length();
5220 size_t bigIntOffset
= initial_
->bigIntData
.length();
5221 size_t objLiteralOffset
= initial_
->objLiteralData
.length();
5222 size_t scopeOffset
= initial_
->scopeData
.length();
5224 // Map delazification's ScriptIndex to initial's ScriptIndex.
5226 // The lazy function's gcthings list stores inner function's ScriptIndex.
5227 // The n-th gcthing holds the ScriptIndex of the (n+1)-th script in
5230 // NOTE: Currently we don't delazify inner functions.
5231 auto lazyFunctionGCThingsOffset
= destFun
.gcThingsOffset
;
5232 auto mapScriptIndex
= [&](ScriptIndex index
) {
5233 if (index
== CompilationStencil::TopLevelIndex
) {
5234 return delazifiedFunctionIndex
;
5237 return initial_
->gcThingData
[lazyFunctionGCThingsOffset
+ index
.index
- 1]
5241 // Map other delazification's indices into initial's indices.
5242 auto mapGCThingIndex
= [&](CompilationGCThingIndex offset
) {
5243 return CompilationGCThingIndex(gcThingOffset
+ offset
.index
);
5245 auto mapRegExpIndex
= [&](RegExpIndex index
) {
5246 return RegExpIndex(regExpOffset
+ index
.index
);
5248 auto mapBigIntIndex
= [&](BigIntIndex index
) {
5249 return BigIntIndex(bigIntOffset
+ index
.index
);
5251 auto mapObjLiteralIndex
= [&](ObjLiteralIndex index
) {
5252 return ObjLiteralIndex(objLiteralOffset
+ index
.index
);
5254 auto mapScopeIndex
= [&](ScopeIndex index
) {
5255 return ScopeIndex(scopeOffset
+ index
.index
);
5258 // Append gcThingData, with mapping TaggedScriptThingIndex.
5259 if (!initial_
->gcThingData
.append(delazification
.gcThingData
.data(),
5260 delazification
.gcThingData
.size())) {
5261 js::ReportOutOfMemory(fc
);
5264 for (size_t i
= gcThingOffset
; i
< initial_
->gcThingData
.length(); i
++) {
5265 auto& index
= initial_
->gcThingData
[i
];
5266 if (index
.isNull()) {
5268 } else if (index
.isAtom()) {
5269 index
= TaggedScriptThingIndex(mapAtomIndex(index
.toAtom()));
5270 } else if (index
.isBigInt()) {
5271 index
= TaggedScriptThingIndex(mapBigIntIndex(index
.toBigInt()));
5272 } else if (index
.isObjLiteral()) {
5273 index
= TaggedScriptThingIndex(mapObjLiteralIndex(index
.toObjLiteral()));
5274 } else if (index
.isRegExp()) {
5275 index
= TaggedScriptThingIndex(mapRegExpIndex(index
.toRegExp()));
5276 } else if (index
.isScope()) {
5277 index
= TaggedScriptThingIndex(mapScopeIndex(index
.toScope()));
5278 } else if (index
.isFunction()) {
5279 index
= TaggedScriptThingIndex(mapScriptIndex(index
.toFunction()));
5281 MOZ_ASSERT(index
.isEmptyGlobalScope());
5286 // Append regExpData, with mapping RegExpStencil.atom_.
5287 if (!initial_
->regExpData
.append(delazification
.regExpData
.data(),
5288 delazification
.regExpData
.size())) {
5289 js::ReportOutOfMemory(fc
);
5292 for (size_t i
= regExpOffset
; i
< initial_
->regExpData
.length(); i
++) {
5293 auto& data
= initial_
->regExpData
[i
];
5294 data
.atom_
= mapAtomIndex(data
.atom_
);
5297 // Append bigIntData, with copying BigIntStencil.source_.
5298 if (!initial_
->bigIntData
.reserve(bigIntOffset
+
5299 delazification
.bigIntData
.size())) {
5300 js::ReportOutOfMemory(fc
);
5303 for (const auto& data
: delazification
.bigIntData
) {
5304 initial_
->bigIntData
.infallibleEmplaceBack();
5305 if (!initial_
->bigIntData
.back().init(fc
, initial_
->alloc
, data
.source())) {
5310 // Append objLiteralData, with copying ObjLiteralStencil.code_, and mapping
5311 // TaggedParserAtomIndex in it.
5312 if (!initial_
->objLiteralData
.reserve(objLiteralOffset
+
5313 delazification
.objLiteralData
.size())) {
5314 js::ReportOutOfMemory(fc
);
5317 for (const auto& data
: delazification
.objLiteralData
) {
5318 size_t length
= data
.code().size();
5319 auto* code
= initial_
->alloc
.newArrayUninitialized
<uint8_t>(length
);
5321 js::ReportOutOfMemory(fc
);
5324 memcpy(code
, data
.code().data(), length
);
5326 ObjLiteralModifier
modifier(mozilla::Span(code
, length
));
5327 modifier
.mapAtom(mapAtomIndex
);
5329 initial_
->objLiteralData
.infallibleEmplaceBack(
5330 code
, length
, data
.kind(), data
.flags(), data
.propertyCount());
5333 // Append scopeData, with mapping indices in ScopeStencil fields.
5334 // And append scopeNames, with copying the entire data, and mapping
5336 if (!initial_
->scopeData
.reserve(scopeOffset
+
5337 delazification
.scopeData
.size())) {
5338 js::ReportOutOfMemory(fc
);
5341 if (!initial_
->scopeNames
.reserve(scopeOffset
+
5342 delazification
.scopeNames
.size())) {
5343 js::ReportOutOfMemory(fc
);
5346 for (size_t i
= 0; i
< delazification
.scopeData
.size(); i
++) {
5347 const auto& srcData
= delazification
.scopeData
[i
];
5348 const auto* srcNames
= delazification
.scopeNames
[i
];
5350 mozilla::Maybe
<ScriptIndex
> functionIndex
= mozilla::Nothing();
5351 if (srcData
.isFunction()) {
5352 // Inner functions should be in the same order as initial, beginning from
5353 // the delazification's index.
5354 functionIndex
= mozilla::Some(mapScriptIndex(srcData
.functionIndex()));
5357 BaseParserScopeData
* destNames
= nullptr;
5359 destNames
= CopyScopeData(fc
, initial_
->alloc
, srcData
.kind(), srcNames
);
5363 auto trailingNames
=
5364 GetParserScopeDataTrailingNames(srcData
.kind(), destNames
);
5365 for (auto& name
: trailingNames
) {
5367 name
.updateNameAfterStencilMerge(mapAtomIndex(name
.name()));
5372 initial_
->scopeData
.infallibleEmplaceBack(
5374 srcData
.hasEnclosing()
5375 ? mozilla::Some(mapScopeIndex(srcData
.enclosing()))
5376 : functionEnclosingScope
,
5377 srcData
.firstFrameSlot(),
5378 srcData
.hasEnvironmentShape()
5379 ? mozilla::Some(srcData
.numEnvironmentSlots())
5380 : mozilla::Nothing(),
5381 functionIndex
, srcData
.isArrow());
5383 initial_
->scopeNames
.infallibleEmplaceBack(destNames
);
5386 // Add delazified function's shared data.
5388 // NOTE: Currently we don't delazify inner functions.
5389 if (!initial_
->sharedData
.addExtraWithoutShare(
5390 fc
, delazifiedFunctionIndex
,
5391 delazification
.sharedData
.get(CompilationStencil::TopLevelIndex
))) {
5395 // Update scriptData, with mapping indices in ScriptStencil fields.
5396 for (uint32_t i
= 0; i
< delazification
.scriptData
.size(); i
++) {
5397 auto destIndex
= mapScriptIndex(ScriptIndex(i
));
5398 MergeScriptStencil(initial_
->scriptData
[destIndex
],
5399 delazification
.scriptData
[i
], mapGCThingIndex
,
5400 mapAtomIndex
, mapScopeIndex
,
5401 i
== CompilationStencil::TopLevelIndex
);
5404 // WARNING: moduleMetadata and asmJS fields are known at script/module
5405 // top-level parsing, any mutation made in this function should be reflected
5406 // to ExtensibleCompilationStencil::steal and CompilationStencil::clone.
5408 // Function shouldn't be a module.
5409 MOZ_ASSERT(!delazification
.moduleMetadata
);
5411 // asm.js shouldn't appear inside delazification, given asm.js forces
5413 MOZ_ASSERT(!delazification
.asmJS
);
5415 failureCase
.release();
5419 void JS::StencilAddRef(JS::Stencil
* stencil
) { stencil
->refCount
++; }
5420 void JS::StencilRelease(JS::Stencil
* stencil
) {
5421 MOZ_RELEASE_ASSERT(stencil
->refCount
> 0);
5422 if (--stencil
->refCount
== 0) {
5427 template <typename CharT
>
5428 static already_AddRefed
<JS::Stencil
> CompileGlobalScriptToStencilImpl(
5429 JSContext
* cx
, const JS::ReadOnlyCompileOptions
& options
,
5430 JS::SourceText
<CharT
>& srcBuf
) {
5431 ScopeKind scopeKind
=
5432 options
.nonSyntacticScope
? ScopeKind::NonSyntactic
: ScopeKind::Global
;
5434 AutoReportFrontendContext
fc(cx
);
5435 NoScopeBindingCache scopeCache
;
5436 Rooted
<CompilationInput
> input(cx
, CompilationInput(options
));
5437 RefPtr
<JS::Stencil
> stencil
= js::frontend::CompileGlobalScriptToStencil(
5438 cx
, &fc
, cx
->tempLifoAlloc(), input
.get(), &scopeCache
, srcBuf
,
5444 // Convert the UniquePtr to a RefPtr and increment the count (to 1).
5445 return stencil
.forget();
5448 already_AddRefed
<JS::Stencil
> JS::CompileGlobalScriptToStencil(
5449 JSContext
* cx
, const JS::ReadOnlyCompileOptions
& options
,
5450 JS::SourceText
<mozilla::Utf8Unit
>& srcBuf
) {
5451 return CompileGlobalScriptToStencilImpl(cx
, options
, srcBuf
);
5454 already_AddRefed
<JS::Stencil
> JS::CompileGlobalScriptToStencil(
5455 JSContext
* cx
, const JS::ReadOnlyCompileOptions
& options
,
5456 JS::SourceText
<char16_t
>& srcBuf
) {
5457 return CompileGlobalScriptToStencilImpl(cx
, options
, srcBuf
);
5460 template <typename CharT
>
5461 static already_AddRefed
<JS::Stencil
> CompileModuleScriptToStencilImpl(
5462 JSContext
* cx
, const JS::ReadOnlyCompileOptions
& optionsInput
,
5463 JS::SourceText
<CharT
>& srcBuf
) {
5464 JS::CompileOptions
options(cx
, optionsInput
);
5465 options
.setModule();
5467 AutoReportFrontendContext
fc(cx
);
5468 NoScopeBindingCache scopeCache
;
5469 Rooted
<CompilationInput
> input(cx
, CompilationInput(options
));
5470 RefPtr
<JS::Stencil
> stencil
= js::frontend::ParseModuleToStencil(
5471 cx
, &fc
, cx
->tempLifoAlloc(), input
.get(), &scopeCache
, srcBuf
);
5476 // Convert the UniquePtr to a RefPtr and increment the count (to 1).
5477 return stencil
.forget();
5480 already_AddRefed
<JS::Stencil
> JS::CompileModuleScriptToStencil(
5481 JSContext
* cx
, const JS::ReadOnlyCompileOptions
& options
,
5482 JS::SourceText
<mozilla::Utf8Unit
>& srcBuf
) {
5483 return CompileModuleScriptToStencilImpl(cx
, options
, srcBuf
);
5486 already_AddRefed
<JS::Stencil
> JS::CompileModuleScriptToStencil(
5487 JSContext
* cx
, const JS::ReadOnlyCompileOptions
& options
,
5488 JS::SourceText
<char16_t
>& srcBuf
) {
5489 return CompileModuleScriptToStencilImpl(cx
, options
, srcBuf
);
5492 JS_PUBLIC_API JSScript
* JS::InstantiateGlobalStencil(
5493 JSContext
* cx
, const JS::InstantiateOptions
& options
, JS::Stencil
* stencil
,
5494 JS::InstantiationStorage
* storage
) {
5495 MOZ_ASSERT_IF(storage
, storage
->isValid());
5497 CompileOptions
compileOptions(cx
);
5498 options
.copyTo(compileOptions
);
5499 Rooted
<CompilationInput
> input(cx
, CompilationInput(compileOptions
));
5500 Rooted
<CompilationGCOutput
> gcOutput(cx
);
5502 gcOutput
.get().steal(std::move(*storage
->gcOutput_
));
5505 if (!InstantiateStencils(cx
, input
.get(), *stencil
, gcOutput
.get())) {
5508 return gcOutput
.get().script
;
5511 JS_PUBLIC_API
bool JS::StencilIsBorrowed(Stencil
* stencil
) {
5512 return stencil
->storageType
== CompilationStencil::StorageType::Borrowed
;
5515 JS_PUBLIC_API JSObject
* JS::InstantiateModuleStencil(
5516 JSContext
* cx
, const JS::InstantiateOptions
& options
, JS::Stencil
* stencil
,
5517 JS::InstantiationStorage
* storage
) {
5518 MOZ_ASSERT_IF(storage
, storage
->isValid());
5520 CompileOptions
compileOptions(cx
);
5521 options
.copyTo(compileOptions
);
5522 compileOptions
.setModule();
5523 Rooted
<CompilationInput
> input(cx
, CompilationInput(compileOptions
));
5524 Rooted
<CompilationGCOutput
> gcOutput(cx
);
5526 gcOutput
.get().steal(std::move(*storage
->gcOutput_
));
5529 if (!InstantiateStencils(cx
, input
.get(), *stencil
, gcOutput
.get())) {
5532 return gcOutput
.get().module
;
5535 JS::TranscodeResult
JS::EncodeStencil(JSContext
* cx
, JS::Stencil
* stencil
,
5536 TranscodeBuffer
& buffer
) {
5537 AutoReportFrontendContext
fc(cx
);
5538 XDRStencilEncoder
encoder(&fc
, buffer
);
5539 XDRResult res
= encoder
.codeStencil(*stencil
);
5541 return res
.unwrapErr();
5543 return TranscodeResult::Ok
;
5546 JS::TranscodeResult
JS::DecodeStencil(JSContext
* cx
,
5547 const JS::ReadOnlyDecodeOptions
& options
,
5548 const JS::TranscodeRange
& range
,
5549 JS::Stencil
** stencilOut
) {
5550 AutoReportFrontendContext
fc(cx
);
5551 return JS::DecodeStencil(&fc
, options
, range
, stencilOut
);
5554 JS::TranscodeResult
JS::DecodeStencil(JS::FrontendContext
* fc
,
5555 const JS::ReadOnlyDecodeOptions
& options
,
5556 const JS::TranscodeRange
& range
,
5557 JS::Stencil
** stencilOut
) {
5558 RefPtr
<ScriptSource
> source
= fc
->getAllocator()->new_
<ScriptSource
>();
5560 return TranscodeResult::Throw
;
5562 RefPtr
<JS::Stencil
> stencil(
5563 fc
->getAllocator()->new_
<CompilationStencil
>(source
));
5565 return TranscodeResult::Throw
;
5567 XDRStencilDecoder
decoder(fc
, range
);
5568 XDRResult res
= decoder
.codeStencil(options
, *stencil
);
5570 return res
.unwrapErr();
5572 *stencilOut
= stencil
.forget().take();
5573 return TranscodeResult::Ok
;
5576 JS_PUBLIC_API
size_t JS::SizeOfStencil(Stencil
* stencil
,
5577 mozilla::MallocSizeOf mallocSizeOf
) {
5578 return stencil
->sizeOfIncludingThis(mallocSizeOf
);
5581 JS::InstantiationStorage::~InstantiationStorage() {
5583 js_delete(gcOutput_
);
5584 gcOutput_
= nullptr;