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