Closed github-actions[bot] closed 1 year ago
/js/src/frontend/CompilationStencil.h
/js/src/frontend/Stencil.cpp
/js/src/frontend/Stencil.h
/js/src/vm/BytecodeUtil.cpp
/js/src/vm/BytecodeUtil.h
/js/src/vm/Opcodes.h
/js/src/vm/SharedStencil.h
--- d73e753cf2bb5ff92c085c7d4e3ad2bb59047535/js/src/frontend/CompilationStencil.h +++ 62177878bdfbb1a5332a8f16ec2d80caca12d841/js/src/frontend/CompilationStencil.h @@ -21,48 +21,53 @@ #include "ds/LifoAlloc.h" #include "frontend/NameAnalysisTypes.h" // EnvironmentCoordinate #include "frontend/ParserAtom.h" // ParserAtomsTable, TaggedParserAtomIndex #include "frontend/ScriptIndex.h" // ScriptIndex #include "frontend/SharedContext.h" #include "frontend/Stencil.h" #include "frontend/TaggedParserAtomIndexHasher.h" // TaggedParserAtomIndexHasher #include "frontend/UsedNameTracker.h" -#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions #include "js/GCVector.h" #include "js/HashTable.h" #include "js/RefCounted.h" // AtomicRefCounted #include "js/Transcoding.h" #include "js/UniquePtr.h" // js::UniquePtr #include "js/Vector.h" #include "js/WasmModule.h" +#include "vm/ErrorContext.h" // MainThreadErrorContext #include "vm/GlobalObject.h" // GlobalObject #include "vm/JSContext.h" #include "vm/JSFunction.h" // JSFunction #include "vm/JSScript.h" // SourceExtent #include "vm/Realm.h" #include "vm/ScopeKind.h" // ScopeKind #include "vm/SharedStencil.h" // SharedImmutableScriptData class JSAtom; class JSString; +namespace JS { +class JS_PUBLIC_API ReadOnlyCompileOptions; +} + namespace js { class AtomSet; class JSONPrinter; class ModuleObject; namespace frontend { struct CompilationInput; struct CompilationStencil; struct CompilationGCOutput; class ScriptStencilIterable; struct InputName; +class ScopeBindingCache; // Reference to a Scope within a CompilationStencil. struct ScopeStencilRef { const CompilationStencil& context_; const ScopeIndex scopeIndex_; // Lookup the ScopeStencil referenced by this ScopeStencilRef. inline const ScopeStencil& scope() const; @@ -351,40 +356,57 @@ struct InputName { : variant_(NameStencilRef{scope.context_, index}) {} InputName(BaseScript*, JSAtom* ptr) : variant_(ptr) {} InputName(const ScriptStencilRef& script, TaggedParserAtomIndex index) : variant_(NameStencilRef{script.context_, index}) {} // The InputName is either from an instantiated name, or from another // CompilationStencil. This method interns the current name in the parser atom // table of a CompilationState, which has a corresponding CompilationInput. - TaggedParserAtomIndex internInto(JSContext* cx, ParserAtomsTable& parserAtoms, + TaggedParserAtomIndex internInto(JSContext* cx, ErrorContext* ec, + ParserAtomsTable& parserAtoms, CompilationAtomCache& atomCache); // Compare an InputName, which is not yet interned, with `other` is either an // interned name or a well-known or static string. // // The `otherCached` argument should be a reference to a JSAtom*, initialized // to nullptr, which is used to cache the JSAtom representation of the `other` // argument if needed. If a different `other` parameter is provided, the // `otherCached` argument should be reset to nullptr. - bool isEqualTo(JSContext* cx, ParserAtomsTable& parserAtoms, + bool isEqualTo(JSContext* cx, ErrorContext* ec, ParserAtomsTable& parserAtoms, CompilationAtomCache& atomCache, TaggedParserAtomIndex other, JSAtom** otherCached) const; bool isNull() const { return variant_.match( [](JSAtom* ptr) { return !ptr; }, [](const NameStencilRef& ref) { return !ref.atomIndex_; }); } }; // ScopeContext holds information derived from the scope and environment chains // to try to avoid the parser needing to traverse VM structures directly. struct ScopeContext { + // Cache: Scope -> (JSAtom/TaggedParserAtomIndex -> NameLocation) + // + // This cache maps the scope to a hash table which can lookup a name of the + // scope to the equivalent NameLocation. + ScopeBindingCache* scopeCache = nullptr; + + // Generation number of the `scopeCache` collected before filling the cache + // with enclosing scope information. + // + // The generation number, obtained from `scopeCache->getCurrentGeneration()` + // is incremented each time the GC invalidate the content of the cache. The + // `scopeCache` can only be used when the generation number collected before + // filling the cache is identical to the generation number seen when querying + // the cached content. + size_t scopeCacheGen = 0; + // Class field initializer info if we are nested within a class constructor. // We may be an combination of arrow and eval context within the constructor. mozilla::Maybe<MemberInitializers> memberInitializers = {}; enum class EnclosingLexicalBindingKind { Let, Const, CatchParameter, @@ -459,48 +481,59 @@ struct ScopeContext { // True if the enclosing scope has non-syntactic scope on chain. bool hasNonSyntacticScopeOnChain = false; // True if the enclosing scope has function scope where the function needs // home object. bool hasFunctionNeedsHomeObjectOnChain = false; #endif - bool init(JSContext* cx, CompilationInput& input, - ParserAtomsTable& parserAtoms, InheritThis inheritThis, - JSObject* enclosingEnv); + bool init(JSContext* cx, ErrorContext* ec, CompilationInput& input, + ParserAtomsTable& parserAtoms, ScopeBindingCache* scopeCache, + InheritThis inheritThis, JSObject* enclosingEnv); mozilla::Maybe<EnclosingLexicalBindingKind> lookupLexicalBindingInEnclosingScope(TaggedParserAtomIndex name); - NameLocation searchInEnclosingScope(JSContext* cx, CompilationInput& input, + NameLocation searchInEnclosingScope(JSContext* cx, ErrorContext* ec, + CompilationInput& input, ParserAtomsTable& parserAtoms, - TaggedParserAtomIndex name, uint8_t hops); + TaggedParserAtomIndex name); bool effectiveScopePrivateFieldCacheHas(TaggedParserAtomIndex name); mozilla::Maybe<NameLocation> getPrivateFieldLocation( TaggedParserAtomIndex name); private: void computeThisBinding(const InputScope& scope); void computeThisEnvironment(const InputScope& enclosingScope); void computeInScope(const InputScope& enclosingScope); void cacheEnclosingScope(const InputScope& enclosingScope); + NameLocation searchInEnclosingScopeWithCache(JSContext* cx, ErrorContext* ec, + CompilationInput& input, + ParserAtomsTable& parserAtoms, + TaggedParserAtomIndex name); + NameLocation searchInEnclosingScopeNoCache(JSContext* cx, ErrorContext* ec, + CompilationInput& input, + ParserAtomsTable& parserAtoms, + TaggedParserAtomIndex name); InputScope determineEffectiveScope(InputScope& scope, JSObject* environment); - bool cachePrivateFieldsForEval(JSContext* cx, CompilationInput& input, + bool cachePrivateFieldsForEval(JSContext* cx, ErrorContext* ec, + CompilationInput& input, JSObject* enclosingEnvironment, const InputScope& effectiveScope, ParserAtomsTable& parserAtoms); - bool cacheEnclosingScopeBindingForEval(JSContext* cx, CompilationInput& input, + bool cacheEnclosingScopeBindingForEval(JSContext* cx, ErrorContext* ec, + CompilationInput& input, ParserAtomsTable& parserAtoms); - bool addToEnclosingLexicalBindingCache(JSContext* cx, + bool addToEnclosingLexicalBindingCache(JSContext* cx, ErrorContext* ec, ParserAtomsTable& parserAtoms, CompilationAtomCache& atomCache, InputName& name, EnclosingLexicalBindingKind kind); }; struct CompilationAtomCache { public: @@ -521,18 +554,18 @@ struct CompilationAtomCache { JSString* getStringAt(ParserAtomIndex index) const; JSAtom* getExistingAtomAt(ParserAtomIndex index) const; JSAtom* getExistingAtomAt(JSContext* cx, TaggedParserAtomIndex taggedIndex) const; JSAtom* getAtomAt(ParserAtomIndex index) const; bool hasAtomAt(ParserAtomIndex index) const; - bool setAtomAt(JSContext* cx, ParserAtomIndex index, JSString* atom); - bool allocate(JSContext* cx, size_t length); + bool setAtomAt(ErrorContext* ec, ParserAtomIndex index, JSString* atom); + bool allocate(ErrorContext* ec, size_t length); bool empty() const { return atoms_.empty(); } void stealBuffer(AtomCacheVector& atoms); void releaseBuffer(AtomCacheVector& atoms); void trace(JSTracer* trc); @@ -576,53 +609,55 @@ struct CompilationInput { // * If the target is Delazification, the non-null enclosing scope of // the function InputScope enclosingScope = InputScope(nullptr); explicit CompilationInput(const JS::ReadOnlyCompileOptions& options) : options(options) {} private: - bool initScriptSource(JSContext* cx); + bool initScriptSource(JSContext* cx, ErrorContext* ec); public: - bool initForGlobal(JSContext* cx) { + bool initForGlobal(JSContext* cx, ErrorContext* ec) { target = CompilationTarget::Global; - return initScriptSource(cx); + return initScriptSource(cx, ec); } bool initForSelfHostingGlobal(JSContext* cx) { target = CompilationTarget::SelfHosting; - return initScriptSource(cx); + MainThreadErrorContext ec(cx); + return initScriptSource(cx, &ec); } - bool initForStandaloneFunction(JSContext* cx) { + bool initForStandaloneFunction(JSContext* cx, ErrorContext* ec) { target = CompilationTarget::StandaloneFunction; - if (!initScriptSource(cx)) { + if (!initScriptSource(cx, ec)) { return false; } enclosingScope = InputScope(&cx->global()->emptyGlobalScope()); return true; } bool initForStandaloneFunctionInNonSyntacticScope( - JSContext* cx, Handle<Scope*> functionEnclosingScope); + JSContext* cx, ErrorContext* ec, Handle<Scope*> functionEnclosingScope); - bool initForEval(JSContext* cx, Handle<Scope*> evalEnclosingScope) { + bool initForEval(JSContext* cx, ErrorContext* ec, + Handle<Scope*> evalEnclosingScope) { target = CompilationTarget::Eval; - if (!initScriptSource(cx)) { + if (!initScriptSource(cx, ec)) { return false; } enclosingScope = InputScope(evalEnclosingScope); return true; } - bool initForModule(JSContext* cx) { + bool initForModule(JSContext* cx, ErrorContext* ec) { target = CompilationTarget::Module; - if (!initScriptSource(cx)) { + if (!initScriptSource(cx, ec)) { return false; } // The `enclosingScope` is the emptyGlobalScope. return true; } void initFromLazy(JSContext* cx, BaseScript* lazyScript, ScriptSource* ss) { MOZ_ASSERT(cx->compartment() == lazyScript->compartment()); @@ -781,17 +816,17 @@ class CompilationSyntaxParseCache { // Return the extra information about the function being delazified, if any. const ScriptStencilExtra& funExtra() const { MOZ_ASSERT(isInitialized); return funExtra_; } // Initialize the SynaxParse cache given a LifoAlloc. The JSContext is only // used for reporting allocation errors. - [[nodiscard]] bool init(JSContext* cx, LifoAlloc& alloc, + [[nodiscard]] bool init(JSContext* cx, ErrorContext* ec, LifoAlloc& alloc, ParserAtomsTable& parseAtoms, CompilationAtomCache& atomCache, const InputScript& lazy); private: // Return the script index of a given inner function. // // WARNING: The ScriptIndex returned by this function corresponds to the index @@ -801,33 +836,37 @@ class CompilationSyntaxParseCache { // not be confused with any ScriptIndex from the CompilationState. ScriptIndex scriptIndex(size_t functionIndex) const { MOZ_ASSERT(isInitialized); auto taggedScriptIndex = cachedGCThings_[functionIndex]; MOZ_ASSERT(taggedScriptIndex.isFunction()); return taggedScriptIndex.toFunction(); } - [[nodiscard]] bool copyFunctionInfo(JSContext* cx, + [[nodiscard]] bool copyFunctionInfo(JSContext* cx, ErrorContext* ec, ParserAtomsTable& parseAtoms, CompilationAtomCache& atomCache, const InputScript& lazy); - [[nodiscard]] bool copyScriptInfo(JSContext* cx, LifoAlloc& alloc, + [[nodiscard]] bool copyScriptInfo(JSContext* cx, ErrorContext* ec, + LifoAlloc& alloc, ParserAtomsTable& parseAtoms, CompilationAtomCache& atomCache, BaseScript* lazy); - [[nodiscard]] bool copyScriptInfo(JSContext* cx, LifoAlloc& alloc, + [[nodiscard]] bool copyScriptInfo(JSContext* cx, ErrorContext* ec, + LifoAlloc& alloc, ParserAtomsTable& parseAtoms, CompilationAtomCache& atomCache, const ScriptStencilRef& lazy); - [[nodiscard]] bool copyClosedOverBindings(JSContext* cx, LifoAlloc& alloc, + [[nodiscard]] bool copyClosedOverBindings(JSContext* cx, ErrorContext* ec, + LifoAlloc& alloc, ParserAtomsTable& parseAtoms, CompilationAtomCache& atomCache, BaseScript* lazy); - [[nodiscard]] bool copyClosedOverBindings(JSContext* cx, LifoAlloc& alloc, + [[nodiscard]] bool copyClosedOverBindings(JSContext* cx, ErrorContext* ec, + LifoAlloc& alloc, ParserAtomsTable& parseAtoms, CompilationAtomCache& atomCache, const ScriptStencilRef& lazy); }; // AsmJS scripts are very rare on-average, so we use a HashMap to associate // data with a ScriptStencil. The ScriptStencil has a flag to indicate if we // need to even do this lookup. @@ -891,20 +930,22 @@ struct SharedDataContainer { std::swap(data_, other.data_); MOZ_ASSERT(other.isEmpty()); return *this; } ~SharedDataContainer(); [[nodiscard]] bool initVector(JSContext* cx); + [[nodiscard]] bool initVector(ErrorContext* ec); [[nodiscard]] bool initMap(JSContext* cx); + [[nodiscard]] bool initMap(ErrorContext* ec); private: - [[nodiscard]] bool convertFromSingleToMap(JSContext* cx); + [[nodiscard]] bool convertFromSingleToMap(ErrorContext* ec); public: bool isEmpty() const { return (data_) == SingleTag; } bool isSingle() const { return (data_ & TagMask) == SingleTag; } bool isVector() const { return (data_ & TagMask) == VectorTag; } bool isMap() const { return (data_ & TagMask) == MapTag; } bool isBorrow() const { return (data_ & TagMask) == BorrowTag; } @@ -935,32 +976,35 @@ struct SharedDataContainer { MOZ_ASSERT(isMap()); return reinterpret_cast<SharedDataMapPtr>(data_ & ~TagMask); } SharedDataContainer* asBorrow() const { MOZ_ASSERT(isBorrow()); return reinterpret_cast<SharedDataContainer*>(data_ & ~TagMask); } - [[nodiscard]] bool prepareStorageFor(JSContext* cx, size_t nonLazyScriptCount, + [[nodiscard]] bool prepareStorageFor(ErrorContext* ec, + size_t nonLazyScriptCount, size_t allScriptCount); - [[nodiscard]] bool cloneFrom(JSContext* cx, const SharedDataContainer& other); + [[nodiscard]] bool cloneFrom(ErrorContext* ec, + const SharedDataContainer& other); // Returns index-th script's shared data, or nullptr if it doesn't have. js::SharedImmutableScriptData* get(ScriptIndex index) const; // Add data for index-th script and share it with VM. - [[nodiscard]] bool addAndShare(JSContext* cx, ScriptIndex index, + [[nodiscard]] bool addAndShare(JSContext* cx, ErrorContext* ec, + ScriptIndex index, js::SharedImmutableScriptData* data); // Add data for index-th script without sharing it with VM. // The data should already be shared with VM. // // The data is supposed to be added from delazification. - [[nodiscard]] bool addExtraWithoutShare(JSContext* cx, ScriptIndex index, + [[nodiscard]] bool addExtraWithoutShare(ErrorContext* ec, ScriptIndex index, js::SharedImmutableScriptData* data); // Dynamic memory associated with this container. Does not include the // SharedImmutableScriptData since we are not the unique owner of it. size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { if (isVector()) { return asVector()->sizeOfIncludingThis(mallocSizeOf); } @@ -1297,26 +1341,28 @@ struct ExtensibleCompilationStencil { functionKey = extent.toFunctionKey(); } bool isInitialStencil() const { return functionKey == SourceExtent::NullFunctionKey; } // Steal CompilationStencil content. - [[nodiscard]] bool steal(JSContext* cx, RefPtr<CompilationStencil>&& other); + [[nodiscard]] bool steal(ErrorContext* ec, + RefPtr<CompilationStencil>&& other); // Clone ExtensibleCompilationStencil content. - [[nodiscard]] bool cloneFrom(JSContext* cx, const CompilationStencil& other); - [[nodiscard]] bool cloneFrom(JSContext* cx, + [[nodiscard]] bool cloneFrom(ErrorContext* ec, + const CompilationStencil& other); + [[nodiscard]] bool cloneFrom(ErrorContext* ec, const ExtensibleCompilationStencil& other); private: template <typename Stencil> - [[nodiscard]] bool cloneFromImpl(JSContext* cx, const Stencil& other); + [[nodiscard]] bool cloneFromImpl(ErrorContext* ec, const Stencil& other); public: const ParserAtomVector& parserAtomsSpan() const { return parserAtoms.entries(); } bool isModule() const; @@ -1362,27 +1408,30 @@ struct MOZ_RAII CompilationState : publi // SharedDataContainer.prepareStorageFor *before* start emitting bytecode. size_t nonLazyFunctionCount = 0; // End of fields. CompilationState(JSContext* cx, LifoAllocScope& parserAllocScope, CompilationInput& input); - bool init(JSContext* cx, InheritThis inheritThis = InheritThis::No, + bool init(JSContext* cx, ErrorContext* ec, ScopeBindingCache* scopeCache, + InheritThis inheritThis = InheritThis::No, JSObject* enclosingEnv = nullptr) { - if (!scopeContext.init(cx, input, parserAtoms, inheritThis, enclosingEnv)) { + if (!scopeContext.init(cx, ec, input, parserAtoms, scopeCache, inheritThis, + enclosingEnv)) { return false; } // gcThings is later used by the full parser initialization. if (input.isDelazifying()) { InputScript lazy = input.lazyOuterScript(); auto& atomCache = input.atomCache; - if (!previousParseCache.init(cx, alloc, parserAtoms, atomCache, lazy)) { + if (!previousParseCache.init(cx, ec, alloc, parserAtoms, atomCache, + lazy)) { return false; } } return true; } // Track the state of key allocations and roll them back as parts of parsing @@ -1390,39 +1439,39 @@ struct MOZ_RAII CompilationState : publi // encounter discarded frontend state. struct CompilationStatePosition { // Temporarily share this token struct with CompilationState. size_t scriptDataLength = 0; size_t asmJSCount = 0; }; - bool prepareSharedDataStorage(JSContext* cx); + bool prepareSharedDataStorage(ErrorContext* ec); CompilationStatePosition getPosition(); void rewind(const CompilationStatePosition& pos); // When parsing arrow function, parameter is parsed twice, and if there are // functions inside parameter expression, stencils will be created for them. // // Those functions exist only for lazy parsing. // Mark them "ghost", so that they don't affect other parts. // // See GHOST_FUNCTION in FunctionFlags.h for more details. void markGhost(const CompilationStatePosition& pos); // Allocate space for `length` gcthings, and return the address of the // first element to `cursor` to initialize on the caller. - bool allocateGCThingsUninitialized(JSContext* cx, ScriptIndex scriptIndex, - size_t length, + bool allocateGCThingsUninitialized(JSContext* cx, ErrorContext* ec, + ScriptIndex scriptIndex, size_t length, TaggedScriptThingIndex** cursor); - bool appendScriptStencilAndData(JSContext* cx); + bool appendScriptStencilAndData(ErrorContext* ec); - bool appendGCThings(JSContext* cx, ScriptIndex scriptIndex, + bool appendGCThings(JSContext* cx, ErrorContext* ec, ScriptIndex scriptIndex, mozilla::Span<const TaggedScriptThingIndex> things); }; // A temporary CompilationStencil instance that borrows // ExtensibleCompilationStencil data. // Ensure that this instance does not outlive the ExtensibleCompilationStencil. class MOZ_STACK_CLASS BorrowingCompilationStencil : public CompilationStencil { public: @@ -1526,42 +1575,42 @@ struct CompilationGCOutput { js::Scope* getScopeNoBaseIndex(ScopeIndex index) const { MOZ_ASSERT(!scopesBaseIndex); return scopes[index]; } // Reserve output vector capacity. This may be called before instantiate to do // allocations ahead of time (off thread). The stencil instantiation code will // also run this to ensure the vectors are ready. - [[nodiscard]] bool ensureReserved(JSContext* cx, size_t scriptDataLength, + [[nodiscard]] bool ensureReserved(ErrorContext* ec, size_t scriptDataLength, size_t scopeDataLength) { if (!functions.reserve(scriptDataLength)) { - ReportOutOfMemory(cx); + ReportOutOfMemory(ec); return false; } if (!scopes.reserve(scopeDataLength)) { - ReportOutOfMemory(cx); + ReportOutOfMemory(ec); return false; } return true; } // A variant of `ensureReserved` that sets a base index for the function and // scope arrays. This is used when instantiating only a subset of the stencil. // Currently this only applies to self-hosted delazification. The ranges // include the start index and exclude the limit index. - [[nodiscard]] bool ensureReservedWithBaseIndex(JSContext* cx, + [[nodiscard]] bool ensureReservedWithBaseIndex(ErrorContext* ec, ScriptIndex scriptStart, ScriptIndex scriptLimit, ScopeIndex scopeStart, ScopeIndex scopeLimit) { this->functionsBaseIndex = scriptStart; this->scopesBaseIndex = scopeStart; - return ensureReserved(cx, scriptLimit - scriptStart, + return ensureReserved(ec, scriptLimit - scriptStart, scopeLimit - scopeStart); } // Size of dynamic data. Note that GC data is counted by GC and not here. size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return functions.sizeOfExcludingThis(mallocSizeOf) + scopes.sizeOfExcludingThis(mallocSizeOf); } @@ -1688,39 +1737,43 @@ struct CompilationStencilMerger { UniquePtr<ExtensibleCompilationStencil> initial_; // A Map from function key to the ScriptIndex in the initial stencil. using FunctionKeyToScriptIndexMap = HashMap<FunctionKey, ScriptIndex, mozilla::DefaultHasher<FunctionKey>, js::SystemAllocPolicy>; FunctionKeyToScriptIndexMap functionKeyToInitialScriptIndex_; - [[nodiscard]] bool buildFunctionKeyToIndex(JSContext* cx); + [[nodiscard]] bool buildFunctionKeyToIndex(ErrorContext* ec); ScriptIndex getInitialScriptIndexFor( const CompilationStencil& delazification) const; // A map from delazification's ParserAtomIndex to // initial's TaggedParserAtomIndex using AtomIndexMap = Vector<TaggedParserAtomIndex, 0, js::SystemAllocPolicy>; - [[nodiscard]] bool buildAtomIndexMap(JSContext* cx, + [[nodiscard]] bool buildAtomIndexMap(ErrorContext* ec, const CompilationStencil& delazification, AtomIndexMap& atomIndexMap); public: CompilationStencilMerger() = default; // Set the initial stencil and prepare for merging. [[nodiscard]] bool setInitial( JSContext* cx, UniquePtr<ExtensibleCompilationStencil>&& initial); + [[nodiscard]] bool setInitial( + ErrorContext* ec, UniquePtr<ExtensibleCompilationStencil>&& initial); // Merge the delazification stencil into the initial stencil. [[nodiscard]] bool addDelazification( JSContext* cx, const CompilationStencil& delazification); + [[nodiscard]] bool addDelazification( + ErrorContext* ec, const CompilationStencil& delazification); ExtensibleCompilationStencil& getResult() const { return *initial_; } UniquePtr<ExtensibleCompilationStencil> takeResult() { return std::move(initial_); } }; const ScopeStencil& ScopeStencilRef::scope() const {
--- ee33ca7b2fc935113c95907f64c71b1058171782/js/src/frontend/Stencil.cpp +++ 62177878bdfbb1a5332a8f16ec2d80caca12d841/js/src/frontend/Stencil.cpp @@ -16,16 +16,17 @@ #include "ds/LifoAlloc.h" // LifoAlloc #include "frontend/AbstractScopePtr.h" // ScopeIndex #include "frontend/BytecodeCompilation.h" // CanLazilyParse, CompileGlobalScriptToStencil #include "frontend/BytecodeCompiler.h" // ParseModuleToStencil #include "frontend/BytecodeSection.h" // EmitScriptThingsVector #include "frontend/CompilationStencil.h" // CompilationStencil, CompilationState, ExtensibleCompilationStencil, CompilationGCOutput, CompilationStencilMerger #include "frontend/NameAnalysisTypes.h" // EnvironmentCoordinate +#include "frontend/ScopeBindingCache.h" // ScopeBindingCache #include "frontend/SharedContext.h" #include "frontend/StencilXdr.h" // XDRStencilEncoder, XDRStencilDecoder #include "gc/AllocKind.h" // gc::AllocKind #include "gc/Tracer.h" // TraceNullableRoot #include "js/CallArgs.h" // JSNative #include "js/CompileOptions.h" // JS::DecodeOptions #include "js/experimental/JSStencil.h" // JS::Stencil #include "js/GCAPI.h" // JS::AutoCheckCannotGC @@ -33,33 +34,30 @@ #include "js/Transcoding.h" // JS::TranscodeBuffer #include "js/Value.h" // ObjectValue #include "js/WasmModule.h" // JS::WasmModule #include "vm/BigIntType.h" // ParseBigIntLiteral, BigIntLiteralIsZero #include "vm/BindingKind.h" // BindingKind #include "vm/EnvironmentObject.h" #include "vm/ErrorContext.h" #include "vm/GeneratorAndAsyncKind.h" // GeneratorKind, FunctionAsyncKind -#include "vm/HelperThreads.h" // js::StartOffThreadParseScript -#include "vm/HelperThreadState.h" -#include "vm/JSContext.h" // JSContext +#include "vm/JSContext.h" // JSContext #include "vm/JSFunction.h" // JSFunction, GetFunctionPrototype, NewFunctionWithProto #include "vm/JSObject.h" // JSObject, TenuredObject #include "vm/JSONPrinter.h" // js::JSONPrinter #include "vm/JSScript.h" // BaseScript, JSScript #include "vm/Printer.h" // js::Fprinter #include "vm/RegExpObject.h" // js::RegExpObject #include "vm/Scope.h" // Scope, *Scope, ScopeKind::*, ScopeKindString, ScopeIter, ScopeKindIsCatch, BindingIter, GetScopeDataTrailingNames, SizeOfParserScopeData #include "vm/ScopeKind.h" // ScopeKind #include "vm/SelfHosting.h" // SetClonedSelfHostedFunctionName #include "vm/StaticStrings.h" #include "vm/StencilEnums.h" // ImmutableScriptFlagsEnum #include "vm/StringType.h" // JSAtom, js::CopyChars #include "wasm/AsmJS.h" // InstantiateAsmJS -#include "wasm/WasmModule.h" // wasm::Module #include "vm/EnvironmentObject-inl.h" // JSObject::enclosingEnvironment #include "vm/JSFunction-inl.h" // JSFunction::create using namespace js; using namespace js::frontend; // These 2 functions are used to write the same code with lambda using auto @@ -92,63 +90,257 @@ InputName InputScript::displayAtom() con [](BaseScript* ptr) { return InputName(ptr, ptr->function()->displayAtom()); }, [](const ScriptStencilRef& ref) { return InputName(ref, ref.scriptData().functionAtom); }); } -TaggedParserAtomIndex InputName::internInto(JSContext* cx, +TaggedParserAtomIndex InputName::internInto(JSContext* cx, ErrorContext* ec, ParserAtomsTable& parserAtoms, CompilationAtomCache& atomCache) { return variant_.match( [&](JSAtom* ptr) -> TaggedParserAtomIndex { - return parserAtoms.internJSAtom(cx, atomCache, ptr); + return parserAtoms.internJSAtom(cx, ec, atomCache, ptr); }, [&](NameStencilRef& ref) -> TaggedParserAtomIndex { - return parserAtoms.internExternalParserAtomIndex(cx, ref.context_, + return parserAtoms.internExternalParserAtomIndex(ec, ref.context_, ref.atomIndex_); }); } -bool InputName::isEqualTo(JSContext* cx, ParserAtomsTable& parserAtoms, +bool InputName::isEqualTo(JSContext* cx, ErrorContext* ec, + ParserAtomsTable& parserAtoms, CompilationAtomCache& atomCache, TaggedParserAtomIndex other, JSAtom** otherCached) const { return variant_.match( [&](const JSAtom* ptr) -> bool { + if (ptr->hash() != parserAtoms.hash(other)) { + return false; + } + if (!*otherCached) { // TODO-Stencil: // Here, we convert our name into a JSAtom*, and hard-crash on failure // to allocate. This conversion should not be required as we should be // able to iterate up snapshotted scope chains that use parser atoms. // // This will be fixed when the enclosing scopes are snapshotted. // // See bug 1690277. AutoEnterOOMUnsafeRegion oomUnsafe; - *otherCached = parserAtoms.toJSAtom(cx, other, atomCache); + *otherCached = parserAtoms.toJSAtom(cx, ec, other, atomCache); if (!*otherCached) { oomUnsafe.crash("InputName::isEqualTo"); } } else { MOZ_ASSERT(atomCache.getExistingAtomAt(cx, other) == *otherCached); } return ptr == *otherCached; }, [&](const NameStencilRef& ref) -> bool { return parserAtoms.isEqualToExternalParserAtomIndex(other, ref.context_, ref.atomIndex_); }); } -bool ScopeContext::init(JSContext* cx, CompilationInput& input, - ParserAtomsTable& parserAtoms, InheritThis inheritThis, +GenericAtom::GenericAtom(JSContext* cx, ErrorContext* ec, + ParserAtomsTable& parserAtoms, + CompilationAtomCache& atomCache, + TaggedParserAtomIndex index) + : ref(EmitterName(cx, ec, parserAtoms, atomCache, index)) { + hash = parserAtoms.hash(index); +} + +GenericAtom::GenericAtom(const CompilationStencil& context, + TaggedParserAtomIndex index) + : ref(StencilName{context, index}) { + if (index.isParserAtomIndex()) { + ParserAtom* atom = context.parserAtomData[index.toParserAtomIndex()]; + hash = atom->hash(); + } else { + hash = index.staticOrWellKnownHash(); + } +} + +GenericAtom::GenericAtom(ScopeStencilRef& scope, TaggedParserAtomIndex index) + : GenericAtom(scope.context_, index) {} + +BindingHasher<TaggedParserAtomIndex>::Lookup::Lookup(ScopeStencilRef& scope_ref, + const GenericAtom& other) + : keyStencil(scope_ref.context_), other(other) {} + +bool GenericAtom::operator==(const GenericAtom& other) const { + return ref.match( + [&other](const EmitterName& name) -> bool { + return other.ref.match( + [&name](const EmitterName& other) -> bool { + // We never have multiple Emitter context at the same time. + MOZ_ASSERT(name.cx == other.cx); + MOZ_ASSERT(&name.parserAtoms == &other.parserAtoms); + MOZ_ASSERT(&name.atomCache == &other.atomCache); + return name.index == other.index; + }, + [&name](const StencilName& other) -> bool { + return name.parserAtoms.isEqualToExternalParserAtomIndex( + name.index, other.stencil, other.index); + }, + [&name](JSAtom* other) -> bool { + AutoEnterOOMUnsafeRegion oomUnsafe; + JSAtom* namePtr = name.parserAtoms.toJSAtom( + name.cx, name.ec, name.index, name.atomCache); + if (!namePtr) { + oomUnsafe.crash("GenericAtom(EmitterName == JSAtom*)"); + } + return namePtr == other; + }); + }, + [&other](const StencilName& name) -> bool { + return other.ref.match( + [&name](const EmitterName& other) -> bool { + return other.parserAtoms.isEqualToExternalParserAtomIndex( + other.index, name.stencil, name.index); + }, + [&name](const StencilName& other) -> bool { + // Technically it is possible to have multiple stencils, but in + // this particular case let's assume we never encounter a case + // where we are comparing names from different stencils. + // + // The reason this assumption is safe today is that we are only + // using this in the context of a stencil-delazification, where + // the only StencilNames are coming from the CompilationStencil + // provided to CompilationInput::initFromStencil. + MOZ_ASSERT(&name.stencil == &other.stencil); + return name.index == other.index; + }, + [](JSAtom* other) -> bool { + MOZ_CRASH("Never used."); + return false; + }); + }, + [&other](JSAtom* name) -> bool { + return other.ref.match( + [&name](const EmitterName& other) -> bool { + AutoEnterOOMUnsafeRegion oomUnsafe; + JSAtom* otherPtr = other.parserAtoms.toJSAtom( + other.cx, other.ec, other.index, other.atomCache); + if (!otherPtr) { + oomUnsafe.crash("GenericAtom(JSAtom* == EmitterName)"); + } + return name == otherPtr; + }, + [](const StencilName& other) -> bool { + MOZ_CRASH("Never used."); + return false; + }, + [&name](JSAtom* other) -> bool { return name == other; }); + }); +} + +#ifdef DEBUG +template <typename SpanT, typename VecT> +void AssertBorrowingSpan(const SpanT& span, const VecT& vec) { + MOZ_ASSERT(span.size() == vec.length()); + MOZ_ASSERT(span.data() == vec.begin()); +} +#endif + +bool ScopeBindingCache::canCacheFor(Scope* ptr) { + MOZ_CRASH("Unexpected scope chain type: Scope*"); +} + +bool ScopeBindingCache::canCacheFor(ScopeStencilRef ref) { + MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef"); +} + +BindingMap<JSAtom*>* ScopeBindingCache::createCacheFor(Scope* ptr) { + MOZ_CRASH("Unexpected scope chain type: Scope*"); +} + +BindingMap<JSAtom*>* ScopeBindingCache::lookupScope(Scope* ptr, + CacheGeneration gen) { + MOZ_CRASH("Unexpected scope chain type: Scope*"); +} + +BindingMap<TaggedParserAtomIndex>* ScopeBindingCache::createCacheFor( + ScopeStencilRef ref) { + MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef"); +} + +BindingMap<TaggedParserAtomIndex>* ScopeBindingCache::lookupScope( + ScopeStencilRef ref, CacheGeneration gen) { + MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef"); +} + +bool NoScopeBindingCache::canCacheFor(Scope* ptr) { return false; } + +bool NoScopeBindingCache::canCacheFor(ScopeStencilRef ref) { return false; } + +bool RuntimeScopeBindingCache::canCacheFor(Scope* ptr) { return true; } + +BindingMap<JSAtom*>* RuntimeScopeBindingCache::createCacheFor(Scope* ptr) { + BaseScopeData* dataPtr = ptr->rawData(); + BindingMap<JSAtom*> bindingCache; + if (!scopeMap.putNew(dataPtr, std::move(bindingCache))) { + return nullptr; + } + + return lookupScope(ptr, cacheGeneration); +} + +BindingMap<JSAtom*>* RuntimeScopeBindingCache::lookupScope( + Scope* ptr, CacheGeneration gen) { + MOZ_ASSERT(gen == cacheGeneration); + BaseScopeData* dataPtr = ptr->rawData(); + auto valuePtr = scopeMap.lookup(dataPtr); + if (!valuePtr) { + return nullptr; + } + return &valuePtr->value(); +} + +bool StencilScopeBindingCache::canCacheFor(ScopeStencilRef ref) { return true; } + +BindingMap<TaggedParserAtomIndex>* StencilScopeBindingCache::createCacheFor( + ScopeStencilRef ref) { +#ifdef DEBUG + AssertBorrowingSpan(ref.context_.scopeNames, merger_.getResult().scopeNames); +#endif + auto* dataPtr = ref.context_.scopeNames[ref.scopeIndex_]; + BindingMap<TaggedParserAtomIndex> bindingCache; + if (!scopeMap.putNew(dataPtr, std::move(bindingCache))) { + return nullptr; + } + + return lookupScope(ref, 1); +} + +BindingMap<TaggedParserAtomIndex>* StencilScopeBindingCache::lookupScope( + ScopeStencilRef ref, CacheGeneration gen) { +#ifdef DEBUG + AssertBorrowingSpan(ref.context_.scopeNames, merger_.getResult().scopeNames); +#endif + auto* dataPtr = ref.context_.scopeNames[ref.scopeIndex_]; + auto ptr = scopeMap.lookup(dataPtr); + if (!ptr) { + return nullptr; + } + return &ptr->value(); +} + +bool ScopeContext::init(JSContext* cx, ErrorContext* ec, + CompilationInput& input, ParserAtomsTable& parserAtoms, + ScopeBindingCache* scopeCache, InheritThis inheritThis, JSObject* enclosingEnv) { + // Record the scopeCache to be used while looking up NameLocation bindings. + this->scopeCache = scopeCache; + scopeCacheGen = scopeCache->getCurrentGeneration(); + InputScope maybeNonDefaultEnclosingScope( input.maybeNonDefaultEnclosingScope()); // If this eval is in response to Debugger.Frame.eval, we may have an // incomplete scope chain. In order to provide a better debugging experience, // we inspect the (optional) environment chain to determine it's enclosing // FunctionScope if there is one. If there is no such scope, we use the // orignal scope provided. @@ -163,20 +355,20 @@ bool ScopeContext::init(JSContext* cx, C computeThisBinding(effectiveScope); computeThisEnvironment(maybeNonDefaultEnclosingScope); } computeInScope(maybeNonDefaultEnclosingScope); cacheEnclosingScope(input.enclosingScope); if (input.target == CompilationInput::CompilationTarget::Eval) { - if (!cacheEnclosingScopeBindingForEval(cx, input, parserAtoms)) { + if (!cacheEnclosingScopeBindingForEval(cx, ec, input, parserAtoms)) { return false; } - if (!cachePrivateFieldsForEval(cx, input, enclosingEnv, effectiveScope, + if (!cachePrivateFieldsForEval(cx, ec, input, enclosingEnv, effectiveScope, parserAtoms)) { return false; } } return true; } @@ -293,16 +485,215 @@ void ScopeContext::cacheEnclosingScope(c } if (si.scope().allowSuperProperty() && si.scope().needsHomeObject()) { hasFunctionNeedsHomeObjectOnChain = true; } break; } } #endif + + // Pre-fill the scope cache by iterating over all the names. Stop iterating + // as soon as we find a scope which already has a filled scope cache. + AutoEnterOOMUnsafeRegion oomUnsafe; + for (InputScopeIter si(enclosingScope); si; si++) { + // If the current scope already exists, then there is no need to go deeper + // as the scope which are encoded after this one should already be present + // in the cache. + bool hasScopeCache = si.scope().match([&](auto& scope_ref) -> bool { + MOZ_ASSERT(scopeCache->canCacheFor(scope_ref)); + return scopeCache->lookupScope(scope_ref, scopeCacheGen); + }); + if (hasScopeCache) { + return; + } + + bool hasEnv = si.hasSyntacticEnvironment(); + auto setCacthAll = [&](NameLocation loc) { + return si.scope().match([&](auto& scope_ref) { + using BindingMapPtr = decltype(scopeCache->createCacheFor(scope_ref)); + BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref); + if (!bindingMapPtr) { + oomUnsafe.crash( + "ScopeContext::cacheEnclosingScope: scopeCache->createCacheFor"); + return; + } + + bindingMapPtr->catchAll.emplace(loc); + }); + }; + auto createEmpty = [&]() { + return si.scope().match([&](auto& scope_ref) { + using BindingMapPtr = decltype(scopeCache->createCacheFor(scope_ref)); + BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref); + if (!bindingMapPtr) { + oomUnsafe.crash( + "ScopeContext::cacheEnclosingScope: scopeCache->createCacheFor"); + return; + } + }); + }; + + switch (si.kind()) { + case ScopeKind::Function: + if (hasEnv) { + if (si.scope().funHasExtensibleScope()) { + setCacthAll(NameLocation::Dynamic()); + return; + } + + si.scope().match([&](auto& scope_ref) { + using BindingMapPtr = + decltype(scopeCache->createCacheFor(scope_ref)); + using Lookup = + typename std::remove_pointer_t<BindingMapPtr>::Lookup; + BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref); + if (!bindingMapPtr) { + oomUnsafe.crash( + "ScopeContext::cacheEnclosingScope: " + "scopeCache->createCacheFor"); + return; + } + + for (auto bi = InputBindingIter(scope_ref); bi; bi++) { + NameLocation loc = bi.nameLocation(); + if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate) { + continue; + } + auto ctxFreeKey = bi.name(); + GenericAtom ctxKey(scope_ref, ctxFreeKey); + Lookup ctxLookup(scope_ref, ctxKey); + if (!bindingMapPtr->hashMap.put(ctxLookup, ctxFreeKey, loc)) { + oomUnsafe.crash( + "ScopeContext::cacheEnclosingScope: bindingMapPtr->put"); + return; + } + } + }); + } else { + createEmpty(); + } + break; + + case ScopeKind::StrictEval: + case ScopeKind::FunctionBodyVar: + case ScopeKind::Lexical: + case ScopeKind::NamedLambda: + case ScopeKind::StrictNamedLambda: + case ScopeKind::SimpleCatch: + case ScopeKind::Catch: + case ScopeKind::FunctionLexical: + case ScopeKind::ClassBody: + if (hasEnv) { + si.scope().match([&](auto& scope_ref) { + using BindingMapPtr = + decltype(scopeCache->createCacheFor(scope_ref)); + using Lookup = + typename std::remove_pointer_t<BindingMapPtr>::Lookup; + BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref); + if (!bindingMapPtr) { + oomUnsafe.crash( + "ScopeContext::cacheEnclosingScope: " + "scopeCache->createCacheFor"); + return; + } + + for (auto bi = InputBindingIter(scope_ref); bi; bi++) { + NameLocation loc = bi.nameLocation(); + if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate) { + continue; + } + auto ctxFreeKey = bi.name(); + GenericAtom ctxKey(scope_ref, ctxFreeKey); + Lookup ctxLookup(scope_ref, ctxKey); + if (!bindingMapPtr->hashMap.putNew(ctxLookup, ctxFreeKey, loc)) { + oomUnsafe.crash( + "ScopeContext::cacheEnclosingScope: bindingMapPtr->put"); + return; + } + } + }); + } else { + createEmpty(); + } + break; + + case ScopeKind::Module: + // This case is used only when delazifying a function inside + // module. + // Initial compilation of module doesn't have enlcosing scope. + if (hasEnv) { + si.scope().match([&](auto& scope_ref) { + using BindingMapPtr = + decltype(scopeCache->createCacheFor(scope_ref)); + using Lookup = + typename std::remove_pointer_t<BindingMapPtr>::Lookup; + BindingMapPtr bindingMapPtr = scopeCache->createCacheFor(scope_ref); + if (!bindingMapPtr) { + oomUnsafe.crash( + "ScopeContext::cacheEnclosingScope: " + "scopeCache->createCacheFor"); + return; + } + + for (auto bi = InputBindingIter(scope_ref); bi; bi++) { + // Imports are on the environment but are indirect + // bindings and must be accessed dynamically instead of + // using an EnvironmentCoordinate. + NameLocation loc = bi.nameLocation(); + if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate && + loc.kind() != NameLocation::Kind::Import) { + continue; + } + auto ctxFreeKey = bi.name(); + GenericAtom ctxKey(scope_ref, ctxFreeKey); + Lookup ctxLookup(scope_ref, ctxKey); + if (!bindingMapPtr->hashMap.putNew(ctxLookup, ctxFreeKey, loc)) { + oomUnsafe.crash( + "ScopeContext::cacheEnclosingScope: bindingMapPtr->put"); + return; + } + } + }); + } else { + createEmpty(); + } + break; + + case ScopeKind::Eval: + // As an optimization, if the eval doesn't have its own var + // environment and its immediate enclosing scope is a global + // scope, all accesses are global. + if (!hasEnv) { + ScopeKind kind = si.scope().enclosing().kind(); + if (kind == ScopeKind::Global || kind == ScopeKind::NonSyntactic) { + setCacthAll(NameLocation::Global(BindingKind::Var)); + return; + } + } + + setCacthAll(NameLocation::Dynamic()); + return; + + case ScopeKind::Global: + setCacthAll(NameLocation::Global(BindingKind::Var)); + return; + + case ScopeKind::With: + case ScopeKind::NonSyntactic: + setCacthAll(NameLocation::Dynamic()); + return; + + case ScopeKind::WasmInstance: + case ScopeKind::WasmFunction: + MOZ_CRASH("No direct eval inside wasm functions"); + } + } + + MOZ_CRASH("Malformed scope chain"); } InputScope ScopeContext::determineEffectiveScope(InputScope& scope, JSObject* environment) { MOZ_ASSERT(effectiveScopeHops == 0); // If the scope-chain is non-syntactic, we may still determine a more precise // effective-scope to use instead. if (environment && scope.hasOnChain(ScopeKind::NonSyntactic)) { @@ -347,17 +738,18 @@ static uint32_t DepthOfNearestVarScopeFo default: break; } } return depth; } bool ScopeContext::cacheEnclosingScopeBindingForEval( - JSContext* cx, CompilationInput& input, ParserAtomsTable& parserAtoms) { + JSContext* cx, ErrorContext* ec, CompilationInput& input, + ParserAtomsTable& parserAtoms) { enclosingLexicalBindingCache_.emplace(); uint32_t varScopeDepth = DepthOfNearestVarScopeForDirectEval(input.enclosingScope); uint32_t depth = 0; for (InputScopeIter si(input.enclosingScope); si; si++) { bool success = si.scope().match([&](auto& scope_ref) { for (auto bi = InputBindingIter(scope_ref); bi; bi++) { @@ -367,47 +759,47 @@ bool ScopeContext::cacheEnclosingScopeBi // catch parameters with var declarations. bool annexB35Allowance = si.kind() == ScopeKind::SimpleCatch; if (!annexB35Allowance) { auto kind = ScopeKindIsCatch(si.kind()) ? EnclosingLexicalBindingKind::CatchParameter : EnclosingLexicalBindingKind::Let; InputName binding(scope_ref, bi.name()); if (!addToEnclosingLexicalBindingCache( - cx, parserAtoms, input.atomCache, binding, kind)) { + cx, ec, parserAtoms, input.atomCache, binding, kind)) { return false; } } break; } case BindingKind::Const: { InputName binding(scope_ref, bi.name()); if (!addToEnclosingLexicalBindingCache( - cx, parserAtoms, input.atomCache, binding, + cx, ec, parserAtoms, input.atomCache, binding, EnclosingLexicalBindingKind::Const)) { return false; } break; } case BindingKind::Synthetic: { InputName binding(scope_ref, bi.name()); if (!addToEnclosingLexicalBindingCache( - cx, parserAtoms, input.atomCache, binding, + cx, ec, parserAtoms, input.atomCache, binding, EnclosingLexicalBindingKind::Synthetic)) { return false; } break; } case BindingKind::PrivateMethod: { InputName binding(scope_ref, bi.name()); if (!addToEnclosingLexicalBindingCache( - cx, parserAtoms, input.atomCache, binding, + cx, ec, parserAtoms, input.atomCache, binding, EnclosingLexicalBindingKind::PrivateMethod)) { return false; } break; } case BindingKind::Import: case BindingKind::FormalParameter: @@ -426,38 +818,38 @@ bool ScopeContext::cacheEnclosingScopeBi break; } } return true; } bool ScopeContext::addToEnclosingLexicalBindingCache( - JSContext* cx, ParserAtomsTable& parserAtoms, + JSContext* cx, ErrorContext* ec, ParserAtomsTable& parserAtoms, CompilationAtomCache& atomCache, InputName& name, EnclosingLexicalBindingKind kind) { TaggedParserAtomIndex parserName = - name.internInto(cx, parserAtoms, atomCache); + name.internInto(cx, ec, parserAtoms, atomCache); if (!parserName) { return false; } // Same lexical binding can appear multiple times across scopes. // // enclosingLexicalBindingCache_ map is used for detecting conflicting // `var` binding, and inner binding should be reported in the error. // // cacheEnclosingScopeBindingForEval iterates from inner scope, and // inner-most binding is added to the map first. // // Do not overwrite the value with outer bindings. auto p = enclosingLexicalBindingCache_->lookupForAdd(parserName); if (!p) { if (!enclosingLexicalBindingCache_->add(p, parserName, kind)) { - ReportOutOfMemory(cx); + ReportOutOfMemory(ec); return false; } } return true; } static bool IsPrivateField(Scope*, JSAtom* atom) { @@ -490,17 +882,17 @@ static bool IsPrivateField(ScopeStencilR // # character is not part of the allowed character of static strings. MOZ_ASSERT(content[0] != '#'); } #endif return false; } -bool ScopeContext::cachePrivateFieldsForEval(JSContext* cx, +bool ScopeContext::cachePrivateFieldsForEval(JSContext* cx, ErrorContext* ec, CompilationInput& input, JSObject* enclosingEnvironment, const InputScope& effectiveScope, ParserAtomsTable& parserAtoms) { effectiveScopePrivateFieldCache_.emplace(); // We (comment length limit exceeeded)
Files
/js/src/frontend/CompilationStencil.h
/js/src/frontend/Stencil.cpp
/js/src/frontend/Stencil.h
/js/src/vm/BytecodeUtil.cpp
/js/src/vm/BytecodeUtil.h
/js/src/vm/Opcodes.h
/js/src/vm/SharedStencil.h
Changesets
Diffs
/js/src/frontend/CompilationStencil.h
/js/src/frontend/Stencil.cpp