diff --git a/config/check_spidermonkey_style.py b/config/check_spidermonkey_style.py index dde0104cca8e..cb456daccbc9 100644 --- a/config/check_spidermonkey_style.py +++ b/config/check_spidermonkey_style.py @@ -69,6 +69,7 @@ included_inclnames_to_ignore = set([ 'jscustomallocator.h', # provided by embedders; allowed to be missing 'js-config.h', # generated in $OBJDIR 'fdlibm.h', # fdlibm + 'mozmemory.h', # included without a path 'pratom.h', # NSPR 'prcvar.h', # NSPR 'prerror.h', # NSPR diff --git a/js/public/Utility.h b/js/public/Utility.h index a2c53e4832fb..93ee414495e0 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -26,6 +26,8 @@ #include "jstypes.h" +#include "mozmemory.h" + /* The public JS engine namespace. */ namespace JS {} @@ -364,22 +366,33 @@ struct MOZ_RAII JS_PUBLIC_DATA(AutoEnterOOMUnsafeRegion) } /* namespace js */ +// Malloc allocation. + +namespace js { + +extern JS_PUBLIC_DATA(arena_id_t) MallocArena; + +extern void InitMallocAllocator(); +extern void ShutDownMallocAllocator(); + +} /* namespace js */ + static inline void* js_malloc(size_t bytes) { JS_OOM_POSSIBLY_FAIL(); - return malloc(bytes); + return moz_arena_malloc(js::MallocArena, bytes); } static inline void* js_calloc(size_t bytes) { JS_OOM_POSSIBLY_FAIL(); - return calloc(bytes, 1); + return moz_arena_calloc(js::MallocArena, bytes, 1); } static inline void* js_calloc(size_t nmemb, size_t size) { JS_OOM_POSSIBLY_FAIL(); - return calloc(nmemb, size); + return moz_arena_calloc(js::MallocArena, nmemb, size); } static inline void* js_realloc(void* p, size_t bytes) @@ -390,19 +403,18 @@ static inline void* js_realloc(void* p, size_t bytes) MOZ_ASSERT(bytes != 0); JS_OOM_POSSIBLY_FAIL(); - return realloc(p, bytes); + return moz_arena_realloc(js::MallocArena, p, bytes); } static inline void js_free(void* p) { + // TODO: This should call |moz_arena_free(js::MallocArena, p)| but we + // currently can't enforce that all memory freed here was allocated by + // js_malloc(). free(p); } -static inline char* js_strdup(const char* s) -{ - JS_OOM_POSSIBLY_FAIL(); - return strdup(s); -} +JS_PUBLIC_API(char*) js_strdup(const char* s); #endif/* JS_USE_CUSTOM_ALLOCATOR */ #include diff --git a/js/src/jsapi-tests/testHashTable.cpp b/js/src/jsapi-tests/testHashTable.cpp index 7919cf5b13df..35cf6b6370da 100644 --- a/js/src/jsapi-tests/testHashTable.cpp +++ b/js/src/jsapi-tests/testHashTable.cpp @@ -394,12 +394,13 @@ END_TEST(testHashMapLookupWithDefaultOOM) BEGIN_TEST(testHashTableMovableEnum) { + IntSet set; CHECK(set.init()); // Exercise returning a hash table Enum object from a function. CHECK(set.put(1)); - for (auto e = enumerateSet(); !e.empty(); e.popFront()) + for (auto e = enumerateSet(set); !e.empty(); e.popFront()) e.removeFront(); CHECK(set.count() == 0); @@ -425,9 +426,7 @@ BEGIN_TEST(testHashTableMovableEnum) return true; } -IntSet set; - -IntSet::Enum enumerateSet() +IntSet::Enum enumerateSet(IntSet& set) { return IntSet::Enum(set); } diff --git a/js/src/jsapi-tests/tests.cpp b/js/src/jsapi-tests/tests.cpp index 5671f161ea9a..6affbde9f9a8 100644 --- a/js/src/jsapi-tests/tests.cpp +++ b/js/src/jsapi-tests/tests.cpp @@ -45,6 +45,7 @@ void JSAPITest::uninit() destroyContext(); cx = nullptr; } + msgs.clear(); } bool JSAPITest::exec(const char* bytes, const char* filename, int lineno) diff --git a/js/src/jsapi-tests/tests.h b/js/src/jsapi-tests/tests.h index d580ad134fce..a9e0f24795e7 100644 --- a/js/src/jsapi-tests/tests.h +++ b/js/src/jsapi-tests/tests.h @@ -33,6 +33,7 @@ class JSAPITestString { const char* begin() const { return chars.begin(); } const char* end() const { return chars.end(); } size_t length() const { return chars.length(); } + void clear() { chars.clearAndFree(); } JSAPITestString& operator +=(const char* s) { if (!chars.append(s, strlen(s))) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 7fde0b04463e..700ea1e037fc 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3868,7 +3868,12 @@ js::DuplicateString(JSContext* cx, const char16_t* s) UniqueChars js::DuplicateString(const char* s) { - return UniqueChars(js_strdup(s)); + size_t n = strlen(s) + 1; + UniqueChars ret(js_pod_malloc(n)); + if (!ret) + return ret; + PodCopy(ret.get(), s, n); + return ret; } UniqueChars @@ -3899,6 +3904,12 @@ js::DuplicateString(const char16_t* s, size_t n) return ret; } +JS_PUBLIC_API(char*) +js_strdup(const char* s) +{ + return DuplicateString(s).release(); +} + template const CharT* js_strchr_limit(const CharT* s, char16_t c, const CharT* limit) diff --git a/js/src/jsutil.cpp b/js/src/jsutil.cpp index a973a7f39101..ffa095eee8b8 100644 --- a/js/src/jsutil.cpp +++ b/js/src/jsutil.cpp @@ -170,6 +170,20 @@ ResetSimulatedInterrupt() } // namespace js #endif // defined(DEBUG) || defined(JS_OOM_BREAKPOINT) +JS_PUBLIC_DATA(arena_id_t) js::MallocArena; + +void +js::InitMallocAllocator() +{ + MallocArena = moz_create_arena(); +} + +void +js::ShutDownMallocAllocator() +{ + moz_dispose_arena(MallocArena); +} + JS_PUBLIC_API(void) JS_Assert(const char* s, const char* file, int ln) { diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 08020fdf536f..498d3ba136a0 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3992,6 +3992,8 @@ KillWorkerThreads(JSContext* cx) thread->join(); } + workerThreads.clearAndFree(); + js_delete(workerThreadsLock); workerThreadsLock = nullptr; @@ -4927,12 +4929,12 @@ NestedShell(JSContext* cx, unsigned argc, Value* vp) JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr, JSSMSG_NESTED_FAIL); return false; } - if (!argv.append(strdup(sArgv[0]))) + if (!argv.append(js_strdup(sArgv[0]))) return false; // Propagate selected flags from the current shell for (unsigned i = 0; i < sPropagatedFlags.length(); i++) { - char* cstr = strdup(sPropagatedFlags[i]); + char* cstr = js_strdup(sPropagatedFlags[i]); if (!cstr || !argv.append(cstr)) return false; } @@ -5753,6 +5755,7 @@ ShutdownBufferStreams() state->shutdown = true; while (!state->jobs.empty()) state.wait(/* jobs empty */); + state->jobs.clearAndFree(); } static bool @@ -8652,6 +8655,12 @@ main(int argc, char** argv, char** envp) SetOutputFile("JS_STDOUT", &rcStdout, &gOutFile); SetOutputFile("JS_STDERR", &rcStderr, &gErrFile); + // Start the engine. + if (!JS_Init()) + return 1; + + auto shutdownEngine = MakeScopeExit([]() { JS_ShutDown(); }); + OptionParser op("Usage: {progname} [options] [[script] scriptArgs*]"); op.setDescription("The SpiderMonkey shell provides a command line interface to the " @@ -8875,10 +8884,6 @@ main(int argc, char** argv, char** envp) if (op.getBoolOption("no-threads")) js::DisableExtraThreads(); - // Start the engine. - if (!JS_Init()) - return 1; - if (!InitSharedArrayBufferMailbox()) return 1; @@ -8979,6 +8984,5 @@ main(int argc, char** argv, char** envp) DestructSharedArrayBufferMailbox(); JS_DestroyContext(cx); - JS_ShutDown(); return result; } diff --git a/js/src/vm/Initialization.cpp b/js/src/vm/Initialization.cpp index 3ef67db836ff..1b035a67e004 100644 --- a/js/src/vm/Initialization.cpp +++ b/js/src/vm/Initialization.cpp @@ -100,6 +100,8 @@ JS::detail::InitWithFailureDiagnostic(bool isDebugBuild) RETURN_IF_FAIL(js::oom::InitThreadType()); #endif + js::InitMallocAllocator(); + RETURN_IF_FAIL(js::Mutex::Init()); RETURN_IF_FAIL(js::wasm::InitInstanceStaticData()); @@ -170,6 +172,7 @@ JS_ShutDown(void) js::MemoryProtectionExceptionHandler::uninstall(); js::wasm::ShutDownInstanceStaticData(); + js::wasm::ShutDownProcessStaticData(); js::Mutex::ShutDown(); @@ -199,6 +202,8 @@ JS_ShutDown(void) js::jit::ReleaseProcessExecutableMemory(); } + js::ShutDownMallocAllocator(); + libraryInitState = InitState::ShutDown; } diff --git a/js/src/wasm/WasmProcess.cpp b/js/src/wasm/WasmProcess.cpp index afc378eac189..9a9920bdb22a 100644 --- a/js/src/wasm/WasmProcess.cpp +++ b/js/src/wasm/WasmProcess.cpp @@ -126,6 +126,13 @@ class ProcessCodeSegmentMap MOZ_ASSERT(segments2_.empty()); } + void freeAll() { + MOZ_ASSERT(segments1_.empty()); + MOZ_ASSERT(segments2_.empty()); + segments1_.clearAndFree(); + segments2_.clearAndFree(); + } + bool insert(const CodeSegment* cs) { LockGuard lock(mutatorsMutex_); @@ -230,3 +237,9 @@ wasm::LookupCode(const void* pc) const CodeSegment* found = LookupCodeSegment(pc); return found ? found->code() : nullptr; } + +void +wasm::ShutDownProcessStaticData() +{ + processCodeSegmentMap.freeAll(); +} diff --git a/js/src/wasm/WasmProcess.h b/js/src/wasm/WasmProcess.h index 08d25d9adfc7..d5b125a1fd35 100644 --- a/js/src/wasm/WasmProcess.h +++ b/js/src/wasm/WasmProcess.h @@ -51,6 +51,9 @@ RegisterCodeSegment(const CodeSegment* cs); void UnregisterCodeSegment(const CodeSegment* cs); +void +ShutDownProcessStaticData(); + } // namespace wasm } // namespace js