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