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