diff options
Diffstat (limited to 'js/src/vm/Initialization.cpp')
-rw-r--r-- | js/src/vm/Initialization.cpp | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/js/src/vm/Initialization.cpp b/js/src/vm/Initialization.cpp new file mode 100644 index 000000000..05cc087cc --- /dev/null +++ b/js/src/vm/Initialization.cpp @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* SpiderMonkey initialization and shutdown code. */ + +#include "js/Initialization.h" + +#include "mozilla/Assertions.h" + +#include <ctype.h> + +#include "jstypes.h" + +#include "builtin/AtomicsObject.h" +#include "ds/MemoryProtectionExceptionHandler.h" +#include "gc/Statistics.h" +#include "jit/ExecutableAllocator.h" +#include "jit/Ion.h" +#include "js/Utility.h" +#if ENABLE_INTL_API +#include "unicode/uclean.h" +#include "unicode/utypes.h" +#endif // ENABLE_INTL_API +#include "vm/DateTime.h" +#include "vm/HelperThreads.h" +#include "vm/Runtime.h" +#include "vm/Time.h" +#include "vm/TraceLogging.h" +#include "wasm/WasmInstance.h" + +using JS::detail::InitState; +using JS::detail::libraryInitState; +using js::FutexRuntime; + +InitState JS::detail::libraryInitState; + +#ifdef DEBUG +static unsigned +MessageParameterCount(const char* format) +{ + unsigned numfmtspecs = 0; + for (const char* fmt = format; *fmt != '\0'; fmt++) { + if (*fmt == '{' && isdigit(fmt[1])) + ++numfmtspecs; + } + return numfmtspecs; +} + +static void +CheckMessageParameterCounts() +{ + // Assert that each message format has the correct number of braced + // parameters. +# define MSG_DEF(name, count, exception, format) \ + MOZ_ASSERT(MessageParameterCount(format) == count); +# include "js.msg" +# undef MSG_DEF +} +#endif /* DEBUG */ + +#define RETURN_IF_FAIL(code) do { if (!code) return #code " failed"; } while (0) + +JS_PUBLIC_API(const char*) +JS::detail::InitWithFailureDiagnostic(bool isDebugBuild) +{ + // Verify that our DEBUG setting matches the caller's. +#ifdef DEBUG + MOZ_RELEASE_ASSERT(isDebugBuild); +#else + MOZ_RELEASE_ASSERT(!isDebugBuild); +#endif + + MOZ_ASSERT(libraryInitState == InitState::Uninitialized, + "must call JS_Init once before any JSAPI operation except " + "JS_SetICUMemoryFunctions"); + MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(), + "how do we have live runtimes before JS_Init?"); + + PRMJ_NowInit(); + + // The first invocation of `ProcessCreation` creates a temporary thread + // and crashes if that fails, i.e. because we're out of memory. To prevent + // that from happening at some later time, get it out of the way during + // startup. + bool ignored; + mozilla::TimeStamp::ProcessCreation(ignored); + +#ifdef DEBUG + CheckMessageParameterCounts(); +#endif + + using js::TlsPerThreadData; + RETURN_IF_FAIL(TlsPerThreadData.init()); + +#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) + RETURN_IF_FAIL(js::oom::InitThreadType()); + js::oom::SetThreadType(js::oom::THREAD_TYPE_MAIN); +#endif + + RETURN_IF_FAIL(js::Mutex::Init()); + + RETURN_IF_FAIL(js::wasm::InitInstanceStaticData()); + + js::gc::InitMemorySubsystem(); // Ensure gc::SystemPageSize() works. + RETURN_IF_FAIL(js::jit::InitProcessExecutableMemory()); + + MOZ_ALWAYS_TRUE(js::MemoryProtectionExceptionHandler::install()); + + RETURN_IF_FAIL(js::jit::InitializeIon()); + + js::DateTimeInfo::init(); + +#if EXPOSE_INTL_API + UErrorCode err = U_ZERO_ERROR; + u_init(&err); + if (U_FAILURE(err)) + return "u_init() failed"; +#endif // EXPOSE_INTL_API + + RETURN_IF_FAIL(js::CreateHelperThreadsState()); + RETURN_IF_FAIL(FutexRuntime::initialize()); + RETURN_IF_FAIL(js::gcstats::Statistics::initialize()); + + libraryInitState = InitState::Running; + return nullptr; +} + +#undef RETURN_IF_FAIL + +JS_PUBLIC_API(void) +JS_ShutDown(void) +{ + MOZ_ASSERT(libraryInitState == InitState::Running, + "JS_ShutDown must only be called after JS_Init and can't race with it"); +#ifdef DEBUG + if (JSRuntime::hasLiveRuntimes()) { + // Gecko is too buggy to assert this just yet. + fprintf(stderr, + "WARNING: YOU ARE LEAKING THE WORLD (at least one JSRuntime " + "and everything alive inside it, that is) AT JS_ShutDown " + "TIME. FIX THIS!\n"); + } +#endif + + FutexRuntime::destroy(); + + js::DestroyHelperThreadsState(); + +#ifdef JS_TRACE_LOGGING + js::DestroyTraceLoggerThreadState(); + js::DestroyTraceLoggerGraphState(); +#endif + + js::MemoryProtectionExceptionHandler::uninstall(); + + js::wasm::ShutDownInstanceStaticData(); + + js::Mutex::ShutDown(); + + // The only difficult-to-address reason for the restriction that you can't + // call JS_Init/stuff/JS_ShutDown multiple times is the Windows PRMJ + // NowInit initialization code, which uses PR_CallOnce to initialize the + // PRMJ_Now subsystem. (For reinitialization to be permitted, we'd need to + // "reset" the called-once status -- doable, but more trouble than it's + // worth now.) Initializing that subsystem from JS_Init eliminates the + // problem, but initialization can take a comparatively long time (15ms or + // so), so we really don't want to do it in JS_Init, and we really do want + // to do it only when PRMJ_Now is eventually called. + PRMJ_NowShutdown(); + +#if EXPOSE_INTL_API + u_cleanup(); +#endif // EXPOSE_INTL_API + + if (!JSRuntime::hasLiveRuntimes()) + js::jit::ReleaseProcessExecutableMemory(); + + libraryInitState = InitState::ShutDown; +} + +JS_PUBLIC_API(bool) +JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_ICUFreeFn freeFn) +{ + MOZ_ASSERT(libraryInitState == InitState::Uninitialized, + "must call JS_SetICUMemoryFunctions before any other JSAPI " + "operation (including JS_Init)"); + +#if EXPOSE_INTL_API + UErrorCode status = U_ZERO_ERROR; + u_setMemoryFunctions(/* context = */ nullptr, allocFn, reallocFn, freeFn, &status); + return U_SUCCESS(status); +#else + return true; +#endif +} |