blob: 1dd5bf0884b390508bf29489a336677b98975da6 [file] [log] [blame] [edit]
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_WASM_MODULE_COMPILER_H_
#define V8_WASM_MODULE_COMPILER_H_
#if !V8_ENABLE_WEBASSEMBLY
#error This header should only be included if WebAssembly is enabled.
#endif // !V8_ENABLE_WEBASSEMBLY
#include <atomic>
#include <memory>
#include "include/v8-metrics.h"
#include "src/base/platform/time.h"
#include "src/common/globals.h"
#include "src/tasks/cancelable-task.h"
#include "src/wasm/compilation-environment.h"
#include "src/wasm/wasm-features.h"
#include "src/wasm/wasm-import-wrapper-cache.h"
#include "src/wasm/wasm-module.h"
namespace v8 {
namespace base {
template <typename T>
class Vector;
} // namespace base
namespace internal {
class JSArrayBuffer;
class JSPromise;
class Counters;
class WasmModuleObject;
class WasmInstanceObject;
class WasmTrustedInstanceData;
namespace wasm {
struct CompilationEnv;
class CompilationResultResolver;
class ErrorThrower;
class ModuleCompiler;
class NativeModule;
class ProfileInformation;
class StreamingDecoder;
class WasmCode;
struct WasmModule;
V8_EXPORT_PRIVATE
std::shared_ptr<NativeModule> CompileToNativeModule(
Isolate* isolate, WasmEnabledFeatures enabled_features,
WasmDetectedFeatures detected_features, CompileTimeImports compile_imports,
ErrorThrower* thrower, std::shared_ptr<const WasmModule> module,
base::OwnedVector<const uint8_t> wire_bytes, int compilation_id,
v8::metrics::Recorder::ContextId context_id, ProfileInformation* pgo_info);
V8_EXPORT_PRIVATE WasmError ValidateAndSetBuiltinImports(
const WasmModule* module, base::Vector<const uint8_t> wire_bytes,
const CompileTimeImports& imports, WasmDetectedFeatures* detected);
// Compiles the wrapper for this (kind, sig) pair and sets the corresponding
// cache entry. Assumes the key already exists in the cache but has not been
// compiled yet.
V8_EXPORT_PRIVATE
std::shared_ptr<wasm::WasmImportWrapperHandle> CompileImportWrapperForTest(
Isolate* isolate, ImportCallKind kind, const CanonicalSig* sig,
int expected_arity, Suspend suspend);
// Triggered by the WasmCompileLazy builtin. The return value indicates whether
// compilation was successful. Lazy compilation can fail only if validation is
// also lazy.
bool CompileLazy(Isolate*, NativeModule*, int func_index);
// Throws the compilation error after failed lazy compilation.
void ThrowLazyCompilationError(Isolate* isolate,
const NativeModule* native_module,
int func_index);
// Trigger tier-up of a particular function to TurboFan. If tier-up was already
// triggered, we instead increase the priority with exponential back-off.
V8_EXPORT_PRIVATE void TriggerTierUp(Isolate*, Tagged<WasmTrustedInstanceData>,
int func_index);
// Synchronous version of the above.
V8_EXPORT_PRIVATE void TierUpNowForTesting(Isolate*,
Tagged<WasmTrustedInstanceData>,
int func_index);
// Same, but all functions.
V8_EXPORT_PRIVATE void TierUpAllForTesting(Isolate*,
Tagged<WasmTrustedInstanceData>);
V8_EXPORT_PRIVATE void InitializeCompilationForTesting(
NativeModule* native_module);
// Publish a set of detected features in a given isolate. If this is the initial
// compilation, also the "kWasmModuleCompilation" use counter is incremented to
// serve as a baseline for the other detected features.
void PublishDetectedFeatures(WasmDetectedFeatures, Isolate*,
bool is_initial_compilation);
// Encapsulates all the state and steps of an asynchronous compilation.
// An asynchronous compile job consists of a number of tasks that are executed
// as foreground and background tasks. Any phase that touches the V8 heap or
// allocates on the V8 heap (e.g. creating the module object) must be a
// foreground task. All other tasks (e.g. decoding and validating, the majority
// of the work of compilation) can be background tasks.
// TODO(wasm): factor out common parts of this with the synchronous pipeline.
class AsyncCompileJob {
public:
AsyncCompileJob(Isolate* isolate, WasmEnabledFeatures enabled_features,
CompileTimeImports compile_imports,
base::OwnedVector<const uint8_t> bytes,
DirectHandle<Context> context,
DirectHandle<NativeContext> incumbent_context,
const char* api_method_name,
std::shared_ptr<CompilationResultResolver> resolver,
int compilation_id);
~AsyncCompileJob();
void Start();
std::shared_ptr<StreamingDecoder> CreateStreamingDecoder();
void Abort();
void CancelPendingForegroundTask();
Isolate* isolate() const { return isolate_; }
DirectHandle<NativeContext> context() const { return native_context_; }
v8::metrics::Recorder::ContextId context_id() const { return context_id_; }
private:
class CompileTask;
class CompileStep;
class CompilationStateCallback;
// States of the AsyncCompileJob.
// Step 1 (async). Decodes the wasm module.
// --> Fail on decoding failure,
// --> PrepareAndStartCompile on success.
class DecodeModule;
// Step 2 (sync). Prepares runtime objects and starts background compilation.
// --> finish directly on native module cache hit,
// --> finish directly on validation error,
// --> trigger eager compilation, if any; FinishCompile is triggered when
// done.
class PrepareAndStartCompile;
// Step 3 (sync). Compilation finished. Finalize the module and resolve the
// promise.
class FinishCompilation;
// Step 4 (sync). Decoding, validation or compilation failed. Reject the
// promise.
class Fail;
friend class AsyncStreamingProcessor;
// Decrements the number of outstanding finishers. The last caller of this
// function should finish the asynchronous compilation, see the comment on
// {outstanding_finishers_}.
V8_WARN_UNUSED_RESULT bool DecrementAndCheckFinisherCount() {
DCHECK_LT(0, outstanding_finishers_.load());
return outstanding_finishers_.fetch_sub(1) == 1;
}
void CreateNativeModule(std::shared_ptr<const WasmModule> module,
size_t code_size_estimate);
// Return true for cache hit, false for cache miss.
bool GetOrCreateNativeModule(std::shared_ptr<const WasmModule> module,
size_t code_size_estimate);
void PrepareRuntimeObjects();
// {FinishCompile} and {Failed} invalidate the {AsyncCompileJob}, so we only
// allow to call them on r-value references to make this clear at call sites.
void FinishCompile(bool is_after_cache_hit) &&;
void Failed() &&;
void AsyncCompileSucceeded(DirectHandle<WasmModuleObject> result);
void FinishSuccessfully();
void StartForegroundTask();
void ExecuteForegroundTaskImmediately();
void StartBackgroundTask();
enum UseExistingForegroundTask : bool {
kUseExistingForegroundTask = true,
kAssertNoExistingForegroundTask = false
};
// Switches to the compilation step {Step} and starts a foreground task to
// execute it. Most of the time we know that there cannot be a running
// foreground task. If there might be one, then pass
// kUseExistingForegroundTask to avoid spawning a second one.
template <typename Step,
UseExistingForegroundTask = kAssertNoExistingForegroundTask,
typename... Args>
void DoSync(Args&&... args);
// Switches to the compilation step {Step} and immediately executes that step.
template <typename Step, typename... Args>
void DoImmediately(Args&&... args);
// Switches to the compilation step {Step} and starts a background task to
// execute it.
template <typename Step, typename... Args>
void DoAsync(Args&&... args);
// Switches to the compilation step {Step} but does not start a task to
// execute it.
template <typename Step, typename... Args>
void NextStep(Args&&... args);
Isolate* const isolate_;
const char* const api_method_name_;
const WasmEnabledFeatures enabled_features_;
WasmDetectedFeatures detected_features_;
CompileTimeImports compile_imports_;
base::TimeTicks start_time_;
// Copy of the module wire bytes, moved into the {native_module_} on its
// creation.
base::OwnedVector<const uint8_t> bytes_copy_;
// Reference to the wire bytes (held in {bytes_copy_} or as part of
// {native_module_}).
ModuleWireBytes wire_bytes_;
IndirectHandle<NativeContext> native_context_;
IndirectHandle<NativeContext> incumbent_context_;
v8::metrics::Recorder::ContextId context_id_;
v8::metrics::WasmModuleDecoded metrics_event_;
const std::shared_ptr<CompilationResultResolver> resolver_;
IndirectHandle<WasmModuleObject> module_object_;
std::shared_ptr<NativeModule> native_module_;
std::unique_ptr<CompileStep> step_;
CancelableTaskManager background_task_manager_;
std::shared_ptr<v8::TaskRunner> foreground_task_runner_;
// For async compilation the AsyncCompileJob is the only finisher. For
// streaming compilation also the AsyncStreamingProcessor has to finish before
// compilation can be finished.
std::atomic<int32_t> outstanding_finishers_{1};
// A reference to a pending foreground task, or {nullptr} if none is pending.
CompileTask* pending_foreground_task_ = nullptr;
// The AsyncCompileJob owns the StreamingDecoder because the StreamingDecoder
// contains data which is needed by the AsyncCompileJob for streaming
// compilation. The AsyncCompileJob does not actively use the
// StreamingDecoder.
std::shared_ptr<StreamingDecoder> stream_;
// The compilation id to identify trace events linked to this compilation.
const int compilation_id_;
};
} // namespace wasm
} // namespace internal
} // namespace v8
#endif // V8_WASM_MODULE_COMPILER_H_