• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <memory>
9 #include <string>
10 
11 #include "v8-local-handle.h"  // NOLINT(build/include_directory)
12 #include "v8-memory-span.h"   // NOLINT(build/include_directory)
13 #include "v8-object.h"        // NOLINT(build/include_directory)
14 #include "v8config.h"         // NOLINT(build/include_directory)
15 
16 namespace v8 {
17 
18 class ArrayBuffer;
19 class Promise;
20 
21 namespace internal {
22 namespace wasm {
23 class NativeModule;
24 class StreamingDecoder;
25 }  // namespace wasm
26 }  // namespace internal
27 
28 /**
29  * An owned byte buffer with associated size.
30  */
31 struct OwnedBuffer {
32   std::unique_ptr<const uint8_t[]> buffer;
33   size_t size = 0;
OwnedBufferOwnedBuffer34   OwnedBuffer(std::unique_ptr<const uint8_t[]> buffer, size_t size)
35       : buffer(std::move(buffer)), size(size) {}
36   OwnedBuffer() = default;
37 };
38 
39 // Wrapper around a compiled WebAssembly module, which is potentially shared by
40 // different WasmModuleObjects.
41 class V8_EXPORT CompiledWasmModule {
42  public:
43   /**
44    * Serialize the compiled module. The serialized data does not include the
45    * wire bytes.
46    */
47   OwnedBuffer Serialize();
48 
49   /**
50    * Get the (wasm-encoded) wire bytes that were used to compile this module.
51    */
52   MemorySpan<const uint8_t> GetWireBytesRef();
53 
source_url()54   const std::string& source_url() const { return source_url_; }
55 
56  private:
57   friend class WasmModuleObject;
58   friend class WasmStreaming;
59 
60   explicit CompiledWasmModule(std::shared_ptr<internal::wasm::NativeModule>,
61                               const char* source_url, size_t url_length);
62 
63   const std::shared_ptr<internal::wasm::NativeModule> native_module_;
64   const std::string source_url_;
65 };
66 
67 // An instance of WebAssembly.Memory.
68 class V8_EXPORT WasmMemoryObject : public Object {
69  public:
70   WasmMemoryObject() = delete;
71 
72   /**
73    * Returns underlying ArrayBuffer.
74    */
75   Local<ArrayBuffer> Buffer();
76 
Cast(Value * value)77   V8_INLINE static WasmMemoryObject* Cast(Value* value) {
78 #ifdef V8_ENABLE_CHECKS
79     CheckCast(value);
80 #endif
81     return static_cast<WasmMemoryObject*>(value);
82   }
83 
84  private:
85   static void CheckCast(Value* object);
86 };
87 
88 // All the tiers of Wasm execution.
89 enum class WasmExecutionTier : int8_t {
90   kNone,
91   kLiftoff,
92   kTurbofan,
93 };
94 
95 // An instance of WebAssembly.Module.
96 class V8_EXPORT WasmModuleObject : public Object {
97  public:
98   WasmModuleObject() = delete;
99 
100   /**
101    * Efficiently re-create a WasmModuleObject, without recompiling, from
102    * a CompiledWasmModule.
103    */
104   static MaybeLocal<WasmModuleObject> FromCompiledModule(
105       Isolate* isolate, const CompiledWasmModule&);
106 
107   /**
108    * Get the compiled module for this module object. The compiled module can be
109    * shared by several module objects.
110    */
111   CompiledWasmModule GetCompiledModule();
112 
113   /**
114    * Compile a Wasm function of the specified index with the specified tier.
115    */
116   bool CompileFunction(Isolate* isolate, uint32_t function_index,
117                        WasmExecutionTier tier);
118 
119   /**
120    * Deserialize or compile Wasm module.
121    */
122   static MaybeLocal<WasmModuleObject> DeserializeOrCompile(
123       Isolate* isolate, MemorySpan<const uint8_t> wire_bytes,
124       MemorySpan<const uint8_t> wasm_cache, bool& cacheRejected);
125 
126   /**
127    * Compile a Wasm module from the provided uncompiled bytes.
128    */
129   static MaybeLocal<WasmModuleObject> Compile(
130       Isolate* isolate, MemorySpan<const uint8_t> wire_bytes);
131 
Cast(Value * value)132   V8_INLINE static WasmModuleObject* Cast(Value* value) {
133 #ifdef V8_ENABLE_CHECKS
134     CheckCast(value);
135 #endif
136     return static_cast<WasmModuleObject*>(value);
137   }
138 
139  private:
140   static void CheckCast(Value* obj);
141 };
142 
143 /**
144  * The V8 interface for WebAssembly streaming compilation. When streaming
145  * compilation is initiated, V8 passes a {WasmStreaming} object to the embedder
146  * such that the embedder can pass the input bytes for streaming compilation to
147  * V8.
148  */
149 class V8_EXPORT WasmStreaming final {
150  public:
151   class WasmStreamingImpl;
152 
153   /**
154    * Client to receive streaming event notifications.
155    */
156   class Client {
157    public:
158     virtual ~Client() = default;
159     /**
160      * Passes the fully compiled module to the client. This can be used to
161      * implement code caching.
162      */
163     virtual void OnModuleCompiled(CompiledWasmModule compiled_module) = 0;
164   };
165 
166   explicit WasmStreaming(std::unique_ptr<WasmStreamingImpl> impl);
167 
168   ~WasmStreaming();
169 
170   /**
171    * Pass a new chunk of bytes to WebAssembly streaming compilation.
172    * The buffer passed into {OnBytesReceived} is owned by the caller.
173    */
174   void OnBytesReceived(const uint8_t* bytes, size_t size);
175 
176   /**
177    * {Finish} should be called after all received bytes where passed to
178    * {OnBytesReceived} to tell V8 that there will be no more bytes. {Finish}
179    * does not have to be called after {Abort} has been called already.
180    * If {can_use_compiled_module} is true and {SetCompiledModuleBytes} was
181    * previously called, the compiled module bytes can be used.
182    * If {can_use_compiled_module} is false, the compiled module bytes previously
183    * set by {SetCompiledModuleBytes} should not be used.
184    */
185   void Finish(bool can_use_compiled_module = true);
186 
187   /**
188    * Abort streaming compilation. If {exception} has a value, then the promise
189    * associated with streaming compilation is rejected with that value. If
190    * {exception} does not have value, the promise does not get rejected.
191    */
192   void Abort(MaybeLocal<Value> exception);
193 
194   /**
195    * Passes previously compiled module bytes. This must be called before
196    * {OnBytesReceived}, {Finish}, or {Abort}. Returns true if the module bytes
197    * can be used, false otherwise. The buffer passed via {bytes} and {size}
198    * is owned by the caller. If {SetCompiledModuleBytes} returns true, the
199    * buffer must remain valid until either {Finish} or {Abort} completes.
200    * The compiled module bytes should not be used until {Finish(true)} is
201    * called, because they can be invalidated later by {Finish(false)}.
202    */
203   bool SetCompiledModuleBytes(const uint8_t* bytes, size_t size);
204 
205   /**
206    * Sets the client object that will receive streaming event notifications.
207    * This must be called before {OnBytesReceived}, {Finish}, or {Abort}.
208    */
209   void SetClient(std::shared_ptr<Client> client);
210 
211   /*
212    * Sets the UTF-8 encoded source URL for the {Script} object. This must be
213    * called before {Finish}.
214    */
215   void SetUrl(const char* url, size_t length);
216 
217   /**
218    * Unpacks a {WasmStreaming} object wrapped in a  {Managed} for the embedder.
219    * Since the embedder is on the other side of the API, it cannot unpack the
220    * {Managed} itself.
221    */
222   static std::shared_ptr<WasmStreaming> Unpack(Isolate* isolate,
223                                                Local<Value> value);
224 
225  private:
226   std::unique_ptr<WasmStreamingImpl> impl_;
227 };
228 
229 // TODO(mtrofin): when streaming compilation is done, we can rename this
230 // to simply WasmModuleObjectBuilder
231 class V8_EXPORT WasmModuleObjectBuilderStreaming final {
232  public:
233   explicit WasmModuleObjectBuilderStreaming(Isolate* isolate);
234   /**
235    * The buffer passed into OnBytesReceived is owned by the caller.
236    */
237   void OnBytesReceived(const uint8_t*, size_t size);
238   void Finish();
239   /**
240    * Abort streaming compilation. If {exception} has a value, then the promise
241    * associated with streaming compilation is rejected with that value. If
242    * {exception} does not have value, the promise does not get rejected.
243    */
244   void Abort(MaybeLocal<Value> exception);
245   Local<Promise> GetPromise();
246 
247   ~WasmModuleObjectBuilderStreaming() = default;
248 
249  private:
250   WasmModuleObjectBuilderStreaming(const WasmModuleObjectBuilderStreaming&) =
251       delete;
252   WasmModuleObjectBuilderStreaming(WasmModuleObjectBuilderStreaming&&) =
253       default;
254   WasmModuleObjectBuilderStreaming& operator=(
255       const WasmModuleObjectBuilderStreaming&) = delete;
256   WasmModuleObjectBuilderStreaming& operator=(
257       WasmModuleObjectBuilderStreaming&&) = default;
258   Isolate* isolate_ = nullptr;
259 
260 #if V8_CC_MSVC
261   /**
262    * We don't need the static Copy API, so the default
263    * NonCopyablePersistentTraits would be sufficient, however,
264    * MSVC eagerly instantiates the Copy.
265    * We ensure we don't use Copy, however, by compiling with the
266    * defaults everywhere else.
267    */
268   Persistent<Promise, CopyablePersistentTraits<Promise>> promise_;
269 #else
270   Persistent<Promise> promise_;
271 #endif
272   std::shared_ptr<internal::wasm::StreamingDecoder> streaming_decoder_;
273 };
274 
275 }  // namespace v8
276 
277 #endif  // INCLUDE_V8_WASM_H_
278