Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /* SpiderMonkey initialization and shutdown code. */
8 :
9 : #include "js/Initialization.h"
10 :
11 : #include "mozilla/Assertions.h"
12 :
13 : #include <ctype.h>
14 :
15 : #include "jstypes.h"
16 :
17 : #include "builtin/AtomicsObject.h"
18 : #include "ds/MemoryProtectionExceptionHandler.h"
19 : #include "gc/Statistics.h"
20 : #include "jit/ExecutableAllocator.h"
21 : #include "jit/Ion.h"
22 : #include "jit/JitCommon.h"
23 : #include "js/Utility.h"
24 : #if ENABLE_INTL_API
25 : #include "unicode/uclean.h"
26 : #include "unicode/utypes.h"
27 : #endif // ENABLE_INTL_API
28 : #include "vm/DateTime.h"
29 : #include "vm/HelperThreads.h"
30 : #include "vm/Runtime.h"
31 : #include "vm/Time.h"
32 : #include "vm/TraceLogging.h"
33 : #include "vtune/VTuneWrapper.h"
34 : #include "wasm/WasmBuiltins.h"
35 : #include "wasm/WasmInstance.h"
36 :
37 : using JS::detail::InitState;
38 : using JS::detail::libraryInitState;
39 : using js::FutexThread;
40 :
41 : InitState JS::detail::libraryInitState;
42 :
43 : #ifdef DEBUG
44 : static unsigned
45 1491 : MessageParameterCount(const char* format)
46 : {
47 1491 : unsigned numfmtspecs = 0;
48 63168 : for (const char* fmt = format; *fmt != '\0'; fmt++) {
49 61677 : if (*fmt == '{' && isdigit(fmt[1]))
50 657 : ++numfmtspecs;
51 : }
52 1491 : return numfmtspecs;
53 : }
54 :
55 : static void
56 3 : CheckMessageParameterCounts()
57 : {
58 : // Assert that each message format has the correct number of braced
59 : // parameters.
60 : # define MSG_DEF(name, count, exception, format) \
61 : MOZ_ASSERT(MessageParameterCount(format) == count);
62 : # include "js.msg"
63 : # undef MSG_DEF
64 3 : }
65 : #endif /* DEBUG */
66 :
67 : #define RETURN_IF_FAIL(code) do { if (!code) return #code " failed"; } while (0)
68 :
69 : JS_PUBLIC_API(const char*)
70 3 : JS::detail::InitWithFailureDiagnostic(bool isDebugBuild)
71 : {
72 : // Verify that our DEBUG setting matches the caller's.
73 : #ifdef DEBUG
74 3 : MOZ_RELEASE_ASSERT(isDebugBuild);
75 : #else
76 : MOZ_RELEASE_ASSERT(!isDebugBuild);
77 : #endif
78 :
79 3 : MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
80 : "must call JS_Init once before any JSAPI operation except "
81 : "JS_SetICUMemoryFunctions");
82 3 : MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
83 : "how do we have live runtimes before JS_Init?");
84 :
85 3 : PRMJ_NowInit();
86 :
87 : // The first invocation of `ProcessCreation` creates a temporary thread
88 : // and crashes if that fails, i.e. because we're out of memory. To prevent
89 : // that from happening at some later time, get it out of the way during
90 : // startup.
91 3 : mozilla::TimeStamp::ProcessCreation();
92 :
93 : #ifdef DEBUG
94 3 : CheckMessageParameterCounts();
95 : #endif
96 :
97 3 : RETURN_IF_FAIL(js::TlsContext.init());
98 :
99 : #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
100 3 : RETURN_IF_FAIL(js::oom::InitThreadType());
101 3 : js::oom::SetThreadType(js::oom::THREAD_TYPE_COOPERATING);
102 : #endif
103 :
104 3 : RETURN_IF_FAIL(js::Mutex::Init());
105 :
106 3 : RETURN_IF_FAIL(js::wasm::InitInstanceStaticData());
107 :
108 3 : js::gc::InitMemorySubsystem(); // Ensure gc::SystemPageSize() works.
109 3 : RETURN_IF_FAIL(js::gc::InitializeStaticData());
110 :
111 3 : RETURN_IF_FAIL(js::jit::InitProcessExecutableMemory());
112 :
113 3 : MOZ_ALWAYS_TRUE(js::MemoryProtectionExceptionHandler::install());
114 :
115 3 : RETURN_IF_FAIL(js::jit::InitializeIon());
116 :
117 3 : RETURN_IF_FAIL(js::InitDateTimeState());
118 :
119 : #ifdef MOZ_VTUNE
120 3 : RETURN_IF_FAIL(js::vtune::Initialize());
121 : #endif
122 :
123 : #if EXPOSE_INTL_API
124 3 : UErrorCode err = U_ZERO_ERROR;
125 3 : u_init(&err);
126 3 : if (U_FAILURE(err))
127 0 : return "u_init() failed";
128 : #endif // EXPOSE_INTL_API
129 :
130 3 : RETURN_IF_FAIL(js::CreateHelperThreadsState());
131 3 : RETURN_IF_FAIL(FutexThread::initialize());
132 3 : RETURN_IF_FAIL(js::gcstats::Statistics::initialize());
133 :
134 : #ifdef JS_SIMULATOR
135 : RETURN_IF_FAIL(js::jit::SimulatorProcess::initialize());
136 : #endif
137 :
138 3 : libraryInitState = InitState::Running;
139 3 : return nullptr;
140 : }
141 :
142 : #undef RETURN_IF_FAIL
143 :
144 : JS_PUBLIC_API(void)
145 0 : JS_ShutDown(void)
146 : {
147 0 : MOZ_ASSERT(libraryInitState == InitState::Running,
148 : "JS_ShutDown must only be called after JS_Init and can't race with it");
149 : #ifdef DEBUG
150 0 : if (JSRuntime::hasLiveRuntimes()) {
151 : // Gecko is too buggy to assert this just yet.
152 : fprintf(stderr,
153 : "WARNING: YOU ARE LEAKING THE WORLD (at least one JSRuntime "
154 : "and everything alive inside it, that is) AT JS_ShutDown "
155 0 : "TIME. FIX THIS!\n");
156 : }
157 : #endif
158 :
159 0 : FutexThread::destroy();
160 :
161 0 : js::DestroyHelperThreadsState();
162 :
163 : #ifdef JS_SIMULATOR
164 : js::jit::SimulatorProcess::destroy();
165 : #endif
166 :
167 : #ifdef JS_TRACE_LOGGING
168 0 : js::DestroyTraceLoggerThreadState();
169 0 : js::DestroyTraceLoggerGraphState();
170 : #endif
171 :
172 0 : js::MemoryProtectionExceptionHandler::uninstall();
173 :
174 0 : js::wasm::ShutDownInstanceStaticData();
175 :
176 0 : js::Mutex::ShutDown();
177 :
178 : // The only difficult-to-address reason for the restriction that you can't
179 : // call JS_Init/stuff/JS_ShutDown multiple times is the Windows PRMJ
180 : // NowInit initialization code, which uses PR_CallOnce to initialize the
181 : // PRMJ_Now subsystem. (For reinitialization to be permitted, we'd need to
182 : // "reset" the called-once status -- doable, but more trouble than it's
183 : // worth now.) Initializing that subsystem from JS_Init eliminates the
184 : // problem, but initialization can take a comparatively long time (15ms or
185 : // so), so we really don't want to do it in JS_Init, and we really do want
186 : // to do it only when PRMJ_Now is eventually called.
187 0 : PRMJ_NowShutdown();
188 :
189 : #if EXPOSE_INTL_API
190 0 : u_cleanup();
191 : #endif // EXPOSE_INTL_API
192 :
193 : #ifdef MOZ_VTUNE
194 0 : js::vtune::Shutdown();
195 : #endif // MOZ_VTUNE
196 :
197 0 : js::FinishDateTimeState();
198 :
199 0 : if (!JSRuntime::hasLiveRuntimes()) {
200 0 : js::wasm::ReleaseBuiltinThunks();
201 0 : js::jit::ReleaseProcessExecutableMemory();
202 : }
203 :
204 0 : libraryInitState = InitState::ShutDown;
205 0 : }
206 :
207 : JS_PUBLIC_API(bool)
208 3 : JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_ICUFreeFn freeFn)
209 : {
210 3 : MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
211 : "must call JS_SetICUMemoryFunctions before any other JSAPI "
212 : "operation (including JS_Init)");
213 :
214 : #if EXPOSE_INTL_API
215 3 : UErrorCode status = U_ZERO_ERROR;
216 3 : u_setMemoryFunctions(/* context = */ nullptr, allocFn, reallocFn, freeFn, &status);
217 3 : return U_SUCCESS(status);
218 : #else
219 : return true;
220 : #endif
221 9 : }
|