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 123038 : struct WasmEngine::IsolateInfo {
86 61534 : explicit IsolateInfo(Isolate* isolate)
87 61534 : : log_codes(WasmCode::ShouldBeLogged(isolate)) {
88 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
89 61534 : v8::Platform* platform = V8::GetCurrentPlatform();
90 123068 : foreground_task_runner = platform->GetForegroundTaskRunner(v8_isolate);
91 61534 : }
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 60134 : WasmEngine::WasmEngine()
108 180402 : : code_manager_(&memory_tracker_, FLAG_wasm_max_code_space * MB) {}
109 :
110 235932 : WasmEngine::~WasmEngine() {
111 : // Synchronize on all background compile tasks.
112 58983 : 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 58983 : }
120 :
121 128010 : bool WasmEngine::SyncValidate(Isolate* isolate, const WasmFeatures& enabled,
122 : const ModuleWireBytes& bytes) {
123 : // TODO(titzer): remove dependency on the isolate.
124 256020 : if (bytes.start() == nullptr || bytes.length() == 0) return false;
125 : ModuleResult result =
126 256020 : DecodeWasmModule(enabled, bytes.start(), bytes.end(), true, kWasmOrigin,
127 256020 : isolate->counters(), allocator());
128 : return result.ok();
129 : }
130 :
131 2457 : 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 4914 : DecodeWasmModule(kAsmjsWasmFeatures, bytes.start(), bytes.end(), false,
137 4914 : kAsmJsOrigin, isolate->counters(), allocator());
138 2457 : 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::shared_ptr<NativeModule> native_module =
144 : CompileToNativeModule(isolate, kAsmjsWasmFeatures, thrower,
145 4914 : std::move(result).value(), bytes, &export_wrappers);
146 2457 : 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 2457 : isolate->factory()->NewByteArray(asm_js_offset_table_bytes.length());
152 : asm_js_offset_table->copy_in(0, asm_js_offset_table_bytes.start(),
153 : asm_js_offset_table_bytes.length());
154 :
155 : return AsmWasmData::New(isolate, std::move(native_module), export_wrappers,
156 4914 : asm_js_offset_table, uses_bitset);
157 : }
158 :
159 5010 : Handle<WasmModuleObject> WasmEngine::FinalizeTranslatedAsmJs(
160 : Isolate* isolate, Handle<AsmWasmData> asm_wasm_data,
161 : Handle<Script> script) {
162 : std::shared_ptr<NativeModule> native_module =
163 : asm_wasm_data->managed_native_module()->get();
164 : Handle<FixedArray> export_wrappers =
165 5010 : handle(asm_wasm_data->export_wrappers(), isolate);
166 : size_t code_size_estimate =
167 : wasm::WasmCodeManager::EstimateNativeModuleCodeSize(
168 5010 : native_module->module());
169 :
170 : Handle<WasmModuleObject> module_object =
171 : WasmModuleObject::New(isolate, std::move(native_module), script,
172 10020 : export_wrappers, code_size_estimate);
173 5010 : module_object->set_asm_js_offset_table(asm_wasm_data->asm_js_offset_table());
174 10020 : return module_object;
175 : }
176 :
177 151215 : MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
178 : Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
179 : const ModuleWireBytes& bytes) {
180 : ModuleResult result =
181 302442 : DecodeWasmModule(enabled, bytes.start(), bytes.end(), false, kWasmOrigin,
182 302451 : isolate->counters(), allocator());
183 151227 : if (result.failed()) {
184 : thrower->CompileFailed(result.error());
185 9074 : return {};
186 : }
187 :
188 : // Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
189 : // in {CompileToModuleObject}.
190 : Handle<FixedArray> export_wrappers;
191 : std::shared_ptr<NativeModule> native_module =
192 : CompileToNativeModule(isolate, enabled, thrower,
193 284306 : std::move(result).value(), bytes, &export_wrappers);
194 142153 : if (!native_module) return {};
195 :
196 : Handle<Script> script =
197 134640 : CreateWasmScript(isolate, bytes, native_module->module()->source_map_url);
198 : size_t code_size_estimate =
199 : wasm::WasmCodeManager::EstimateNativeModuleCodeSize(
200 134640 : 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 269280 : export_wrappers, code_size_estimate);
214 :
215 : // Finish the Wasm script now and make it public to the debugger.
216 134640 : isolate->debug()->OnAfterCompile(script);
217 134637 : return module_object;
218 : }
219 :
220 134198 : 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 136594 : memory);
226 : }
227 :
228 2396 : void WasmEngine::AsyncInstantiate(
229 : Isolate* isolate, std::unique_ptr<InstantiationResultResolver> resolver,
230 : Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports) {
231 1112 : 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 3508 : v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
237 2396 : catcher.SetVerbose(false);
238 2396 : catcher.SetCaptureMessage(false);
239 :
240 : MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
241 : isolate, &thrower, module_object, imports, Handle<JSArrayBuffer>::null());
242 :
243 2396 : if (!instance_object.is_null()) {
244 2568 : resolver->OnInstantiationSucceeded(instance_object.ToHandleChecked());
245 1284 : 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 : 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 : }
261 : }
262 :
263 2363 : void WasmEngine::AsyncCompile(
264 : Isolate* isolate, const WasmFeatures& enabled,
265 : std::shared_ptr<CompilationResultResolver> resolver,
266 : const ModuleWireBytes& bytes, bool is_shared) {
267 2363 : if (!FLAG_wasm_async_compilation) {
268 : // Asynchronous compilation disabled; fall back on synchronous compilation.
269 0 : 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 2363 : if (FLAG_wasm_test_streaming) {
291 : std::shared_ptr<StreamingDecoder> streaming_decoder =
292 : StartStreamingCompilation(isolate, enabled,
293 : handle(isolate->context(), isolate),
294 400 : std::move(resolver));
295 200 : streaming_decoder->OnBytesReceived(bytes.module_bytes());
296 200 : 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 2163 : std::unique_ptr<byte[]> copy(new byte[bytes.length()]);
302 : memcpy(copy.get(), bytes.start(), bytes.length());
303 :
304 4326 : AsyncCompileJob* job = CreateAsyncCompileJob(
305 : isolate, enabled, std::move(copy), bytes.length(),
306 2163 : handle(isolate->context(), isolate), std::move(resolver));
307 2163 : job->Start();
308 : }
309 :
310 380 : 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 760 : CreateAsyncCompileJob(isolate, enabled, std::unique_ptr<byte[]>(nullptr),
315 380 : 0, context, std::move(resolver));
316 380 : 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 32 : &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 155 : Handle<WasmModuleObject> WasmEngine::ImportNativeModule(
334 : Isolate* isolate, std::shared_ptr<NativeModule> shared_native_module) {
335 155 : 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 155 : CreateWasmScript(isolate, wire_bytes, module->source_map_url);
340 155 : size_t code_size = native_module->committed_code_space();
341 : Handle<WasmModuleObject> module_object = WasmModuleObject::New(
342 310 : isolate, std::move(shared_native_module), script, code_size);
343 310 : CompileJsToWasmWrappers(isolate, native_module->module(),
344 155 : handle(module_object->export_wrappers(), isolate));
345 : {
346 156 : 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 156 : 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 0 : 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 2543 : 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 10172 : context, std::move(resolver));
385 : // Pass ownership to the unique_ptr in {async_compile_jobs_}.
386 2543 : base::MutexGuard guard(&mutex_);
387 5086 : async_compile_jobs_[job] = std::unique_ptr<AsyncCompileJob>(job);
388 5086 : return job;
389 : }
390 :
391 2531 : std::unique_ptr<AsyncCompileJob> WasmEngine::RemoveCompileJob(
392 : AsyncCompileJob* job) {
393 2531 : 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 2531 : return result;
399 : }
400 :
401 54896 : bool WasmEngine::HasRunningCompileJob(Isolate* isolate) {
402 54896 : base::MutexGuard guard(&mutex_);
403 : DCHECK_EQ(1, isolates_.count(isolate));
404 54896 : for (auto& entry : async_compile_jobs_) {
405 2804 : if (entry.first->isolate() == isolate) return true;
406 : }
407 : return false;
408 : }
409 :
410 61528 : 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 61529 : std::vector<std::unique_ptr<AsyncCompileJob>> jobs_to_delete;
414 : {
415 61528 : base::MutexGuard guard(&mutex_);
416 : DCHECK_EQ(1, isolates_.count(isolate));
417 61543 : for (auto it = async_compile_jobs_.begin();
418 : it != async_compile_jobs_.end();) {
419 14 : if (it->first->isolate() != isolate) {
420 : ++it;
421 : continue;
422 : }
423 12 : jobs_to_delete.push_back(std::move(it->second));
424 : it = async_compile_jobs_.erase(it);
425 : }
426 : }
427 61529 : }
428 :
429 61534 : void WasmEngine::AddIsolate(Isolate* isolate) {
430 61534 : base::MutexGuard guard(&mutex_);
431 : DCHECK_EQ(0, isolates_.count(isolate));
432 61534 : 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 147886 : v8::GCCallbackFlags flags, void* data) {
440 73943 : Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
441 : Counters* counters = isolate->counters();
442 : WasmEngine* engine = isolate->wasm_engine();
443 73943 : base::MutexGuard lock(&engine->mutex_);
444 : DCHECK_EQ(1, engine->isolates_.count(isolate));
445 804569 : for (auto* native_module : engine->isolates_[isolate]->native_modules) {
446 730626 : native_module->SampleCodeSize(counters, NativeModule::kSampling);
447 : }
448 147886 : };
449 61534 : isolate->heap()->AddGCEpilogueCallback(callback, v8::kGCTypeMarkSweepCompact,
450 61534 : nullptr);
451 61534 : }
452 :
453 61517 : void WasmEngine::RemoveIsolate(Isolate* isolate) {
454 61517 : base::MutexGuard guard(&mutex_);
455 : auto it = isolates_.find(isolate);
456 : DCHECK_NE(isolates_.end(), it);
457 61691 : for (NativeModule* native_module : it->second->native_modules) {
458 : DCHECK_EQ(1, isolates_per_native_module_[native_module].count(isolate));
459 : isolates_per_native_module_[native_module].erase(isolate);
460 : }
461 61519 : if (auto* task = it->second->log_codes_task) task->Cancel();
462 : isolates_.erase(it);
463 61519 : }
464 :
465 203708 : void WasmEngine::LogCode(WasmCode* code) {
466 203708 : base::MutexGuard guard(&mutex_);
467 203708 : NativeModule* native_module = code->native_module();
468 : DCHECK_EQ(1, isolates_per_native_module_.count(native_module));
469 406659 : for (Isolate* isolate : isolates_per_native_module_[native_module]) {
470 : DCHECK_EQ(1, isolates_.count(isolate));
471 : IsolateInfo* info = isolates_[isolate].get();
472 202951 : if (info->log_codes == false) continue;
473 0 : if (info->log_codes_task == nullptr) {
474 : auto new_task = base::make_unique<LogCodesTask>(
475 0 : &mutex_, &info->log_codes_task, isolate);
476 0 : info->log_codes_task = new_task.get();
477 0 : info->foreground_task_runner->PostTask(std::move(new_task));
478 : }
479 0 : info->log_codes_task->AddCode(code);
480 : }
481 203708 : }
482 :
483 811 : void WasmEngine::EnableCodeLogging(Isolate* isolate) {
484 811 : base::MutexGuard guard(&mutex_);
485 : auto it = isolates_.find(isolate);
486 : DCHECK_NE(isolates_.end(), it);
487 811 : it->second->log_codes = true;
488 811 : }
489 :
490 1241892 : std::shared_ptr<NativeModule> WasmEngine::NewNativeModule(
491 : Isolate* isolate, const WasmFeatures& enabled, size_t code_size_estimate,
492 : bool can_request_more, std::shared_ptr<const WasmModule> module) {
493 : std::shared_ptr<NativeModule> native_module =
494 : code_manager_.NewNativeModule(this, isolate, enabled, code_size_estimate,
495 2483794 : can_request_more, std::move(module));
496 1241902 : base::MutexGuard lock(&mutex_);
497 2483804 : isolates_per_native_module_[native_module.get()].insert(isolate);
498 : DCHECK_EQ(1, isolates_.count(isolate));
499 2483804 : isolates_[isolate]->native_modules.insert(native_module.get());
500 1241902 : return native_module;
501 : }
502 :
503 1241901 : void WasmEngine::FreeNativeModule(NativeModule* native_module) {
504 : {
505 1241901 : base::MutexGuard guard(&mutex_);
506 : auto it = isolates_per_native_module_.find(native_module);
507 : DCHECK_NE(isolates_per_native_module_.end(), it);
508 2483784 : for (Isolate* isolate : it->second) {
509 : DCHECK_EQ(1, isolates_.count(isolate));
510 : DCHECK_EQ(1, isolates_[isolate]->native_modules.count(native_module));
511 : isolates_[isolate]->native_modules.erase(native_module);
512 : }
513 : isolates_per_native_module_.erase(it);
514 : }
515 1241902 : code_manager_.FreeNativeModule(native_module);
516 1241902 : }
517 :
518 : namespace {
519 1050 : class SampleTopTierCodeSizeTask : public CancelableTask {
520 : public:
521 : SampleTopTierCodeSizeTask(Isolate* isolate,
522 : std::weak_ptr<NativeModule> native_module)
523 : : CancelableTask(isolate),
524 : isolate_(isolate),
525 350 : native_module_(std::move(native_module)) {}
526 :
527 347 : void RunInternal() override {
528 347 : if (std::shared_ptr<NativeModule> native_module = native_module_.lock()) {
529 346 : native_module->SampleCodeSize(isolate_->counters(),
530 346 : NativeModule::kAfterTopTier);
531 : }
532 347 : }
533 :
534 : private:
535 : Isolate* const isolate_;
536 : const std::weak_ptr<NativeModule> native_module_;
537 : };
538 : } // namespace
539 :
540 351 : void WasmEngine::SampleTopTierCodeSizeInAllIsolates(
541 : const std::shared_ptr<NativeModule>& native_module) {
542 351 : base::MutexGuard lock(&mutex_);
543 : DCHECK_EQ(1, isolates_per_native_module_.count(native_module.get()));
544 702 : for (Isolate* isolate : isolates_per_native_module_[native_module.get()]) {
545 : DCHECK_EQ(1, isolates_.count(isolate));
546 : IsolateInfo* info = isolates_[isolate].get();
547 350 : info->foreground_task_runner->PostTask(
548 1050 : base::make_unique<SampleTopTierCodeSizeTask>(isolate, native_module));
549 : }
550 351 : }
551 :
552 : namespace {
553 :
554 240651 : DEFINE_LAZY_LEAKY_OBJECT_GETTER(std::shared_ptr<WasmEngine>,
555 : GetSharedWasmEngine)
556 :
557 : } // namespace
558 :
559 : // static
560 60106 : void WasmEngine::InitializeOncePerProcess() {
561 60106 : if (!FLAG_wasm_shared_engine) return;
562 120212 : *GetSharedWasmEngine() = std::make_shared<WasmEngine>();
563 : }
564 :
565 : // static
566 58997 : void WasmEngine::GlobalTearDown() {
567 58997 : if (!FLAG_wasm_shared_engine) return;
568 58997 : GetSharedWasmEngine()->reset();
569 : }
570 :
571 : // static
572 61450 : std::shared_ptr<WasmEngine> WasmEngine::GetWasmEngine() {
573 61450 : if (FLAG_wasm_shared_engine) return *GetSharedWasmEngine();
574 : return std::make_shared<WasmEngine>();
575 : }
576 :
577 : // {max_mem_pages} is declared in wasm-limits.h.
578 1654620 : uint32_t max_mem_pages() {
579 : STATIC_ASSERT(kV8MaxWasmMemoryPages <= kMaxUInt32);
580 3309240 : return std::min(uint32_t{kV8MaxWasmMemoryPages}, FLAG_wasm_max_mem_pages);
581 : }
582 :
583 : // {max_table_init_entries} is declared in wasm-limits.h.
584 6503 : uint32_t max_table_init_entries() {
585 : return std::min(uint32_t{kV8MaxWasmTableInitEntries},
586 13006 : FLAG_wasm_max_table_size);
587 : }
588 :
589 : } // namespace wasm
590 : } // namespace internal
591 120216 : } // namespace v8
|