#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/AtomicOperations.h"
#include "jit/ExecutableAllocator.h"
#include "jit/Ion.h"
#include "jit/JitCommon.h"
#include "js/Utility.h"
#if ENABLE_INTL_API
# include "unicode/uclean.h"
# include "unicode/utypes.h"
#endif #include "vm/BigIntType.h"
#include "vm/DateTime.h"
#include "vm/HelperThreads.h"
#include "vm/Runtime.h"
#include "vm/Time.h"
#include "vm/TraceLogging.h"
#include "vtune/VTuneWrapper.h"
#include "wasm/WasmProcess.h"
using js::FutexThread;
using JS::detail::InitState;
using JS::detail::libraryInitState;
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() {
# define MSG_DEF(name, count, exception, format) \
MOZ_ASSERT(MessageParameterCount(format) == count);
# include "js.msg"
# undef MSG_DEF
}
#endif
#define RETURN_IF_FAIL(code) \
do { \
if (!code) return #code " failed"; \
} while (0)
JS_PUBLIC_API const char* JS::detail::InitWithFailureDiagnostic(
bool isDebugBuild) {
#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?");
libraryInitState = InitState::Initializing;
PRMJ_NowInit();
js::SliceBudget::Init();
mozilla::TimeStamp::ProcessCreation();
#ifdef DEBUG
CheckMessageParameterCounts();
#endif
RETURN_IF_FAIL(js::TlsContext.init());
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
RETURN_IF_FAIL(js::oom::InitThreadType());
#endif
js::gDisablePoisoning = bool(getenv("JSGC_DISABLE_POISONING"));
js::InitMallocAllocator();
RETURN_IF_FAIL(js::Mutex::Init());
RETURN_IF_FAIL(js::wasm::Init());
js::gc::InitMemorySubsystem();
RETURN_IF_FAIL(js::jit::InitProcessExecutableMemory());
RETURN_IF_FAIL(js::MemoryProtectionExceptionHandler::install());
RETURN_IF_FAIL(js::jit::InitializeIon());
RETURN_IF_FAIL(js::InitDateTimeState());
#ifdef MOZ_VTUNE
RETURN_IF_FAIL(js::vtune::Initialize());
#endif
RETURN_IF_FAIL(js::jit::AtomicOperations::Initialize());
#if EXPOSE_INTL_API
UErrorCode err = U_ZERO_ERROR;
u_init(&err);
if (U_FAILURE(err)) {
return "u_init() failed";
}
#endif
RETURN_IF_FAIL(js::CreateHelperThreadsState());
RETURN_IF_FAIL(FutexThread::initialize());
RETURN_IF_FAIL(js::gcstats::Statistics::initialize());
#ifdef JS_SIMULATOR
RETURN_IF_FAIL(js::jit::SimulatorProcess::initialize());
#endif
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()) {
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
FutexThread::destroy();
js::DestroyHelperThreadsState();
#ifdef JS_SIMULATOR
js::jit::SimulatorProcess::destroy();
#endif
js::jit::AtomicOperations::ShutDown();
#ifdef JS_TRACE_LOGGING
js::DestroyTraceLoggerThreadState();
js::DestroyTraceLoggerGraphState();
#endif
js::MemoryProtectionExceptionHandler::uninstall();
js::wasm::ShutDown();
js::Mutex::ShutDown();
PRMJ_NowShutdown();
#if EXPOSE_INTL_API
u_cleanup();
#endif
#ifdef MOZ_VTUNE
js::vtune::Shutdown();
#endif
js::FinishDateTimeState();
if (!JSRuntime::hasLiveRuntimes()) {
js::jit::ReleaseProcessExecutableMemory();
MOZ_ASSERT(!js::LiveMappedBufferCount());
}
js::ShutDownMallocAllocator();
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( nullptr, allocFn, reallocFn, freeFn,
&status);
return U_SUCCESS(status);
#else
return true;
#endif
}