1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef INCLUDE_V8_WASM_H_
6#define INCLUDE_V8_WASM_H_
7
8#include <functional>
9#include <memory>
10#include <string>
11
12#include "v8-local-handle.h"  // NOLINT(build/include_directory)
13#include "v8-memory-span.h"   // NOLINT(build/include_directory)
14#include "v8-object.h"        // NOLINT(build/include_directory)
15#include "v8config.h"         // NOLINT(build/include_directory)
16
17namespace v8 {
18
19class ArrayBuffer;
20class Promise;
21
22namespace internal {
23namespace wasm {
24class NativeModule;
25class StreamingDecoder;
26}  // namespace wasm
27}  // namespace internal
28
29/**
30 * An owned byte buffer with associated size.
31 */
32struct OwnedBuffer {
33  std::unique_ptr<const uint8_t[]> buffer;
34  size_t size = 0;
35  OwnedBuffer(std::unique_ptr<const uint8_t[]> buffer, size_t size)
36      : buffer(std::move(buffer)), size(size) {}
37  OwnedBuffer() = default;
38};
39
40// Wrapper around a compiled WebAssembly module, which is potentially shared by
41// different WasmModuleObjects.
42class V8_EXPORT CompiledWasmModule {
43 public:
44  /**
45   * Serialize the compiled module. The serialized data does not include the
46   * wire bytes.
47   */
48  OwnedBuffer Serialize();
49
50  /**
51   * Get the (wasm-encoded) wire bytes that were used to compile this module.
52   */
53  MemorySpan<const uint8_t> GetWireBytesRef();
54
55  const std::string& source_url() const { return source_url_; }
56
57 private:
58  friend class WasmModuleObject;
59  friend class WasmStreaming;
60
61  explicit CompiledWasmModule(std::shared_ptr<internal::wasm::NativeModule>,
62                              const char* source_url, size_t url_length);
63
64  const std::shared_ptr<internal::wasm::NativeModule> native_module_;
65  const std::string source_url_;
66};
67
68// An instance of WebAssembly.Memory.
69class V8_EXPORT WasmMemoryObject : public Object {
70 public:
71  WasmMemoryObject() = delete;
72
73  /**
74   * Returns underlying ArrayBuffer.
75   */
76  Local<ArrayBuffer> Buffer();
77
78  V8_INLINE static WasmMemoryObject* Cast(Value* value) {
79#ifdef V8_ENABLE_CHECKS
80    CheckCast(value);
81#endif
82    return static_cast<WasmMemoryObject*>(value);
83  }
84
85 private:
86  static void CheckCast(Value* object);
87};
88
89// All the tiers of Wasm execution.
90enum class WasmExecutionTier : int8_t {
91  kNone,
92  kLiftoff,
93  kTurbofan,
94};
95
96// An instance of WebAssembly.Module.
97class V8_EXPORT WasmModuleObject : public Object {
98 public:
99  WasmModuleObject() = delete;
100
101  /**
102   * Efficiently re-create a WasmModuleObject, without recompiling, from
103   * a CompiledWasmModule.
104   */
105  static MaybeLocal<WasmModuleObject> FromCompiledModule(
106      Isolate* isolate, const CompiledWasmModule&);
107
108  /**
109   * Get the compiled module for this module object. The compiled module can be
110   * shared by several module objects.
111   */
112  CompiledWasmModule GetCompiledModule();
113
114  /**
115   * Compile a Wasm function of the specified index with the specified tier.
116   */
117  bool CompileFunction(Isolate* isolate, uint32_t function_index,
118                       WasmExecutionTier tier);
119
120  /**
121   * Deserialize or compile Wasm module.
122   */
123  static MaybeLocal<WasmModuleObject> DeserializeOrCompile(
124      Isolate* isolate, MemorySpan<const uint8_t> wire_bytes,
125      MemorySpan<const uint8_t> wasm_cache, bool& cacheRejected);
126
127  /**
128   * Compile a Wasm module from the provided uncompiled bytes.
129   */
130  static MaybeLocal<WasmModuleObject> Compile(
131      Isolate* isolate, MemorySpan<const uint8_t> wire_bytes);
132
133  V8_INLINE static WasmModuleObject* Cast(Value* value) {
134#ifdef V8_ENABLE_CHECKS
135    CheckCast(value);
136#endif
137    return static_cast<WasmModuleObject*>(value);
138  }
139
140 private:
141  static void CheckCast(Value* obj);
142};
143
144/**
145 * The V8 interface for WebAssembly streaming compilation. When streaming
146 * compilation is initiated, V8 passes a {WasmStreaming} object to the embedder
147 * such that the embedder can pass the input bytes for streaming compilation to
148 * V8.
149 */
150class V8_EXPORT WasmStreaming final {
151 public:
152  class WasmStreamingImpl;
153
154  explicit WasmStreaming(std::unique_ptr<WasmStreamingImpl> impl);
155
156  ~WasmStreaming();
157
158  /**
159   * Pass a new chunk of bytes to WebAssembly streaming compilation.
160   * The buffer passed into {OnBytesReceived} is owned by the caller.
161   */
162  void OnBytesReceived(const uint8_t* bytes, size_t size);
163
164  /**
165   * {Finish} should be called after all received bytes where passed to
166   * {OnBytesReceived} to tell V8 that there will be no more bytes. {Finish}
167   * must not be called after {Abort} has been called already.
168   * If {can_use_compiled_module} is true and {SetCompiledModuleBytes} was
169   * previously called, the compiled module bytes can be used.
170   * If {can_use_compiled_module} is false, the compiled module bytes previously
171   * set by {SetCompiledModuleBytes} should not be used.
172   */
173  void Finish(bool can_use_compiled_module = true);
174
175  /**
176   * Abort streaming compilation. If {exception} has a value, then the promise
177   * associated with streaming compilation is rejected with that value. If
178   * {exception} does not have value, the promise does not get rejected.
179   * {Abort} must not be called repeatedly, or after {Finish}.
180   */
181  void Abort(MaybeLocal<Value> exception);
182
183  /**
184   * Passes previously compiled module bytes. This must be called before
185   * {OnBytesReceived}, {Finish}, or {Abort}. Returns true if the module bytes
186   * can be used, false otherwise. The buffer passed via {bytes} and {size}
187   * is owned by the caller. If {SetCompiledModuleBytes} returns true, the
188   * buffer must remain valid until either {Finish} or {Abort} completes.
189   * The compiled module bytes should not be used until {Finish(true)} is
190   * called, because they can be invalidated later by {Finish(false)}.
191   */
192  bool SetCompiledModuleBytes(const uint8_t* bytes, size_t size);
193
194  /**
195   * Sets a callback which is called whenever a significant number of new
196   * functions are ready for serialization.
197   */
198  void SetMoreFunctionsCanBeSerializedCallback(
199      std::function<void(CompiledWasmModule)>);
200
201  /*
202   * Sets the UTF-8 encoded source URL for the {Script} object. This must be
203   * called before {Finish}.
204   */
205  void SetUrl(const char* url, size_t length);
206
207  /**
208   * Unpacks a {WasmStreaming} object wrapped in a  {Managed} for the embedder.
209   * Since the embedder is on the other side of the API, it cannot unpack the
210   * {Managed} itself.
211   */
212  static std::shared_ptr<WasmStreaming> Unpack(Isolate* isolate,
213                                               Local<Value> value);
214
215 private:
216  std::unique_ptr<WasmStreamingImpl> impl_;
217};
218
219}  // namespace v8
220
221#endif  // INCLUDE_V8_WASM_H_
222