11cb0ef41Sopenharmony_ci// Copyright 2018 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/wasm/wasm-engine.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/base/functional.h" 81cb0ef41Sopenharmony_ci#include "src/base/platform/time.h" 91cb0ef41Sopenharmony_ci#include "src/common/globals.h" 101cb0ef41Sopenharmony_ci#include "src/diagnostics/code-tracer.h" 111cb0ef41Sopenharmony_ci#include "src/diagnostics/compilation-statistics.h" 121cb0ef41Sopenharmony_ci#include "src/execution/frames.h" 131cb0ef41Sopenharmony_ci#include "src/execution/v8threads.h" 141cb0ef41Sopenharmony_ci#include "src/handles/global-handles-inl.h" 151cb0ef41Sopenharmony_ci#include "src/logging/counters.h" 161cb0ef41Sopenharmony_ci#include "src/logging/metrics.h" 171cb0ef41Sopenharmony_ci#include "src/objects/heap-number.h" 181cb0ef41Sopenharmony_ci#include "src/objects/js-promise.h" 191cb0ef41Sopenharmony_ci#include "src/objects/managed-inl.h" 201cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 211cb0ef41Sopenharmony_ci#include "src/strings/string-hasher-inl.h" 221cb0ef41Sopenharmony_ci#include "src/utils/ostreams.h" 231cb0ef41Sopenharmony_ci#include "src/wasm/function-compiler.h" 241cb0ef41Sopenharmony_ci#include "src/wasm/memory-protection-key.h" 251cb0ef41Sopenharmony_ci#include "src/wasm/module-compiler.h" 261cb0ef41Sopenharmony_ci#include "src/wasm/module-decoder.h" 271cb0ef41Sopenharmony_ci#include "src/wasm/module-instantiate.h" 281cb0ef41Sopenharmony_ci#include "src/wasm/streaming-decoder.h" 291cb0ef41Sopenharmony_ci#include "src/wasm/wasm-debug.h" 301cb0ef41Sopenharmony_ci#include "src/wasm/wasm-limits.h" 311cb0ef41Sopenharmony_ci#include "src/wasm/wasm-objects-inl.h" 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING 341cb0ef41Sopenharmony_ci#include "src/base/platform/wrappers.h" 351cb0ef41Sopenharmony_ci#include "src/debug/wasm/gdb-server/gdb-server.h" 361cb0ef41Sopenharmony_ci#endif // V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_cinamespace v8 { 391cb0ef41Sopenharmony_cinamespace internal { 401cb0ef41Sopenharmony_cinamespace wasm { 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci#define TRACE_CODE_GC(...) \ 431cb0ef41Sopenharmony_ci do { \ 441cb0ef41Sopenharmony_ci if (FLAG_trace_wasm_code_gc) PrintF("[wasm-gc] " __VA_ARGS__); \ 451cb0ef41Sopenharmony_ci } while (false) 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_cinamespace { 481cb0ef41Sopenharmony_ci// A task to log a set of {WasmCode} objects in an isolate. It does not own any 491cb0ef41Sopenharmony_ci// data itself, since it is owned by the platform, so lifetime is not really 501cb0ef41Sopenharmony_ci// bound to the wasm engine. 511cb0ef41Sopenharmony_ciclass LogCodesTask : public Task { 521cb0ef41Sopenharmony_ci public: 531cb0ef41Sopenharmony_ci LogCodesTask(base::Mutex* mutex, LogCodesTask** task_slot, Isolate* isolate, 541cb0ef41Sopenharmony_ci WasmEngine* engine) 551cb0ef41Sopenharmony_ci : mutex_(mutex), 561cb0ef41Sopenharmony_ci task_slot_(task_slot), 571cb0ef41Sopenharmony_ci isolate_(isolate), 581cb0ef41Sopenharmony_ci engine_(engine) { 591cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(task_slot); 601cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(isolate); 611cb0ef41Sopenharmony_ci } 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci ~LogCodesTask() override { 641cb0ef41Sopenharmony_ci // If the platform deletes this task before executing it, we also deregister 651cb0ef41Sopenharmony_ci // it to avoid use-after-free from still-running background threads. 661cb0ef41Sopenharmony_ci if (!cancelled()) DeregisterTask(); 671cb0ef41Sopenharmony_ci } 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci void Run() override { 701cb0ef41Sopenharmony_ci if (cancelled()) return; 711cb0ef41Sopenharmony_ci DeregisterTask(); 721cb0ef41Sopenharmony_ci engine_->LogOutstandingCodesForIsolate(isolate_); 731cb0ef41Sopenharmony_ci } 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci void Cancel() { 761cb0ef41Sopenharmony_ci // Cancel will only be called on Isolate shutdown, which happens on the 771cb0ef41Sopenharmony_ci // Isolate's foreground thread. Thus no synchronization needed. 781cb0ef41Sopenharmony_ci isolate_ = nullptr; 791cb0ef41Sopenharmony_ci } 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci bool cancelled() const { return isolate_ == nullptr; } 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci void DeregisterTask() { 841cb0ef41Sopenharmony_ci // The task will only be deregistered from the foreground thread (executing 851cb0ef41Sopenharmony_ci // this task or calling its destructor), thus we do not need synchronization 861cb0ef41Sopenharmony_ci // on this field access. 871cb0ef41Sopenharmony_ci if (task_slot_ == nullptr) return; // already deregistered. 881cb0ef41Sopenharmony_ci // Remove this task from the {IsolateInfo} in the engine. The next 891cb0ef41Sopenharmony_ci // logging request will allocate and schedule a new task. 901cb0ef41Sopenharmony_ci base::MutexGuard guard(mutex_); 911cb0ef41Sopenharmony_ci DCHECK_EQ(this, *task_slot_); 921cb0ef41Sopenharmony_ci *task_slot_ = nullptr; 931cb0ef41Sopenharmony_ci task_slot_ = nullptr; 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci private: 971cb0ef41Sopenharmony_ci // The mutex of the WasmEngine. 981cb0ef41Sopenharmony_ci base::Mutex* const mutex_; 991cb0ef41Sopenharmony_ci // The slot in the WasmEngine where this LogCodesTask is stored. This is 1001cb0ef41Sopenharmony_ci // cleared by this task before execution or on task destruction. 1011cb0ef41Sopenharmony_ci LogCodesTask** task_slot_; 1021cb0ef41Sopenharmony_ci Isolate* isolate_; 1031cb0ef41Sopenharmony_ci WasmEngine* const engine_; 1041cb0ef41Sopenharmony_ci}; 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_civoid CheckNoArchivedThreads(Isolate* isolate) { 1071cb0ef41Sopenharmony_ci class ArchivedThreadsVisitor : public ThreadVisitor { 1081cb0ef41Sopenharmony_ci void VisitThread(Isolate* isolate, ThreadLocalTop* top) override { 1091cb0ef41Sopenharmony_ci // Archived threads are rarely used, and not combined with Wasm at the 1101cb0ef41Sopenharmony_ci // moment. Implement this and test it properly once we have a use case for 1111cb0ef41Sopenharmony_ci // that. 1121cb0ef41Sopenharmony_ci FATAL("archived threads in combination with wasm not supported"); 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci } archived_threads_visitor; 1151cb0ef41Sopenharmony_ci isolate->thread_manager()->IterateArchivedThreads(&archived_threads_visitor); 1161cb0ef41Sopenharmony_ci} 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ciclass WasmGCForegroundTask : public CancelableTask { 1191cb0ef41Sopenharmony_ci public: 1201cb0ef41Sopenharmony_ci explicit WasmGCForegroundTask(Isolate* isolate) 1211cb0ef41Sopenharmony_ci : CancelableTask(isolate->cancelable_task_manager()), isolate_(isolate) {} 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci void RunInternal() final { 1241cb0ef41Sopenharmony_ci // The stack can contain live frames, for instance when this is invoked 1251cb0ef41Sopenharmony_ci // during a pause or a breakpoint. 1261cb0ef41Sopenharmony_ci GetWasmEngine()->ReportLiveCodeFromStackForGC(isolate_); 1271cb0ef41Sopenharmony_ci } 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci private: 1301cb0ef41Sopenharmony_ci Isolate* isolate_; 1311cb0ef41Sopenharmony_ci}; 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ciclass WeakScriptHandle { 1341cb0ef41Sopenharmony_ci public: 1351cb0ef41Sopenharmony_ci explicit WeakScriptHandle(Handle<Script> script) : script_id_(script->id()) { 1361cb0ef41Sopenharmony_ci DCHECK(script->name().IsString() || script->name().IsUndefined()); 1371cb0ef41Sopenharmony_ci if (script->name().IsString()) { 1381cb0ef41Sopenharmony_ci std::unique_ptr<char[]> source_url = 1391cb0ef41Sopenharmony_ci String::cast(script->name()).ToCString(); 1401cb0ef41Sopenharmony_ci // Convert from {unique_ptr} to {shared_ptr}. 1411cb0ef41Sopenharmony_ci source_url_ = {source_url.release(), source_url.get_deleter()}; 1421cb0ef41Sopenharmony_ci } 1431cb0ef41Sopenharmony_ci auto global_handle = 1441cb0ef41Sopenharmony_ci script->GetIsolate()->global_handles()->Create(*script); 1451cb0ef41Sopenharmony_ci location_ = std::make_unique<Address*>(global_handle.location()); 1461cb0ef41Sopenharmony_ci GlobalHandles::MakeWeak(location_.get()); 1471cb0ef41Sopenharmony_ci } 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci // Usually the destructor of this class should always be called after the weak 1501cb0ef41Sopenharmony_ci // callback because the Script keeps the NativeModule alive. So we expect the 1511cb0ef41Sopenharmony_ci // handle to be destroyed and the location to be reset already. 1521cb0ef41Sopenharmony_ci // We cannot check this because of one exception. When the native module is 1531cb0ef41Sopenharmony_ci // freed during isolate shutdown, the destructor will be called 1541cb0ef41Sopenharmony_ci // first, and the callback will never be called. 1551cb0ef41Sopenharmony_ci ~WeakScriptHandle() = default; 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci WeakScriptHandle(WeakScriptHandle&&) V8_NOEXCEPT = default; 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci Handle<Script> handle() const { return Handle<Script>(*location_); } 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci int script_id() const { return script_id_; } 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci const std::shared_ptr<const char>& source_url() const { return source_url_; } 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci private: 1661cb0ef41Sopenharmony_ci // Store the location in a unique_ptr so that its address stays the same even 1671cb0ef41Sopenharmony_ci // when this object is moved/copied. 1681cb0ef41Sopenharmony_ci std::unique_ptr<Address*> location_; 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_ci // Store the script ID independent of the weak handle, such that it's always 1711cb0ef41Sopenharmony_ci // available. 1721cb0ef41Sopenharmony_ci int script_id_; 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci // Similar for the source URL. We cannot dereference the Handle from arbitrary 1751cb0ef41Sopenharmony_ci // threads, but we need the URL available for code logging. 1761cb0ef41Sopenharmony_ci // The shared pointer is kept alive by unlogged code, even if this entry is 1771cb0ef41Sopenharmony_ci // collected in the meantime. 1781cb0ef41Sopenharmony_ci // TODO(chromium:1132260): Revisit this for huge URLs. 1791cb0ef41Sopenharmony_ci std::shared_ptr<const char> source_url_; 1801cb0ef41Sopenharmony_ci}; 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci} // namespace 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_cistd::shared_ptr<NativeModule> NativeModuleCache::MaybeGetNativeModule( 1851cb0ef41Sopenharmony_ci ModuleOrigin origin, base::Vector<const uint8_t> wire_bytes) { 1861cb0ef41Sopenharmony_ci if (origin != kWasmOrigin) return nullptr; 1871cb0ef41Sopenharmony_ci base::MutexGuard lock(&mutex_); 1881cb0ef41Sopenharmony_ci size_t prefix_hash = PrefixHash(wire_bytes); 1891cb0ef41Sopenharmony_ci NativeModuleCache::Key key{prefix_hash, wire_bytes}; 1901cb0ef41Sopenharmony_ci while (true) { 1911cb0ef41Sopenharmony_ci auto it = map_.find(key); 1921cb0ef41Sopenharmony_ci if (it == map_.end()) { 1931cb0ef41Sopenharmony_ci // Even though this exact key is not in the cache, there might be a 1941cb0ef41Sopenharmony_ci // matching prefix hash indicating that a streaming compilation is 1951cb0ef41Sopenharmony_ci // currently compiling a module with the same prefix. {OnFinishedStream} 1961cb0ef41Sopenharmony_ci // happens on the main thread too, so waiting for streaming compilation to 1971cb0ef41Sopenharmony_ci // finish would create a deadlock. Instead, compile the module twice and 1981cb0ef41Sopenharmony_ci // handle the conflict in {UpdateNativeModuleCache}. 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci // Insert a {nullopt} entry to let other threads know that this 2011cb0ef41Sopenharmony_ci // {NativeModule} is already being created on another thread. 2021cb0ef41Sopenharmony_ci auto p = map_.emplace(key, base::nullopt); 2031cb0ef41Sopenharmony_ci USE(p); 2041cb0ef41Sopenharmony_ci DCHECK(p.second); 2051cb0ef41Sopenharmony_ci return nullptr; 2061cb0ef41Sopenharmony_ci } 2071cb0ef41Sopenharmony_ci if (it->second.has_value()) { 2081cb0ef41Sopenharmony_ci if (auto shared_native_module = it->second.value().lock()) { 2091cb0ef41Sopenharmony_ci DCHECK_EQ(shared_native_module->wire_bytes(), wire_bytes); 2101cb0ef41Sopenharmony_ci return shared_native_module; 2111cb0ef41Sopenharmony_ci } 2121cb0ef41Sopenharmony_ci } 2131cb0ef41Sopenharmony_ci // TODO(11858): This deadlocks in predictable mode, because there is only a 2141cb0ef41Sopenharmony_ci // single thread. 2151cb0ef41Sopenharmony_ci cache_cv_.Wait(&mutex_); 2161cb0ef41Sopenharmony_ci } 2171cb0ef41Sopenharmony_ci} 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_cibool NativeModuleCache::GetStreamingCompilationOwnership(size_t prefix_hash) { 2201cb0ef41Sopenharmony_ci base::MutexGuard lock(&mutex_); 2211cb0ef41Sopenharmony_ci auto it = map_.lower_bound(Key{prefix_hash, {}}); 2221cb0ef41Sopenharmony_ci if (it != map_.end() && it->first.prefix_hash == prefix_hash) { 2231cb0ef41Sopenharmony_ci DCHECK_IMPLIES(!it->first.bytes.empty(), 2241cb0ef41Sopenharmony_ci PrefixHash(it->first.bytes) == prefix_hash); 2251cb0ef41Sopenharmony_ci return false; 2261cb0ef41Sopenharmony_ci } 2271cb0ef41Sopenharmony_ci Key key{prefix_hash, {}}; 2281cb0ef41Sopenharmony_ci DCHECK_EQ(0, map_.count(key)); 2291cb0ef41Sopenharmony_ci map_.emplace(key, base::nullopt); 2301cb0ef41Sopenharmony_ci return true; 2311cb0ef41Sopenharmony_ci} 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_civoid NativeModuleCache::StreamingCompilationFailed(size_t prefix_hash) { 2341cb0ef41Sopenharmony_ci base::MutexGuard lock(&mutex_); 2351cb0ef41Sopenharmony_ci Key key{prefix_hash, {}}; 2361cb0ef41Sopenharmony_ci DCHECK_EQ(1, map_.count(key)); 2371cb0ef41Sopenharmony_ci map_.erase(key); 2381cb0ef41Sopenharmony_ci cache_cv_.NotifyAll(); 2391cb0ef41Sopenharmony_ci} 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_cistd::shared_ptr<NativeModule> NativeModuleCache::Update( 2421cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module, bool error) { 2431cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(native_module); 2441cb0ef41Sopenharmony_ci if (native_module->module()->origin != kWasmOrigin) return native_module; 2451cb0ef41Sopenharmony_ci base::Vector<const uint8_t> wire_bytes = native_module->wire_bytes(); 2461cb0ef41Sopenharmony_ci DCHECK(!wire_bytes.empty()); 2471cb0ef41Sopenharmony_ci size_t prefix_hash = PrefixHash(native_module->wire_bytes()); 2481cb0ef41Sopenharmony_ci base::MutexGuard lock(&mutex_); 2491cb0ef41Sopenharmony_ci map_.erase(Key{prefix_hash, {}}); 2501cb0ef41Sopenharmony_ci const Key key{prefix_hash, wire_bytes}; 2511cb0ef41Sopenharmony_ci auto it = map_.find(key); 2521cb0ef41Sopenharmony_ci if (it != map_.end()) { 2531cb0ef41Sopenharmony_ci if (it->second.has_value()) { 2541cb0ef41Sopenharmony_ci auto conflicting_module = it->second.value().lock(); 2551cb0ef41Sopenharmony_ci if (conflicting_module != nullptr) { 2561cb0ef41Sopenharmony_ci DCHECK_EQ(conflicting_module->wire_bytes(), wire_bytes); 2571cb0ef41Sopenharmony_ci return conflicting_module; 2581cb0ef41Sopenharmony_ci } 2591cb0ef41Sopenharmony_ci } 2601cb0ef41Sopenharmony_ci map_.erase(it); 2611cb0ef41Sopenharmony_ci } 2621cb0ef41Sopenharmony_ci if (!error) { 2631cb0ef41Sopenharmony_ci // The key now points to the new native module's owned copy of the bytes, 2641cb0ef41Sopenharmony_ci // so that it stays valid until the native module is freed and erased from 2651cb0ef41Sopenharmony_ci // the map. 2661cb0ef41Sopenharmony_ci auto p = map_.emplace( 2671cb0ef41Sopenharmony_ci key, base::Optional<std::weak_ptr<NativeModule>>(native_module)); 2681cb0ef41Sopenharmony_ci USE(p); 2691cb0ef41Sopenharmony_ci DCHECK(p.second); 2701cb0ef41Sopenharmony_ci } 2711cb0ef41Sopenharmony_ci cache_cv_.NotifyAll(); 2721cb0ef41Sopenharmony_ci return native_module; 2731cb0ef41Sopenharmony_ci} 2741cb0ef41Sopenharmony_ci 2751cb0ef41Sopenharmony_civoid NativeModuleCache::Erase(NativeModule* native_module) { 2761cb0ef41Sopenharmony_ci if (native_module->module()->origin != kWasmOrigin) return; 2771cb0ef41Sopenharmony_ci // Happens in some tests where bytes are set directly. 2781cb0ef41Sopenharmony_ci if (native_module->wire_bytes().empty()) return; 2791cb0ef41Sopenharmony_ci base::MutexGuard lock(&mutex_); 2801cb0ef41Sopenharmony_ci size_t prefix_hash = PrefixHash(native_module->wire_bytes()); 2811cb0ef41Sopenharmony_ci map_.erase(Key{prefix_hash, native_module->wire_bytes()}); 2821cb0ef41Sopenharmony_ci cache_cv_.NotifyAll(); 2831cb0ef41Sopenharmony_ci} 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_ci// static 2861cb0ef41Sopenharmony_cisize_t NativeModuleCache::WireBytesHash(base::Vector<const uint8_t> bytes) { 2871cb0ef41Sopenharmony_ci return StringHasher::HashSequentialString( 2881cb0ef41Sopenharmony_ci reinterpret_cast<const char*>(bytes.begin()), bytes.length(), 2891cb0ef41Sopenharmony_ci kZeroHashSeed); 2901cb0ef41Sopenharmony_ci} 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ci// static 2931cb0ef41Sopenharmony_cisize_t NativeModuleCache::PrefixHash(base::Vector<const uint8_t> wire_bytes) { 2941cb0ef41Sopenharmony_ci // Compute the hash as a combined hash of the sections up to the code section 2951cb0ef41Sopenharmony_ci // header, to mirror the way streaming compilation does it. 2961cb0ef41Sopenharmony_ci Decoder decoder(wire_bytes.begin(), wire_bytes.end()); 2971cb0ef41Sopenharmony_ci decoder.consume_bytes(8, "module header"); 2981cb0ef41Sopenharmony_ci size_t hash = NativeModuleCache::WireBytesHash(wire_bytes.SubVector(0, 8)); 2991cb0ef41Sopenharmony_ci SectionCode section_id = SectionCode::kUnknownSectionCode; 3001cb0ef41Sopenharmony_ci while (decoder.ok() && decoder.more()) { 3011cb0ef41Sopenharmony_ci section_id = static_cast<SectionCode>(decoder.consume_u8()); 3021cb0ef41Sopenharmony_ci uint32_t section_size = decoder.consume_u32v("section size"); 3031cb0ef41Sopenharmony_ci if (section_id == SectionCode::kCodeSectionCode) { 3041cb0ef41Sopenharmony_ci uint32_t num_functions = decoder.consume_u32v("num functions"); 3051cb0ef41Sopenharmony_ci // If {num_functions} is 0, the streaming decoder skips the section. Do 3061cb0ef41Sopenharmony_ci // the same here to ensure hashes are consistent. 3071cb0ef41Sopenharmony_ci if (num_functions != 0) { 3081cb0ef41Sopenharmony_ci hash = base::hash_combine(hash, section_size); 3091cb0ef41Sopenharmony_ci } 3101cb0ef41Sopenharmony_ci break; 3111cb0ef41Sopenharmony_ci } 3121cb0ef41Sopenharmony_ci const uint8_t* payload_start = decoder.pc(); 3131cb0ef41Sopenharmony_ci decoder.consume_bytes(section_size, "section payload"); 3141cb0ef41Sopenharmony_ci size_t section_hash = NativeModuleCache::WireBytesHash( 3151cb0ef41Sopenharmony_ci base::Vector<const uint8_t>(payload_start, section_size)); 3161cb0ef41Sopenharmony_ci hash = base::hash_combine(hash, section_hash); 3171cb0ef41Sopenharmony_ci } 3181cb0ef41Sopenharmony_ci return hash; 3191cb0ef41Sopenharmony_ci} 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_cistruct WasmEngine::CurrentGCInfo { 3221cb0ef41Sopenharmony_ci explicit CurrentGCInfo(int8_t gc_sequence_index) 3231cb0ef41Sopenharmony_ci : gc_sequence_index(gc_sequence_index) { 3241cb0ef41Sopenharmony_ci DCHECK_NE(0, gc_sequence_index); 3251cb0ef41Sopenharmony_ci } 3261cb0ef41Sopenharmony_ci 3271cb0ef41Sopenharmony_ci // Set of isolates that did not scan their stack yet for used WasmCode, and 3281cb0ef41Sopenharmony_ci // their scheduled foreground task. 3291cb0ef41Sopenharmony_ci std::unordered_map<Isolate*, WasmGCForegroundTask*> outstanding_isolates; 3301cb0ef41Sopenharmony_ci 3311cb0ef41Sopenharmony_ci // Set of dead code. Filled with all potentially dead code on initialization. 3321cb0ef41Sopenharmony_ci // Code that is still in-use is removed by the individual isolates. 3331cb0ef41Sopenharmony_ci std::unordered_set<WasmCode*> dead_code; 3341cb0ef41Sopenharmony_ci 3351cb0ef41Sopenharmony_ci // The number of GCs triggered in the native module that triggered this GC. 3361cb0ef41Sopenharmony_ci // This is stored in the histogram for each participating isolate during 3371cb0ef41Sopenharmony_ci // execution of that isolate's foreground task. 3381cb0ef41Sopenharmony_ci const int8_t gc_sequence_index; 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci // If during this GC, another GC was requested, we skipped that other GC (we 3411cb0ef41Sopenharmony_ci // only run one GC at a time). Remember though to trigger another one once 3421cb0ef41Sopenharmony_ci // this one finishes. {next_gc_sequence_index} is 0 if no next GC is needed, 3431cb0ef41Sopenharmony_ci // and >0 otherwise. It stores the {num_code_gcs_triggered} of the native 3441cb0ef41Sopenharmony_ci // module which triggered the next GC. 3451cb0ef41Sopenharmony_ci int8_t next_gc_sequence_index = 0; 3461cb0ef41Sopenharmony_ci 3471cb0ef41Sopenharmony_ci // The start time of this GC; used for tracing and sampled via {Counters}. 3481cb0ef41Sopenharmony_ci // Can be null ({TimeTicks::IsNull()}) if timer is not high resolution. 3491cb0ef41Sopenharmony_ci base::TimeTicks start_time; 3501cb0ef41Sopenharmony_ci}; 3511cb0ef41Sopenharmony_ci 3521cb0ef41Sopenharmony_cistruct WasmEngine::IsolateInfo { 3531cb0ef41Sopenharmony_ci explicit IsolateInfo(Isolate* isolate) 3541cb0ef41Sopenharmony_ci : log_codes(WasmCode::ShouldBeLogged(isolate)), 3551cb0ef41Sopenharmony_ci async_counters(isolate->async_counters()), 3561cb0ef41Sopenharmony_ci wrapper_compilation_barrier_(std::make_shared<OperationsBarrier>()) { 3571cb0ef41Sopenharmony_ci v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 3581cb0ef41Sopenharmony_ci v8::Platform* platform = V8::GetCurrentPlatform(); 3591cb0ef41Sopenharmony_ci foreground_task_runner = platform->GetForegroundTaskRunner(v8_isolate); 3601cb0ef41Sopenharmony_ci } 3611cb0ef41Sopenharmony_ci 3621cb0ef41Sopenharmony_ci#ifdef DEBUG 3631cb0ef41Sopenharmony_ci ~IsolateInfo() { 3641cb0ef41Sopenharmony_ci // Before destructing, the {WasmEngine} must have cleared outstanding code 3651cb0ef41Sopenharmony_ci // to log. 3661cb0ef41Sopenharmony_ci DCHECK_EQ(0, code_to_log.size()); 3671cb0ef41Sopenharmony_ci } 3681cb0ef41Sopenharmony_ci#endif 3691cb0ef41Sopenharmony_ci 3701cb0ef41Sopenharmony_ci // All native modules that are being used by this Isolate. 3711cb0ef41Sopenharmony_ci std::unordered_set<NativeModule*> native_modules; 3721cb0ef41Sopenharmony_ci 3731cb0ef41Sopenharmony_ci // Scripts created for each native module in this isolate. 3741cb0ef41Sopenharmony_ci std::unordered_map<NativeModule*, WeakScriptHandle> scripts; 3751cb0ef41Sopenharmony_ci 3761cb0ef41Sopenharmony_ci // Caches whether code needs to be logged on this isolate. 3771cb0ef41Sopenharmony_ci bool log_codes; 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_ci // The currently scheduled LogCodesTask. 3801cb0ef41Sopenharmony_ci LogCodesTask* log_codes_task = nullptr; 3811cb0ef41Sopenharmony_ci 3821cb0ef41Sopenharmony_ci // Maps script ID to vector of code objects that still need to be logged, and 3831cb0ef41Sopenharmony_ci // the respective source URL. 3841cb0ef41Sopenharmony_ci struct CodeToLogPerScript { 3851cb0ef41Sopenharmony_ci std::vector<WasmCode*> code; 3861cb0ef41Sopenharmony_ci std::shared_ptr<const char> source_url; 3871cb0ef41Sopenharmony_ci }; 3881cb0ef41Sopenharmony_ci std::unordered_map<int, CodeToLogPerScript> code_to_log; 3891cb0ef41Sopenharmony_ci 3901cb0ef41Sopenharmony_ci // The foreground task runner of the isolate (can be called from background). 3911cb0ef41Sopenharmony_ci std::shared_ptr<v8::TaskRunner> foreground_task_runner; 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_ci const std::shared_ptr<Counters> async_counters; 3941cb0ef41Sopenharmony_ci 3951cb0ef41Sopenharmony_ci // Keep new modules in tiered down state. 3961cb0ef41Sopenharmony_ci bool keep_tiered_down = false; 3971cb0ef41Sopenharmony_ci 3981cb0ef41Sopenharmony_ci // Keep track whether we already added a sample for PKU support (we only want 3991cb0ef41Sopenharmony_ci // one sample per Isolate). 4001cb0ef41Sopenharmony_ci bool pku_support_sampled = false; 4011cb0ef41Sopenharmony_ci 4021cb0ef41Sopenharmony_ci // Elapsed time since last throw/rethrow/catch event. 4031cb0ef41Sopenharmony_ci base::ElapsedTimer throw_timer; 4041cb0ef41Sopenharmony_ci base::ElapsedTimer rethrow_timer; 4051cb0ef41Sopenharmony_ci base::ElapsedTimer catch_timer; 4061cb0ef41Sopenharmony_ci 4071cb0ef41Sopenharmony_ci // Total number of exception events in this isolate. 4081cb0ef41Sopenharmony_ci int throw_count = 0; 4091cb0ef41Sopenharmony_ci int rethrow_count = 0; 4101cb0ef41Sopenharmony_ci int catch_count = 0; 4111cb0ef41Sopenharmony_ci 4121cb0ef41Sopenharmony_ci // Operations barrier to synchronize on wrapper compilation on isolate 4131cb0ef41Sopenharmony_ci // shutdown. 4141cb0ef41Sopenharmony_ci // TODO(wasm): Remove this once we can use the generic js-to-wasm wrapper 4151cb0ef41Sopenharmony_ci // everywhere. 4161cb0ef41Sopenharmony_ci std::shared_ptr<OperationsBarrier> wrapper_compilation_barrier_; 4171cb0ef41Sopenharmony_ci}; 4181cb0ef41Sopenharmony_ci 4191cb0ef41Sopenharmony_cistruct WasmEngine::NativeModuleInfo { 4201cb0ef41Sopenharmony_ci explicit NativeModuleInfo(std::weak_ptr<NativeModule> native_module) 4211cb0ef41Sopenharmony_ci : weak_ptr(std::move(native_module)) {} 4221cb0ef41Sopenharmony_ci 4231cb0ef41Sopenharmony_ci // Weak pointer, to gain back a shared_ptr if needed. 4241cb0ef41Sopenharmony_ci std::weak_ptr<NativeModule> weak_ptr; 4251cb0ef41Sopenharmony_ci 4261cb0ef41Sopenharmony_ci // Set of isolates using this NativeModule. 4271cb0ef41Sopenharmony_ci std::unordered_set<Isolate*> isolates; 4281cb0ef41Sopenharmony_ci 4291cb0ef41Sopenharmony_ci // Set of potentially dead code. This set holds one ref for each code object, 4301cb0ef41Sopenharmony_ci // until code is detected to be really dead. At that point, the ref count is 4311cb0ef41Sopenharmony_ci // decremented and code is move to the {dead_code} set. If the code is finally 4321cb0ef41Sopenharmony_ci // deleted, it is also removed from {dead_code}. 4331cb0ef41Sopenharmony_ci std::unordered_set<WasmCode*> potentially_dead_code; 4341cb0ef41Sopenharmony_ci 4351cb0ef41Sopenharmony_ci // Code that is not being executed in any isolate any more, but the ref count 4361cb0ef41Sopenharmony_ci // did not drop to zero yet. 4371cb0ef41Sopenharmony_ci std::unordered_set<WasmCode*> dead_code; 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_ci // Number of code GCs triggered because code in this native module became 4401cb0ef41Sopenharmony_ci // potentially dead. 4411cb0ef41Sopenharmony_ci int8_t num_code_gcs_triggered = 0; 4421cb0ef41Sopenharmony_ci}; 4431cb0ef41Sopenharmony_ci 4441cb0ef41Sopenharmony_ciWasmEngine::WasmEngine() = default; 4451cb0ef41Sopenharmony_ci 4461cb0ef41Sopenharmony_ciWasmEngine::~WasmEngine() { 4471cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING 4481cb0ef41Sopenharmony_ci // Synchronize on the GDB-remote thread, if running. 4491cb0ef41Sopenharmony_ci gdb_server_.reset(); 4501cb0ef41Sopenharmony_ci#endif // V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING 4511cb0ef41Sopenharmony_ci 4521cb0ef41Sopenharmony_ci operations_barrier_->CancelAndWait(); 4531cb0ef41Sopenharmony_ci 4541cb0ef41Sopenharmony_ci // All AsyncCompileJobs have been canceled. 4551cb0ef41Sopenharmony_ci DCHECK(async_compile_jobs_.empty()); 4561cb0ef41Sopenharmony_ci // All Isolates have been deregistered. 4571cb0ef41Sopenharmony_ci DCHECK(isolates_.empty()); 4581cb0ef41Sopenharmony_ci // All NativeModules did die. 4591cb0ef41Sopenharmony_ci DCHECK(native_modules_.empty()); 4601cb0ef41Sopenharmony_ci // Native module cache does not leak. 4611cb0ef41Sopenharmony_ci DCHECK(native_module_cache_.empty()); 4621cb0ef41Sopenharmony_ci} 4631cb0ef41Sopenharmony_ci 4641cb0ef41Sopenharmony_cibool WasmEngine::SyncValidate(Isolate* isolate, const WasmFeatures& enabled, 4651cb0ef41Sopenharmony_ci const ModuleWireBytes& bytes, 4661cb0ef41Sopenharmony_ci std::string* error_message) { 4671cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "wasm.SyncValidate"); 4681cb0ef41Sopenharmony_ci // TODO(titzer): remove dependency on the isolate. 4691cb0ef41Sopenharmony_ci if (bytes.start() == nullptr || bytes.length() == 0) { 4701cb0ef41Sopenharmony_ci if (error_message) *error_message = "empty module wire bytes"; 4711cb0ef41Sopenharmony_ci return false; 4721cb0ef41Sopenharmony_ci } 4731cb0ef41Sopenharmony_ci auto result = DecodeWasmModule( 4741cb0ef41Sopenharmony_ci enabled, bytes.start(), bytes.end(), true, kWasmOrigin, 4751cb0ef41Sopenharmony_ci isolate->counters(), isolate->metrics_recorder(), 4761cb0ef41Sopenharmony_ci isolate->GetOrRegisterRecorderContextId(isolate->native_context()), 4771cb0ef41Sopenharmony_ci DecodingMethod::kSync, allocator()); 4781cb0ef41Sopenharmony_ci if (result.failed() && error_message) { 4791cb0ef41Sopenharmony_ci *error_message = result.error().message(); 4801cb0ef41Sopenharmony_ci } 4811cb0ef41Sopenharmony_ci return result.ok(); 4821cb0ef41Sopenharmony_ci} 4831cb0ef41Sopenharmony_ci 4841cb0ef41Sopenharmony_ciMaybeHandle<AsmWasmData> WasmEngine::SyncCompileTranslatedAsmJs( 4851cb0ef41Sopenharmony_ci Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes, 4861cb0ef41Sopenharmony_ci base::Vector<const byte> asm_js_offset_table_bytes, 4871cb0ef41Sopenharmony_ci Handle<HeapNumber> uses_bitset, LanguageMode language_mode) { 4881cb0ef41Sopenharmony_ci int compilation_id = next_compilation_id_.fetch_add(1); 4891cb0ef41Sopenharmony_ci TRACE_EVENT1("v8.wasm", "wasm.SyncCompileTranslatedAsmJs", "id", 4901cb0ef41Sopenharmony_ci compilation_id); 4911cb0ef41Sopenharmony_ci ModuleOrigin origin = language_mode == LanguageMode::kSloppy 4921cb0ef41Sopenharmony_ci ? kAsmJsSloppyOrigin 4931cb0ef41Sopenharmony_ci : kAsmJsStrictOrigin; 4941cb0ef41Sopenharmony_ci // TODO(leszeks): If we want asm.js in UKM, we should figure out a way to pass 4951cb0ef41Sopenharmony_ci // the context id in here. 4961cb0ef41Sopenharmony_ci v8::metrics::Recorder::ContextId context_id = 4971cb0ef41Sopenharmony_ci v8::metrics::Recorder::ContextId::Empty(); 4981cb0ef41Sopenharmony_ci ModuleResult result = DecodeWasmModule( 4991cb0ef41Sopenharmony_ci WasmFeatures::ForAsmjs(), bytes.start(), bytes.end(), false, origin, 5001cb0ef41Sopenharmony_ci isolate->counters(), isolate->metrics_recorder(), context_id, 5011cb0ef41Sopenharmony_ci DecodingMethod::kSync, allocator()); 5021cb0ef41Sopenharmony_ci if (result.failed()) { 5031cb0ef41Sopenharmony_ci // This happens once in a while when we have missed some limit check 5041cb0ef41Sopenharmony_ci // in the asm parser. Output an error message to help diagnose, but crash. 5051cb0ef41Sopenharmony_ci std::cout << result.error().message(); 5061cb0ef41Sopenharmony_ci UNREACHABLE(); 5071cb0ef41Sopenharmony_ci } 5081cb0ef41Sopenharmony_ci 5091cb0ef41Sopenharmony_ci result.value()->asm_js_offset_information = 5101cb0ef41Sopenharmony_ci std::make_unique<AsmJsOffsetInformation>(asm_js_offset_table_bytes); 5111cb0ef41Sopenharmony_ci 5121cb0ef41Sopenharmony_ci // Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated 5131cb0ef41Sopenharmony_ci // in {CompileToNativeModule}. 5141cb0ef41Sopenharmony_ci Handle<FixedArray> export_wrappers; 5151cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module = CompileToNativeModule( 5161cb0ef41Sopenharmony_ci isolate, WasmFeatures::ForAsmjs(), thrower, std::move(result).value(), 5171cb0ef41Sopenharmony_ci bytes, &export_wrappers, compilation_id, context_id); 5181cb0ef41Sopenharmony_ci if (!native_module) return {}; 5191cb0ef41Sopenharmony_ci 5201cb0ef41Sopenharmony_ci return AsmWasmData::New(isolate, std::move(native_module), export_wrappers, 5211cb0ef41Sopenharmony_ci uses_bitset); 5221cb0ef41Sopenharmony_ci} 5231cb0ef41Sopenharmony_ci 5241cb0ef41Sopenharmony_ciHandle<WasmModuleObject> WasmEngine::FinalizeTranslatedAsmJs( 5251cb0ef41Sopenharmony_ci Isolate* isolate, Handle<AsmWasmData> asm_wasm_data, 5261cb0ef41Sopenharmony_ci Handle<Script> script) { 5271cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module = 5281cb0ef41Sopenharmony_ci asm_wasm_data->managed_native_module().get(); 5291cb0ef41Sopenharmony_ci Handle<FixedArray> export_wrappers = 5301cb0ef41Sopenharmony_ci handle(asm_wasm_data->export_wrappers(), isolate); 5311cb0ef41Sopenharmony_ci Handle<WasmModuleObject> module_object = WasmModuleObject::New( 5321cb0ef41Sopenharmony_ci isolate, std::move(native_module), script, export_wrappers); 5331cb0ef41Sopenharmony_ci return module_object; 5341cb0ef41Sopenharmony_ci} 5351cb0ef41Sopenharmony_ci 5361cb0ef41Sopenharmony_ciMaybeHandle<WasmModuleObject> WasmEngine::SyncCompile( 5371cb0ef41Sopenharmony_ci Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower, 5381cb0ef41Sopenharmony_ci const ModuleWireBytes& bytes) { 5391cb0ef41Sopenharmony_ci int compilation_id = next_compilation_id_.fetch_add(1); 5401cb0ef41Sopenharmony_ci TRACE_EVENT1("v8.wasm", "wasm.SyncCompile", "id", compilation_id); 5411cb0ef41Sopenharmony_ci v8::metrics::Recorder::ContextId context_id = 5421cb0ef41Sopenharmony_ci isolate->GetOrRegisterRecorderContextId(isolate->native_context()); 5431cb0ef41Sopenharmony_ci ModuleResult result = 5441cb0ef41Sopenharmony_ci DecodeWasmModule(enabled, bytes.start(), bytes.end(), false, kWasmOrigin, 5451cb0ef41Sopenharmony_ci isolate->counters(), isolate->metrics_recorder(), 5461cb0ef41Sopenharmony_ci context_id, DecodingMethod::kSync, allocator()); 5471cb0ef41Sopenharmony_ci if (result.failed()) { 5481cb0ef41Sopenharmony_ci thrower->CompileFailed(result.error()); 5491cb0ef41Sopenharmony_ci return {}; 5501cb0ef41Sopenharmony_ci } 5511cb0ef41Sopenharmony_ci 5521cb0ef41Sopenharmony_ci // Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated 5531cb0ef41Sopenharmony_ci // in {CompileToNativeModule}. 5541cb0ef41Sopenharmony_ci Handle<FixedArray> export_wrappers; 5551cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module = CompileToNativeModule( 5561cb0ef41Sopenharmony_ci isolate, enabled, thrower, std::move(result).value(), bytes, 5571cb0ef41Sopenharmony_ci &export_wrappers, compilation_id, context_id); 5581cb0ef41Sopenharmony_ci if (!native_module) return {}; 5591cb0ef41Sopenharmony_ci 5601cb0ef41Sopenharmony_ci#ifdef DEBUG 5611cb0ef41Sopenharmony_ci // Ensure that code GC will check this isolate for live code. 5621cb0ef41Sopenharmony_ci { 5631cb0ef41Sopenharmony_ci base::MutexGuard lock(&mutex_); 5641cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 5651cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_[isolate]->native_modules.count(native_module.get())); 5661cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_.count(native_module.get())); 5671cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_[native_module.get()]->isolates.count(isolate)); 5681cb0ef41Sopenharmony_ci } 5691cb0ef41Sopenharmony_ci#endif 5701cb0ef41Sopenharmony_ci 5711cb0ef41Sopenharmony_ci constexpr base::Vector<const char> kNoSourceUrl; 5721cb0ef41Sopenharmony_ci Handle<Script> script = 5731cb0ef41Sopenharmony_ci GetOrCreateScript(isolate, native_module, kNoSourceUrl); 5741cb0ef41Sopenharmony_ci 5751cb0ef41Sopenharmony_ci native_module->LogWasmCodes(isolate, *script); 5761cb0ef41Sopenharmony_ci 5771cb0ef41Sopenharmony_ci // Create the compiled module object and populate with compiled functions 5781cb0ef41Sopenharmony_ci // and information needed at instantiation time. This object needs to be 5791cb0ef41Sopenharmony_ci // serializable. Instantiation may occur off a deserialized version of this 5801cb0ef41Sopenharmony_ci // object. 5811cb0ef41Sopenharmony_ci Handle<WasmModuleObject> module_object = WasmModuleObject::New( 5821cb0ef41Sopenharmony_ci isolate, std::move(native_module), script, export_wrappers); 5831cb0ef41Sopenharmony_ci 5841cb0ef41Sopenharmony_ci // Finish the Wasm script now and make it public to the debugger. 5851cb0ef41Sopenharmony_ci isolate->debug()->OnAfterCompile(script); 5861cb0ef41Sopenharmony_ci return module_object; 5871cb0ef41Sopenharmony_ci} 5881cb0ef41Sopenharmony_ci 5891cb0ef41Sopenharmony_ciMaybeHandle<WasmInstanceObject> WasmEngine::SyncInstantiate( 5901cb0ef41Sopenharmony_ci Isolate* isolate, ErrorThrower* thrower, 5911cb0ef41Sopenharmony_ci Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports, 5921cb0ef41Sopenharmony_ci MaybeHandle<JSArrayBuffer> memory) { 5931cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "wasm.SyncInstantiate"); 5941cb0ef41Sopenharmony_ci return InstantiateToInstanceObject(isolate, thrower, module_object, imports, 5951cb0ef41Sopenharmony_ci memory); 5961cb0ef41Sopenharmony_ci} 5971cb0ef41Sopenharmony_ci 5981cb0ef41Sopenharmony_civoid WasmEngine::AsyncInstantiate( 5991cb0ef41Sopenharmony_ci Isolate* isolate, std::unique_ptr<InstantiationResultResolver> resolver, 6001cb0ef41Sopenharmony_ci Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports) { 6011cb0ef41Sopenharmony_ci ErrorThrower thrower(isolate, "WebAssembly.instantiate()"); 6021cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "wasm.AsyncInstantiate"); 6031cb0ef41Sopenharmony_ci // Instantiate a TryCatch so that caught exceptions won't progagate out. 6041cb0ef41Sopenharmony_ci // They will still be set as pending exceptions on the isolate. 6051cb0ef41Sopenharmony_ci // TODO(clemensb): Avoid TryCatch, use Execution::TryCall internally to invoke 6061cb0ef41Sopenharmony_ci // start function and report thrown exception explicitly via out argument. 6071cb0ef41Sopenharmony_ci v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate)); 6081cb0ef41Sopenharmony_ci catcher.SetVerbose(false); 6091cb0ef41Sopenharmony_ci catcher.SetCaptureMessage(false); 6101cb0ef41Sopenharmony_ci 6111cb0ef41Sopenharmony_ci MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate( 6121cb0ef41Sopenharmony_ci isolate, &thrower, module_object, imports, Handle<JSArrayBuffer>::null()); 6131cb0ef41Sopenharmony_ci 6141cb0ef41Sopenharmony_ci if (!instance_object.is_null()) { 6151cb0ef41Sopenharmony_ci resolver->OnInstantiationSucceeded(instance_object.ToHandleChecked()); 6161cb0ef41Sopenharmony_ci return; 6171cb0ef41Sopenharmony_ci } 6181cb0ef41Sopenharmony_ci 6191cb0ef41Sopenharmony_ci if (isolate->has_pending_exception()) { 6201cb0ef41Sopenharmony_ci // The JS code executed during instantiation has thrown an exception. 6211cb0ef41Sopenharmony_ci // We have to move the exception to the promise chain. 6221cb0ef41Sopenharmony_ci Handle<Object> exception(isolate->pending_exception(), isolate); 6231cb0ef41Sopenharmony_ci isolate->clear_pending_exception(); 6241cb0ef41Sopenharmony_ci *isolate->external_caught_exception_address() = false; 6251cb0ef41Sopenharmony_ci resolver->OnInstantiationFailed(exception); 6261cb0ef41Sopenharmony_ci thrower.Reset(); 6271cb0ef41Sopenharmony_ci } else { 6281cb0ef41Sopenharmony_ci DCHECK(thrower.error()); 6291cb0ef41Sopenharmony_ci resolver->OnInstantiationFailed(thrower.Reify()); 6301cb0ef41Sopenharmony_ci } 6311cb0ef41Sopenharmony_ci} 6321cb0ef41Sopenharmony_ci 6331cb0ef41Sopenharmony_civoid WasmEngine::AsyncCompile( 6341cb0ef41Sopenharmony_ci Isolate* isolate, const WasmFeatures& enabled, 6351cb0ef41Sopenharmony_ci std::shared_ptr<CompilationResultResolver> resolver, 6361cb0ef41Sopenharmony_ci const ModuleWireBytes& bytes, bool is_shared, 6371cb0ef41Sopenharmony_ci const char* api_method_name_for_errors) { 6381cb0ef41Sopenharmony_ci int compilation_id = next_compilation_id_.fetch_add(1); 6391cb0ef41Sopenharmony_ci TRACE_EVENT1("v8.wasm", "wasm.AsyncCompile", "id", compilation_id); 6401cb0ef41Sopenharmony_ci if (!FLAG_wasm_async_compilation) { 6411cb0ef41Sopenharmony_ci // Asynchronous compilation disabled; fall back on synchronous compilation. 6421cb0ef41Sopenharmony_ci ErrorThrower thrower(isolate, api_method_name_for_errors); 6431cb0ef41Sopenharmony_ci MaybeHandle<WasmModuleObject> module_object; 6441cb0ef41Sopenharmony_ci if (is_shared) { 6451cb0ef41Sopenharmony_ci // Make a copy of the wire bytes to avoid concurrent modification. 6461cb0ef41Sopenharmony_ci std::unique_ptr<uint8_t[]> copy(new uint8_t[bytes.length()]); 6471cb0ef41Sopenharmony_ci memcpy(copy.get(), bytes.start(), bytes.length()); 6481cb0ef41Sopenharmony_ci ModuleWireBytes bytes_copy(copy.get(), copy.get() + bytes.length()); 6491cb0ef41Sopenharmony_ci module_object = SyncCompile(isolate, enabled, &thrower, bytes_copy); 6501cb0ef41Sopenharmony_ci } else { 6511cb0ef41Sopenharmony_ci // The wire bytes are not shared, OK to use them directly. 6521cb0ef41Sopenharmony_ci module_object = SyncCompile(isolate, enabled, &thrower, bytes); 6531cb0ef41Sopenharmony_ci } 6541cb0ef41Sopenharmony_ci if (thrower.error()) { 6551cb0ef41Sopenharmony_ci resolver->OnCompilationFailed(thrower.Reify()); 6561cb0ef41Sopenharmony_ci return; 6571cb0ef41Sopenharmony_ci } 6581cb0ef41Sopenharmony_ci Handle<WasmModuleObject> module = module_object.ToHandleChecked(); 6591cb0ef41Sopenharmony_ci resolver->OnCompilationSucceeded(module); 6601cb0ef41Sopenharmony_ci return; 6611cb0ef41Sopenharmony_ci } 6621cb0ef41Sopenharmony_ci 6631cb0ef41Sopenharmony_ci if (FLAG_wasm_test_streaming) { 6641cb0ef41Sopenharmony_ci std::shared_ptr<StreamingDecoder> streaming_decoder = 6651cb0ef41Sopenharmony_ci StartStreamingCompilation( 6661cb0ef41Sopenharmony_ci isolate, enabled, handle(isolate->context(), isolate), 6671cb0ef41Sopenharmony_ci api_method_name_for_errors, std::move(resolver)); 6681cb0ef41Sopenharmony_ci streaming_decoder->OnBytesReceived(bytes.module_bytes()); 6691cb0ef41Sopenharmony_ci streaming_decoder->Finish(); 6701cb0ef41Sopenharmony_ci return; 6711cb0ef41Sopenharmony_ci } 6721cb0ef41Sopenharmony_ci // Make a copy of the wire bytes in case the user program changes them 6731cb0ef41Sopenharmony_ci // during asynchronous compilation. 6741cb0ef41Sopenharmony_ci std::unique_ptr<byte[]> copy(new byte[bytes.length()]); 6751cb0ef41Sopenharmony_ci memcpy(copy.get(), bytes.start(), bytes.length()); 6761cb0ef41Sopenharmony_ci 6771cb0ef41Sopenharmony_ci AsyncCompileJob* job = CreateAsyncCompileJob( 6781cb0ef41Sopenharmony_ci isolate, enabled, std::move(copy), bytes.length(), 6791cb0ef41Sopenharmony_ci handle(isolate->context(), isolate), api_method_name_for_errors, 6801cb0ef41Sopenharmony_ci std::move(resolver), compilation_id); 6811cb0ef41Sopenharmony_ci job->Start(); 6821cb0ef41Sopenharmony_ci} 6831cb0ef41Sopenharmony_ci 6841cb0ef41Sopenharmony_cistd::shared_ptr<StreamingDecoder> WasmEngine::StartStreamingCompilation( 6851cb0ef41Sopenharmony_ci Isolate* isolate, const WasmFeatures& enabled, Handle<Context> context, 6861cb0ef41Sopenharmony_ci const char* api_method_name, 6871cb0ef41Sopenharmony_ci std::shared_ptr<CompilationResultResolver> resolver) { 6881cb0ef41Sopenharmony_ci int compilation_id = next_compilation_id_.fetch_add(1); 6891cb0ef41Sopenharmony_ci TRACE_EVENT1("v8.wasm", "wasm.StartStreamingCompilation", "id", 6901cb0ef41Sopenharmony_ci compilation_id); 6911cb0ef41Sopenharmony_ci if (FLAG_wasm_async_compilation) { 6921cb0ef41Sopenharmony_ci AsyncCompileJob* job = CreateAsyncCompileJob( 6931cb0ef41Sopenharmony_ci isolate, enabled, std::unique_ptr<byte[]>(nullptr), 0, context, 6941cb0ef41Sopenharmony_ci api_method_name, std::move(resolver), compilation_id); 6951cb0ef41Sopenharmony_ci return job->CreateStreamingDecoder(); 6961cb0ef41Sopenharmony_ci } 6971cb0ef41Sopenharmony_ci return StreamingDecoder::CreateSyncStreamingDecoder( 6981cb0ef41Sopenharmony_ci isolate, enabled, context, api_method_name, std::move(resolver)); 6991cb0ef41Sopenharmony_ci} 7001cb0ef41Sopenharmony_ci 7011cb0ef41Sopenharmony_civoid WasmEngine::CompileFunction(Isolate* isolate, NativeModule* native_module, 7021cb0ef41Sopenharmony_ci uint32_t function_index, ExecutionTier tier) { 7031cb0ef41Sopenharmony_ci // Note we assume that "one-off" compilations can discard detected features. 7041cb0ef41Sopenharmony_ci WasmFeatures detected = WasmFeatures::None(); 7051cb0ef41Sopenharmony_ci WasmCompilationUnit::CompileWasmFunction( 7061cb0ef41Sopenharmony_ci isolate, native_module, &detected, 7071cb0ef41Sopenharmony_ci &native_module->module()->functions[function_index], tier); 7081cb0ef41Sopenharmony_ci} 7091cb0ef41Sopenharmony_ci 7101cb0ef41Sopenharmony_civoid WasmEngine::TierDownAllModulesPerIsolate(Isolate* isolate) { 7111cb0ef41Sopenharmony_ci std::vector<std::shared_ptr<NativeModule>> native_modules; 7121cb0ef41Sopenharmony_ci { 7131cb0ef41Sopenharmony_ci base::MutexGuard lock(&mutex_); 7141cb0ef41Sopenharmony_ci if (isolates_[isolate]->keep_tiered_down) return; 7151cb0ef41Sopenharmony_ci isolates_[isolate]->keep_tiered_down = true; 7161cb0ef41Sopenharmony_ci for (auto* native_module : isolates_[isolate]->native_modules) { 7171cb0ef41Sopenharmony_ci native_module->SetTieringState(kTieredDown); 7181cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_.count(native_module)); 7191cb0ef41Sopenharmony_ci if (auto shared_ptr = native_modules_[native_module]->weak_ptr.lock()) { 7201cb0ef41Sopenharmony_ci native_modules.emplace_back(std::move(shared_ptr)); 7211cb0ef41Sopenharmony_ci } 7221cb0ef41Sopenharmony_ci } 7231cb0ef41Sopenharmony_ci } 7241cb0ef41Sopenharmony_ci for (auto& native_module : native_modules) { 7251cb0ef41Sopenharmony_ci native_module->RecompileForTiering(); 7261cb0ef41Sopenharmony_ci } 7271cb0ef41Sopenharmony_ci} 7281cb0ef41Sopenharmony_ci 7291cb0ef41Sopenharmony_civoid WasmEngine::TierUpAllModulesPerIsolate(Isolate* isolate) { 7301cb0ef41Sopenharmony_ci // Only trigger recompilation after releasing the mutex, otherwise we risk 7311cb0ef41Sopenharmony_ci // deadlocks because of lock inversion. The bool tells whether the module 7321cb0ef41Sopenharmony_ci // needs recompilation for tier up. 7331cb0ef41Sopenharmony_ci std::vector<std::pair<std::shared_ptr<NativeModule>, bool>> native_modules; 7341cb0ef41Sopenharmony_ci { 7351cb0ef41Sopenharmony_ci base::MutexGuard lock(&mutex_); 7361cb0ef41Sopenharmony_ci isolates_[isolate]->keep_tiered_down = false; 7371cb0ef41Sopenharmony_ci auto test_can_tier_up = [this](NativeModule* native_module) { 7381cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_.count(native_module)); 7391cb0ef41Sopenharmony_ci for (auto* isolate : native_modules_[native_module]->isolates) { 7401cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 7411cb0ef41Sopenharmony_ci if (isolates_[isolate]->keep_tiered_down) return false; 7421cb0ef41Sopenharmony_ci } 7431cb0ef41Sopenharmony_ci return true; 7441cb0ef41Sopenharmony_ci }; 7451cb0ef41Sopenharmony_ci for (auto* native_module : isolates_[isolate]->native_modules) { 7461cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_.count(native_module)); 7471cb0ef41Sopenharmony_ci auto shared_ptr = native_modules_[native_module]->weak_ptr.lock(); 7481cb0ef41Sopenharmony_ci if (!shared_ptr) continue; // The module is not used any more. 7491cb0ef41Sopenharmony_ci if (!native_module->IsTieredDown()) continue; 7501cb0ef41Sopenharmony_ci // Only start tier-up if no other isolate needs this module in tiered 7511cb0ef41Sopenharmony_ci // down state. 7521cb0ef41Sopenharmony_ci bool tier_up = test_can_tier_up(native_module); 7531cb0ef41Sopenharmony_ci if (tier_up) native_module->SetTieringState(kTieredUp); 7541cb0ef41Sopenharmony_ci native_modules.emplace_back(std::move(shared_ptr), tier_up); 7551cb0ef41Sopenharmony_ci } 7561cb0ef41Sopenharmony_ci } 7571cb0ef41Sopenharmony_ci for (auto& entry : native_modules) { 7581cb0ef41Sopenharmony_ci auto& native_module = entry.first; 7591cb0ef41Sopenharmony_ci bool tier_up = entry.second; 7601cb0ef41Sopenharmony_ci // Remove all breakpoints set by this isolate. 7611cb0ef41Sopenharmony_ci if (native_module->HasDebugInfo()) { 7621cb0ef41Sopenharmony_ci native_module->GetDebugInfo()->RemoveIsolate(isolate); 7631cb0ef41Sopenharmony_ci } 7641cb0ef41Sopenharmony_ci if (tier_up) native_module->RecompileForTiering(); 7651cb0ef41Sopenharmony_ci } 7661cb0ef41Sopenharmony_ci} 7671cb0ef41Sopenharmony_ci 7681cb0ef41Sopenharmony_cistd::shared_ptr<NativeModule> WasmEngine::ExportNativeModule( 7691cb0ef41Sopenharmony_ci Handle<WasmModuleObject> module_object) { 7701cb0ef41Sopenharmony_ci return module_object->shared_native_module(); 7711cb0ef41Sopenharmony_ci} 7721cb0ef41Sopenharmony_ci 7731cb0ef41Sopenharmony_cinamespace { 7741cb0ef41Sopenharmony_ciHandle<Script> CreateWasmScript(Isolate* isolate, 7751cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module, 7761cb0ef41Sopenharmony_ci base::Vector<const char> source_url) { 7771cb0ef41Sopenharmony_ci Handle<Script> script = 7781cb0ef41Sopenharmony_ci isolate->factory()->NewScript(isolate->factory()->undefined_value()); 7791cb0ef41Sopenharmony_ci script->set_compilation_state(Script::COMPILATION_STATE_COMPILED); 7801cb0ef41Sopenharmony_ci script->set_context_data(isolate->native_context()->debug_context_id()); 7811cb0ef41Sopenharmony_ci script->set_type(Script::TYPE_WASM); 7821cb0ef41Sopenharmony_ci 7831cb0ef41Sopenharmony_ci base::Vector<const uint8_t> wire_bytes = native_module->wire_bytes(); 7841cb0ef41Sopenharmony_ci 7851cb0ef41Sopenharmony_ci // The source URL of the script is 7861cb0ef41Sopenharmony_ci // - the original source URL if available (from the streaming API), 7871cb0ef41Sopenharmony_ci // - wasm://wasm/<module name>-<hash> if a module name has been set, or 7881cb0ef41Sopenharmony_ci // - wasm://wasm/<hash> otherwise. 7891cb0ef41Sopenharmony_ci const WasmModule* module = native_module->module(); 7901cb0ef41Sopenharmony_ci Handle<String> url_str; 7911cb0ef41Sopenharmony_ci if (!source_url.empty()) { 7921cb0ef41Sopenharmony_ci url_str = isolate->factory() 7931cb0ef41Sopenharmony_ci ->NewStringFromUtf8(source_url, AllocationType::kOld) 7941cb0ef41Sopenharmony_ci .ToHandleChecked(); 7951cb0ef41Sopenharmony_ci } else { 7961cb0ef41Sopenharmony_ci int hash = StringHasher::HashSequentialString( 7971cb0ef41Sopenharmony_ci reinterpret_cast<const char*>(wire_bytes.begin()), wire_bytes.length(), 7981cb0ef41Sopenharmony_ci kZeroHashSeed); 7991cb0ef41Sopenharmony_ci 8001cb0ef41Sopenharmony_ci base::EmbeddedVector<char, 32> buffer; 8011cb0ef41Sopenharmony_ci if (module->name.is_empty()) { 8021cb0ef41Sopenharmony_ci // Build the URL in the form "wasm://wasm/<hash>". 8031cb0ef41Sopenharmony_ci int url_len = SNPrintF(buffer, "wasm://wasm/%08x", hash); 8041cb0ef41Sopenharmony_ci DCHECK(url_len >= 0 && url_len < buffer.length()); 8051cb0ef41Sopenharmony_ci url_str = isolate->factory() 8061cb0ef41Sopenharmony_ci ->NewStringFromUtf8(buffer.SubVector(0, url_len), 8071cb0ef41Sopenharmony_ci AllocationType::kOld) 8081cb0ef41Sopenharmony_ci .ToHandleChecked(); 8091cb0ef41Sopenharmony_ci } else { 8101cb0ef41Sopenharmony_ci // Build the URL in the form "wasm://wasm/<module name>-<hash>". 8111cb0ef41Sopenharmony_ci int hash_len = SNPrintF(buffer, "-%08x", hash); 8121cb0ef41Sopenharmony_ci DCHECK(hash_len >= 0 && hash_len < buffer.length()); 8131cb0ef41Sopenharmony_ci Handle<String> prefix = 8141cb0ef41Sopenharmony_ci isolate->factory()->NewStringFromStaticChars("wasm://wasm/"); 8151cb0ef41Sopenharmony_ci Handle<String> module_name = 8161cb0ef41Sopenharmony_ci WasmModuleObject::ExtractUtf8StringFromModuleBytes( 8171cb0ef41Sopenharmony_ci isolate, wire_bytes, module->name, kNoInternalize); 8181cb0ef41Sopenharmony_ci Handle<String> hash_str = 8191cb0ef41Sopenharmony_ci isolate->factory() 8201cb0ef41Sopenharmony_ci ->NewStringFromUtf8(buffer.SubVector(0, hash_len)) 8211cb0ef41Sopenharmony_ci .ToHandleChecked(); 8221cb0ef41Sopenharmony_ci // Concatenate the three parts. 8231cb0ef41Sopenharmony_ci url_str = isolate->factory() 8241cb0ef41Sopenharmony_ci ->NewConsString(prefix, module_name) 8251cb0ef41Sopenharmony_ci .ToHandleChecked(); 8261cb0ef41Sopenharmony_ci url_str = isolate->factory() 8271cb0ef41Sopenharmony_ci ->NewConsString(url_str, hash_str) 8281cb0ef41Sopenharmony_ci .ToHandleChecked(); 8291cb0ef41Sopenharmony_ci } 8301cb0ef41Sopenharmony_ci } 8311cb0ef41Sopenharmony_ci script->set_name(*url_str); 8321cb0ef41Sopenharmony_ci 8331cb0ef41Sopenharmony_ci const WasmDebugSymbols& debug_symbols = module->debug_symbols; 8341cb0ef41Sopenharmony_ci if (debug_symbols.type == WasmDebugSymbols::Type::SourceMap && 8351cb0ef41Sopenharmony_ci !debug_symbols.external_url.is_empty()) { 8361cb0ef41Sopenharmony_ci base::Vector<const char> external_url = 8371cb0ef41Sopenharmony_ci ModuleWireBytes(wire_bytes).GetNameOrNull(debug_symbols.external_url); 8381cb0ef41Sopenharmony_ci MaybeHandle<String> src_map_str = isolate->factory()->NewStringFromUtf8( 8391cb0ef41Sopenharmony_ci external_url, AllocationType::kOld); 8401cb0ef41Sopenharmony_ci script->set_source_mapping_url(*src_map_str.ToHandleChecked()); 8411cb0ef41Sopenharmony_ci } 8421cb0ef41Sopenharmony_ci 8431cb0ef41Sopenharmony_ci // Use the given shared {NativeModule}, but increase its reference count by 8441cb0ef41Sopenharmony_ci // allocating a new {Managed<T>} that the {Script} references. 8451cb0ef41Sopenharmony_ci size_t code_size_estimate = native_module->committed_code_space(); 8461cb0ef41Sopenharmony_ci size_t memory_estimate = 8471cb0ef41Sopenharmony_ci code_size_estimate + 8481cb0ef41Sopenharmony_ci wasm::WasmCodeManager::EstimateNativeModuleMetaDataSize(module); 8491cb0ef41Sopenharmony_ci Handle<Managed<wasm::NativeModule>> managed_native_module = 8501cb0ef41Sopenharmony_ci Managed<wasm::NativeModule>::FromSharedPtr(isolate, memory_estimate, 8511cb0ef41Sopenharmony_ci std::move(native_module)); 8521cb0ef41Sopenharmony_ci script->set_wasm_managed_native_module(*managed_native_module); 8531cb0ef41Sopenharmony_ci script->set_wasm_breakpoint_infos(ReadOnlyRoots(isolate).empty_fixed_array()); 8541cb0ef41Sopenharmony_ci script->set_wasm_weak_instance_list( 8551cb0ef41Sopenharmony_ci ReadOnlyRoots(isolate).empty_weak_array_list()); 8561cb0ef41Sopenharmony_ci return script; 8571cb0ef41Sopenharmony_ci} 8581cb0ef41Sopenharmony_ci} // namespace 8591cb0ef41Sopenharmony_ci 8601cb0ef41Sopenharmony_ciHandle<WasmModuleObject> WasmEngine::ImportNativeModule( 8611cb0ef41Sopenharmony_ci Isolate* isolate, std::shared_ptr<NativeModule> shared_native_module, 8621cb0ef41Sopenharmony_ci base::Vector<const char> source_url) { 8631cb0ef41Sopenharmony_ci NativeModule* native_module = shared_native_module.get(); 8641cb0ef41Sopenharmony_ci ModuleWireBytes wire_bytes(native_module->wire_bytes()); 8651cb0ef41Sopenharmony_ci Handle<Script> script = 8661cb0ef41Sopenharmony_ci GetOrCreateScript(isolate, shared_native_module, source_url); 8671cb0ef41Sopenharmony_ci Handle<FixedArray> export_wrappers; 8681cb0ef41Sopenharmony_ci CompileJsToWasmWrappers(isolate, native_module->module(), &export_wrappers); 8691cb0ef41Sopenharmony_ci Handle<WasmModuleObject> module_object = WasmModuleObject::New( 8701cb0ef41Sopenharmony_ci isolate, std::move(shared_native_module), script, export_wrappers); 8711cb0ef41Sopenharmony_ci { 8721cb0ef41Sopenharmony_ci base::MutexGuard lock(&mutex_); 8731cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 8741cb0ef41Sopenharmony_ci isolates_[isolate]->native_modules.insert(native_module); 8751cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_.count(native_module)); 8761cb0ef41Sopenharmony_ci native_modules_[native_module]->isolates.insert(isolate); 8771cb0ef41Sopenharmony_ci } 8781cb0ef41Sopenharmony_ci 8791cb0ef41Sopenharmony_ci // Finish the Wasm script now and make it public to the debugger. 8801cb0ef41Sopenharmony_ci isolate->debug()->OnAfterCompile(script); 8811cb0ef41Sopenharmony_ci return module_object; 8821cb0ef41Sopenharmony_ci} 8831cb0ef41Sopenharmony_ci 8841cb0ef41Sopenharmony_ciCompilationStatistics* WasmEngine::GetOrCreateTurboStatistics() { 8851cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 8861cb0ef41Sopenharmony_ci if (compilation_stats_ == nullptr) { 8871cb0ef41Sopenharmony_ci compilation_stats_.reset(new CompilationStatistics()); 8881cb0ef41Sopenharmony_ci } 8891cb0ef41Sopenharmony_ci return compilation_stats_.get(); 8901cb0ef41Sopenharmony_ci} 8911cb0ef41Sopenharmony_ci 8921cb0ef41Sopenharmony_civoid WasmEngine::DumpAndResetTurboStatistics() { 8931cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 8941cb0ef41Sopenharmony_ci if (compilation_stats_ != nullptr) { 8951cb0ef41Sopenharmony_ci StdoutStream os; 8961cb0ef41Sopenharmony_ci os << AsPrintableStatistics{*compilation_stats_.get(), false} << std::endl; 8971cb0ef41Sopenharmony_ci } 8981cb0ef41Sopenharmony_ci compilation_stats_.reset(); 8991cb0ef41Sopenharmony_ci} 9001cb0ef41Sopenharmony_ci 9011cb0ef41Sopenharmony_civoid WasmEngine::DumpTurboStatistics() { 9021cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 9031cb0ef41Sopenharmony_ci if (compilation_stats_ != nullptr) { 9041cb0ef41Sopenharmony_ci StdoutStream os; 9051cb0ef41Sopenharmony_ci os << AsPrintableStatistics{*compilation_stats_.get(), false} << std::endl; 9061cb0ef41Sopenharmony_ci } 9071cb0ef41Sopenharmony_ci} 9081cb0ef41Sopenharmony_ci 9091cb0ef41Sopenharmony_ciCodeTracer* WasmEngine::GetCodeTracer() { 9101cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 9111cb0ef41Sopenharmony_ci if (code_tracer_ == nullptr) code_tracer_.reset(new CodeTracer(-1)); 9121cb0ef41Sopenharmony_ci return code_tracer_.get(); 9131cb0ef41Sopenharmony_ci} 9141cb0ef41Sopenharmony_ci 9151cb0ef41Sopenharmony_ciAsyncCompileJob* WasmEngine::CreateAsyncCompileJob( 9161cb0ef41Sopenharmony_ci Isolate* isolate, const WasmFeatures& enabled, 9171cb0ef41Sopenharmony_ci std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context, 9181cb0ef41Sopenharmony_ci const char* api_method_name, 9191cb0ef41Sopenharmony_ci std::shared_ptr<CompilationResultResolver> resolver, int compilation_id) { 9201cb0ef41Sopenharmony_ci Handle<Context> incumbent_context = isolate->GetIncumbentContext(); 9211cb0ef41Sopenharmony_ci AsyncCompileJob* job = new AsyncCompileJob( 9221cb0ef41Sopenharmony_ci isolate, enabled, std::move(bytes_copy), length, context, 9231cb0ef41Sopenharmony_ci incumbent_context, api_method_name, std::move(resolver), compilation_id); 9241cb0ef41Sopenharmony_ci // Pass ownership to the unique_ptr in {async_compile_jobs_}. 9251cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 9261cb0ef41Sopenharmony_ci async_compile_jobs_[job] = std::unique_ptr<AsyncCompileJob>(job); 9271cb0ef41Sopenharmony_ci return job; 9281cb0ef41Sopenharmony_ci} 9291cb0ef41Sopenharmony_ci 9301cb0ef41Sopenharmony_cistd::unique_ptr<AsyncCompileJob> WasmEngine::RemoveCompileJob( 9311cb0ef41Sopenharmony_ci AsyncCompileJob* job) { 9321cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 9331cb0ef41Sopenharmony_ci auto item = async_compile_jobs_.find(job); 9341cb0ef41Sopenharmony_ci DCHECK(item != async_compile_jobs_.end()); 9351cb0ef41Sopenharmony_ci std::unique_ptr<AsyncCompileJob> result = std::move(item->second); 9361cb0ef41Sopenharmony_ci async_compile_jobs_.erase(item); 9371cb0ef41Sopenharmony_ci return result; 9381cb0ef41Sopenharmony_ci} 9391cb0ef41Sopenharmony_ci 9401cb0ef41Sopenharmony_cibool WasmEngine::HasRunningCompileJob(Isolate* isolate) { 9411cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 9421cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 9431cb0ef41Sopenharmony_ci for (auto& entry : async_compile_jobs_) { 9441cb0ef41Sopenharmony_ci if (entry.first->isolate() == isolate) return true; 9451cb0ef41Sopenharmony_ci } 9461cb0ef41Sopenharmony_ci return false; 9471cb0ef41Sopenharmony_ci} 9481cb0ef41Sopenharmony_ci 9491cb0ef41Sopenharmony_civoid WasmEngine::DeleteCompileJobsOnContext(Handle<Context> context) { 9501cb0ef41Sopenharmony_ci // Under the mutex get all jobs to delete. Then delete them without holding 9511cb0ef41Sopenharmony_ci // the mutex, such that deletion can reenter the WasmEngine. 9521cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<AsyncCompileJob>> jobs_to_delete; 9531cb0ef41Sopenharmony_ci { 9541cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 9551cb0ef41Sopenharmony_ci for (auto it = async_compile_jobs_.begin(); 9561cb0ef41Sopenharmony_ci it != async_compile_jobs_.end();) { 9571cb0ef41Sopenharmony_ci if (!it->first->context().is_identical_to(context)) { 9581cb0ef41Sopenharmony_ci ++it; 9591cb0ef41Sopenharmony_ci continue; 9601cb0ef41Sopenharmony_ci } 9611cb0ef41Sopenharmony_ci jobs_to_delete.push_back(std::move(it->second)); 9621cb0ef41Sopenharmony_ci it = async_compile_jobs_.erase(it); 9631cb0ef41Sopenharmony_ci } 9641cb0ef41Sopenharmony_ci } 9651cb0ef41Sopenharmony_ci} 9661cb0ef41Sopenharmony_ci 9671cb0ef41Sopenharmony_civoid WasmEngine::DeleteCompileJobsOnIsolate(Isolate* isolate) { 9681cb0ef41Sopenharmony_ci // Under the mutex get all jobs to delete. Then delete them without holding 9691cb0ef41Sopenharmony_ci // the mutex, such that deletion can reenter the WasmEngine. 9701cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<AsyncCompileJob>> jobs_to_delete; 9711cb0ef41Sopenharmony_ci std::vector<std::weak_ptr<NativeModule>> modules_in_isolate; 9721cb0ef41Sopenharmony_ci std::shared_ptr<OperationsBarrier> wrapper_compilation_barrier; 9731cb0ef41Sopenharmony_ci { 9741cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 9751cb0ef41Sopenharmony_ci for (auto it = async_compile_jobs_.begin(); 9761cb0ef41Sopenharmony_ci it != async_compile_jobs_.end();) { 9771cb0ef41Sopenharmony_ci if (it->first->isolate() != isolate) { 9781cb0ef41Sopenharmony_ci ++it; 9791cb0ef41Sopenharmony_ci continue; 9801cb0ef41Sopenharmony_ci } 9811cb0ef41Sopenharmony_ci jobs_to_delete.push_back(std::move(it->second)); 9821cb0ef41Sopenharmony_ci it = async_compile_jobs_.erase(it); 9831cb0ef41Sopenharmony_ci } 9841cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 9851cb0ef41Sopenharmony_ci auto* isolate_info = isolates_[isolate].get(); 9861cb0ef41Sopenharmony_ci wrapper_compilation_barrier = isolate_info->wrapper_compilation_barrier_; 9871cb0ef41Sopenharmony_ci for (auto* native_module : isolate_info->native_modules) { 9881cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_.count(native_module)); 9891cb0ef41Sopenharmony_ci modules_in_isolate.emplace_back(native_modules_[native_module]->weak_ptr); 9901cb0ef41Sopenharmony_ci } 9911cb0ef41Sopenharmony_ci } 9921cb0ef41Sopenharmony_ci 9931cb0ef41Sopenharmony_ci // All modules that have not finished initial compilation yet cannot be 9941cb0ef41Sopenharmony_ci // shared with other isolates. Hence we cancel their compilation. In 9951cb0ef41Sopenharmony_ci // particular, this will cancel wrapper compilation which is bound to this 9961cb0ef41Sopenharmony_ci // isolate (this would be a UAF otherwise). 9971cb0ef41Sopenharmony_ci for (auto& weak_module : modules_in_isolate) { 9981cb0ef41Sopenharmony_ci if (auto shared_module = weak_module.lock()) { 9991cb0ef41Sopenharmony_ci shared_module->compilation_state()->CancelInitialCompilation(); 10001cb0ef41Sopenharmony_ci } 10011cb0ef41Sopenharmony_ci } 10021cb0ef41Sopenharmony_ci 10031cb0ef41Sopenharmony_ci // After cancelling, wait for all current wrapper compilation to actually 10041cb0ef41Sopenharmony_ci // finish. 10051cb0ef41Sopenharmony_ci wrapper_compilation_barrier->CancelAndWait(); 10061cb0ef41Sopenharmony_ci} 10071cb0ef41Sopenharmony_ci 10081cb0ef41Sopenharmony_ciOperationsBarrier::Token WasmEngine::StartWrapperCompilation(Isolate* isolate) { 10091cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 10101cb0ef41Sopenharmony_ci auto isolate_info_it = isolates_.find(isolate); 10111cb0ef41Sopenharmony_ci if (isolate_info_it == isolates_.end()) return {}; 10121cb0ef41Sopenharmony_ci return isolate_info_it->second->wrapper_compilation_barrier_->TryLock(); 10131cb0ef41Sopenharmony_ci} 10141cb0ef41Sopenharmony_ci 10151cb0ef41Sopenharmony_civoid WasmEngine::AddIsolate(Isolate* isolate) { 10161cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 10171cb0ef41Sopenharmony_ci DCHECK_EQ(0, isolates_.count(isolate)); 10181cb0ef41Sopenharmony_ci isolates_.emplace(isolate, std::make_unique<IsolateInfo>(isolate)); 10191cb0ef41Sopenharmony_ci 10201cb0ef41Sopenharmony_ci // The isolate might access existing (cached) code without ever compiling any. 10211cb0ef41Sopenharmony_ci // In that case, the current thread might still have the default permissions 10221cb0ef41Sopenharmony_ci // for the memory protection key (== no access). Thus initialize the 10231cb0ef41Sopenharmony_ci // permissions now. 10241cb0ef41Sopenharmony_ci GetWasmCodeManager()->InitializeMemoryProtectionKeyPermissionsIfSupported(); 10251cb0ef41Sopenharmony_ci 10261cb0ef41Sopenharmony_ci // Install sampling GC callback. 10271cb0ef41Sopenharmony_ci // TODO(v8:7424): For now we sample module sizes in a GC callback. This will 10281cb0ef41Sopenharmony_ci // bias samples towards apps with high memory pressure. We should switch to 10291cb0ef41Sopenharmony_ci // using sampling based on regular intervals independent of the GC. 10301cb0ef41Sopenharmony_ci auto callback = [](v8::Isolate* v8_isolate, v8::GCType type, 10311cb0ef41Sopenharmony_ci v8::GCCallbackFlags flags, void* data) { 10321cb0ef41Sopenharmony_ci Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 10331cb0ef41Sopenharmony_ci Counters* counters = isolate->counters(); 10341cb0ef41Sopenharmony_ci WasmEngine* engine = GetWasmEngine(); 10351cb0ef41Sopenharmony_ci base::MutexGuard lock(&engine->mutex_); 10361cb0ef41Sopenharmony_ci DCHECK_EQ(1, engine->isolates_.count(isolate)); 10371cb0ef41Sopenharmony_ci for (auto* native_module : engine->isolates_[isolate]->native_modules) { 10381cb0ef41Sopenharmony_ci native_module->SampleCodeSize(counters, NativeModule::kSampling); 10391cb0ef41Sopenharmony_ci } 10401cb0ef41Sopenharmony_ci }; 10411cb0ef41Sopenharmony_ci isolate->heap()->AddGCEpilogueCallback(callback, v8::kGCTypeMarkSweepCompact, 10421cb0ef41Sopenharmony_ci nullptr); 10431cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING 10441cb0ef41Sopenharmony_ci if (gdb_server_) { 10451cb0ef41Sopenharmony_ci gdb_server_->AddIsolate(isolate); 10461cb0ef41Sopenharmony_ci } 10471cb0ef41Sopenharmony_ci#endif // V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING 10481cb0ef41Sopenharmony_ci} 10491cb0ef41Sopenharmony_ci 10501cb0ef41Sopenharmony_civoid WasmEngine::RemoveIsolate(Isolate* isolate) { 10511cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING 10521cb0ef41Sopenharmony_ci if (gdb_server_) { 10531cb0ef41Sopenharmony_ci gdb_server_->RemoveIsolate(isolate); 10541cb0ef41Sopenharmony_ci } 10551cb0ef41Sopenharmony_ci#endif // V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING 10561cb0ef41Sopenharmony_ci 10571cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 10581cb0ef41Sopenharmony_ci auto it = isolates_.find(isolate); 10591cb0ef41Sopenharmony_ci DCHECK_NE(isolates_.end(), it); 10601cb0ef41Sopenharmony_ci std::unique_ptr<IsolateInfo> info = std::move(it->second); 10611cb0ef41Sopenharmony_ci isolates_.erase(it); 10621cb0ef41Sopenharmony_ci for (auto* native_module : info->native_modules) { 10631cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_.count(native_module)); 10641cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_[native_module]->isolates.count(isolate)); 10651cb0ef41Sopenharmony_ci auto* module = native_modules_[native_module].get(); 10661cb0ef41Sopenharmony_ci module->isolates.erase(isolate); 10671cb0ef41Sopenharmony_ci if (current_gc_info_) { 10681cb0ef41Sopenharmony_ci for (WasmCode* code : module->potentially_dead_code) { 10691cb0ef41Sopenharmony_ci current_gc_info_->dead_code.erase(code); 10701cb0ef41Sopenharmony_ci } 10711cb0ef41Sopenharmony_ci } 10721cb0ef41Sopenharmony_ci if (native_module->HasDebugInfo()) { 10731cb0ef41Sopenharmony_ci native_module->GetDebugInfo()->RemoveIsolate(isolate); 10741cb0ef41Sopenharmony_ci } 10751cb0ef41Sopenharmony_ci } 10761cb0ef41Sopenharmony_ci if (current_gc_info_) { 10771cb0ef41Sopenharmony_ci if (RemoveIsolateFromCurrentGC(isolate)) PotentiallyFinishCurrentGC(); 10781cb0ef41Sopenharmony_ci } 10791cb0ef41Sopenharmony_ci if (auto* task = info->log_codes_task) { 10801cb0ef41Sopenharmony_ci task->Cancel(); 10811cb0ef41Sopenharmony_ci for (auto& log_entry : info->code_to_log) { 10821cb0ef41Sopenharmony_ci WasmCode::DecrementRefCount(base::VectorOf(log_entry.second.code)); 10831cb0ef41Sopenharmony_ci } 10841cb0ef41Sopenharmony_ci info->code_to_log.clear(); 10851cb0ef41Sopenharmony_ci } 10861cb0ef41Sopenharmony_ci DCHECK(info->code_to_log.empty()); 10871cb0ef41Sopenharmony_ci} 10881cb0ef41Sopenharmony_ci 10891cb0ef41Sopenharmony_civoid WasmEngine::LogCode(base::Vector<WasmCode*> code_vec) { 10901cb0ef41Sopenharmony_ci if (code_vec.empty()) return; 10911cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 10921cb0ef41Sopenharmony_ci NativeModule* native_module = code_vec[0]->native_module(); 10931cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_.count(native_module)); 10941cb0ef41Sopenharmony_ci for (Isolate* isolate : native_modules_[native_module]->isolates) { 10951cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 10961cb0ef41Sopenharmony_ci IsolateInfo* info = isolates_[isolate].get(); 10971cb0ef41Sopenharmony_ci if (info->log_codes == false) continue; 10981cb0ef41Sopenharmony_ci if (info->log_codes_task == nullptr) { 10991cb0ef41Sopenharmony_ci auto new_task = std::make_unique<LogCodesTask>( 11001cb0ef41Sopenharmony_ci &mutex_, &info->log_codes_task, isolate, this); 11011cb0ef41Sopenharmony_ci info->log_codes_task = new_task.get(); 11021cb0ef41Sopenharmony_ci info->foreground_task_runner->PostTask(std::move(new_task)); 11031cb0ef41Sopenharmony_ci } 11041cb0ef41Sopenharmony_ci if (info->code_to_log.empty()) { 11051cb0ef41Sopenharmony_ci isolate->stack_guard()->RequestLogWasmCode(); 11061cb0ef41Sopenharmony_ci } 11071cb0ef41Sopenharmony_ci for (WasmCode* code : code_vec) { 11081cb0ef41Sopenharmony_ci DCHECK_EQ(native_module, code->native_module()); 11091cb0ef41Sopenharmony_ci code->IncRef(); 11101cb0ef41Sopenharmony_ci } 11111cb0ef41Sopenharmony_ci 11121cb0ef41Sopenharmony_ci auto script_it = info->scripts.find(native_module); 11131cb0ef41Sopenharmony_ci // If the script does not yet exist, logging will happen later. If the weak 11141cb0ef41Sopenharmony_ci // handle is cleared already, we also don't need to log any more. 11151cb0ef41Sopenharmony_ci if (script_it == info->scripts.end()) continue; 11161cb0ef41Sopenharmony_ci auto& log_entry = info->code_to_log[script_it->second.script_id()]; 11171cb0ef41Sopenharmony_ci if (!log_entry.source_url) { 11181cb0ef41Sopenharmony_ci log_entry.source_url = script_it->second.source_url(); 11191cb0ef41Sopenharmony_ci } 11201cb0ef41Sopenharmony_ci log_entry.code.insert(log_entry.code.end(), code_vec.begin(), 11211cb0ef41Sopenharmony_ci code_vec.end()); 11221cb0ef41Sopenharmony_ci } 11231cb0ef41Sopenharmony_ci} 11241cb0ef41Sopenharmony_ci 11251cb0ef41Sopenharmony_civoid WasmEngine::EnableCodeLogging(Isolate* isolate) { 11261cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 11271cb0ef41Sopenharmony_ci auto it = isolates_.find(isolate); 11281cb0ef41Sopenharmony_ci DCHECK_NE(isolates_.end(), it); 11291cb0ef41Sopenharmony_ci it->second->log_codes = true; 11301cb0ef41Sopenharmony_ci} 11311cb0ef41Sopenharmony_ci 11321cb0ef41Sopenharmony_civoid WasmEngine::LogOutstandingCodesForIsolate(Isolate* isolate) { 11331cb0ef41Sopenharmony_ci // Under the mutex, get the vector of wasm code to log. Then log and decrement 11341cb0ef41Sopenharmony_ci // the ref count without holding the mutex. 11351cb0ef41Sopenharmony_ci std::unordered_map<int, IsolateInfo::CodeToLogPerScript> code_to_log; 11361cb0ef41Sopenharmony_ci { 11371cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 11381cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 11391cb0ef41Sopenharmony_ci code_to_log.swap(isolates_[isolate]->code_to_log); 11401cb0ef41Sopenharmony_ci } 11411cb0ef41Sopenharmony_ci 11421cb0ef41Sopenharmony_ci // Check again whether we still need to log code. 11431cb0ef41Sopenharmony_ci bool should_log = WasmCode::ShouldBeLogged(isolate); 11441cb0ef41Sopenharmony_ci 11451cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "wasm.LogCode"); 11461cb0ef41Sopenharmony_ci for (auto& pair : code_to_log) { 11471cb0ef41Sopenharmony_ci for (WasmCode* code : pair.second.code) { 11481cb0ef41Sopenharmony_ci if (should_log) { 11491cb0ef41Sopenharmony_ci code->LogCode(isolate, pair.second.source_url.get(), pair.first); 11501cb0ef41Sopenharmony_ci } 11511cb0ef41Sopenharmony_ci } 11521cb0ef41Sopenharmony_ci WasmCode::DecrementRefCount(base::VectorOf(pair.second.code)); 11531cb0ef41Sopenharmony_ci } 11541cb0ef41Sopenharmony_ci} 11551cb0ef41Sopenharmony_ci 11561cb0ef41Sopenharmony_cistd::shared_ptr<NativeModule> WasmEngine::NewNativeModule( 11571cb0ef41Sopenharmony_ci Isolate* isolate, const WasmFeatures& enabled, 11581cb0ef41Sopenharmony_ci std::shared_ptr<const WasmModule> module, size_t code_size_estimate) { 11591cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING 11601cb0ef41Sopenharmony_ci if (FLAG_wasm_gdb_remote && !gdb_server_) { 11611cb0ef41Sopenharmony_ci gdb_server_ = gdb_server::GdbServer::Create(); 11621cb0ef41Sopenharmony_ci gdb_server_->AddIsolate(isolate); 11631cb0ef41Sopenharmony_ci } 11641cb0ef41Sopenharmony_ci#endif // V8_ENABLE_WASM_GDB_REMOTE_DEBUGGING 11651cb0ef41Sopenharmony_ci 11661cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module = 11671cb0ef41Sopenharmony_ci GetWasmCodeManager()->NewNativeModule( 11681cb0ef41Sopenharmony_ci isolate, enabled, code_size_estimate, std::move(module)); 11691cb0ef41Sopenharmony_ci base::MutexGuard lock(&mutex_); 11701cb0ef41Sopenharmony_ci auto pair = native_modules_.insert(std::make_pair( 11711cb0ef41Sopenharmony_ci native_module.get(), std::make_unique<NativeModuleInfo>(native_module))); 11721cb0ef41Sopenharmony_ci DCHECK(pair.second); // inserted new entry. 11731cb0ef41Sopenharmony_ci pair.first->second.get()->isolates.insert(isolate); 11741cb0ef41Sopenharmony_ci auto* isolate_info = isolates_[isolate].get(); 11751cb0ef41Sopenharmony_ci isolate_info->native_modules.insert(native_module.get()); 11761cb0ef41Sopenharmony_ci if (isolate_info->keep_tiered_down) { 11771cb0ef41Sopenharmony_ci native_module->SetTieringState(kTieredDown); 11781cb0ef41Sopenharmony_ci } 11791cb0ef41Sopenharmony_ci 11801cb0ef41Sopenharmony_ci // Record memory protection key support. 11811cb0ef41Sopenharmony_ci if (!isolate_info->pku_support_sampled) { 11821cb0ef41Sopenharmony_ci isolate_info->pku_support_sampled = true; 11831cb0ef41Sopenharmony_ci auto* histogram = 11841cb0ef41Sopenharmony_ci isolate->counters()->wasm_memory_protection_keys_support(); 11851cb0ef41Sopenharmony_ci bool has_mpk = GetWasmCodeManager()->HasMemoryProtectionKeySupport(); 11861cb0ef41Sopenharmony_ci histogram->AddSample(has_mpk ? 1 : 0); 11871cb0ef41Sopenharmony_ci } 11881cb0ef41Sopenharmony_ci 11891cb0ef41Sopenharmony_ci isolate->counters()->wasm_modules_per_isolate()->AddSample( 11901cb0ef41Sopenharmony_ci static_cast<int>(isolate_info->native_modules.size())); 11911cb0ef41Sopenharmony_ci isolate->counters()->wasm_modules_per_engine()->AddSample( 11921cb0ef41Sopenharmony_ci static_cast<int>(native_modules_.size())); 11931cb0ef41Sopenharmony_ci return native_module; 11941cb0ef41Sopenharmony_ci} 11951cb0ef41Sopenharmony_ci 11961cb0ef41Sopenharmony_cistd::shared_ptr<NativeModule> WasmEngine::MaybeGetNativeModule( 11971cb0ef41Sopenharmony_ci ModuleOrigin origin, base::Vector<const uint8_t> wire_bytes, 11981cb0ef41Sopenharmony_ci Isolate* isolate) { 11991cb0ef41Sopenharmony_ci TRACE_EVENT1("v8.wasm", "wasm.GetNativeModuleFromCache", "wire_bytes", 12001cb0ef41Sopenharmony_ci wire_bytes.size()); 12011cb0ef41Sopenharmony_ci std::shared_ptr<NativeModule> native_module = 12021cb0ef41Sopenharmony_ci native_module_cache_.MaybeGetNativeModule(origin, wire_bytes); 12031cb0ef41Sopenharmony_ci bool recompile_module = false; 12041cb0ef41Sopenharmony_ci if (native_module) { 12051cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "CacheHit"); 12061cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 12071cb0ef41Sopenharmony_ci auto& native_module_info = native_modules_[native_module.get()]; 12081cb0ef41Sopenharmony_ci if (!native_module_info) { 12091cb0ef41Sopenharmony_ci native_module_info = std::make_unique<NativeModuleInfo>(native_module); 12101cb0ef41Sopenharmony_ci } 12111cb0ef41Sopenharmony_ci native_module_info->isolates.insert(isolate); 12121cb0ef41Sopenharmony_ci isolates_[isolate]->native_modules.insert(native_module.get()); 12131cb0ef41Sopenharmony_ci if (isolates_[isolate]->keep_tiered_down) { 12141cb0ef41Sopenharmony_ci native_module->SetTieringState(kTieredDown); 12151cb0ef41Sopenharmony_ci recompile_module = true; 12161cb0ef41Sopenharmony_ci } 12171cb0ef41Sopenharmony_ci } 12181cb0ef41Sopenharmony_ci // Potentially recompile the module for tier down, after releasing the mutex. 12191cb0ef41Sopenharmony_ci if (recompile_module) native_module->RecompileForTiering(); 12201cb0ef41Sopenharmony_ci return native_module; 12211cb0ef41Sopenharmony_ci} 12221cb0ef41Sopenharmony_ci 12231cb0ef41Sopenharmony_cibool WasmEngine::UpdateNativeModuleCache( 12241cb0ef41Sopenharmony_ci bool error, std::shared_ptr<NativeModule>* native_module, 12251cb0ef41Sopenharmony_ci Isolate* isolate) { 12261cb0ef41Sopenharmony_ci // Pass {native_module} by value here to keep it alive until at least after 12271cb0ef41Sopenharmony_ci // we returned from {Update}. Otherwise, we might {Erase} it inside {Update} 12281cb0ef41Sopenharmony_ci // which would lock the mutex twice. 12291cb0ef41Sopenharmony_ci auto prev = native_module->get(); 12301cb0ef41Sopenharmony_ci *native_module = native_module_cache_.Update(*native_module, error); 12311cb0ef41Sopenharmony_ci 12321cb0ef41Sopenharmony_ci if (prev == native_module->get()) return true; 12331cb0ef41Sopenharmony_ci 12341cb0ef41Sopenharmony_ci bool recompile_module = false; 12351cb0ef41Sopenharmony_ci { 12361cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 12371cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_.count(native_module->get())); 12381cb0ef41Sopenharmony_ci native_modules_[native_module->get()]->isolates.insert(isolate); 12391cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 12401cb0ef41Sopenharmony_ci isolates_[isolate]->native_modules.insert(native_module->get()); 12411cb0ef41Sopenharmony_ci if (isolates_[isolate]->keep_tiered_down) { 12421cb0ef41Sopenharmony_ci native_module->get()->SetTieringState(kTieredDown); 12431cb0ef41Sopenharmony_ci recompile_module = true; 12441cb0ef41Sopenharmony_ci } 12451cb0ef41Sopenharmony_ci } 12461cb0ef41Sopenharmony_ci // Potentially recompile the module for tier down, after releasing the mutex. 12471cb0ef41Sopenharmony_ci if (recompile_module) native_module->get()->RecompileForTiering(); 12481cb0ef41Sopenharmony_ci return false; 12491cb0ef41Sopenharmony_ci} 12501cb0ef41Sopenharmony_ci 12511cb0ef41Sopenharmony_cibool WasmEngine::GetStreamingCompilationOwnership(size_t prefix_hash) { 12521cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "wasm.GetStreamingCompilationOwnership"); 12531cb0ef41Sopenharmony_ci if (native_module_cache_.GetStreamingCompilationOwnership(prefix_hash)) { 12541cb0ef41Sopenharmony_ci return true; 12551cb0ef41Sopenharmony_ci } 12561cb0ef41Sopenharmony_ci // This is only a marker, not for tracing execution time. There should be a 12571cb0ef41Sopenharmony_ci // later "wasm.GetNativeModuleFromCache" event for trying to get the module 12581cb0ef41Sopenharmony_ci // from the cache. 12591cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "CacheHit"); 12601cb0ef41Sopenharmony_ci return false; 12611cb0ef41Sopenharmony_ci} 12621cb0ef41Sopenharmony_ci 12631cb0ef41Sopenharmony_civoid WasmEngine::StreamingCompilationFailed(size_t prefix_hash) { 12641cb0ef41Sopenharmony_ci native_module_cache_.StreamingCompilationFailed(prefix_hash); 12651cb0ef41Sopenharmony_ci} 12661cb0ef41Sopenharmony_ci 12671cb0ef41Sopenharmony_civoid WasmEngine::FreeNativeModule(NativeModule* native_module) { 12681cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 12691cb0ef41Sopenharmony_ci auto module = native_modules_.find(native_module); 12701cb0ef41Sopenharmony_ci DCHECK_NE(native_modules_.end(), module); 12711cb0ef41Sopenharmony_ci for (Isolate* isolate : module->second->isolates) { 12721cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 12731cb0ef41Sopenharmony_ci IsolateInfo* info = isolates_[isolate].get(); 12741cb0ef41Sopenharmony_ci DCHECK_EQ(1, info->native_modules.count(native_module)); 12751cb0ef41Sopenharmony_ci info->native_modules.erase(native_module); 12761cb0ef41Sopenharmony_ci info->scripts.erase(native_module); 12771cb0ef41Sopenharmony_ci // If there are {WasmCode} objects of the deleted {NativeModule} 12781cb0ef41Sopenharmony_ci // outstanding to be logged in this isolate, remove them. Decrementing the 12791cb0ef41Sopenharmony_ci // ref count is not needed, since the {NativeModule} dies anyway. 12801cb0ef41Sopenharmony_ci for (auto& log_entry : info->code_to_log) { 12811cb0ef41Sopenharmony_ci auto part_of_native_module = [native_module](WasmCode* code) { 12821cb0ef41Sopenharmony_ci return code->native_module() == native_module; 12831cb0ef41Sopenharmony_ci }; 12841cb0ef41Sopenharmony_ci std::vector<WasmCode*>& code = log_entry.second.code; 12851cb0ef41Sopenharmony_ci auto new_end = 12861cb0ef41Sopenharmony_ci std::remove_if(code.begin(), code.end(), part_of_native_module); 12871cb0ef41Sopenharmony_ci code.erase(new_end, code.end()); 12881cb0ef41Sopenharmony_ci } 12891cb0ef41Sopenharmony_ci // Now remove empty entries in {code_to_log}. 12901cb0ef41Sopenharmony_ci for (auto it = info->code_to_log.begin(), end = info->code_to_log.end(); 12911cb0ef41Sopenharmony_ci it != end;) { 12921cb0ef41Sopenharmony_ci if (it->second.code.empty()) { 12931cb0ef41Sopenharmony_ci it = info->code_to_log.erase(it); 12941cb0ef41Sopenharmony_ci } else { 12951cb0ef41Sopenharmony_ci ++it; 12961cb0ef41Sopenharmony_ci } 12971cb0ef41Sopenharmony_ci } 12981cb0ef41Sopenharmony_ci } 12991cb0ef41Sopenharmony_ci // If there is a GC running which has references to code contained in the 13001cb0ef41Sopenharmony_ci // deleted {NativeModule}, remove those references. 13011cb0ef41Sopenharmony_ci if (current_gc_info_) { 13021cb0ef41Sopenharmony_ci for (auto it = current_gc_info_->dead_code.begin(), 13031cb0ef41Sopenharmony_ci end = current_gc_info_->dead_code.end(); 13041cb0ef41Sopenharmony_ci it != end;) { 13051cb0ef41Sopenharmony_ci if ((*it)->native_module() == native_module) { 13061cb0ef41Sopenharmony_ci it = current_gc_info_->dead_code.erase(it); 13071cb0ef41Sopenharmony_ci } else { 13081cb0ef41Sopenharmony_ci ++it; 13091cb0ef41Sopenharmony_ci } 13101cb0ef41Sopenharmony_ci } 13111cb0ef41Sopenharmony_ci TRACE_CODE_GC("Native module %p died, reducing dead code objects to %zu.\n", 13121cb0ef41Sopenharmony_ci native_module, current_gc_info_->dead_code.size()); 13131cb0ef41Sopenharmony_ci } 13141cb0ef41Sopenharmony_ci native_module_cache_.Erase(native_module); 13151cb0ef41Sopenharmony_ci native_modules_.erase(module); 13161cb0ef41Sopenharmony_ci} 13171cb0ef41Sopenharmony_ci 13181cb0ef41Sopenharmony_cinamespace { 13191cb0ef41Sopenharmony_ciclass SampleTopTierCodeSizeTask : public CancelableTask { 13201cb0ef41Sopenharmony_ci public: 13211cb0ef41Sopenharmony_ci SampleTopTierCodeSizeTask(Isolate* isolate, 13221cb0ef41Sopenharmony_ci std::weak_ptr<NativeModule> native_module) 13231cb0ef41Sopenharmony_ci : CancelableTask(isolate), 13241cb0ef41Sopenharmony_ci isolate_(isolate), 13251cb0ef41Sopenharmony_ci native_module_(std::move(native_module)) {} 13261cb0ef41Sopenharmony_ci 13271cb0ef41Sopenharmony_ci void RunInternal() override { 13281cb0ef41Sopenharmony_ci if (std::shared_ptr<NativeModule> native_module = native_module_.lock()) { 13291cb0ef41Sopenharmony_ci native_module->SampleCodeSize(isolate_->counters(), 13301cb0ef41Sopenharmony_ci NativeModule::kAfterTopTier); 13311cb0ef41Sopenharmony_ci } 13321cb0ef41Sopenharmony_ci } 13331cb0ef41Sopenharmony_ci 13341cb0ef41Sopenharmony_ci private: 13351cb0ef41Sopenharmony_ci Isolate* const isolate_; 13361cb0ef41Sopenharmony_ci const std::weak_ptr<NativeModule> native_module_; 13371cb0ef41Sopenharmony_ci}; 13381cb0ef41Sopenharmony_ci} // namespace 13391cb0ef41Sopenharmony_ci 13401cb0ef41Sopenharmony_civoid WasmEngine::SampleTopTierCodeSizeInAllIsolates( 13411cb0ef41Sopenharmony_ci const std::shared_ptr<NativeModule>& native_module) { 13421cb0ef41Sopenharmony_ci base::MutexGuard lock(&mutex_); 13431cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_.count(native_module.get())); 13441cb0ef41Sopenharmony_ci for (Isolate* isolate : native_modules_[native_module.get()]->isolates) { 13451cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 13461cb0ef41Sopenharmony_ci IsolateInfo* info = isolates_[isolate].get(); 13471cb0ef41Sopenharmony_ci info->foreground_task_runner->PostTask( 13481cb0ef41Sopenharmony_ci std::make_unique<SampleTopTierCodeSizeTask>(isolate, native_module)); 13491cb0ef41Sopenharmony_ci } 13501cb0ef41Sopenharmony_ci} 13511cb0ef41Sopenharmony_ci 13521cb0ef41Sopenharmony_civoid WasmEngine::ReportLiveCodeForGC(Isolate* isolate, 13531cb0ef41Sopenharmony_ci base::Vector<WasmCode*> live_code) { 13541cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "wasm.ReportLiveCodeForGC"); 13551cb0ef41Sopenharmony_ci TRACE_CODE_GC("Isolate %d reporting %zu live code objects.\n", isolate->id(), 13561cb0ef41Sopenharmony_ci live_code.size()); 13571cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 13581cb0ef41Sopenharmony_ci // This report might come in late (note that we trigger both a stack guard and 13591cb0ef41Sopenharmony_ci // a foreground task). In that case, ignore it. 13601cb0ef41Sopenharmony_ci if (current_gc_info_ == nullptr) return; 13611cb0ef41Sopenharmony_ci if (!RemoveIsolateFromCurrentGC(isolate)) return; 13621cb0ef41Sopenharmony_ci isolate->counters()->wasm_module_num_triggered_code_gcs()->AddSample( 13631cb0ef41Sopenharmony_ci current_gc_info_->gc_sequence_index); 13641cb0ef41Sopenharmony_ci for (WasmCode* code : live_code) current_gc_info_->dead_code.erase(code); 13651cb0ef41Sopenharmony_ci PotentiallyFinishCurrentGC(); 13661cb0ef41Sopenharmony_ci} 13671cb0ef41Sopenharmony_ci 13681cb0ef41Sopenharmony_cinamespace { 13691cb0ef41Sopenharmony_civoid ReportLiveCodeFromFrameForGC( 13701cb0ef41Sopenharmony_ci StackFrame* frame, std::unordered_set<wasm::WasmCode*>& live_wasm_code) { 13711cb0ef41Sopenharmony_ci if (frame->type() != StackFrame::WASM) return; 13721cb0ef41Sopenharmony_ci live_wasm_code.insert(WasmFrame::cast(frame)->wasm_code()); 13731cb0ef41Sopenharmony_ci#if V8_TARGET_ARCH_X64 13741cb0ef41Sopenharmony_ci if (WasmFrame::cast(frame)->wasm_code()->for_debugging()) { 13751cb0ef41Sopenharmony_ci Address osr_target = base::Memory<Address>(WasmFrame::cast(frame)->fp() - 13761cb0ef41Sopenharmony_ci kOSRTargetOffset); 13771cb0ef41Sopenharmony_ci if (osr_target) { 13781cb0ef41Sopenharmony_ci WasmCode* osr_code = GetWasmCodeManager()->LookupCode(osr_target); 13791cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(osr_code); 13801cb0ef41Sopenharmony_ci live_wasm_code.insert(osr_code); 13811cb0ef41Sopenharmony_ci } 13821cb0ef41Sopenharmony_ci } 13831cb0ef41Sopenharmony_ci#endif 13841cb0ef41Sopenharmony_ci} 13851cb0ef41Sopenharmony_ci} // namespace 13861cb0ef41Sopenharmony_ci 13871cb0ef41Sopenharmony_civoid WasmEngine::ReportLiveCodeFromStackForGC(Isolate* isolate) { 13881cb0ef41Sopenharmony_ci wasm::WasmCodeRefScope code_ref_scope; 13891cb0ef41Sopenharmony_ci std::unordered_set<wasm::WasmCode*> live_wasm_code; 13901cb0ef41Sopenharmony_ci if (FLAG_experimental_wasm_stack_switching) { 13911cb0ef41Sopenharmony_ci wasm::StackMemory* current = isolate->wasm_stacks(); 13921cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(current); 13931cb0ef41Sopenharmony_ci do { 13941cb0ef41Sopenharmony_ci if (current->IsActive()) { 13951cb0ef41Sopenharmony_ci // The active stack's jump buffer does not match the current state, use 13961cb0ef41Sopenharmony_ci // the thread info below instead. 13971cb0ef41Sopenharmony_ci current = current->next(); 13981cb0ef41Sopenharmony_ci continue; 13991cb0ef41Sopenharmony_ci } 14001cb0ef41Sopenharmony_ci for (StackFrameIterator it(isolate, current); !it.done(); it.Advance()) { 14011cb0ef41Sopenharmony_ci StackFrame* const frame = it.frame(); 14021cb0ef41Sopenharmony_ci ReportLiveCodeFromFrameForGC(frame, live_wasm_code); 14031cb0ef41Sopenharmony_ci } 14041cb0ef41Sopenharmony_ci current = current->next(); 14051cb0ef41Sopenharmony_ci } while (current != isolate->wasm_stacks()); 14061cb0ef41Sopenharmony_ci } 14071cb0ef41Sopenharmony_ci for (StackFrameIterator it(isolate); !it.done(); it.Advance()) { 14081cb0ef41Sopenharmony_ci StackFrame* const frame = it.frame(); 14091cb0ef41Sopenharmony_ci ReportLiveCodeFromFrameForGC(frame, live_wasm_code); 14101cb0ef41Sopenharmony_ci } 14111cb0ef41Sopenharmony_ci 14121cb0ef41Sopenharmony_ci CheckNoArchivedThreads(isolate); 14131cb0ef41Sopenharmony_ci 14141cb0ef41Sopenharmony_ci ReportLiveCodeForGC( 14151cb0ef41Sopenharmony_ci isolate, base::OwnedVector<WasmCode*>::Of(live_wasm_code).as_vector()); 14161cb0ef41Sopenharmony_ci} 14171cb0ef41Sopenharmony_ci 14181cb0ef41Sopenharmony_cibool WasmEngine::AddPotentiallyDeadCode(WasmCode* code) { 14191cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 14201cb0ef41Sopenharmony_ci auto it = native_modules_.find(code->native_module()); 14211cb0ef41Sopenharmony_ci DCHECK_NE(native_modules_.end(), it); 14221cb0ef41Sopenharmony_ci NativeModuleInfo* info = it->second.get(); 14231cb0ef41Sopenharmony_ci if (info->dead_code.count(code)) return false; // Code is already dead. 14241cb0ef41Sopenharmony_ci auto added = info->potentially_dead_code.insert(code); 14251cb0ef41Sopenharmony_ci if (!added.second) return false; // An entry already existed. 14261cb0ef41Sopenharmony_ci new_potentially_dead_code_size_ += code->instructions().size(); 14271cb0ef41Sopenharmony_ci if (FLAG_wasm_code_gc) { 14281cb0ef41Sopenharmony_ci // Trigger a GC if 64kB plus 10% of committed code are potentially dead. 14291cb0ef41Sopenharmony_ci size_t dead_code_limit = 14301cb0ef41Sopenharmony_ci FLAG_stress_wasm_code_gc 14311cb0ef41Sopenharmony_ci ? 0 14321cb0ef41Sopenharmony_ci : 64 * KB + GetWasmCodeManager()->committed_code_space() / 10; 14331cb0ef41Sopenharmony_ci if (new_potentially_dead_code_size_ > dead_code_limit) { 14341cb0ef41Sopenharmony_ci bool inc_gc_count = 14351cb0ef41Sopenharmony_ci info->num_code_gcs_triggered < std::numeric_limits<int8_t>::max(); 14361cb0ef41Sopenharmony_ci if (current_gc_info_ == nullptr) { 14371cb0ef41Sopenharmony_ci if (inc_gc_count) ++info->num_code_gcs_triggered; 14381cb0ef41Sopenharmony_ci TRACE_CODE_GC( 14391cb0ef41Sopenharmony_ci "Triggering GC (potentially dead: %zu bytes; limit: %zu bytes).\n", 14401cb0ef41Sopenharmony_ci new_potentially_dead_code_size_, dead_code_limit); 14411cb0ef41Sopenharmony_ci TriggerGC(info->num_code_gcs_triggered); 14421cb0ef41Sopenharmony_ci } else if (current_gc_info_->next_gc_sequence_index == 0) { 14431cb0ef41Sopenharmony_ci if (inc_gc_count) ++info->num_code_gcs_triggered; 14441cb0ef41Sopenharmony_ci TRACE_CODE_GC( 14451cb0ef41Sopenharmony_ci "Scheduling another GC after the current one (potentially dead: " 14461cb0ef41Sopenharmony_ci "%zu bytes; limit: %zu bytes).\n", 14471cb0ef41Sopenharmony_ci new_potentially_dead_code_size_, dead_code_limit); 14481cb0ef41Sopenharmony_ci current_gc_info_->next_gc_sequence_index = info->num_code_gcs_triggered; 14491cb0ef41Sopenharmony_ci DCHECK_NE(0, current_gc_info_->next_gc_sequence_index); 14501cb0ef41Sopenharmony_ci } 14511cb0ef41Sopenharmony_ci } 14521cb0ef41Sopenharmony_ci } 14531cb0ef41Sopenharmony_ci return true; 14541cb0ef41Sopenharmony_ci} 14551cb0ef41Sopenharmony_ci 14561cb0ef41Sopenharmony_civoid WasmEngine::FreeDeadCode(const DeadCodeMap& dead_code) { 14571cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 14581cb0ef41Sopenharmony_ci FreeDeadCodeLocked(dead_code); 14591cb0ef41Sopenharmony_ci} 14601cb0ef41Sopenharmony_ci 14611cb0ef41Sopenharmony_civoid WasmEngine::FreeDeadCodeLocked(const DeadCodeMap& dead_code) { 14621cb0ef41Sopenharmony_ci TRACE_EVENT0("v8.wasm", "wasm.FreeDeadCode"); 14631cb0ef41Sopenharmony_ci DCHECK(!mutex_.TryLock()); 14641cb0ef41Sopenharmony_ci for (auto& dead_code_entry : dead_code) { 14651cb0ef41Sopenharmony_ci NativeModule* native_module = dead_code_entry.first; 14661cb0ef41Sopenharmony_ci const std::vector<WasmCode*>& code_vec = dead_code_entry.second; 14671cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_.count(native_module)); 14681cb0ef41Sopenharmony_ci auto* info = native_modules_[native_module].get(); 14691cb0ef41Sopenharmony_ci TRACE_CODE_GC("Freeing %zu code object%s of module %p.\n", code_vec.size(), 14701cb0ef41Sopenharmony_ci code_vec.size() == 1 ? "" : "s", native_module); 14711cb0ef41Sopenharmony_ci for (WasmCode* code : code_vec) { 14721cb0ef41Sopenharmony_ci DCHECK_EQ(1, info->dead_code.count(code)); 14731cb0ef41Sopenharmony_ci info->dead_code.erase(code); 14741cb0ef41Sopenharmony_ci } 14751cb0ef41Sopenharmony_ci native_module->FreeCode(base::VectorOf(code_vec)); 14761cb0ef41Sopenharmony_ci } 14771cb0ef41Sopenharmony_ci} 14781cb0ef41Sopenharmony_ci 14791cb0ef41Sopenharmony_ciHandle<Script> WasmEngine::GetOrCreateScript( 14801cb0ef41Sopenharmony_ci Isolate* isolate, const std::shared_ptr<NativeModule>& native_module, 14811cb0ef41Sopenharmony_ci base::Vector<const char> source_url) { 14821cb0ef41Sopenharmony_ci { 14831cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 14841cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 14851cb0ef41Sopenharmony_ci auto& scripts = isolates_[isolate]->scripts; 14861cb0ef41Sopenharmony_ci auto it = scripts.find(native_module.get()); 14871cb0ef41Sopenharmony_ci if (it != scripts.end()) { 14881cb0ef41Sopenharmony_ci Handle<Script> weak_global_handle = it->second.handle(); 14891cb0ef41Sopenharmony_ci if (weak_global_handle.is_null()) { 14901cb0ef41Sopenharmony_ci scripts.erase(it); 14911cb0ef41Sopenharmony_ci } else { 14921cb0ef41Sopenharmony_ci return Handle<Script>::New(*weak_global_handle, isolate); 14931cb0ef41Sopenharmony_ci } 14941cb0ef41Sopenharmony_ci } 14951cb0ef41Sopenharmony_ci } 14961cb0ef41Sopenharmony_ci // Temporarily release the mutex to let the GC collect native modules. 14971cb0ef41Sopenharmony_ci auto script = CreateWasmScript(isolate, native_module, source_url); 14981cb0ef41Sopenharmony_ci { 14991cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 15001cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 15011cb0ef41Sopenharmony_ci auto& scripts = isolates_[isolate]->scripts; 15021cb0ef41Sopenharmony_ci DCHECK_EQ(0, scripts.count(native_module.get())); 15031cb0ef41Sopenharmony_ci scripts.emplace(native_module.get(), WeakScriptHandle(script)); 15041cb0ef41Sopenharmony_ci return script; 15051cb0ef41Sopenharmony_ci } 15061cb0ef41Sopenharmony_ci} 15071cb0ef41Sopenharmony_ci 15081cb0ef41Sopenharmony_cistd::shared_ptr<OperationsBarrier> 15091cb0ef41Sopenharmony_ciWasmEngine::GetBarrierForBackgroundCompile() { 15101cb0ef41Sopenharmony_ci return operations_barrier_; 15111cb0ef41Sopenharmony_ci} 15121cb0ef41Sopenharmony_ci 15131cb0ef41Sopenharmony_cinamespace { 15141cb0ef41Sopenharmony_civoid SampleExceptionEvent(base::ElapsedTimer* timer, TimedHistogram* counter) { 15151cb0ef41Sopenharmony_ci if (!timer->IsStarted()) { 15161cb0ef41Sopenharmony_ci timer->Start(); 15171cb0ef41Sopenharmony_ci return; 15181cb0ef41Sopenharmony_ci } 15191cb0ef41Sopenharmony_ci counter->AddSample(static_cast<int>(timer->Elapsed().InMilliseconds())); 15201cb0ef41Sopenharmony_ci timer->Restart(); 15211cb0ef41Sopenharmony_ci} 15221cb0ef41Sopenharmony_ci} // namespace 15231cb0ef41Sopenharmony_ci 15241cb0ef41Sopenharmony_civoid WasmEngine::SampleThrowEvent(Isolate* isolate) { 15251cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 15261cb0ef41Sopenharmony_ci IsolateInfo* isolate_info = isolates_[isolate].get(); 15271cb0ef41Sopenharmony_ci int& throw_count = isolate_info->throw_count; 15281cb0ef41Sopenharmony_ci // To avoid an int overflow, clip the count to the histogram's max value. 15291cb0ef41Sopenharmony_ci throw_count = 15301cb0ef41Sopenharmony_ci std::min(throw_count + 1, isolate->counters()->wasm_throw_count()->max()); 15311cb0ef41Sopenharmony_ci isolate->counters()->wasm_throw_count()->AddSample(throw_count); 15321cb0ef41Sopenharmony_ci SampleExceptionEvent(&isolate_info->throw_timer, 15331cb0ef41Sopenharmony_ci isolate->counters()->wasm_time_between_throws()); 15341cb0ef41Sopenharmony_ci} 15351cb0ef41Sopenharmony_ci 15361cb0ef41Sopenharmony_civoid WasmEngine::SampleRethrowEvent(Isolate* isolate) { 15371cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 15381cb0ef41Sopenharmony_ci IsolateInfo* isolate_info = isolates_[isolate].get(); 15391cb0ef41Sopenharmony_ci int& rethrow_count = isolate_info->rethrow_count; 15401cb0ef41Sopenharmony_ci // To avoid an int overflow, clip the count to the histogram's max value. 15411cb0ef41Sopenharmony_ci rethrow_count = std::min(rethrow_count + 1, 15421cb0ef41Sopenharmony_ci isolate->counters()->wasm_rethrow_count()->max()); 15431cb0ef41Sopenharmony_ci isolate->counters()->wasm_rethrow_count()->AddSample(rethrow_count); 15441cb0ef41Sopenharmony_ci SampleExceptionEvent(&isolate_info->rethrow_timer, 15451cb0ef41Sopenharmony_ci isolate->counters()->wasm_time_between_rethrows()); 15461cb0ef41Sopenharmony_ci} 15471cb0ef41Sopenharmony_ci 15481cb0ef41Sopenharmony_civoid WasmEngine::SampleCatchEvent(Isolate* isolate) { 15491cb0ef41Sopenharmony_ci base::MutexGuard guard(&mutex_); 15501cb0ef41Sopenharmony_ci IsolateInfo* isolate_info = isolates_[isolate].get(); 15511cb0ef41Sopenharmony_ci int& catch_count = isolate_info->catch_count; 15521cb0ef41Sopenharmony_ci // To avoid an int overflow, clip the count to the histogram's max value. 15531cb0ef41Sopenharmony_ci catch_count = 15541cb0ef41Sopenharmony_ci std::min(catch_count + 1, isolate->counters()->wasm_catch_count()->max()); 15551cb0ef41Sopenharmony_ci isolate->counters()->wasm_catch_count()->AddSample(catch_count); 15561cb0ef41Sopenharmony_ci SampleExceptionEvent(&isolate_info->catch_timer, 15571cb0ef41Sopenharmony_ci isolate->counters()->wasm_time_between_catch()); 15581cb0ef41Sopenharmony_ci} 15591cb0ef41Sopenharmony_ci 15601cb0ef41Sopenharmony_civoid WasmEngine::TriggerGC(int8_t gc_sequence_index) { 15611cb0ef41Sopenharmony_ci DCHECK(!mutex_.TryLock()); 15621cb0ef41Sopenharmony_ci DCHECK_NULL(current_gc_info_); 15631cb0ef41Sopenharmony_ci DCHECK(FLAG_wasm_code_gc); 15641cb0ef41Sopenharmony_ci new_potentially_dead_code_size_ = 0; 15651cb0ef41Sopenharmony_ci current_gc_info_.reset(new CurrentGCInfo(gc_sequence_index)); 15661cb0ef41Sopenharmony_ci // Add all potentially dead code to this GC, and trigger a GC task in each 15671cb0ef41Sopenharmony_ci // isolate. 15681cb0ef41Sopenharmony_ci for (auto& entry : native_modules_) { 15691cb0ef41Sopenharmony_ci NativeModuleInfo* info = entry.second.get(); 15701cb0ef41Sopenharmony_ci if (info->potentially_dead_code.empty()) continue; 15711cb0ef41Sopenharmony_ci for (auto* isolate : native_modules_[entry.first]->isolates) { 15721cb0ef41Sopenharmony_ci auto& gc_task = current_gc_info_->outstanding_isolates[isolate]; 15731cb0ef41Sopenharmony_ci if (!gc_task) { 15741cb0ef41Sopenharmony_ci auto new_task = std::make_unique<WasmGCForegroundTask>(isolate); 15751cb0ef41Sopenharmony_ci gc_task = new_task.get(); 15761cb0ef41Sopenharmony_ci DCHECK_EQ(1, isolates_.count(isolate)); 15771cb0ef41Sopenharmony_ci isolates_[isolate]->foreground_task_runner->PostTask( 15781cb0ef41Sopenharmony_ci std::move(new_task)); 15791cb0ef41Sopenharmony_ci } 15801cb0ef41Sopenharmony_ci isolate->stack_guard()->RequestWasmCodeGC(); 15811cb0ef41Sopenharmony_ci } 15821cb0ef41Sopenharmony_ci for (WasmCode* code : info->potentially_dead_code) { 15831cb0ef41Sopenharmony_ci current_gc_info_->dead_code.insert(code); 15841cb0ef41Sopenharmony_ci } 15851cb0ef41Sopenharmony_ci } 15861cb0ef41Sopenharmony_ci TRACE_CODE_GC( 15871cb0ef41Sopenharmony_ci "Starting GC (nr %d). Number of potentially dead code objects: %zu\n", 15881cb0ef41Sopenharmony_ci current_gc_info_->gc_sequence_index, current_gc_info_->dead_code.size()); 15891cb0ef41Sopenharmony_ci // Ensure that there are outstanding isolates that will eventually finish this 15901cb0ef41Sopenharmony_ci // GC. If there are no outstanding isolates, we finish the GC immediately. 15911cb0ef41Sopenharmony_ci PotentiallyFinishCurrentGC(); 15921cb0ef41Sopenharmony_ci DCHECK(current_gc_info_ == nullptr || 15931cb0ef41Sopenharmony_ci !current_gc_info_->outstanding_isolates.empty()); 15941cb0ef41Sopenharmony_ci} 15951cb0ef41Sopenharmony_ci 15961cb0ef41Sopenharmony_cibool WasmEngine::RemoveIsolateFromCurrentGC(Isolate* isolate) { 15971cb0ef41Sopenharmony_ci DCHECK(!mutex_.TryLock()); 15981cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(current_gc_info_); 15991cb0ef41Sopenharmony_ci return current_gc_info_->outstanding_isolates.erase(isolate) != 0; 16001cb0ef41Sopenharmony_ci} 16011cb0ef41Sopenharmony_ci 16021cb0ef41Sopenharmony_civoid WasmEngine::PotentiallyFinishCurrentGC() { 16031cb0ef41Sopenharmony_ci DCHECK(!mutex_.TryLock()); 16041cb0ef41Sopenharmony_ci TRACE_CODE_GC( 16051cb0ef41Sopenharmony_ci "Remaining dead code objects: %zu; outstanding isolates: %zu.\n", 16061cb0ef41Sopenharmony_ci current_gc_info_->dead_code.size(), 16071cb0ef41Sopenharmony_ci current_gc_info_->outstanding_isolates.size()); 16081cb0ef41Sopenharmony_ci 16091cb0ef41Sopenharmony_ci // If there are more outstanding isolates, return immediately. 16101cb0ef41Sopenharmony_ci if (!current_gc_info_->outstanding_isolates.empty()) return; 16111cb0ef41Sopenharmony_ci 16121cb0ef41Sopenharmony_ci // All remaining code in {current_gc_info->dead_code} is really dead. 16131cb0ef41Sopenharmony_ci // Move it from the set of potentially dead code to the set of dead code, 16141cb0ef41Sopenharmony_ci // and decrement its ref count. 16151cb0ef41Sopenharmony_ci size_t num_freed = 0; 16161cb0ef41Sopenharmony_ci DeadCodeMap dead_code; 16171cb0ef41Sopenharmony_ci for (WasmCode* code : current_gc_info_->dead_code) { 16181cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_modules_.count(code->native_module())); 16191cb0ef41Sopenharmony_ci auto* native_module_info = native_modules_[code->native_module()].get(); 16201cb0ef41Sopenharmony_ci DCHECK_EQ(1, native_module_info->potentially_dead_code.count(code)); 16211cb0ef41Sopenharmony_ci native_module_info->potentially_dead_code.erase(code); 16221cb0ef41Sopenharmony_ci DCHECK_EQ(0, native_module_info->dead_code.count(code)); 16231cb0ef41Sopenharmony_ci native_module_info->dead_code.insert(code); 16241cb0ef41Sopenharmony_ci if (code->DecRefOnDeadCode()) { 16251cb0ef41Sopenharmony_ci dead_code[code->native_module()].push_back(code); 16261cb0ef41Sopenharmony_ci ++num_freed; 16271cb0ef41Sopenharmony_ci } 16281cb0ef41Sopenharmony_ci } 16291cb0ef41Sopenharmony_ci 16301cb0ef41Sopenharmony_ci FreeDeadCodeLocked(dead_code); 16311cb0ef41Sopenharmony_ci 16321cb0ef41Sopenharmony_ci TRACE_CODE_GC("Found %zu dead code objects, freed %zu.\n", 16331cb0ef41Sopenharmony_ci current_gc_info_->dead_code.size(), num_freed); 16341cb0ef41Sopenharmony_ci USE(num_freed); 16351cb0ef41Sopenharmony_ci 16361cb0ef41Sopenharmony_ci int8_t next_gc_sequence_index = current_gc_info_->next_gc_sequence_index; 16371cb0ef41Sopenharmony_ci current_gc_info_.reset(); 16381cb0ef41Sopenharmony_ci if (next_gc_sequence_index != 0) TriggerGC(next_gc_sequence_index); 16391cb0ef41Sopenharmony_ci} 16401cb0ef41Sopenharmony_ci 16411cb0ef41Sopenharmony_cinamespace { 16421cb0ef41Sopenharmony_ci 16431cb0ef41Sopenharmony_cistruct GlobalWasmState { 16441cb0ef41Sopenharmony_ci // Note: The order of fields is important here, as the WasmEngine's destructor 16451cb0ef41Sopenharmony_ci // must run first. It contains a barrier which ensures that background threads 16461cb0ef41Sopenharmony_ci // finished, and that has to happen before the WasmCodeManager gets destroyed. 16471cb0ef41Sopenharmony_ci WasmCodeManager code_manager; 16481cb0ef41Sopenharmony_ci WasmEngine engine; 16491cb0ef41Sopenharmony_ci}; 16501cb0ef41Sopenharmony_ci 16511cb0ef41Sopenharmony_ciGlobalWasmState* global_wasm_state = nullptr; 16521cb0ef41Sopenharmony_ci 16531cb0ef41Sopenharmony_ci} // namespace 16541cb0ef41Sopenharmony_ci 16551cb0ef41Sopenharmony_ci// static 16561cb0ef41Sopenharmony_civoid WasmEngine::InitializeOncePerProcess() { 16571cb0ef41Sopenharmony_ci InitializeMemoryProtectionKeySupport(); 16581cb0ef41Sopenharmony_ci DCHECK_NULL(global_wasm_state); 16591cb0ef41Sopenharmony_ci global_wasm_state = new GlobalWasmState(); 16601cb0ef41Sopenharmony_ci} 16611cb0ef41Sopenharmony_ci 16621cb0ef41Sopenharmony_ci// static 16631cb0ef41Sopenharmony_civoid WasmEngine::GlobalTearDown() { 16641cb0ef41Sopenharmony_ci // Note: This can be called multiple times in a row (see 16651cb0ef41Sopenharmony_ci // test-api/InitializeAndDisposeMultiple). This is fine, as 16661cb0ef41Sopenharmony_ci // {global_wasm_engine} will be nullptr then. 16671cb0ef41Sopenharmony_ci delete global_wasm_state; 16681cb0ef41Sopenharmony_ci global_wasm_state = nullptr; 16691cb0ef41Sopenharmony_ci} 16701cb0ef41Sopenharmony_ci 16711cb0ef41Sopenharmony_ciWasmEngine* GetWasmEngine() { 16721cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(global_wasm_state); 16731cb0ef41Sopenharmony_ci return &global_wasm_state->engine; 16741cb0ef41Sopenharmony_ci} 16751cb0ef41Sopenharmony_ci 16761cb0ef41Sopenharmony_ciWasmCodeManager* GetWasmCodeManager() { 16771cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(global_wasm_state); 16781cb0ef41Sopenharmony_ci return &global_wasm_state->code_manager; 16791cb0ef41Sopenharmony_ci} 16801cb0ef41Sopenharmony_ci 16811cb0ef41Sopenharmony_ci// {max_mem_pages} is declared in wasm-limits.h. 16821cb0ef41Sopenharmony_ciuint32_t max_mem_pages() { 16831cb0ef41Sopenharmony_ci static_assert( 16841cb0ef41Sopenharmony_ci kV8MaxWasmMemoryPages * kWasmPageSize <= JSArrayBuffer::kMaxByteLength, 16851cb0ef41Sopenharmony_ci "Wasm memories must not be bigger than JSArrayBuffers"); 16861cb0ef41Sopenharmony_ci STATIC_ASSERT(kV8MaxWasmMemoryPages <= kMaxUInt32); 16871cb0ef41Sopenharmony_ci return std::min(uint32_t{kV8MaxWasmMemoryPages}, FLAG_wasm_max_mem_pages); 16881cb0ef41Sopenharmony_ci} 16891cb0ef41Sopenharmony_ci 16901cb0ef41Sopenharmony_ci// {max_table_init_entries} is declared in wasm-limits.h. 16911cb0ef41Sopenharmony_ciuint32_t max_table_init_entries() { 16921cb0ef41Sopenharmony_ci return std::min(uint32_t{kV8MaxWasmTableInitEntries}, 16931cb0ef41Sopenharmony_ci FLAG_wasm_max_table_size); 16941cb0ef41Sopenharmony_ci} 16951cb0ef41Sopenharmony_ci 16961cb0ef41Sopenharmony_ci// {max_module_size} is declared in wasm-limits.h. 16971cb0ef41Sopenharmony_cisize_t max_module_size() { 16981cb0ef41Sopenharmony_ci return FLAG_experimental_wasm_allow_huge_modules 16991cb0ef41Sopenharmony_ci ? RoundDown<kSystemPointerSize>(size_t{kMaxInt}) 17001cb0ef41Sopenharmony_ci : kV8MaxWasmModuleSize; 17011cb0ef41Sopenharmony_ci} 17021cb0ef41Sopenharmony_ci 17031cb0ef41Sopenharmony_ci#undef TRACE_CODE_GC 17041cb0ef41Sopenharmony_ci 17051cb0ef41Sopenharmony_ci} // namespace wasm 17061cb0ef41Sopenharmony_ci} // namespace internal 17071cb0ef41Sopenharmony_ci} // namespace v8 1708