11cb0ef41Sopenharmony_ci// Copyright 2017 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#if !V8_ENABLE_WEBASSEMBLY
61cb0ef41Sopenharmony_ci#error This header should only be included if WebAssembly is enabled.
71cb0ef41Sopenharmony_ci#endif  // !V8_ENABLE_WEBASSEMBLY
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci#ifndef V8_WASM_MODULE_COMPILER_H_
101cb0ef41Sopenharmony_ci#define V8_WASM_MODULE_COMPILER_H_
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci#include <atomic>
131cb0ef41Sopenharmony_ci#include <functional>
141cb0ef41Sopenharmony_ci#include <memory>
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ci#include "include/v8-metrics.h"
171cb0ef41Sopenharmony_ci#include "src/base/optional.h"
181cb0ef41Sopenharmony_ci#include "src/common/globals.h"
191cb0ef41Sopenharmony_ci#include "src/logging/metrics.h"
201cb0ef41Sopenharmony_ci#include "src/tasks/cancelable-task.h"
211cb0ef41Sopenharmony_ci#include "src/wasm/compilation-environment.h"
221cb0ef41Sopenharmony_ci#include "src/wasm/wasm-features.h"
231cb0ef41Sopenharmony_ci#include "src/wasm/wasm-import-wrapper-cache.h"
241cb0ef41Sopenharmony_ci#include "src/wasm/wasm-module.h"
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_cinamespace v8 {
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_cinamespace base {
291cb0ef41Sopenharmony_citemplate <typename T>
301cb0ef41Sopenharmony_ciclass Vector;
311cb0ef41Sopenharmony_ci}  // namespace base
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_cinamespace internal {
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ciclass JSArrayBuffer;
361cb0ef41Sopenharmony_ciclass JSPromise;
371cb0ef41Sopenharmony_ciclass Counters;
381cb0ef41Sopenharmony_ciclass WasmModuleObject;
391cb0ef41Sopenharmony_ciclass WasmInstanceObject;
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_cinamespace wasm {
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_cistruct CompilationEnv;
441cb0ef41Sopenharmony_ciclass CompilationResultResolver;
451cb0ef41Sopenharmony_ciclass ErrorThrower;
461cb0ef41Sopenharmony_ciclass ModuleCompiler;
471cb0ef41Sopenharmony_ciclass NativeModule;
481cb0ef41Sopenharmony_ciclass StreamingDecoder;
491cb0ef41Sopenharmony_ciclass WasmCode;
501cb0ef41Sopenharmony_cistruct WasmModule;
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ciV8_EXPORT_PRIVATE
531cb0ef41Sopenharmony_cistd::shared_ptr<NativeModule> CompileToNativeModule(
541cb0ef41Sopenharmony_ci    Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
551cb0ef41Sopenharmony_ci    std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
561cb0ef41Sopenharmony_ci    Handle<FixedArray>* export_wrappers_out, int compilation_id,
571cb0ef41Sopenharmony_ci    v8::metrics::Recorder::ContextId context_id);
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_civoid RecompileNativeModule(NativeModule* native_module,
601cb0ef41Sopenharmony_ci                           TieringState new_tiering_state);
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ciV8_EXPORT_PRIVATE
631cb0ef41Sopenharmony_civoid CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
641cb0ef41Sopenharmony_ci                             Handle<FixedArray>* export_wrappers_out);
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci// Compiles the wrapper for this (kind, sig) pair and sets the corresponding
671cb0ef41Sopenharmony_ci// cache entry. Assumes the key already exists in the cache but has not been
681cb0ef41Sopenharmony_ci// compiled yet.
691cb0ef41Sopenharmony_ciV8_EXPORT_PRIVATE
701cb0ef41Sopenharmony_ciWasmCode* CompileImportWrapper(
711cb0ef41Sopenharmony_ci    NativeModule* native_module, Counters* counters,
721cb0ef41Sopenharmony_ci    compiler::WasmImportCallKind kind, const FunctionSig* sig,
731cb0ef41Sopenharmony_ci    int expected_arity, Suspend suspend,
741cb0ef41Sopenharmony_ci    WasmImportWrapperCache::ModificationScope* cache_scope);
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci// Triggered by the WasmCompileLazy builtin. The return value indicates whether
771cb0ef41Sopenharmony_ci// compilation was successful. Lazy compilation can fail only if validation is
781cb0ef41Sopenharmony_ci// also lazy.
791cb0ef41Sopenharmony_cibool CompileLazy(Isolate*, Handle<WasmInstanceObject>, int func_index);
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ciV8_EXPORT_PRIVATE void TriggerTierUp(Isolate*, NativeModule*, int func_index,
821cb0ef41Sopenharmony_ci                                     Handle<WasmInstanceObject> instance);
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_citemplate <typename Key, typename Hash>
851cb0ef41Sopenharmony_ciclass WrapperQueue {
861cb0ef41Sopenharmony_ci public:
871cb0ef41Sopenharmony_ci  // Removes an arbitrary key from the queue and returns it.
881cb0ef41Sopenharmony_ci  // If the queue is empty, returns nullopt.
891cb0ef41Sopenharmony_ci  // Thread-safe.
901cb0ef41Sopenharmony_ci  base::Optional<Key> pop() {
911cb0ef41Sopenharmony_ci    base::Optional<Key> key = base::nullopt;
921cb0ef41Sopenharmony_ci    base::MutexGuard lock(&mutex_);
931cb0ef41Sopenharmony_ci    auto it = queue_.begin();
941cb0ef41Sopenharmony_ci    if (it != queue_.end()) {
951cb0ef41Sopenharmony_ci      key = *it;
961cb0ef41Sopenharmony_ci      queue_.erase(it);
971cb0ef41Sopenharmony_ci    }
981cb0ef41Sopenharmony_ci    return key;
991cb0ef41Sopenharmony_ci  }
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci  // Add the given key to the queue and returns true iff the insert was
1021cb0ef41Sopenharmony_ci  // successful.
1031cb0ef41Sopenharmony_ci  // Not thread-safe.
1041cb0ef41Sopenharmony_ci  bool insert(const Key& key) { return queue_.insert(key).second; }
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci  size_t size() {
1071cb0ef41Sopenharmony_ci    base::MutexGuard lock(&mutex_);
1081cb0ef41Sopenharmony_ci    return queue_.size();
1091cb0ef41Sopenharmony_ci  }
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci private:
1121cb0ef41Sopenharmony_ci  base::Mutex mutex_;
1131cb0ef41Sopenharmony_ci  std::unordered_set<Key, Hash> queue_;
1141cb0ef41Sopenharmony_ci};
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci// Encapsulates all the state and steps of an asynchronous compilation.
1171cb0ef41Sopenharmony_ci// An asynchronous compile job consists of a number of tasks that are executed
1181cb0ef41Sopenharmony_ci// as foreground and background tasks. Any phase that touches the V8 heap or
1191cb0ef41Sopenharmony_ci// allocates on the V8 heap (e.g. creating the module object) must be a
1201cb0ef41Sopenharmony_ci// foreground task. All other tasks (e.g. decoding and validating, the majority
1211cb0ef41Sopenharmony_ci// of the work of compilation) can be background tasks.
1221cb0ef41Sopenharmony_ci// TODO(wasm): factor out common parts of this with the synchronous pipeline.
1231cb0ef41Sopenharmony_ciclass AsyncCompileJob {
1241cb0ef41Sopenharmony_ci public:
1251cb0ef41Sopenharmony_ci  AsyncCompileJob(Isolate* isolate, const WasmFeatures& enabled_features,
1261cb0ef41Sopenharmony_ci                  std::unique_ptr<byte[]> bytes_copy, size_t length,
1271cb0ef41Sopenharmony_ci                  Handle<Context> context, Handle<Context> incumbent_context,
1281cb0ef41Sopenharmony_ci                  const char* api_method_name,
1291cb0ef41Sopenharmony_ci                  std::shared_ptr<CompilationResultResolver> resolver,
1301cb0ef41Sopenharmony_ci                  int compilation_id);
1311cb0ef41Sopenharmony_ci  ~AsyncCompileJob();
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  void Start();
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci  std::shared_ptr<StreamingDecoder> CreateStreamingDecoder();
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci  void Abort();
1381cb0ef41Sopenharmony_ci  void CancelPendingForegroundTask();
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci  Isolate* isolate() const { return isolate_; }
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci  Handle<NativeContext> context() const { return native_context_; }
1431cb0ef41Sopenharmony_ci  v8::metrics::Recorder::ContextId context_id() const { return context_id_; }
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci private:
1461cb0ef41Sopenharmony_ci  class CompileTask;
1471cb0ef41Sopenharmony_ci  class CompileStep;
1481cb0ef41Sopenharmony_ci  class CompilationStateCallback;
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci  // States of the AsyncCompileJob.
1511cb0ef41Sopenharmony_ci  class DecodeModule;            // Step 1  (async)
1521cb0ef41Sopenharmony_ci  class DecodeFail;              // Step 1b (sync)
1531cb0ef41Sopenharmony_ci  class PrepareAndStartCompile;  // Step 2  (sync)
1541cb0ef41Sopenharmony_ci  class CompileFailed;           // Step 3a (sync)
1551cb0ef41Sopenharmony_ci  class CompileFinished;         // Step 3b (sync)
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci  friend class AsyncStreamingProcessor;
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci  // Decrements the number of outstanding finishers. The last caller of this
1601cb0ef41Sopenharmony_ci  // function should finish the asynchronous compilation, see the comment on
1611cb0ef41Sopenharmony_ci  // {outstanding_finishers_}.
1621cb0ef41Sopenharmony_ci  V8_WARN_UNUSED_RESULT bool DecrementAndCheckFinisherCount() {
1631cb0ef41Sopenharmony_ci    DCHECK_LT(0, outstanding_finishers_.load());
1641cb0ef41Sopenharmony_ci    return outstanding_finishers_.fetch_sub(1) == 1;
1651cb0ef41Sopenharmony_ci  }
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci  void CreateNativeModule(std::shared_ptr<const WasmModule> module,
1681cb0ef41Sopenharmony_ci                          size_t code_size_estimate);
1691cb0ef41Sopenharmony_ci  // Return true for cache hit, false for cache miss.
1701cb0ef41Sopenharmony_ci  bool GetOrCreateNativeModule(std::shared_ptr<const WasmModule> module,
1711cb0ef41Sopenharmony_ci                               size_t code_size_estimate);
1721cb0ef41Sopenharmony_ci  void PrepareRuntimeObjects();
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  void FinishCompile(bool is_after_cache_hit);
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci  void DecodeFailed(const WasmError&);
1771cb0ef41Sopenharmony_ci  void AsyncCompileFailed();
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci  void AsyncCompileSucceeded(Handle<WasmModuleObject> result);
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci  void FinishModule();
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_ci  void StartForegroundTask();
1841cb0ef41Sopenharmony_ci  void ExecuteForegroundTaskImmediately();
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci  void StartBackgroundTask();
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci  enum UseExistingForegroundTask : bool {
1891cb0ef41Sopenharmony_ci    kUseExistingForegroundTask = true,
1901cb0ef41Sopenharmony_ci    kAssertNoExistingForegroundTask = false
1911cb0ef41Sopenharmony_ci  };
1921cb0ef41Sopenharmony_ci  // Switches to the compilation step {Step} and starts a foreground task to
1931cb0ef41Sopenharmony_ci  // execute it. Most of the time we know that there cannot be a running
1941cb0ef41Sopenharmony_ci  // foreground task. If there might be one, then pass
1951cb0ef41Sopenharmony_ci  // kUseExistingForegroundTask to avoid spawning a second one.
1961cb0ef41Sopenharmony_ci  template <typename Step,
1971cb0ef41Sopenharmony_ci            UseExistingForegroundTask = kAssertNoExistingForegroundTask,
1981cb0ef41Sopenharmony_ci            typename... Args>
1991cb0ef41Sopenharmony_ci  void DoSync(Args&&... args);
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci  // Switches to the compilation step {Step} and immediately executes that step.
2021cb0ef41Sopenharmony_ci  template <typename Step, typename... Args>
2031cb0ef41Sopenharmony_ci  void DoImmediately(Args&&... args);
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_ci  // Switches to the compilation step {Step} and starts a background task to
2061cb0ef41Sopenharmony_ci  // execute it.
2071cb0ef41Sopenharmony_ci  template <typename Step, typename... Args>
2081cb0ef41Sopenharmony_ci  void DoAsync(Args&&... args);
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci  // Switches to the compilation step {Step} but does not start a task to
2111cb0ef41Sopenharmony_ci  // execute it.
2121cb0ef41Sopenharmony_ci  template <typename Step, typename... Args>
2131cb0ef41Sopenharmony_ci  void NextStep(Args&&... args);
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ci  Isolate* const isolate_;
2161cb0ef41Sopenharmony_ci  const char* const api_method_name_;
2171cb0ef41Sopenharmony_ci  const WasmFeatures enabled_features_;
2181cb0ef41Sopenharmony_ci  const DynamicTiering dynamic_tiering_;
2191cb0ef41Sopenharmony_ci  const bool wasm_lazy_compilation_;
2201cb0ef41Sopenharmony_ci  base::TimeTicks start_time_;
2211cb0ef41Sopenharmony_ci  // Copy of the module wire bytes, moved into the {native_module_} on its
2221cb0ef41Sopenharmony_ci  // creation.
2231cb0ef41Sopenharmony_ci  std::unique_ptr<byte[]> bytes_copy_;
2241cb0ef41Sopenharmony_ci  // Reference to the wire bytes (held in {bytes_copy_} or as part of
2251cb0ef41Sopenharmony_ci  // {native_module_}).
2261cb0ef41Sopenharmony_ci  ModuleWireBytes wire_bytes_;
2271cb0ef41Sopenharmony_ci  Handle<NativeContext> native_context_;
2281cb0ef41Sopenharmony_ci  Handle<Context> incumbent_context_;
2291cb0ef41Sopenharmony_ci  v8::metrics::Recorder::ContextId context_id_;
2301cb0ef41Sopenharmony_ci  v8::metrics::WasmModuleDecoded metrics_event_;
2311cb0ef41Sopenharmony_ci  const std::shared_ptr<CompilationResultResolver> resolver_;
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci  Handle<WasmModuleObject> module_object_;
2341cb0ef41Sopenharmony_ci  std::shared_ptr<NativeModule> native_module_;
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci  std::unique_ptr<CompileStep> step_;
2371cb0ef41Sopenharmony_ci  CancelableTaskManager background_task_manager_;
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci  std::shared_ptr<v8::TaskRunner> foreground_task_runner_;
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci  // For async compilation the AsyncCompileJob is the only finisher. For
2421cb0ef41Sopenharmony_ci  // streaming compilation also the AsyncStreamingProcessor has to finish before
2431cb0ef41Sopenharmony_ci  // compilation can be finished.
2441cb0ef41Sopenharmony_ci  std::atomic<int32_t> outstanding_finishers_{1};
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_ci  // A reference to a pending foreground task, or {nullptr} if none is pending.
2471cb0ef41Sopenharmony_ci  CompileTask* pending_foreground_task_ = nullptr;
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_ci  // The AsyncCompileJob owns the StreamingDecoder because the StreamingDecoder
2501cb0ef41Sopenharmony_ci  // contains data which is needed by the AsyncCompileJob for streaming
2511cb0ef41Sopenharmony_ci  // compilation. The AsyncCompileJob does not actively use the
2521cb0ef41Sopenharmony_ci  // StreamingDecoder.
2531cb0ef41Sopenharmony_ci  std::shared_ptr<StreamingDecoder> stream_;
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_ci  // The compilation id to identify trace events linked to this compilation.
2561cb0ef41Sopenharmony_ci  const int compilation_id_;
2571cb0ef41Sopenharmony_ci};
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_ci}  // namespace wasm
2601cb0ef41Sopenharmony_ci}  // namespace internal
2611cb0ef41Sopenharmony_ci}  // namespace v8
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci#endif  // V8_WASM_MODULE_COMPILER_H_
264