diff --git a/js/src/builtin/TestingUtility.cpp b/js/src/builtin/TestingUtility.cpp index b7b6b5e4222b6..8cf1eaffe7903 100644 --- a/js/src/builtin/TestingUtility.cpp +++ b/js/src/builtin/TestingUtility.cpp @@ -191,7 +191,7 @@ bool js::SetSourceOptions(JSContext* cx, ErrorContext* ec, ScriptSource* source, if (!chars) { return false; } - if (!source->setSourceMapURL(ec, std::move(chars))) { + if (!source->setSourceMapURL(cx, ec, std::move(chars))) { return false; } } diff --git a/js/src/debugger/Source.cpp b/js/src/debugger/Source.cpp index 8ef09b4d6e0b3..d509e3b158b32 100644 --- a/js/src/debugger/Source.cpp +++ b/js/src/debugger/Source.cpp @@ -528,7 +528,7 @@ bool DebuggerSource::CallData::setSourceMapURL() { } AutoReportFrontendContext ec(cx); - if (!ss->setSourceMapURL(&ec, std::move(chars))) { + if (!ss->setSourceMapURL(cx, &ec, std::move(chars))) { return false; } diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index fb1987cd1055d..1eedf85d41ec8 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -214,7 +214,7 @@ class MOZ_STACK_CLASS ScriptCompiler : public SourceAwareCompiler { return true; } - return stencilOut->source->assignSource(ec, input.options, srcBuf); + return stencilOut->source->assignSource(cx, ec, input.options, srcBuf); } [[nodiscard]] static bool TrySmoosh( @@ -634,7 +634,7 @@ bool SourceAwareCompiler::createSourceAndParser(JSContext* cx, errorContext = ec; - if (!compilationState_.source->assignSource(ec, options, sourceBuffer_)) { + if (!compilationState_.source->assignSource(cx, ec, options, sourceBuffer_)) { return false; } @@ -1132,7 +1132,7 @@ static GetCachedResult GetCachedLazyFunctionStencilMaybeInstantiate( } if (output.is>()) { - auto extensible = cx->make_unique(input); + auto extensible = cx->make_unique(cx, input); if (!extensible) { return GetCachedResult::Error; } diff --git a/js/src/frontend/CompilationStencil.h b/js/src/frontend/CompilationStencil.h index d06b0bb9a47d9..fba54f2f9a628 100644 --- a/js/src/frontend/CompilationStencil.h +++ b/js/src/frontend/CompilationStencil.h @@ -1282,10 +1282,11 @@ struct ExtensibleCompilationStencil { RefPtr asmJS; - explicit ExtensibleCompilationStencil(ScriptSource* source); + explicit ExtensibleCompilationStencil(JSContext* cx, ScriptSource* source); - explicit ExtensibleCompilationStencil(CompilationInput& input); - ExtensibleCompilationStencil(const JS::ReadOnlyCompileOptions& options, + ExtensibleCompilationStencil(JSContext* cx, CompilationInput& input); + ExtensibleCompilationStencil(JSContext* cx, + const JS::ReadOnlyCompileOptions& options, RefPtr source); ExtensibleCompilationStencil(ExtensibleCompilationStencil&& other) noexcept diff --git a/js/src/frontend/ParserAtom.cpp b/js/src/frontend/ParserAtom.cpp index 9248d15ff9de6..485772f53a386 100644 --- a/js/src/frontend/ParserAtom.cpp +++ b/js/src/frontend/ParserAtom.cpp @@ -18,8 +18,7 @@ #include "util/Text.h" // AsciiDigitToNumber #include "util/Unicode.h" #include "vm/JSContext.h" -#include "vm/MutexIDs.h" // mutexid -#include "vm/Printer.h" // Sprinter, QuoteString +#include "vm/Printer.h" // Sprinter, QuoteString #include "vm/Runtime.h" #include "vm/SelfHosting.h" // ExtendedUnclonedSelfHostedFunctionNamePrefix #include "vm/StaticStrings.h" @@ -326,7 +325,8 @@ void ParserAtomsTable::dumpCharsNoQuote(js::GenericPrinter& out, } #endif -ParserAtomsTable::ParserAtomsTable(LifoAlloc& alloc) : alloc_(&alloc) {} +ParserAtomsTable::ParserAtomsTable(JSRuntime* rt, LifoAlloc& alloc) + : wellKnownTable_(*rt->commonParserNames), alloc_(&alloc) {} TaggedParserAtomIndex ParserAtomsTable::addEntry(ErrorContext* ec, EntryMap::AddPtr& addPtr, @@ -376,15 +376,14 @@ TaggedParserAtomIndex ParserAtomsTable::internAscii(ErrorContext* ec, TaggedParserAtomIndex ParserAtomsTable::internLatin1( ErrorContext* ec, const Latin1Char* latin1Ptr, uint32_t length) { // Check for tiny strings which are abundant in minified code. - if (auto tiny = WellKnownParserAtoms::getSingleton().lookupTinyIndex( - latin1Ptr, length)) { + if (auto tiny = wellKnownTable_.lookupTinyIndex(latin1Ptr, length)) { return tiny; } // Check for well-known atom. InflatedChar16Sequence seq(latin1Ptr, length); SpecificParserAtomLookup lookup(seq); - if (auto wk = WellKnownParserAtoms::getSingleton().lookupChar16Seq(lookup)) { + if (auto wk = wellKnownTable_.lookupChar16Seq(lookup)) { return wk; } @@ -542,8 +541,7 @@ static inline bool IsLatin1(mozilla::Utf8Unit c1, mozilla::Utf8Unit c2) { TaggedParserAtomIndex ParserAtomsTable::internUtf8( ErrorContext* ec, const mozilla::Utf8Unit* utf8Ptr, uint32_t nbyte) { - if (auto tiny = WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8( - utf8Ptr, nbyte)) { + if (auto tiny = wellKnownTable_.lookupTinyIndexUTF8(utf8Ptr, nbyte)) { return tiny; } @@ -564,7 +562,7 @@ TaggedParserAtomIndex ParserAtomsTable::internUtf8( // NOTE: Well-known are all ASCII so have been handled above. InflatedChar16Sequence seq(utf8Ptr, nbyte); SpecificParserAtomLookup lookup(seq); - MOZ_ASSERT(!WellKnownParserAtoms::getSingleton().lookupChar16Seq(lookup)); + MOZ_ASSERT(!wellKnownTable_.lookupChar16Seq(lookup)); EntryMap::AddPtr addPtr = entryMap_.lookupForAdd(lookup); if (addPtr) { return addPtr->value(); @@ -590,15 +588,14 @@ TaggedParserAtomIndex ParserAtomsTable::internChar16(ErrorContext* ec, const char16_t* char16Ptr, uint32_t length) { // Check for tiny strings which are abundant in minified code. - if (auto tiny = WellKnownParserAtoms::getSingleton().lookupTinyIndex( - char16Ptr, length)) { + if (auto tiny = wellKnownTable_.lookupTinyIndex(char16Ptr, length)) { return tiny; } // Check against well-known. InflatedChar16Sequence seq(char16Ptr, length); SpecificParserAtomLookup lookup(seq); - if (auto wk = WellKnownParserAtoms::getSingleton().lookupChar16Seq(lookup)) { + if (auto wk = wellKnownTable_.lookupChar16Seq(lookup)) { return wk; } @@ -1211,16 +1208,6 @@ bool InstantiateMarkedAtomsAsPermanent(JSContext* cx, ErrorContext* ec, return true; } -/* static */ -WellKnownParserAtoms WellKnownParserAtoms::singleton_; - -WellKnownParserAtoms::WellKnownParserAtoms() -#ifdef DEBUG - : initLock_(mutexid::WellKnownParserAtomsInit) -#endif -{ -} - template TaggedParserAtomIndex WellKnownParserAtoms::lookupChar16Seq( const SpecificParserAtomLookup& lookup) const { @@ -1251,7 +1238,8 @@ TaggedParserAtomIndex WellKnownParserAtoms::lookupTinyIndexUTF8( return lookupTinyIndex(reinterpret_cast(utf8Ptr), nbyte); } -bool WellKnownParserAtoms::initSingle(const WellKnownAtomInfo& info, +bool WellKnownParserAtoms::initSingle(JSContext* cx, + const WellKnownAtomInfo& info, TaggedParserAtomIndex index) { unsigned int len = info.length; const Latin1Char* str = reinterpret_cast(info.content); @@ -1271,40 +1259,34 @@ bool WellKnownParserAtoms::initSingle(const WellKnownAtomInfo& info, // Save name for returning after moving entry into set. if (!wellKnownMap_.putNew(lookup, &info, index)) { + js::ReportOutOfMemory(cx); return false; } return true; } -bool WellKnownParserAtoms::init() { -#ifdef DEBUG - LockGuard guard(initLock_); - MOZ_ASSERT(!initialized_); - initialized_ = true; -#endif - MOZ_ASSERT(wellKnownMap_.empty()); - +bool WellKnownParserAtoms::init(JSContext* cx) { // Add well-known strings to the HashMap. The HashMap is used for dynamic // lookups later and does not change once this init method is complete. -#define COMMON_NAME_INIT_(_, NAME, _2) \ - if (!initSingle(GetWellKnownAtomInfo(WellKnownAtomId::NAME), \ - TaggedParserAtomIndex::WellKnown::NAME())) { \ - return false; \ +#define COMMON_NAME_INIT_(_, NAME, _2) \ + if (!initSingle(cx, GetWellKnownAtomInfo(WellKnownAtomId::NAME), \ + TaggedParserAtomIndex::WellKnown::NAME())) { \ + return false; \ } FOR_EACH_NONTINY_COMMON_PROPERTYNAME(COMMON_NAME_INIT_) #undef COMMON_NAME_INIT_ -#define COMMON_NAME_INIT_(NAME, _) \ - if (!initSingle(GetWellKnownAtomInfo(WellKnownAtomId::NAME), \ - TaggedParserAtomIndex::WellKnown::NAME())) { \ - return false; \ +#define COMMON_NAME_INIT_(NAME, _) \ + if (!initSingle(cx, GetWellKnownAtomInfo(WellKnownAtomId::NAME), \ + TaggedParserAtomIndex::WellKnown::NAME())) { \ + return false; \ } JS_FOR_EACH_PROTOTYPE(COMMON_NAME_INIT_) #undef COMMON_NAME_INIT_ -#define COMMON_NAME_INIT_(NAME) \ - if (!initSingle(GetWellKnownAtomInfo(WellKnownAtomId::NAME), \ - TaggedParserAtomIndex::WellKnown::NAME())) { \ - return false; \ +#define COMMON_NAME_INIT_(NAME) \ + if (!initSingle(cx, GetWellKnownAtomInfo(WellKnownAtomId::NAME), \ + TaggedParserAtomIndex::WellKnown::NAME())) { \ + return false; \ } JS_FOR_EACH_WELL_KNOWN_SYMBOL(COMMON_NAME_INIT_) #undef COMMON_NAME_INIT_ @@ -1312,35 +1294,29 @@ bool WellKnownParserAtoms::init() { return true; } -void WellKnownParserAtoms::free() { - initialized_ = false; - wellKnownMap_.clear(); -} - -/* static */ bool WellKnownParserAtoms::initSingleton() { - return singleton_.init(); -} - -/* static */ void WellKnownParserAtoms::freeSingleton() { singleton_.free(); } - } /* namespace frontend */ } /* namespace js */ bool JSRuntime::initializeParserAtoms(JSContext* cx) { + MOZ_ASSERT(!commonParserNames); + if (parentRuntime) { + commonParserNames = parentRuntime->commonParserNames; return true; } - if (!js::frontend::WellKnownParserAtoms::initSingleton()) { - js::ReportOutOfMemory(cx); + UniquePtr names( + js_new()); + if (!names || !names->init(cx)) { return false; } + commonParserNames = names.release(); return true; } void JSRuntime::finishParserAtoms() { if (!parentRuntime) { - js::frontend::WellKnownParserAtoms::freeSingleton(); + js_delete(commonParserNames.ref()); } } diff --git a/js/src/frontend/ParserAtom.h b/js/src/frontend/ParserAtom.h index cc3466b8006e9..016a89733c7b8 100644 --- a/js/src/frontend/ParserAtom.h +++ b/js/src/frontend/ParserAtom.h @@ -25,13 +25,13 @@ #include "js/TypeDecls.h" // Latin1Char #include "js/Utility.h" // UniqueChars #include "js/Vector.h" // Vector -#include "threading/Mutex.h" // Mutex #include "util/Text.h" // InflatedChar16Sequence #include "vm/CommonPropertyNames.h" #include "vm/StaticStrings.h" #include "vm/WellKnownAtom.h" // WellKnownAtomId, WellKnownAtomInfo struct JS_PUBLIC_API JSContext; +struct JSRuntime; class JSAtom; class JSString; @@ -572,34 +572,18 @@ using ParserAtomSpan = mozilla::Span; * constant time. */ class WellKnownParserAtoms { - static WellKnownParserAtoms singleton_; - -#ifdef DEBUG - js::Mutex initLock_ MOZ_UNANNOTATED; - bool initialized_ = false; -#endif - - WellKnownParserAtoms(); - + public: // Common property and prototype names are tracked in a hash table. This table // does not key for any items already in a direct-indexing tiny atom table. using EntryMap = HashMap; EntryMap wellKnownMap_; - bool initSingle(const WellKnownAtomInfo& info, TaggedParserAtomIndex index); - - bool init(); - void free(); + bool initSingle(JSContext* cx, const WellKnownAtomInfo& info, + TaggedParserAtomIndex index); public: - static bool initSingleton(); - static void freeSingleton(); - - static WellKnownParserAtoms& getSingleton() { - MOZ_ASSERT(!singleton_.wellKnownMap_.empty()); - return singleton_; - } + bool init(JSContext* cx); // Maximum length of any well known atoms. This can be increased if needed. static constexpr size_t MaxWellKnownLength = 32; @@ -675,6 +659,8 @@ class ParserAtomsTable { friend struct CompilationStencil; private: + const WellKnownParserAtoms& wellKnownTable_; + LifoAlloc* alloc_; // The ParserAtom are owned by the LifoAlloc. @@ -684,7 +670,7 @@ class ParserAtomsTable { ParserAtomVector entries_; public: - explicit ParserAtomsTable(LifoAlloc& alloc); + ParserAtomsTable(JSRuntime* rt, LifoAlloc& alloc); ParserAtomsTable(ParserAtomsTable&&) = default; ParserAtomsTable& operator=(ParserAtomsTable&& other) noexcept { entryMap_ = std::move(other.entryMap_); diff --git a/js/src/frontend/Stencil.cpp b/js/src/frontend/Stencil.cpp index ea433379c2e6e..6d95262bfebeb 100644 --- a/js/src/frontend/Stencil.cpp +++ b/js/src/frontend/Stencil.cpp @@ -2760,29 +2760,31 @@ bool CompilationStencil::deserializeStencils(JSContext* cx, ErrorContext* ec, return true; } -ExtensibleCompilationStencil::ExtensibleCompilationStencil(ScriptSource* source) +ExtensibleCompilationStencil::ExtensibleCompilationStencil(JSContext* cx, + ScriptSource* source) : alloc(CompilationStencil::LifoAllocChunkSize), source(source), - parserAtoms(alloc) {} + parserAtoms(cx->runtime(), alloc) {} ExtensibleCompilationStencil::ExtensibleCompilationStencil( - CompilationInput& input) + JSContext* cx, CompilationInput& input) : canLazilyParse(CanLazilyParse(input.options)), alloc(CompilationStencil::LifoAllocChunkSize), source(input.source), - parserAtoms(alloc) {} + parserAtoms(cx->runtime(), alloc) {} ExtensibleCompilationStencil::ExtensibleCompilationStencil( - const JS::ReadOnlyCompileOptions& options, RefPtr source) + JSContext* cx, const JS::ReadOnlyCompileOptions& options, + RefPtr source) : canLazilyParse(CanLazilyParse(options)), alloc(CompilationStencil::LifoAllocChunkSize), source(std::move(source)), - parserAtoms(alloc) {} + parserAtoms(cx->runtime(), alloc) {} CompilationState::CompilationState(JSContext* cx, LifoAllocScope& parserAllocScope, CompilationInput& input) - : ExtensibleCompilationStencil(input), + : ExtensibleCompilationStencil(cx, input), directives(input.options.forceStrictMode()), usedNames(cx), parserAllocScope(parserAllocScope), diff --git a/js/src/frontend/StencilXdr.cpp b/js/src/frontend/StencilXdr.cpp index 7f747a4ed1a78..1d0d992018b81 100644 --- a/js/src/frontend/StencilXdr.cpp +++ b/js/src/frontend/StencilXdr.cpp @@ -1238,7 +1238,7 @@ XDRResult StencilXDR::codeSource(XDRState* xdr, } MOZ_TRY(xdr->codeCharsZ(chars)); if (mode == XDR_DECODE) { - if (!source->setFilename(ec, std::move(chars.ref()))) { + if (!source->setFilename(cx, ec, std::move(chars.ref()))) { return xdr->fail(JS::TranscodeResult::Throw); } } @@ -1268,7 +1268,7 @@ XDRResult StencilXDR::codeSource(XDRState* xdr, MOZ_TRY(xdr->codeCharsZ(chars)); if (mode == XDR_DECODE) { if (!source->setSourceMapURL( - ec, std::move(chars.ref()))) { + cx, ec, std::move(chars.ref()))) { return xdr->fail(JS::TranscodeResult::Throw); } } diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp index 4716e9fe9f2d5..52a768592f2cb 100644 --- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -702,7 +702,7 @@ static bool ParseZealModeName(CharRange text, uint32_t* modeOut) { }; static const ModeInfo zealModes[] = {{"None", 0}, -# define ZEAL_MODE(name, value) {#name, strlen(#name), value}, +# define ZEAL_MODE(name, value) {# name, strlen(# name), value}, JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE) # undef ZEAL_MODE }; @@ -781,7 +781,7 @@ bool GCRuntime::parseAndSetZeal(const char* str) { const char* js::gc::AllocKindName(AllocKind kind) { static const char* const names[] = { -# define EXPAND_THING_NAME(allocKind, _1, _2, _3, _4, _5, _6) #allocKind, +# define EXPAND_THING_NAME(allocKind, _1, _2, _3, _4, _5, _6) # allocKind, FOR_EACH_ALLOCKIND(EXPAND_THING_NAME) # undef EXPAND_THING_NAME }; @@ -2126,8 +2126,8 @@ void GCRuntime::purgeRuntime() { rt->caches().purge(); - if (rt->isMainRuntime()) { - SharedImmutableStringsCache::getSingleton().purge(); + if (auto cache = rt->maybeThisRuntimeSharedImmutableStrings()) { + cache->purge(); } MOZ_ASSERT(unmarkGrayStack.empty()); diff --git a/js/src/jit/CacheIRHealth.cpp b/js/src/jit/CacheIRHealth.cpp index 7a84dc1fa2b28..5f68a4b69f80f 100644 --- a/js/src/jit/CacheIRHealth.cpp +++ b/js/src/jit/CacheIRHealth.cpp @@ -321,7 +321,7 @@ static bool addScriptToFinalWarmUpCountMap(JSContext* cx, HandleScript script) { } SharedImmutableString sfilename = - SharedImmutableStringsCache::getSingleton().getOrCreate( + cx->runtime()->sharedImmutableStrings().getOrCreate( script->filename(), strlen(script->filename())); if (!sfilename) { ReportOutOfMemory(cx); diff --git a/js/src/jsapi-tests/testParserAtom.cpp b/js/src/jsapi-tests/testParserAtom.cpp index 74702955e2153..6bb8bff09942e 100644 --- a/js/src/jsapi-tests/testParserAtom.cpp +++ b/js/src/jsapi-tests/testParserAtom.cpp @@ -9,8 +9,8 @@ #include // std::initializer_list #include // std::vector -#include "frontend/ParserAtom.h" // js::frontend::ParserAtomsTable, js::frontend::WellKnownParserAtoms -#include "js/TypeDecls.h" // JS::Latin1Char +#include "frontend/ParserAtom.h" // js::frontend::ParserAtomsTable +#include "js/TypeDecls.h" // JS::Latin1Char #include "jsapi-tests/tests.h" #include "vm/ErrorContext.h" // AutoReportFrontendContext @@ -23,7 +23,7 @@ BEGIN_TEST(testParserAtom_empty) { js::AutoReportFrontendContext ec(cx); js::LifoAlloc alloc(512); - ParserAtomsTable atomTable(alloc); + ParserAtomsTable atomTable(cx->runtime(), alloc); const char ascii[] = {}; const JS::Latin1Char latin1[] = {}; @@ -46,11 +46,10 @@ BEGIN_TEST(testParserAtom_tiny1_ASCII) { using js::frontend::ParserAtom; using js::frontend::ParserAtomsTable; using js::frontend::ParserAtomVector; - using js::frontend::WellKnownParserAtoms; js::AutoReportFrontendContext ec(cx); js::LifoAlloc alloc(512); - ParserAtomsTable atomTable(alloc); + ParserAtomsTable atomTable(cx->runtime(), alloc); char16_t a = 'a'; const char ascii[] = {'a'}; @@ -58,7 +57,7 @@ BEGIN_TEST(testParserAtom_tiny1_ASCII) { const mozilla::Utf8Unit utf8[] = {mozilla::Utf8Unit('a')}; char16_t char16[] = {'a'}; - auto refIndex = WellKnownParserAtoms::getSingleton().lookupTinyIndex(&a, 1); + auto refIndex = cx->runtime()->commonParserNames->lookupTinyIndex(&a, 1); CHECK(refIndex); CHECK(atomTable.internAscii(&ec, ascii, 1) == refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 1) == refIndex); @@ -74,11 +73,10 @@ BEGIN_TEST(testParserAtom_tiny1_nonASCII) { using js::frontend::ParserAtom; using js::frontend::ParserAtomsTable; using js::frontend::ParserAtomVector; - using js::frontend::WellKnownParserAtoms; js::AutoReportFrontendContext ec(cx); js::LifoAlloc alloc(512); - ParserAtomsTable atomTable(alloc); + ParserAtomsTable atomTable(cx->runtime(), alloc); { char16_t euro = 0x0080; @@ -88,8 +86,7 @@ BEGIN_TEST(testParserAtom_tiny1_nonASCII) { mozilla::Utf8Unit(static_cast(0x80))}; char16_t char16[] = {0x0080}; - auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndex(&euro, 1); + auto refIndex = cx->runtime()->commonParserNames->lookupTinyIndex(&euro, 1); CHECK(refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 1) == refIndex); CHECK(atomTable.internUtf8(&ec, utf8, 2) == refIndex); @@ -105,7 +102,7 @@ BEGIN_TEST(testParserAtom_tiny1_nonASCII) { char16_t char16[] = {0x00BD}; auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndex(½, 1); + cx->runtime()->commonParserNames->lookupTinyIndex(½, 1); CHECK(refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 1) == refIndex); CHECK(atomTable.internUtf8(&ec, utf8, 2) == refIndex); @@ -121,7 +118,7 @@ BEGIN_TEST(testParserAtom_tiny1_nonASCII) { char16_t char16[] = {0x00BF}; auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndex(¿, 1); + cx->runtime()->commonParserNames->lookupTinyIndex(¿, 1); CHECK(refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 1) == refIndex); CHECK(atomTable.internUtf8(&ec, utf8, 2) == refIndex); @@ -137,7 +134,7 @@ BEGIN_TEST(testParserAtom_tiny1_nonASCII) { char16_t char16[] = {0x00C0}; auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndex(à, 1); + cx->runtime()->commonParserNames->lookupTinyIndex(à, 1); CHECK(refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 1) == refIndex); CHECK(atomTable.internUtf8(&ec, utf8, 2) == refIndex); @@ -152,8 +149,7 @@ BEGIN_TEST(testParserAtom_tiny1_nonASCII) { mozilla::Utf8Unit(static_cast(0xA6))}; char16_t char16[] = {0x00E6}; - auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndex(&ae, 1); + auto refIndex = cx->runtime()->commonParserNames->lookupTinyIndex(&ae, 1); CHECK(refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 1) == refIndex); CHECK(atomTable.internUtf8(&ec, utf8, 2) == refIndex); @@ -168,8 +164,7 @@ BEGIN_TEST(testParserAtom_tiny1_nonASCII) { mozilla::Utf8Unit(static_cast(0xBF))}; char16_t char16[] = {0x00FF}; - auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndex(ÿ, 1); + auto refIndex = cx->runtime()->commonParserNames->lookupTinyIndex(ÿ, 1); CHECK(refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 1) == refIndex); CHECK(atomTable.internUtf8(&ec, utf8, 2) == refIndex); @@ -188,18 +183,17 @@ END_TEST(testParserAtom_tiny1_nonASCII) BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { using js::frontend::ParserAtom; using js::frontend::ParserAtomsTable; - using js::frontend::WellKnownParserAtoms; js::AutoReportFrontendContext ec(cx); js::LifoAlloc alloc(512); - ParserAtomsTable atomTable(alloc); + ParserAtomsTable atomTable(cx->runtime(), alloc); { const mozilla::Utf8Unit utf8[] = { mozilla::Utf8Unit(static_cast(0xC1)), mozilla::Utf8Unit(static_cast(0x80))}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2)); } { @@ -207,7 +201,7 @@ BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { mozilla::Utf8Unit(static_cast(0xC2)), mozilla::Utf8Unit(static_cast(0x7F))}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2)); } { @@ -217,7 +211,7 @@ BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { mozilla::Utf8Unit(static_cast(0x80))}; auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2); + cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2); CHECK(refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 1) == refIndex); } @@ -229,7 +223,7 @@ BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { mozilla::Utf8Unit(static_cast(0xBF))}; auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2); + cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2); CHECK(refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 1) == refIndex); } @@ -239,7 +233,7 @@ BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { mozilla::Utf8Unit(static_cast(0xC2)), mozilla::Utf8Unit(static_cast(0xC0))}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2)); } { @@ -247,7 +241,7 @@ BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { mozilla::Utf8Unit(static_cast(0xC3)), mozilla::Utf8Unit(static_cast(0x7F))}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2)); } { @@ -257,7 +251,7 @@ BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { mozilla::Utf8Unit(static_cast(0x80))}; auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2); + cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2); CHECK(refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 1) == refIndex); } @@ -269,7 +263,7 @@ BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { mozilla::Utf8Unit(static_cast(0xBF))}; auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2); + cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2); CHECK(refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 1) == refIndex); } @@ -279,7 +273,7 @@ BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { mozilla::Utf8Unit(static_cast(0xC3)), mozilla::Utf8Unit(static_cast(0xC0))}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2)); } { @@ -287,7 +281,7 @@ BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { mozilla::Utf8Unit(static_cast(0xC4)), mozilla::Utf8Unit(static_cast(0x7F))}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2)); } { @@ -295,7 +289,7 @@ BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { mozilla::Utf8Unit(static_cast(0xC4)), mozilla::Utf8Unit(static_cast(0x80))}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2)); } { @@ -303,7 +297,7 @@ BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { mozilla::Utf8Unit(static_cast(0xC4)), mozilla::Utf8Unit(static_cast(0xBF))}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2)); } { @@ -311,7 +305,7 @@ BEGIN_TEST(testParserAtom_tiny1_invalidUTF8) { mozilla::Utf8Unit(static_cast(0xC4)), mozilla::Utf8Unit(static_cast(0xC0))}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndexUTF8(utf8, 2)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndexUTF8(utf8, 2)); } return true; @@ -323,11 +317,10 @@ BEGIN_TEST(testParserAtom_tiny2) { using js::frontend::ParserAtom; using js::frontend::ParserAtomsTable; using js::frontend::ParserAtomVector; - using js::frontend::WellKnownParserAtoms; js::AutoReportFrontendContext ec(cx); js::LifoAlloc alloc(512); - ParserAtomsTable atomTable(alloc); + ParserAtomsTable atomTable(cx->runtime(), alloc); const char ascii[] = {'a', '0'}; JS::Latin1Char latin1[] = {'a', '0'}; @@ -335,8 +328,7 @@ BEGIN_TEST(testParserAtom_tiny2) { mozilla::Utf8Unit('0')}; char16_t char16[] = {'a', '0'}; - auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndex(ascii, 2); + auto refIndex = cx->runtime()->commonParserNames->lookupTinyIndex(ascii, 2); CHECK(refIndex); CHECK(atomTable.internAscii(&ec, ascii, 2) == refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 2) == refIndex); @@ -346,7 +338,7 @@ BEGIN_TEST(testParserAtom_tiny2) { // Note: If Latin1-Extended characters become supported, then UTF-8 behaviour // should be tested. char16_t ae0[] = {0x00E6, '0'}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndex(ae0, 2)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndex(ae0, 2)); return true; } @@ -357,11 +349,10 @@ BEGIN_TEST(testParserAtom_int) { using js::frontend::ParserAtom; using js::frontend::ParserAtomsTable; using js::frontend::ParserAtomVector; - using js::frontend::WellKnownParserAtoms; js::AutoReportFrontendContext ec(cx); js::LifoAlloc alloc(512); - ParserAtomsTable atomTable(alloc); + ParserAtomsTable atomTable(cx->runtime(), alloc); { const char ascii[] = {'1', '0', '0'}; @@ -370,8 +361,7 @@ BEGIN_TEST(testParserAtom_int) { mozilla::Utf8Unit('1'), mozilla::Utf8Unit('0'), mozilla::Utf8Unit('0')}; char16_t char16[] = {'1', '0', '0'}; - auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndex(ascii, 3); + auto refIndex = cx->runtime()->commonParserNames->lookupTinyIndex(ascii, 3); CHECK(refIndex); CHECK(atomTable.internAscii(&ec, ascii, 3) == refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 3) == refIndex); @@ -386,8 +376,7 @@ BEGIN_TEST(testParserAtom_int) { mozilla::Utf8Unit('2'), mozilla::Utf8Unit('5'), mozilla::Utf8Unit('5')}; char16_t char16[] = {'2', '5', '5'}; - auto refIndex = - WellKnownParserAtoms::getSingleton().lookupTinyIndex(ascii, 3); + auto refIndex = cx->runtime()->commonParserNames->lookupTinyIndex(ascii, 3); CHECK(refIndex); CHECK(atomTable.internAscii(&ec, ascii, 3) == refIndex); CHECK(atomTable.internLatin1(&ec, latin1, 3) == refIndex); @@ -398,37 +387,37 @@ BEGIN_TEST(testParserAtom_int) { { const char ascii[] = {'0', '9', '9'}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndex(ascii, 3)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndex(ascii, 3)); } { const char ascii[] = {'0', 'F', 'F'}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndex(ascii, 3)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndex(ascii, 3)); } { const char ascii[] = {'1', '0', 'A'}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndex(ascii, 3)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndex(ascii, 3)); } { const char ascii[] = {'1', '0', 'a'}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndex(ascii, 3)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndex(ascii, 3)); } { const char ascii[] = {'2', '5', '6'}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndex(ascii, 3)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndex(ascii, 3)); } { const char ascii[] = {'3', '0', '0'}; - CHECK(!WellKnownParserAtoms::getSingleton().lookupTinyIndex(ascii, 3)); + CHECK(!cx->runtime()->commonParserNames->lookupTinyIndex(ascii, 3)); } return true; diff --git a/js/src/jsapi-tests/testSharedImmutableStringsCache.cpp b/js/src/jsapi-tests/testSharedImmutableStringsCache.cpp index 461bd6b21d7fe..7dd1b0a5b5136 100644 --- a/js/src/jsapi-tests/testSharedImmutableStringsCache.cpp +++ b/js/src/jsapi-tests/testSharedImmutableStringsCache.cpp @@ -51,7 +51,9 @@ static void getString(CacheAndIndex* cacheAndIndex) { } BEGIN_TEST(testSharedImmutableStringsCache) { - auto& cache = js::SharedImmutableStringsCache::getSingleton(); + auto maybeCache = js::SharedImmutableStringsCache::Create(); + CHECK(maybeCache.isSome()); + auto& cache = *maybeCache; js::Vector threads(cx); CHECK(threads.reserve(NUM_THREADS)); diff --git a/js/src/vm/CompilationAndEvaluation.cpp b/js/src/vm/CompilationAndEvaluation.cpp index 54761c7b9b5c3..fec237b0b6fa1 100644 --- a/js/src/vm/CompilationAndEvaluation.cpp +++ b/js/src/vm/CompilationAndEvaluation.cpp @@ -100,7 +100,7 @@ JS_PUBLIC_API bool JS::StartIncrementalEncoding(JSContext* cx, stencil = nullptr; } else { initial = cx->make_unique( - stencil->source); + cx, stencil->source); if (!initial) { return false; } diff --git a/js/src/vm/HelperThreadState.h b/js/src/vm/HelperThreadState.h index e4709fc41150b..d384a105c8f67 100644 --- a/js/src/vm/HelperThreadState.h +++ b/js/src/vm/HelperThreadState.h @@ -673,7 +673,8 @@ struct DelazifyTask : public mozilla::LinkedListElement, // optimization and the VM should remain working even without this // optimization in place. static UniquePtr Create( - JSRuntime* runtime, const JS::ContextOptions& contextOptions, + JSContext* cx, JSRuntime* runtime, + const JS::ContextOptions& contextOptions, const JS::ReadOnlyCompileOptions& options, const frontend::CompilationStencil& stencil); diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index df1579ae04318..b96c84daa1c30 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -648,9 +648,11 @@ void ParseTask::scheduleDelazifyTask(AutoLockHelperThreadState& lock) { { AutoSetHelperThreadContext usesContext(contextOptions, lock); AutoUnlockHelperThreadState unlock(lock); + JSContext* cx = TlsContext.get(); AutoSetContextRuntime ascr(runtime); - task = DelazifyTask::Create(runtime, contextOptions, options, *stencil_); + task = + DelazifyTask::Create(cx, runtime, contextOptions, options, *stencil_); if (!task) { return; } @@ -871,7 +873,7 @@ void js::StartOffThreadDelazification( JSRuntime* runtime = cx->runtime(); UniquePtr task; - task = DelazifyTask::Create(runtime, cx->options(), options, stencil); + task = DelazifyTask::Create(cx, runtime, cx->options(), options, stencil); if (!task) { return; } @@ -999,7 +1001,7 @@ bool LargeFirstDelazification::insert(ScriptIndex index, } UniquePtr DelazifyTask::Create( - JSRuntime* runtime, const JS::ContextOptions& contextOptions, + JSContext* cx, JSRuntime* runtime, const JS::ContextOptions& contextOptions, const JS::ReadOnlyCompileOptions& options, const frontend::CompilationStencil& stencil) { UniquePtr task; @@ -1018,7 +1020,7 @@ UniquePtr DelazifyTask::Create( // Clone the extensible stencil to be used for eager delazification. auto initial = task->ec_.getAllocator() ->make_unique( - options, stencil.source); + cx, options, stencil.source); if (!initial || !initial->cloneFrom(&task->ec_, stencil)) { // In case of errors, skip this and delazify on-demand. return nullptr; diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp index 36ccf36d2497e..9d029cb4fb4bb 100644 --- a/js/src/vm/JSScript.cpp +++ b/js/src/vm/JSScript.cpp @@ -1326,7 +1326,7 @@ template [[nodiscard]] bool ScriptSource::setUncompressedSourceHelper( JSContext* cx, EntryUnits&& source, size_t length, SourceRetrievable retrievable) { - auto& cache = SharedImmutableStringsCache::getSingleton(); + auto& cache = cx->runtime()->sharedImmutableStrings(); auto uniqueChars = SourceTypeTraits::toCacheable(std::move(source)); auto deduped = cache.getOrCreate(std::move(uniqueChars), length); @@ -1444,7 +1444,7 @@ template MOZ_ASSERT(data.is(), "shouldn't be double-initializing"); MOZ_ASSERT(compressed != nullptr); - auto& cache = SharedImmutableStringsCache::getSingleton(); + auto& cache = cx->runtime()->sharedImmutableStrings(); auto deduped = cache.getOrCreate(std::move(compressed), rawLength); if (!deduped) { ReportOutOfMemory(cx); @@ -1476,7 +1476,7 @@ template bool ScriptSource::initializeWithUnretrievableCompressedSource< size_t sourceLength); template -bool ScriptSource::assignSource(ErrorContext* ec, +bool ScriptSource::assignSource(JSContext* cx, ErrorContext* ec, const ReadOnlyCompileOptions& options, SourceText& srcBuf) { MOZ_ASSERT(data.is(), @@ -1494,7 +1494,8 @@ bool ScriptSource::assignSource(ErrorContext* ec, return true; } - auto& cache = SharedImmutableStringsCache::getSingleton(); + JSRuntime* runtime = cx->runtime(); + auto& cache = runtime->sharedImmutableStrings(); auto deduped = cache.getOrCreate(srcBuf.get(), srcBuf.length(), [&srcBuf]() { using CharT = typename SourceTypeTraits::CharT; return srcBuf.ownsUnits() @@ -1511,10 +1512,10 @@ bool ScriptSource::assignSource(ErrorContext* ec, return true; } -template bool ScriptSource::assignSource(ErrorContext* ec, +template bool ScriptSource::assignSource(JSContext* cx, ErrorContext* ec, const ReadOnlyCompileOptions& options, SourceText& srcBuf); -template bool ScriptSource::assignSource(ErrorContext* ec, +template bool ScriptSource::assignSource(JSContext* cx, ErrorContext* ec, const ReadOnlyCompileOptions& options, SourceText& srcBuf); @@ -1598,7 +1599,7 @@ void SourceCompressionTask::workEncodingSpecific() { return; } - auto& strings = SharedImmutableStringsCache::getSingleton(); + auto& strings = runtime_->sharedImmutableStrings(); resultString_ = strings.getOrCreate(std::move(compressed), totalBytes); } @@ -1873,7 +1874,7 @@ bool ScriptSource::initFromOptions(JSContext* cx, ErrorContext* ec, if (!formatted) { return false; } - if (!setFilename(ec, std::move(formatted))) { + if (!setFilename(cx, ec, std::move(formatted))) { return false; } } else if (options.filename()) { @@ -1894,25 +1895,28 @@ bool ScriptSource::initFromOptions(JSContext* cx, ErrorContext* ec, // Use the SharedImmutableString map to deduplicate input string. The input // string must be null-terminated. template -static SharedT GetOrCreateStringZ(ErrorContext* ec, +static SharedT GetOrCreateStringZ(JSContext* cx, ErrorContext* ec, UniquePtr&& str) { + JSRuntime* rt = cx->runtime(); size_t lengthWithNull = std::char_traits::length(str.get()) + 1; - auto res = SharedImmutableStringsCache::getSingleton().getOrCreate( - std::move(str), lengthWithNull); + auto res = + rt->sharedImmutableStrings().getOrCreate(std::move(str), lengthWithNull); if (!res) { ReportOutOfMemory(ec); } return res; } -SharedImmutableString ScriptSource::getOrCreateStringZ(ErrorContext* ec, +SharedImmutableString ScriptSource::getOrCreateStringZ(JSContext* cx, + ErrorContext* ec, UniqueChars&& str) { - return GetOrCreateStringZ(ec, std::move(str)); + return GetOrCreateStringZ(cx, ec, std::move(str)); } SharedImmutableTwoByteString ScriptSource::getOrCreateStringZ( - ErrorContext* ec, UniqueTwoByteChars&& str) { - return GetOrCreateStringZ(ec, std::move(str)); + JSContext* cx, ErrorContext* ec, UniqueTwoByteChars&& str) { + return GetOrCreateStringZ(cx, ec, + std::move(str)); } bool ScriptSource::setFilename(JSContext* cx, ErrorContext* ec, @@ -1921,12 +1925,13 @@ bool ScriptSource::setFilename(JSContext* cx, ErrorContext* ec, if (!owned) { return false; } - return setFilename(ec, std::move(owned)); + return setFilename(cx, ec, std::move(owned)); } -bool ScriptSource::setFilename(ErrorContext* ec, UniqueChars&& filename) { +bool ScriptSource::setFilename(JSContext* cx, ErrorContext* ec, + UniqueChars&& filename) { MOZ_ASSERT(!filename_); - filename_ = getOrCreateStringZ(ec, std::move(filename)); + filename_ = getOrCreateStringZ(cx, ec, std::move(filename)); return bool(filename_); } @@ -1936,13 +1941,13 @@ bool ScriptSource::setIntroducerFilename(JSContext* cx, ErrorContext* ec, if (!owned) { return false; } - return setIntroducerFilename(ec, std::move(owned)); + return setIntroducerFilename(cx, ec, std::move(owned)); } -bool ScriptSource::setIntroducerFilename(ErrorContext* ec, +bool ScriptSource::setIntroducerFilename(JSContext* cx, ErrorContext* ec, UniqueChars&& filename) { MOZ_ASSERT(!introducerFilename_); - introducerFilename_ = getOrCreateStringZ(ec, std::move(filename)); + introducerFilename_ = getOrCreateStringZ(cx, ec, std::move(filename)); return bool(introducerFilename_); } @@ -1971,7 +1976,7 @@ bool ScriptSource::setDisplayURL(JSContext* cx, ErrorContext* ec, return true; } - displayURL_ = getOrCreateStringZ(ec, std::move(url)); + displayURL_ = getOrCreateStringZ(cx, ec, std::move(url)); return bool(displayURL_); } @@ -1981,16 +1986,17 @@ bool ScriptSource::setSourceMapURL(JSContext* cx, ErrorContext* ec, if (!owned) { return false; } - return setSourceMapURL(ec, std::move(owned)); + return setSourceMapURL(cx, ec, std::move(owned)); } -bool ScriptSource::setSourceMapURL(ErrorContext* ec, UniqueTwoByteChars&& url) { +bool ScriptSource::setSourceMapURL(JSContext* cx, ErrorContext* ec, + UniqueTwoByteChars&& url) { MOZ_ASSERT(url); if (url[0] == '\0') { return true; } - sourceMapURL_ = getOrCreateStringZ(ec, std::move(url)); + sourceMapURL_ = getOrCreateStringZ(cx, ec, std::move(url)); return bool(sourceMapURL_); } diff --git a/js/src/vm/JSScript.h b/js/src/vm/JSScript.h index df6bc2b8a9033..8591196d7434c 100644 --- a/js/src/vm/JSScript.h +++ b/js/src/vm/JSScript.h @@ -651,8 +651,10 @@ class ScriptSource { */ static constexpr size_t MinimumCompressibleLength = 256; - SharedImmutableString getOrCreateStringZ(ErrorContext* ec, UniqueChars&& str); - SharedImmutableTwoByteString getOrCreateStringZ(ErrorContext* ec, + SharedImmutableString getOrCreateStringZ(JSContext* cx, ErrorContext* ec, + UniqueChars&& str); + SharedImmutableTwoByteString getOrCreateStringZ(JSContext* cx, + ErrorContext* ec, UniqueTwoByteChars&& str); private: @@ -667,7 +669,7 @@ class ScriptSource { // Assign source data from |srcBuf| to this recently-created |ScriptSource|. template - [[nodiscard]] bool assignSource(ErrorContext* ec, + [[nodiscard]] bool assignSource(JSContext* cx, ErrorContext* ec, const JS::ReadOnlyCompileOptions& options, JS::SourceText& srcBuf); @@ -993,14 +995,15 @@ class ScriptSource { } [[nodiscard]] bool setFilename(JSContext* cx, ErrorContext* ec, const char* filename); - [[nodiscard]] bool setFilename(ErrorContext* ec, UniqueChars&& filename); + [[nodiscard]] bool setFilename(JSContext* cx, ErrorContext* ec, + UniqueChars&& filename); const char* introducerFilename() const { return introducerFilename_ ? introducerFilename_.chars() : filename(); } [[nodiscard]] bool setIntroducerFilename(JSContext* cx, ErrorContext* ec, const char* filename); - [[nodiscard]] bool setIntroducerFilename(ErrorContext* ec, + [[nodiscard]] bool setIntroducerFilename(JSContext* cx, ErrorContext* ec, UniqueChars&& filename); bool hasIntroductionType() const { return introductionType_; } @@ -1022,7 +1025,7 @@ class ScriptSource { // Source maps [[nodiscard]] bool setSourceMapURL(JSContext* cx, ErrorContext* ec, const char16_t* url); - [[nodiscard]] bool setSourceMapURL(ErrorContext* ec, + [[nodiscard]] bool setSourceMapURL(JSContext* cx, ErrorContext* ec, UniqueTwoByteChars&& url); bool hasSourceMapURL() const { return bool(sourceMapURL_); } const char16_t* sourceMapURL() { return sourceMapURL_.chars(); } diff --git a/js/src/vm/MutexIDs.h b/js/src/vm/MutexIDs.h index b27387c5407ce..35fd81e93a0b8 100644 --- a/js/src/vm/MutexIDs.h +++ b/js/src/vm/MutexIDs.h @@ -20,7 +20,6 @@ _(ShellContextWatchdog, 100) \ _(ShellWorkerThreads, 100) \ _(ShellObjectMailbox, 100) \ - _(WellKnownParserAtomsInit, 100) \ \ _(WasmInitBuiltinThunks, 250) \ _(WasmLazyStubsTier1, 250) \ diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 78b9810d58105..e549112a67d9c 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -21,7 +21,6 @@ #include "jsmath.h" #include "frontend/CompilationStencil.h" -#include "frontend/ParserAtom.h" // frontend::WellKnownParserAtoms #include "gc/GC.h" #include "gc/PublicIterators.h" #include "jit/IonCompileTask.h" @@ -40,8 +39,7 @@ #include "vm/JSObject.h" #include "vm/JSScript.h" #include "vm/PromiseObject.h" // js::PromiseObject -#include "vm/SharedImmutableStringsCache.h" -#include "vm/Warnings.h" // js::WarnNumberUC +#include "vm/Warnings.h" // js::WarnNumberUC #include "wasm/WasmSignalHandlers.h" #include "debugger/DebugAPI-inl.h" @@ -208,6 +206,13 @@ bool JSRuntime::init(JSContext* cx, uint32_t maxbytes) { // Also see the comment in JS::Realm::init(). js::ResetTimeZoneInternal(ResetTimeZoneMode::DontResetIfOffsetUnchanged); + if (!parentRuntime) { + sharedImmutableStrings_ = js::SharedImmutableStringsCache::Create(); + if (!sharedImmutableStrings_) { + return false; + } + } + return true; } @@ -321,6 +326,8 @@ void JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, rtSizes->atomsTable += mallocSizeOf(staticStrings); rtSizes->atomsTable += mallocSizeOf(commonNames); rtSizes->atomsTable += permanentAtoms()->sizeOfIncludingThis(mallocSizeOf); + rtSizes->atomsTable += + commonParserNames.ref()->sizeOfIncludingThis(mallocSizeOf); rtSizes->selfHostStencil = selfHostStencilInput_->sizeOfIncludingThis(mallocSizeOf) + @@ -341,13 +348,9 @@ void JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, gc.nursery().sizeOfMallocedBuffers(mallocSizeOf); gc.storeBuffer().addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc); - if (isMainRuntime()) { + if (sharedImmutableStrings_) { rtSizes->sharedImmutableStringsCache += - js::SharedImmutableStringsCache::getSingleton().sizeOfExcludingThis( - mallocSizeOf); - rtSizes->atomsTable += - js::frontend::WellKnownParserAtoms::getSingleton().sizeOfIncludingThis( - mallocSizeOf); + sharedImmutableStrings_->sizeOfExcludingThis(mallocSizeOf); } #ifdef JS_HAS_INTL_API diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 96cc348fd251c..169f08a5b4b69 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -51,6 +51,7 @@ #include "vm/GeckoProfiler.h" #include "vm/JSScript.h" #include "vm/OffThreadPromiseRuntimeState.h" // js::OffThreadPromiseRuntimeState +#include "vm/SharedImmutableStringsCache.h" #include "vm/SharedStencil.h" // js::SharedImmutableScriptDataTable #include "vm/Stack.h" #include "wasm/WasmTypeDecls.h" @@ -108,6 +109,7 @@ class Simulator; namespace frontend { struct CompilationInput; struct CompilationStencil; +class WellKnownParserAtoms; } // namespace frontend // [SMDOC] JS Engine Threading @@ -783,6 +785,26 @@ struct JSRuntime { js::WriteOnceData numGrouping; #endif + private: + mozilla::Maybe sharedImmutableStrings_; + + public: + // If this particular JSRuntime has a SharedImmutableStringsCache, return a + // pointer to it, otherwise return nullptr. + js::SharedImmutableStringsCache* maybeThisRuntimeSharedImmutableStrings() { + return sharedImmutableStrings_.isSome() ? &*sharedImmutableStrings_ + : nullptr; + } + + // Get a reference to this JSRuntime's or its parent's + // SharedImmutableStringsCache. + js::SharedImmutableStringsCache& sharedImmutableStrings() { + MOZ_ASSERT_IF(parentRuntime, !sharedImmutableStrings_); + MOZ_ASSERT_IF(!parentRuntime, sharedImmutableStrings_); + return parentRuntime ? parentRuntime->sharedImmutableStrings() + : *sharedImmutableStrings_; + } + private: js::WriteOnceData beingDestroyed_; @@ -851,6 +873,7 @@ struct JSRuntime { // Cached pointers to various permanent property names. js::WriteOnceData commonNames; + js::WriteOnceData commonParserNames; // All permanent atoms in the runtime, other than those in staticStrings. // Access to this does not require a lock because it is frozen and thus diff --git a/js/src/vm/SharedImmutableStringsCache-inl.h b/js/src/vm/SharedImmutableStringsCache-inl.h index 3473a8013add2..eba4c4e1e45b1 100644 --- a/js/src/vm/SharedImmutableStringsCache-inl.h +++ b/js/src/vm/SharedImmutableStringsCache-inl.h @@ -14,10 +14,11 @@ namespace js { template [[nodiscard]] SharedImmutableString SharedImmutableStringsCache::getOrCreate( const char* chars, size_t length, IntoOwnedChars intoOwnedChars) { + MOZ_ASSERT(inner_); MOZ_ASSERT(chars); Hasher::Lookup lookup(Hasher::hashLongString(chars, length), chars, length); - auto locked = inner_.lock(); + auto locked = inner_->lock(); auto entry = locked->set.lookupForAdd(lookup); if (!entry) { OwnedChars ownedChars(intoOwnedChars()); @@ -26,7 +27,7 @@ template } MOZ_ASSERT(ownedChars.get() == chars || memcmp(ownedChars.get(), chars, length) == 0); - auto box = StringBox::Create(std::move(ownedChars), length, &inner_); + auto box = StringBox::Create(std::move(ownedChars), length, this->inner_); if (!box || !locked->set.add(entry, std::move(box))) { return SharedImmutableString(); } @@ -41,12 +42,13 @@ template SharedImmutableStringsCache::getOrCreate( const char16_t* chars, size_t length, IntoOwnedTwoByteChars intoOwnedTwoByteChars) { + MOZ_ASSERT(inner_); MOZ_ASSERT(chars); auto hash = Hasher::hashLongString(reinterpret_cast(chars), length * sizeof(char16_t)); Hasher::Lookup lookup(hash, chars, length); - auto locked = inner_.lock(); + auto locked = inner_->lock(); auto entry = locked->set.lookupForAdd(lookup); if (!entry) { OwnedTwoByteChars ownedTwoByteChars(intoOwnedTwoByteChars()); @@ -58,7 +60,7 @@ SharedImmutableStringsCache::getOrCreate( memcmp(ownedTwoByteChars.get(), chars, length * sizeof(char16_t)) == 0); OwnedChars ownedChars(reinterpret_cast(ownedTwoByteChars.release())); auto box = StringBox::Create(std::move(ownedChars), - length * sizeof(char16_t), &inner_); + length * sizeof(char16_t), this->inner_); if (!box || !locked->set.add(entry, std::move(box))) { return SharedImmutableTwoByteString(); } diff --git a/js/src/vm/SharedImmutableStringsCache.cpp b/js/src/vm/SharedImmutableStringsCache.cpp index 96786bda507b1..6599dc89892a6 100644 --- a/js/src/vm/SharedImmutableStringsCache.cpp +++ b/js/src/vm/SharedImmutableStringsCache.cpp @@ -10,9 +10,6 @@ namespace js { -/* static */ -SharedImmutableStringsCache SharedImmutableStringsCache::singleton_; - SharedImmutableString::SharedImmutableString( SharedImmutableStringsCache::StringBox* box) : box_(box) { diff --git a/js/src/vm/SharedImmutableStringsCache.h b/js/src/vm/SharedImmutableStringsCache.h index 24e08fcab4f90..cfc0b6603aa9d 100644 --- a/js/src/vm/SharedImmutableStringsCache.h +++ b/js/src/vm/SharedImmutableStringsCache.h @@ -39,8 +39,6 @@ class SharedImmutableTwoByteString; * data stored within the cache when this lock is acquired. */ class SharedImmutableStringsCache { - static SharedImmutableStringsCache singleton_; - friend class SharedImmutableString; friend class SharedImmutableTwoByteString; struct Hasher; @@ -137,10 +135,13 @@ class SharedImmutableStringsCache { size_t length); size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - auto locked = inner_.lock(); + MOZ_ASSERT(inner_); + size_t n = mallocSizeOf(inner_); + + auto locked = inner_->lock(); // Size of the table. - size_t n = locked->set.shallowSizeOfExcludingThis(mallocSizeOf); + n += locked->set.shallowSizeOfExcludingThis(mallocSizeOf); // Sizes of the strings and their boxes. for (auto r = locked->set.all(); !r.empty(); r.popFront()) { @@ -153,29 +154,69 @@ class SharedImmutableStringsCache { return n; } - static SharedImmutableStringsCache& getSingleton() { return singleton_; } + /** + * Construct a new cache of shared, immutable strings. Returns + * `mozilla::Nothing` on out of memory failure. + */ + static mozilla::Maybe Create() { + auto inner = + js_new>(mutexid::SharedImmutableStringsCache); + if (!inner) { + return mozilla::Nothing(); + } - private: - SharedImmutableStringsCache() - : inner_(mutexid::SharedImmutableStringsCache) {} + auto locked = inner->lock(); + return mozilla::Some(SharedImmutableStringsCache(locked)); + } - public: - SharedImmutableStringsCache(const SharedImmutableStringsCache& rhs) = delete; - SharedImmutableStringsCache(SharedImmutableStringsCache&& rhs) = delete; + SharedImmutableStringsCache(SharedImmutableStringsCache&& rhs) + : inner_(rhs.inner_) { + MOZ_ASSERT(inner_); + rhs.inner_ = nullptr; + } - SharedImmutableStringsCache& operator=(SharedImmutableStringsCache&& rhs) = - delete; + SharedImmutableStringsCache& operator=(SharedImmutableStringsCache&& rhs) { + MOZ_ASSERT(this != &rhs, "self move not allowed"); + new (this) SharedImmutableStringsCache(std::move(rhs)); + return *this; + } SharedImmutableStringsCache& operator=(const SharedImmutableStringsCache&) = delete; - ~SharedImmutableStringsCache() = default; + SharedImmutableStringsCache clone() { + MOZ_ASSERT(inner_); + auto locked = inner_->lock(); + return SharedImmutableStringsCache(locked); + } + + ~SharedImmutableStringsCache() { + if (!inner_) { + return; + } + + bool shouldDestroy = false; + { + // ~ExclusiveData takes the lock, so be sure to drop the lock before + // attempting to destroy the inner. + auto locked = inner_->lock(); + MOZ_ASSERT(locked->refcount > 0); + locked->refcount--; + if (locked->refcount == 0) { + shouldDestroy = true; + } + } + if (shouldDestroy) { + js_delete(inner_); + } + } /** * Purge the cache of all refcount == 0 entries. */ void purge() { - auto locked = inner_.lock(); + auto locked = inner_->lock(); + MOZ_ASSERT(locked->refcount > 0); for (Inner::Set::Enum e(locked->set); !e.empty(); e.popFront()) { if (e.front()->refcount == 0) { @@ -290,21 +331,29 @@ class SharedImmutableStringsCache { } }; - // The `Inner` struct contains the actual cached contents and shared between - // the `SharedImmutableStringsCache` singleton and all + // The `Inner` struct contains the actual cached contents, and is reference + // counted and shared between all `SharedImmutableStringsCache` and // `SharedImmutable[TwoByte]String` holders. struct Inner { using Set = HashSet; + size_t refcount; Set set; - Inner() : set() {} + Inner() : refcount(0), set() {} Inner(const Inner&) = delete; Inner& operator=(const Inner&) = delete; + + ~Inner() { MOZ_ASSERT(refcount == 0); } }; - ExclusiveData inner_; + const ExclusiveData* inner_; + + explicit SharedImmutableStringsCache(ExclusiveData::Guard& locked) + : inner_(locked.parent()) { + locked->refcount++; + } }; /**