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 // An instance of WebAssembly.Module.
89 class V8_EXPORT WasmModuleObject : public Object {
90  public:
91   WasmModuleObject() = delete;
92 
93   /**
94    * Efficiently re-create a WasmModuleObject, without recompiling, from
95    * a CompiledWasmModule.
96    */
97   static MaybeLocal<WasmModuleObject> FromCompiledModule(
98       Isolate* isolate, const CompiledWasmModule&);
99 
100   /**
101    * Get the compiled module for this module object. The compiled module can be
102    * shared by several module objects.
103    */
104   CompiledWasmModule GetCompiledModule();
105 
Cast(Value * value)106   V8_INLINE static WasmModuleObject* Cast(Value* value) {
107 #ifdef V8_ENABLE_CHECKS
108     CheckCast(value);
109 #endif
110     return static_cast<WasmModuleObject*>(value);
111   }
112 
113  private:
114   static void CheckCast(Value* obj);
115 };
116 
117 /**
118  * The V8 interface for WebAssembly streaming compilation. When streaming
119  * compilation is initiated, V8 passes a {WasmStreaming} object to the embedder
120  * such that the embedder can pass the input bytes for streaming compilation to
121  * V8.
122  */
123 class V8_EXPORT WasmStreaming final {
124  public:
125   class WasmStreamingImpl;
126 
127   /**
128    * Client to receive streaming event notifications.
129    */
130   class Client {
131    public:
132     virtual ~Client() = default;
133     /**
134      * Passes the fully compiled module to the client. This can be used to
135      * implement code caching.
136      */
137     virtual void OnModuleCompiled(CompiledWasmModule compiled_module) = 0;
138   };
139 
140   explicit WasmStreaming(std::unique_ptr<WasmStreamingImpl> impl);
141 
142   ~WasmStreaming();
143 
144   /**
145    * Pass a new chunk of bytes to WebAssembly streaming compilation.
146    * The buffer passed into {OnBytesReceived} is owned by the caller.
147    */
148   void OnBytesReceived(const uint8_t* bytes, size_t size);
149 
150   /**
151    * {Finish} should be called after all received bytes where passed to
152    * {OnBytesReceived} to tell V8 that there will be no more bytes. {Finish}
153    * does not have to be called after {Abort} has been called already.
154    */
155   void Finish();
156 
157   /**
158    * Abort streaming compilation. If {exception} has a value, then the promise
159    * associated with streaming compilation is rejected with that value. If
160    * {exception} does not have value, the promise does not get rejected.
161    */
162   void Abort(MaybeLocal<Value> exception);
163 
164   /**
165    * Passes previously compiled module bytes. This must be called before
166    * {OnBytesReceived}, {Finish}, or {Abort}. Returns true if the module bytes
167    * can be used, false otherwise. The buffer passed via {bytes} and {size}
168    * is owned by the caller. If {SetCompiledModuleBytes} returns true, the
169    * buffer must remain valid until either {Finish} or {Abort} completes.
170    */
171   bool SetCompiledModuleBytes(const uint8_t* bytes, size_t size);
172 
173   /**
174    * Sets the client object that will receive streaming event notifications.
175    * This must be called before {OnBytesReceived}, {Finish}, or {Abort}.
176    */
177   void SetClient(std::shared_ptr<Client> client);
178 
179   /*
180    * Sets the UTF-8 encoded source URL for the {Script} object. This must be
181    * called before {Finish}.
182    */
183   void SetUrl(const char* url, size_t length);
184 
185   /**
186    * Unpacks a {WasmStreaming} object wrapped in a  {Managed} for the embedder.
187    * Since the embedder is on the other side of the API, it cannot unpack the
188    * {Managed} itself.
189    */
190   static std::shared_ptr<WasmStreaming> Unpack(Isolate* isolate,
191                                                Local<Value> value);
192 
193  private:
194   std::unique_ptr<WasmStreamingImpl> impl_;
195 };
196 
197 // TODO(mtrofin): when streaming compilation is done, we can rename this
198 // to simply WasmModuleObjectBuilder
199 class V8_EXPORT WasmModuleObjectBuilderStreaming final {
200  public:
201   explicit WasmModuleObjectBuilderStreaming(Isolate* isolate);
202   /**
203    * The buffer passed into OnBytesReceived is owned by the caller.
204    */
205   void OnBytesReceived(const uint8_t*, size_t size);
206   void Finish();
207   /**
208    * Abort streaming compilation. If {exception} has a value, then the promise
209    * associated with streaming compilation is rejected with that value. If
210    * {exception} does not have value, the promise does not get rejected.
211    */
212   void Abort(MaybeLocal<Value> exception);
213   Local<Promise> GetPromise();
214 
215   ~WasmModuleObjectBuilderStreaming() = default;
216 
217  private:
218   WasmModuleObjectBuilderStreaming(const WasmModuleObjectBuilderStreaming&) =
219       delete;
220   WasmModuleObjectBuilderStreaming(WasmModuleObjectBuilderStreaming&&) =
221       default;
222   WasmModuleObjectBuilderStreaming& operator=(
223       const WasmModuleObjectBuilderStreaming&) = delete;
224   WasmModuleObjectBuilderStreaming& operator=(
225       WasmModuleObjectBuilderStreaming&&) = default;
226   Isolate* isolate_ = nullptr;
227 
228 #if V8_CC_MSVC
229   /**
230    * We don't need the static Copy API, so the default
231    * NonCopyablePersistentTraits would be sufficient, however,
232    * MSVC eagerly instantiates the Copy.
233    * We ensure we don't use Copy, however, by compiling with the
234    * defaults everywhere else.
235    */
236   Persistent<Promise, CopyablePersistentTraits<Promise>> promise_;
237 #else
238   Persistent<Promise> promise_;
239 #endif
240   std::shared_ptr<internal::wasm::StreamingDecoder> streaming_decoder_;
241 };
242 
243 }  // namespace v8
244 
245 #endif  // INCLUDE_V8_WASM_H_
246