Line data Source code
1 : // Copyright 2018 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/wasm/wasm-engine.h"
6 :
7 : #include "src/code-tracer.h"
8 : #include "src/compilation-statistics.h"
9 : #include "src/counters.h"
10 : #include "src/objects-inl.h"
11 : #include "src/objects/heap-number.h"
12 : #include "src/objects/js-promise.h"
13 : #include "src/ostreams.h"
14 : #include "src/wasm/function-compiler.h"
15 : #include "src/wasm/module-compiler.h"
16 : #include "src/wasm/module-decoder.h"
17 : #include "src/wasm/module-instantiate.h"
18 : #include "src/wasm/streaming-decoder.h"
19 : #include "src/wasm/wasm-objects-inl.h"
20 :
21 : namespace v8 {
22 : namespace internal {
23 : namespace wasm {
24 :
25 : namespace {
26 : class LogCodesTask : public Task {
27 : public:
28 : LogCodesTask(base::Mutex* mutex, LogCodesTask** task_slot, Isolate* isolate)
29 0 : : mutex_(mutex), task_slot_(task_slot), isolate_(isolate) {
30 : DCHECK_NOT_NULL(task_slot);
31 : DCHECK_NOT_NULL(isolate);
32 : }
33 :
34 0 : ~LogCodesTask() {
35 : // If the platform deletes this task before executing it, we also deregister
36 : // it to avoid use-after-free from still-running background threads.
37 0 : if (!cancelled()) DeregisterTask();
38 0 : }
39 :
40 : // Hold the {mutex_} when calling this method.
41 0 : void AddCode(WasmCode* code) { code_to_log_.push_back(code); }
42 :
43 0 : void Run() override {
44 0 : if (cancelled()) return;
45 0 : DeregisterTask();
46 : // If by now we should not log code any more, do not log it.
47 0 : if (!WasmCode::ShouldBeLogged(isolate_)) return;
48 0 : for (WasmCode* code : code_to_log_) {
49 0 : code->LogCode(isolate_);
50 : }
51 : }
52 :
53 : void Cancel() {
54 : // Cancel will only be called on Isolate shutdown, which happens on the
55 : // Isolate's foreground thread. Thus no synchronization needed.
56 0 : isolate_ = nullptr;
57 : }
58 :
59 : bool cancelled() const { return isolate_ == nullptr; }
60 :
61 0 : void DeregisterTask() {
62 : // The task will only be deregistered from the foreground thread (executing
63 : // this task or calling its destructor), thus we do not need synchronization
64 : // on this field access.
65 0 : if (task_slot_ == nullptr) return; // already deregistered.
66 : // Remove this task from the {IsolateInfo} in the engine. The next
67 : // logging request will allocate and schedule a new task.
68 0 : base::MutexGuard guard(mutex_);
69 : DCHECK_EQ(this, *task_slot_);
70 0 : *task_slot_ = nullptr;
71 0 : task_slot_ = nullptr;
72 : }
73 :
74 : private:
75 : // The mutex of the WasmEngine.
76 : base::Mutex* const mutex_;
77 : // The slot in the WasmEngine where this LogCodesTask is stored. This is
78 : // cleared by this task before execution or on task destruction.
79 : LogCodesTask** task_slot_;
80 : Isolate* isolate_;
81 : std::vector<WasmCode*> code_to_log_;
82 : };
83 : } // namespace
84 :
85 122068 : struct WasmEngine::IsolateInfo {
86 61049 : explicit IsolateInfo(Isolate* isolate)
87 61049 : : log_codes(WasmCode::ShouldBeLogged(isolate)) {
88 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
89 61049 : v8::Platform* platform = V8::GetCurrentPlatform();
90 122098 : foreground_task_runner = platform->GetForegroundTaskRunner(v8_isolate);
91 61049 : }
92 :
93 : // All native modules that are being used by this Isolate (currently only
94 : // grows, never shrinks).
95 : std::set<NativeModule*> native_modules;
96 :
97 : // Caches whether code needs to be logged on this isolate.
98 : bool log_codes;
99 :
100 : // The currently scheduled LogCodesTask.
101 : LogCodesTask* log_codes_task = nullptr;
102 :
103 : // The foreground task runner of the isolate (can be called from background).
104 : std::shared_ptr<v8::TaskRunner> foreground_task_runner;
105 : };
106 :
107 59619 : WasmEngine::WasmEngine()
108 238476 : : code_manager_(&memory_tracker_, FLAG_wasm_max_code_space * MB) {}
109 :
110 117004 : WasmEngine::~WasmEngine() {
111 : // Synchronize on all background compile tasks.
112 58502 : background_compile_task_manager_.CancelAndWait();
113 : // All AsyncCompileJobs have been canceled.
114 : DCHECK(async_compile_jobs_.empty());
115 : // All Isolates have been deregistered.
116 : DCHECK(isolates_.empty());
117 : // All NativeModules did die.
118 : DCHECK(isolates_per_native_module_.empty());
119 58502 : }
120 :
121 127090 : bool WasmEngine::SyncValidate(Isolate* isolate, const WasmFeatures& enabled,
122 : const ModuleWireBytes& bytes) {
123 : // TODO(titzer): remove dependency on the isolate.
124 254180 : if (bytes.start() == nullptr || bytes.length() == 0) return false;
125 : ModuleResult result =
126 : DecodeWasmModule(enabled, bytes.start(), bytes.end(), true, kWasmOrigin,
127 381270 : isolate->counters(), allocator());
128 127090 : return result.ok();
129 : }
130 :
131 2439 : MaybeHandle<AsmWasmData> WasmEngine::SyncCompileTranslatedAsmJs(
132 : Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes,
133 : Vector<const byte> asm_js_offset_table_bytes,
134 : Handle<HeapNumber> uses_bitset) {
135 : ModuleResult result =
136 : DecodeWasmModule(kAsmjsWasmFeatures, bytes.start(), bytes.end(), false,
137 7317 : kAsmJsOrigin, isolate->counters(), allocator());
138 2439 : CHECK(!result.failed());
139 :
140 : // Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
141 : // in {CompileToNativeModule}.
142 : Handle<FixedArray> export_wrappers;
143 : std::unique_ptr<NativeModule> native_module =
144 : CompileToNativeModule(isolate, kAsmjsWasmFeatures, thrower,
145 4878 : std::move(result).value(), bytes, &export_wrappers);
146 2439 : if (!native_module) return {};
147 :
148 : // Create heap objects for asm.js offset table to be stored in the module
149 : // object.
150 : Handle<ByteArray> asm_js_offset_table =
151 2439 : isolate->factory()->NewByteArray(asm_js_offset_table_bytes.length());
152 : asm_js_offset_table->copy_in(0, asm_js_offset_table_bytes.start(),
153 2439 : asm_js_offset_table_bytes.length());
154 :
155 : return AsmWasmData::New(isolate, std::move(native_module), export_wrappers,
156 7317 : asm_js_offset_table, uses_bitset);
157 : }
158 :
159 4962 : Handle<WasmModuleObject> WasmEngine::FinalizeTranslatedAsmJs(
160 : Isolate* isolate, Handle<AsmWasmData> asm_wasm_data,
161 : Handle<Script> script) {
162 : std::shared_ptr<NativeModule> native_module =
163 9924 : asm_wasm_data->managed_native_module()->get();
164 : Handle<FixedArray> export_wrappers =
165 9924 : handle(asm_wasm_data->export_wrappers(), isolate);
166 : size_t code_size_estimate =
167 : wasm::WasmCodeManager::EstimateNativeModuleCodeSize(
168 9924 : native_module->module());
169 :
170 : Handle<WasmModuleObject> module_object =
171 : WasmModuleObject::New(isolate, std::move(native_module), script,
172 9924 : export_wrappers, code_size_estimate);
173 9924 : module_object->set_asm_js_offset_table(asm_wasm_data->asm_js_offset_table());
174 9924 : return module_object;
175 : }
176 :
177 149705 : MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
178 134089 : Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
179 : const ModuleWireBytes& bytes) {
180 : ModuleResult result =
181 : DecodeWasmModule(enabled, bytes.start(), bytes.end(), false, kWasmOrigin,
182 449120 : isolate->counters(), allocator());
183 149710 : if (result.failed()) {
184 : thrower->CompileFailed(result.error());
185 9037 : return {};
186 : }
187 :
188 : // Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
189 : // in {CompileToModuleObject}.
190 : Handle<FixedArray> export_wrappers;
191 : std::unique_ptr<NativeModule> native_module =
192 : CompileToNativeModule(isolate, enabled, thrower,
193 281347 : std::move(result).value(), bytes, &export_wrappers);
194 140674 : if (!native_module) return {};
195 :
196 : Handle<Script> script =
197 134089 : CreateWasmScript(isolate, bytes, native_module->module()->source_map_url);
198 : size_t code_size_estimate =
199 : wasm::WasmCodeManager::EstimateNativeModuleCodeSize(
200 134089 : native_module->module());
201 :
202 : // Create the module object.
203 : // TODO(clemensh): For the same module (same bytes / same hash), we should
204 : // only have one WasmModuleObject. Otherwise, we might only set
205 : // breakpoints on a (potentially empty) subset of the instances.
206 :
207 : // Create the compiled module object and populate with compiled functions
208 : // and information needed at instantiation time. This object needs to be
209 : // serializable. Instantiation may occur off a deserialized version of this
210 : // object.
211 : Handle<WasmModuleObject> module_object =
212 : WasmModuleObject::New(isolate, std::move(native_module), script,
213 268178 : export_wrappers, code_size_estimate);
214 :
215 : // Finish the Wasm script now and make it public to the debugger.
216 134089 : isolate->debug()->OnAfterCompile(script);
217 283799 : return module_object;
218 : }
219 :
220 133571 : MaybeHandle<WasmInstanceObject> WasmEngine::SyncInstantiate(
221 : Isolate* isolate, ErrorThrower* thrower,
222 : Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
223 : MaybeHandle<JSArrayBuffer> memory) {
224 : return InstantiateToInstanceObject(isolate, thrower, module_object, imports,
225 135943 : memory);
226 : }
227 :
228 2372 : void WasmEngine::AsyncInstantiate(
229 : Isolate* isolate, std::unique_ptr<InstantiationResultResolver> resolver,
230 : Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports) {
231 : ErrorThrower thrower(isolate, "WebAssembly.instantiate()");
232 : // Instantiate a TryCatch so that caught exceptions won't progagate out.
233 : // They will still be set as pending exceptions on the isolate.
234 : // TODO(clemensh): Avoid TryCatch, use Execution::TryCall internally to invoke
235 : // start function and report thrown exception explicitly via out argument.
236 3484 : v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
237 2372 : catcher.SetVerbose(false);
238 2372 : catcher.SetCaptureMessage(false);
239 :
240 : MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
241 : isolate, &thrower, module_object, imports, Handle<JSArrayBuffer>::null());
242 :
243 2372 : if (!instance_object.is_null()) {
244 2520 : resolver->OnInstantiationSucceeded(instance_object.ToHandleChecked());
245 3632 : return;
246 : }
247 :
248 1112 : if (isolate->has_pending_exception()) {
249 : // The JS code executed during instantiation has thrown an exception.
250 : // We have to move the exception to the promise chain.
251 : Handle<Object> exception(isolate->pending_exception(), isolate);
252 40 : isolate->clear_pending_exception();
253 : DCHECK(*isolate->external_caught_exception_address());
254 40 : *isolate->external_caught_exception_address() = false;
255 40 : resolver->OnInstantiationFailed(exception);
256 40 : thrower.Reset();
257 : } else {
258 : DCHECK(thrower.error());
259 1072 : resolver->OnInstantiationFailed(thrower.Reify());
260 1112 : }
261 : }
262 :
263 2331 : void WasmEngine::AsyncCompile(
264 : Isolate* isolate, const WasmFeatures& enabled,
265 : std::shared_ptr<CompilationResultResolver> resolver,
266 : const ModuleWireBytes& bytes, bool is_shared) {
267 2331 : if (!FLAG_wasm_async_compilation) {
268 : // Asynchronous compilation disabled; fall back on synchronous compilation.
269 : ErrorThrower thrower(isolate, "WasmCompile");
270 : MaybeHandle<WasmModuleObject> module_object;
271 0 : if (is_shared) {
272 : // Make a copy of the wire bytes to avoid concurrent modification.
273 0 : std::unique_ptr<uint8_t[]> copy(new uint8_t[bytes.length()]);
274 : memcpy(copy.get(), bytes.start(), bytes.length());
275 0 : ModuleWireBytes bytes_copy(copy.get(), copy.get() + bytes.length());
276 0 : module_object = SyncCompile(isolate, enabled, &thrower, bytes_copy);
277 : } else {
278 : // The wire bytes are not shared, OK to use them directly.
279 0 : module_object = SyncCompile(isolate, enabled, &thrower, bytes);
280 : }
281 0 : if (thrower.error()) {
282 0 : resolver->OnCompilationFailed(thrower.Reify());
283 0 : return;
284 : }
285 0 : Handle<WasmModuleObject> module = module_object.ToHandleChecked();
286 0 : resolver->OnCompilationSucceeded(module);
287 0 : return;
288 : }
289 :
290 2331 : if (FLAG_wasm_test_streaming) {
291 : std::shared_ptr<StreamingDecoder> streaming_decoder =
292 : StartStreamingCompilation(isolate, enabled,
293 : handle(isolate->context(), isolate),
294 368 : std::move(resolver));
295 184 : streaming_decoder->OnBytesReceived(bytes.module_bytes());
296 184 : streaming_decoder->Finish();
297 : return;
298 : }
299 : // Make a copy of the wire bytes in case the user program changes them
300 : // during asynchronous compilation.
301 2147 : std::unique_ptr<byte[]> copy(new byte[bytes.length()]);
302 : memcpy(copy.get(), bytes.start(), bytes.length());
303 :
304 : AsyncCompileJob* job = CreateAsyncCompileJob(
305 : isolate, enabled, std::move(copy), bytes.length(),
306 6441 : handle(isolate->context(), isolate), std::move(resolver));
307 2147 : job->Start();
308 : }
309 :
310 356 : std::shared_ptr<StreamingDecoder> WasmEngine::StartStreamingCompilation(
311 : Isolate* isolate, const WasmFeatures& enabled, Handle<Context> context,
312 : std::shared_ptr<CompilationResultResolver> resolver) {
313 : AsyncCompileJob* job =
314 : CreateAsyncCompileJob(isolate, enabled, std::unique_ptr<byte[]>(nullptr),
315 1068 : 0, context, std::move(resolver));
316 356 : return job->CreateStreamingDecoder();
317 : }
318 :
319 16 : void WasmEngine::CompileFunction(Isolate* isolate, NativeModule* native_module,
320 : uint32_t function_index, ExecutionTier tier) {
321 : // Note we assume that "one-off" compilations can discard detected features.
322 16 : WasmFeatures detected = kNoWasmFeatures;
323 : WasmCompilationUnit::CompileWasmFunction(
324 : isolate, native_module, &detected,
325 48 : &native_module->module()->functions[function_index], tier);
326 16 : }
327 :
328 0 : std::shared_ptr<NativeModule> WasmEngine::ExportNativeModule(
329 : Handle<WasmModuleObject> module_object) {
330 0 : return module_object->shared_native_module();
331 : }
332 :
333 136 : Handle<WasmModuleObject> WasmEngine::ImportNativeModule(
334 : Isolate* isolate, std::shared_ptr<NativeModule> shared_native_module) {
335 136 : NativeModule* native_module = shared_native_module.get();
336 : ModuleWireBytes wire_bytes(native_module->wire_bytes());
337 : const WasmModule* module = native_module->module();
338 : Handle<Script> script =
339 136 : CreateWasmScript(isolate, wire_bytes, module->source_map_url);
340 136 : size_t code_size = native_module->committed_code_space();
341 : Handle<WasmModuleObject> module_object = WasmModuleObject::New(
342 272 : isolate, std::move(shared_native_module), script, code_size);
343 : CompileJsToWasmWrappers(isolate, native_module->module(),
344 544 : handle(module_object->export_wrappers(), isolate));
345 : {
346 136 : base::MutexGuard lock(&mutex_);
347 : DCHECK_EQ(1, isolates_.count(isolate));
348 : isolates_[isolate]->native_modules.insert(native_module);
349 : DCHECK_EQ(1, isolates_per_native_module_.count(native_module));
350 : isolates_per_native_module_[native_module].insert(isolate);
351 : }
352 136 : return module_object;
353 : }
354 :
355 0 : CompilationStatistics* WasmEngine::GetOrCreateTurboStatistics() {
356 0 : base::MutexGuard guard(&mutex_);
357 0 : if (compilation_stats_ == nullptr) {
358 0 : compilation_stats_.reset(new CompilationStatistics());
359 : }
360 0 : return compilation_stats_.get();
361 : }
362 :
363 0 : void WasmEngine::DumpAndResetTurboStatistics() {
364 0 : base::MutexGuard guard(&mutex_);
365 0 : if (compilation_stats_ != nullptr) {
366 0 : StdoutStream os;
367 0 : os << AsPrintableStatistics{*compilation_stats_.get(), false} << std::endl;
368 : }
369 : compilation_stats_.reset();
370 0 : }
371 :
372 0 : CodeTracer* WasmEngine::GetCodeTracer() {
373 0 : base::MutexGuard guard(&mutex_);
374 0 : if (code_tracer_ == nullptr) code_tracer_.reset(new CodeTracer(-1));
375 0 : return code_tracer_.get();
376 : }
377 :
378 2503 : AsyncCompileJob* WasmEngine::CreateAsyncCompileJob(
379 : Isolate* isolate, const WasmFeatures& enabled,
380 : std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
381 : std::shared_ptr<CompilationResultResolver> resolver) {
382 : AsyncCompileJob* job =
383 : new AsyncCompileJob(isolate, enabled, std::move(bytes_copy), length,
384 10012 : context, std::move(resolver));
385 : // Pass ownership to the unique_ptr in {async_compile_jobs_}.
386 2503 : base::MutexGuard guard(&mutex_);
387 2503 : async_compile_jobs_[job] = std::unique_ptr<AsyncCompileJob>(job);
388 5006 : return job;
389 : }
390 :
391 2493 : std::unique_ptr<AsyncCompileJob> WasmEngine::RemoveCompileJob(
392 : AsyncCompileJob* job) {
393 2493 : base::MutexGuard guard(&mutex_);
394 : auto item = async_compile_jobs_.find(job);
395 : DCHECK(item != async_compile_jobs_.end());
396 : std::unique_ptr<AsyncCompileJob> result = std::move(item->second);
397 : async_compile_jobs_.erase(item);
398 2493 : return result;
399 : }
400 :
401 54345 : bool WasmEngine::HasRunningCompileJob(Isolate* isolate) {
402 54345 : base::MutexGuard guard(&mutex_);
403 : DCHECK_EQ(1, isolates_.count(isolate));
404 108690 : for (auto& entry : async_compile_jobs_) {
405 2107 : if (entry.first->isolate() == isolate) return true;
406 : }
407 : return false;
408 : }
409 :
410 61043 : void WasmEngine::DeleteCompileJobsOnIsolate(Isolate* isolate) {
411 : // Under the mutex get all jobs to delete. Then delete them without holding
412 : // the mutex, such that deletion can reenter the WasmEngine.
413 : std::vector<std::unique_ptr<AsyncCompileJob>> jobs_to_delete;
414 : {
415 61043 : base::MutexGuard guard(&mutex_);
416 : DCHECK_EQ(1, isolates_.count(isolate));
417 122101 : for (auto it = async_compile_jobs_.begin();
418 : it != async_compile_jobs_.end();) {
419 13 : if (it->first->isolate() != isolate) {
420 : ++it;
421 : continue;
422 : }
423 10 : jobs_to_delete.push_back(std::move(it->second));
424 : it = async_compile_jobs_.erase(it);
425 : }
426 61044 : }
427 61044 : }
428 :
429 61047 : void WasmEngine::AddIsolate(Isolate* isolate) {
430 61047 : base::MutexGuard guard(&mutex_);
431 : DCHECK_EQ(0, isolates_.count(isolate));
432 122098 : isolates_.emplace(isolate, base::make_unique<IsolateInfo>(isolate));
433 :
434 : // Install sampling GC callback.
435 : // TODO(v8:7424): For now we sample module sizes in a GC callback. This will
436 : // bias samples towards apps with high memory pressure. We should switch to
437 : // using sampling based on regular intervals independent of the GC.
438 : auto callback = [](v8::Isolate* v8_isolate, v8::GCType type,
439 148996 : v8::GCCallbackFlags flags, void* data) {
440 74498 : Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
441 : WasmEngine* engine = isolate->wasm_engine();
442 74498 : base::MutexGuard lock(&engine->mutex_);
443 : DCHECK_EQ(1, engine->isolates_.count(isolate));
444 768337 : for (NativeModule* native_module :
445 693839 : engine->isolates_[isolate]->native_modules) {
446 : int code_size =
447 693839 : static_cast<int>(native_module->committed_code_space() / MB);
448 1387678 : isolate->counters()->wasm_module_code_size_mb()->AddSample(code_size);
449 : }
450 148996 : };
451 : isolate->heap()->AddGCEpilogueCallback(callback, v8::kGCTypeMarkSweepCompact,
452 61049 : nullptr);
453 61049 : }
454 :
455 61034 : void WasmEngine::RemoveIsolate(Isolate* isolate) {
456 61034 : base::MutexGuard guard(&mutex_);
457 : auto it = isolates_.find(isolate);
458 : DCHECK_NE(isolates_.end(), it);
459 122216 : for (NativeModule* native_module : it->second->native_modules) {
460 : DCHECK_EQ(1, isolates_per_native_module_[native_module].count(isolate));
461 : isolates_per_native_module_[native_module].erase(isolate);
462 : }
463 61034 : if (auto* task = it->second->log_codes_task) task->Cancel();
464 : isolates_.erase(it);
465 61034 : }
466 :
467 407128 : void WasmEngine::LogCode(WasmCode* code) {
468 203564 : base::MutexGuard guard(&mutex_);
469 203564 : NativeModule* native_module = code->native_module();
470 : DCHECK_EQ(1, isolates_per_native_module_.count(native_module));
471 610692 : for (Isolate* isolate : isolates_per_native_module_[native_module]) {
472 : DCHECK_EQ(1, isolates_.count(isolate));
473 : IsolateInfo* info = isolates_[isolate].get();
474 203564 : if (info->log_codes == false) continue;
475 0 : if (info->log_codes_task == nullptr) {
476 : auto new_task = base::make_unique<LogCodesTask>(
477 0 : &mutex_, &info->log_codes_task, isolate);
478 0 : info->log_codes_task = new_task.get();
479 0 : info->foreground_task_runner->PostTask(std::move(new_task));
480 : }
481 0 : info->log_codes_task->AddCode(code);
482 : }
483 203564 : }
484 :
485 763 : void WasmEngine::EnableCodeLogging(Isolate* isolate) {
486 763 : base::MutexGuard guard(&mutex_);
487 : auto it = isolates_.find(isolate);
488 : DCHECK_NE(isolates_.end(), it);
489 763 : it->second->log_codes = true;
490 763 : }
491 :
492 1240019 : std::unique_ptr<NativeModule> WasmEngine::NewNativeModule(
493 : Isolate* isolate, const WasmFeatures& enabled, size_t code_size_estimate,
494 : bool can_request_more, std::shared_ptr<const WasmModule> module) {
495 : std::unique_ptr<NativeModule> native_module =
496 : code_manager_.NewNativeModule(this, isolate, enabled, code_size_estimate,
497 2480042 : can_request_more, std::move(module));
498 1240023 : base::MutexGuard lock(&mutex_);
499 2480046 : isolates_per_native_module_[native_module.get()].insert(isolate);
500 : DCHECK_EQ(1, isolates_.count(isolate));
501 2480046 : isolates_[isolate]->native_modules.insert(native_module.get());
502 1240023 : return native_module;
503 : }
504 :
505 1240022 : void WasmEngine::FreeNativeModule(NativeModule* native_module) {
506 : {
507 1240022 : base::MutexGuard guard(&mutex_);
508 : auto it = isolates_per_native_module_.find(native_module);
509 : DCHECK_NE(isolates_per_native_module_.end(), it);
510 3720053 : for (Isolate* isolate : it->second) {
511 : DCHECK_EQ(1, isolates_.count(isolate));
512 : DCHECK_EQ(1, isolates_[isolate]->native_modules.count(native_module));
513 : isolates_[isolate]->native_modules.erase(native_module);
514 : }
515 : isolates_per_native_module_.erase(it);
516 : }
517 1240023 : code_manager_.FreeNativeModule(native_module);
518 1240023 : }
519 :
520 : namespace {
521 :
522 179071 : DEFINE_LAZY_LEAKY_OBJECT_GETTER(std::shared_ptr<WasmEngine>,
523 : GetSharedWasmEngine)
524 :
525 : } // namespace
526 :
527 : // static
528 59591 : void WasmEngine::InitializeOncePerProcess() {
529 119182 : if (!FLAG_wasm_shared_engine) return;
530 119182 : *GetSharedWasmEngine() = std::make_shared<WasmEngine>();
531 : }
532 :
533 : // static
534 58516 : void WasmEngine::GlobalTearDown() {
535 117032 : if (!FLAG_wasm_shared_engine) return;
536 58516 : GetSharedWasmEngine()->reset();
537 : }
538 :
539 : // static
540 60964 : std::shared_ptr<WasmEngine> WasmEngine::GetWasmEngine() {
541 60964 : if (FLAG_wasm_shared_engine) return *GetSharedWasmEngine();
542 : return std::make_shared<WasmEngine>();
543 : }
544 :
545 : // {max_mem_pages} is declared in wasm-limits.h.
546 1651264 : uint32_t max_mem_pages() {
547 : STATIC_ASSERT(kV8MaxWasmMemoryPages <= kMaxUInt32);
548 3302528 : return std::min(uint32_t{kV8MaxWasmMemoryPages}, FLAG_wasm_max_mem_pages);
549 : }
550 :
551 : } // namespace wasm
552 : } // namespace internal
553 178779 : } // namespace v8
|