#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
#include <atomic>
#include <memory>
#include "include/v8-metrics.h"
#include "src/base/platform/time.h"
#include "src/common/globals.h"
#include "src/handles/maybe-handles.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 internal {
class JSArrayBuffer;
class JSPromise;
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);
V8_EXPORT_PRIVATE
std::shared_ptr<wasm::WasmImportWrapperHandle> CompileImportWrapperForTest(
Isolate* isolate, ImportCallKind kind, const CanonicalSig* sig,
int expected_arity, Suspend suspend);
bool CompileLazy(Isolate*, NativeModule*, int func_index);
void ThrowLazyCompilationError(Isolate* isolate,
const NativeModule* native_module,
int func_index);
V8_EXPORT_PRIVATE void TriggerTierUp(Isolate*, Tagged<WasmTrustedInstanceData>,
int func_index);
V8_EXPORT_PRIVATE void TierUpNowForTesting(Isolate*,
Tagged<WasmTrustedInstanceData>,
int func_index);
V8_EXPORT_PRIVATE void TierUpAllForTesting(Isolate*,
Tagged<WasmTrustedInstanceData>);
V8_EXPORT_PRIVATE void InitializeCompilationForTesting(
NativeModule* native_module);
void PublishDetectedFeatures(WasmDetectedFeatures, Isolate*,
bool is_initial_compilation);
class AsyncCompileJob {
public:
AsyncCompileJob(WasmEnabledFeatures enabled_features,
CompileTimeImports compile_imports,
base::OwnedVector<const uint8_t> bytes,
const char* api_method_name,
std::shared_ptr<CompilationResultResolver> resolver,
int compilation_id);
~AsyncCompileJob();
void InitializeIsolateSpecificInfo(Isolate*);
void StartAsyncDecoding();
std::shared_ptr<StreamingDecoder> CreateStreamingDecoder();
void Abort();
void CancelPendingForegroundTask();
Isolate* isolate() const {
if (!has_isolate_specific_info_.load(std::memory_order_acquire)) return {};
return isolate_specific_info_.isolate_;
}
MaybeDirectHandle<NativeContext> context() const {
if (!has_isolate_specific_info_.load(std::memory_order_acquire)) return {};
return isolate_specific_info_.native_context_;
}
private:
class CompileTask;
class CompileStep;
class CompilationStateCallback;
class DecodeModule;
class PrepareNativeModule;
class FinishCompilation;
class Fail;
friend class AsyncStreamingProcessor;
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);
std::tuple<std::shared_ptr<NativeModule>, bool> GetOrCreateNativeModule(
std::shared_ptr<const WasmModule> module, size_t code_size_estimate);
void FinishCompile(std::shared_ptr<NativeModule> final_native_module,
DirectHandle<WasmModuleObject> deserialized_module_object,
bool cache_hit) &&;
void Failed() &&;
void AsyncCompileSucceeded(DirectHandle<WasmModuleObject> result);
void StartForegroundTask();
void StartBackgroundTask();
enum UseExistingForegroundTask : bool {
kUseExistingForegroundTask = true,
kAssertNoExistingForegroundTask = false
};
template <typename Step,
UseExistingForegroundTask = kAssertNoExistingForegroundTask,
typename... Args>
void DoSync(Args&&... args);
template <typename Step, typename... Args>
void DoAsync(Args&&... args);
template <typename Step, typename... Args>
void NextStep(Args&&... args);
struct IsolateSpecificInfo {
Isolate* isolate_;
IndirectHandle<NativeContext> native_context_;
IndirectHandle<NativeContext> incumbent_context_;
v8::metrics::Recorder::ContextId context_id_;
std::shared_ptr<v8::TaskRunner> foreground_task_runner_;
};
std::atomic<bool> has_isolate_specific_info_{false};
IsolateSpecificInfo isolate_specific_info_;
const char* const api_method_name_;
const WasmEnabledFeatures enabled_features_;
WasmDetectedFeatures detected_features_;
CompileTimeImports compile_imports_;
base::TimeTicks start_time_;
base::TimeTicks compilation_finished_time_;
base::OwnedVector<const uint8_t> bytes_copy_;
ModuleWireBytes wire_bytes_;
const std::shared_ptr<CompilationResultResolver> resolver_;
std::shared_ptr<NativeModule> new_native_module_;
DelayedCounterUpdates delayed_counters_;
std::optional<v8::metrics::WasmModuleDecoded> decoding_metrics_event_;
std::unique_ptr<CompileStep> step_;
CancelableTaskManager background_task_manager_;
std::atomic<int32_t> outstanding_finishers_{1};
CompileTask* pending_foreground_task_ = nullptr;
std::shared_ptr<StreamingDecoder> stream_;
const int compilation_id_;
};
class V8_EXPORT_PRIVATE TransitiveTypeFeedbackProcessor {
public:
static void Process(Isolate* isolate,
Tagged<WasmTrustedInstanceData> trusted_instance_data,
int func_index) {
TransitiveTypeFeedbackProcessor ttfp{isolate, trusted_instance_data};
ttfp.queue_.insert(func_index);
ttfp.ProcessQueue();
}
static void ProcessAll(Isolate* isolate,
Tagged<WasmTrustedInstanceData> trusted_instance_data);
private:
TransitiveTypeFeedbackProcessor(
Isolate* isolate, Tagged<WasmTrustedInstanceData> trusted_instance_data);
~TransitiveTypeFeedbackProcessor() { DCHECK(queue_.empty()); }
void ProcessQueue() {
while (!queue_.empty()) {
auto next = queue_.cbegin();
ProcessFunction(*next);
queue_.erase(next);
}
}
void ProcessFunction(int func_index);
void EnqueueCallees(base::Vector<CallSiteFeedback> feedback) {
for (const CallSiteFeedback& csf : feedback) {
for (int j = 0; j < csf.num_cases(); j++) {
int func = csf.function_index(j);
if (csf.call_count(j) == 0) continue;
auto existing = feedback_for_function_.find(func);
if (existing != feedback_for_function_.end() &&
!existing->second.feedback_vector.empty()) {
if (!existing->second.needs_reprocessing_after_deopt) {
continue;
}
DCHECK(v8_flags.wasm_deopt);
existing->second.needs_reprocessing_after_deopt = false;
}
queue_.insert(func);
}
}
}
DisallowGarbageCollection no_gc_scope_;
Isolate* const isolate_;
const Tagged<WasmTrustedInstanceData> instance_data_;
const WasmModule* const module_;
base::MutexGuard mutex_guard;
std::unordered_map<uint32_t, FunctionTypeFeedback>& feedback_for_function_;
std::set<int> queue_;
};
}
}
}
#endif