1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/init/v8.h"
6
7 #include <fstream>
8
9 #include "include/cppgc/platform.h"
10 #include "src/api/api.h"
11 #include "src/base/atomicops.h"
12 #include "src/base/once.h"
13 #include "src/base/platform/platform.h"
14 #include "src/codegen/cpu-features.h"
15 #include "src/codegen/interface-descriptors.h"
16 #include "src/debug/debug.h"
17 #include "src/deoptimizer/deoptimizer.h"
18 #include "src/execution/frames.h"
19 #include "src/execution/isolate.h"
20 #include "src/execution/simulator.h"
21 #include "src/init/bootstrapper.h"
22 #include "src/libsampler/sampler.h"
23 #include "src/objects/elements.h"
24 #include "src/objects/objects-inl.h"
25 #include "src/profiler/heap-profiler.h"
26 #include "src/sandbox/sandbox.h"
27 #include "src/snapshot/snapshot.h"
28 #include "src/tracing/tracing-category-observer.h"
29
30 #if V8_ENABLE_WEBASSEMBLY
31 #include "src/wasm/wasm-engine.h"
32 #endif // V8_ENABLE_WEBASSEMBLY
33
34 #if defined(V8_OS_WIN) && defined(V8_ENABLE_SYSTEM_INSTRUMENTATION)
35 #include "src/diagnostics/system-jit-win.h"
36 #endif
37
38 namespace v8 {
39 namespace internal {
40
41 v8::Platform* V8::platform_ = nullptr;
42
43 namespace {
44 enum class V8StartupState {
45 kIdle,
46 kPlatformInitializing,
47 kPlatformInitialized,
48 kV8Initializing,
49 kV8Initialized,
50 kV8Disposing,
51 kV8Disposed,
52 kPlatformDisposing,
53 kPlatformDisposed
54 };
55
56 std::atomic<V8StartupState> v8_startup_state_(V8StartupState::kIdle);
57
AdvanceStartupState(V8StartupState expected_next_state)58 void AdvanceStartupState(V8StartupState expected_next_state) {
59 V8StartupState current_state = v8_startup_state_;
60 CHECK_NE(current_state, V8StartupState::kPlatformDisposed);
61 V8StartupState next_state =
62 static_cast<V8StartupState>(static_cast<int>(current_state) + 1);
63 if (next_state != expected_next_state) {
64 // Ensure the following order:
65 // v8::V8::InitializePlatform(platform);
66 // v8::V8::Initialize();
67 // v8::Isolate* isolate = v8::Isolate::New(...);
68 // ...
69 // isolate->Dispose();
70 // v8::V8::Dispose();
71 // v8::V8::DisposePlatform();
72 FATAL("Wrong initialization order: got %d expected %d!",
73 static_cast<int>(current_state), static_cast<int>(next_state));
74 }
75 if (!v8_startup_state_.compare_exchange_strong(current_state, next_state)) {
76 FATAL(
77 "Multiple threads are initializating V8 in the wrong order: expected "
78 "%d got %d!",
79 static_cast<int>(current_state),
80 static_cast<int>(v8_startup_state_.load()));
81 }
82 }
83
84 } // namespace
85
86 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
87 V8_DECLARE_ONCE(init_snapshot_once);
88 #endif
89
InitializePlatform(v8::Platform * platform)90 void V8::InitializePlatform(v8::Platform* platform) {
91 AdvanceStartupState(V8StartupState::kPlatformInitializing);
92 CHECK(!platform_);
93 CHECK_NOT_NULL(platform);
94 platform_ = platform;
95 v8::base::SetPrintStackTrace(platform_->GetStackTracePrinter());
96 v8::tracing::TracingCategoryObserver::SetUp();
97 #if defined(V8_OS_WIN) && defined(V8_ENABLE_SYSTEM_INSTRUMENTATION)
98 if (FLAG_enable_system_instrumentation) {
99 // TODO(sartang@microsoft.com): Move to platform specific diagnostics object
100 v8::internal::ETWJITInterface::Register();
101 }
102 #endif
103 AdvanceStartupState(V8StartupState::kPlatformInitialized);
104 }
105
106 #ifdef V8_SANDBOX
InitializeSandbox()107 bool V8::InitializeSandbox() {
108 // Platform must have been initialized already.
109 CHECK(platform_);
110 v8::VirtualAddressSpace* vas = GetPlatformVirtualAddressSpace();
111 return GetProcessWideSandbox()->Initialize(vas);
112 }
113 #endif // V8_SANDBOX
114
115 #define DISABLE_FLAG(flag) \
116 if (FLAG_##flag) { \
117 PrintF(stderr, \
118 "Warning: disabling flag --" #flag " due to conflicting flags\n"); \
119 FLAG_##flag = false; \
120 }
121
Initialize()122 void V8::Initialize() {
123 AdvanceStartupState(V8StartupState::kV8Initializing);
124 CHECK(platform_);
125
126 #ifdef V8_SANDBOX
127 if (!GetProcessWideSandbox()->is_initialized()) {
128 // For now, we still allow the cage to be disabled even if V8 was compiled
129 // with V8_SANDBOX. This will eventually be forbidden.
130 CHECK(kAllowBackingStoresOutsideSandbox);
131 GetProcessWideSandbox()->Disable();
132 }
133 #endif
134
135 // Update logging information before enforcing flag implications.
136 bool* log_all_flags[] = {&FLAG_turbo_profiling_log_builtins,
137 &FLAG_log_all,
138 &FLAG_log_code,
139 &FLAG_log_code_disassemble,
140 &FLAG_log_source_code,
141 &FLAG_log_function_events,
142 &FLAG_log_internal_timer_events,
143 &FLAG_log_deopt,
144 &FLAG_log_ic,
145 &FLAG_log_maps};
146 if (FLAG_log_all) {
147 // Enable all logging flags
148 for (auto* flag : log_all_flags) {
149 *flag = true;
150 }
151 FLAG_log = true;
152 } else if (!FLAG_log) {
153 // Enable --log if any log flag is set.
154 for (const auto* flag : log_all_flags) {
155 if (!*flag) continue;
156 FLAG_log = true;
157 break;
158 }
159 // Profiling flags depend on logging.
160 FLAG_log |= FLAG_perf_prof || FLAG_perf_basic_prof || FLAG_ll_prof ||
161 FLAG_prof || FLAG_prof_cpp;
162 FLAG_log |= FLAG_gdbjit;
163 #if defined(V8_OS_WIN) && defined(V8_ENABLE_SYSTEM_INSTRUMENTATION)
164 FLAG_log |= FLAG_enable_system_instrumentation;
165 #endif
166 }
167
168 FlagList::EnforceFlagImplications();
169
170 if (FLAG_predictable && FLAG_random_seed == 0) {
171 // Avoid random seeds in predictable mode.
172 FLAG_random_seed = 12347;
173 }
174
175 if (FLAG_stress_compaction) {
176 FLAG_force_marking_deque_overflows = true;
177 FLAG_gc_global = true;
178 FLAG_max_semi_space_size = 1;
179 }
180
181 if (FLAG_trace_turbo) {
182 // Create an empty file shared by the process (e.g. the wasm engine).
183 std::ofstream(Isolate::GetTurboCfgFileName(nullptr).c_str(),
184 std::ios_base::trunc);
185 }
186
187 // Do not expose wasm in jitless mode.
188 //
189 // Even in interpreter-only mode, wasm currently still creates executable
190 // memory at runtime. Unexpose wasm until this changes.
191 // The correctness fuzzers are a special case: many of their test cases are
192 // built by fetching a random property from the the global object, and thus
193 // the global object layout must not change between configs. That is why we
194 // continue exposing wasm on correctness fuzzers even in jitless mode.
195 // TODO(jgruber): Remove this once / if wasm can run without executable
196 // memory.
197 #if V8_ENABLE_WEBASSEMBLY
198 if (FLAG_jitless && !FLAG_correctness_fuzzer_suppressions) {
199 DISABLE_FLAG(expose_wasm);
200 }
201 #endif
202
203 // When fuzzing and concurrent compilation is enabled, disable Turbofan
204 // tracing flags since reading/printing heap state is not thread-safe and
205 // leads to false positives on TSAN bots.
206 // TODO(chromium:1205289): Teach relevant fuzzers to not pass TF tracing
207 // flags instead, and remove this section.
208 if (FLAG_fuzzing && FLAG_concurrent_recompilation) {
209 DISABLE_FLAG(trace_turbo);
210 DISABLE_FLAG(trace_turbo_graph);
211 DISABLE_FLAG(trace_turbo_scheduled);
212 DISABLE_FLAG(trace_turbo_reduction);
213 DISABLE_FLAG(trace_turbo_trimming);
214 DISABLE_FLAG(trace_turbo_jt);
215 DISABLE_FLAG(trace_turbo_ceq);
216 DISABLE_FLAG(trace_turbo_loop);
217 DISABLE_FLAG(trace_turbo_alloc);
218 DISABLE_FLAG(trace_all_uses);
219 DISABLE_FLAG(trace_representation);
220 DISABLE_FLAG(trace_turbo_stack_accesses);
221 }
222
223 // The --jitless and --interpreted-frames-native-stack flags are incompatible
224 // since the latter requires code generation while the former prohibits code
225 // generation.
226 CHECK(!FLAG_interpreted_frames_native_stack || !FLAG_jitless);
227
228 base::OS::Initialize(FLAG_hard_abort, FLAG_gc_fake_mmap);
229
230 if (FLAG_random_seed) SetRandomMmapSeed(FLAG_random_seed);
231
232 if (FLAG_print_flag_values) FlagList::PrintValues();
233
234 // Initialize the default FlagList::Hash
235 FlagList::Hash();
236
237 #if defined(V8_USE_PERFETTO)
238 if (perfetto::Tracing::IsInitialized()) TrackEvent::Register();
239 #endif
240 IsolateAllocator::InitializeOncePerProcess();
241 Isolate::InitializeOncePerProcess();
242
243 #if defined(USE_SIMULATOR)
244 Simulator::InitializeOncePerProcess();
245 #endif
246 CpuFeatures::Probe(false);
247 ElementsAccessor::InitializeOncePerProcess();
248 Bootstrapper::InitializeOncePerProcess();
249 CallDescriptors::InitializeOncePerProcess();
250 #if V8_ENABLE_WEBASSEMBLY
251 wasm::WasmEngine::InitializeOncePerProcess();
252 #endif // V8_ENABLE_WEBASSEMBLY
253
254 ExternalReferenceTable::InitializeOncePerProcess();
255
256 AdvanceStartupState(V8StartupState::kV8Initialized);
257 }
258
259 #undef DISABLE_FLAG
260
Dispose()261 void V8::Dispose() {
262 AdvanceStartupState(V8StartupState::kV8Disposing);
263 CHECK(platform_);
264 #if V8_ENABLE_WEBASSEMBLY
265 wasm::WasmEngine::GlobalTearDown();
266 #endif // V8_ENABLE_WEBASSEMBLY
267 #if defined(USE_SIMULATOR)
268 Simulator::GlobalTearDown();
269 #endif
270 CallDescriptors::TearDown();
271 ElementsAccessor::TearDown();
272 RegisteredExtension::UnregisterAll();
273 Isolate::DisposeOncePerProcess();
274 FlagList::ResetAllFlags(); // Frees memory held by string arguments.
275 AdvanceStartupState(V8StartupState::kV8Disposed);
276 }
277
DisposePlatform()278 void V8::DisposePlatform() {
279 AdvanceStartupState(V8StartupState::kPlatformDisposing);
280 CHECK(platform_);
281 #if defined(V8_OS_WIN) && defined(V8_ENABLE_SYSTEM_INSTRUMENTATION)
282 if (FLAG_enable_system_instrumentation) {
283 v8::internal::ETWJITInterface::Unregister();
284 }
285 #endif
286 v8::tracing::TracingCategoryObserver::TearDown();
287 v8::base::SetPrintStackTrace(nullptr);
288
289 #ifdef V8_SANDBOX
290 // TODO(chromium:1218005) alternatively, this could move to its own
291 // public TearDownSandbox function.
292 GetProcessWideSandbox()->TearDown();
293 #endif
294
295 platform_ = nullptr;
296 AdvanceStartupState(V8StartupState::kPlatformDisposed);
297 }
298
GetCurrentPlatform()299 v8::Platform* V8::GetCurrentPlatform() {
300 v8::Platform* platform = reinterpret_cast<v8::Platform*>(
301 base::Relaxed_Load(reinterpret_cast<base::AtomicWord*>(&platform_)));
302 DCHECK(platform);
303 return platform;
304 }
305
SetPlatformForTesting(v8::Platform * platform)306 void V8::SetPlatformForTesting(v8::Platform* platform) {
307 base::Relaxed_Store(reinterpret_cast<base::AtomicWord*>(&platform_),
308 reinterpret_cast<base::AtomicWord>(platform));
309 }
310
SetSnapshotBlob(StartupData * snapshot_blob)311 void V8::SetSnapshotBlob(StartupData* snapshot_blob) {
312 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
313 base::CallOnce(&init_snapshot_once, &SetSnapshotFromFile, snapshot_blob);
314 #else
315 UNREACHABLE();
316 #endif
317 }
318 } // namespace internal
319
320 // static
SystemClockTimeMillis()321 double Platform::SystemClockTimeMillis() {
322 return base::OS::TimeCurrentMillis();
323 }
324 } // namespace v8
325