1 /** 2 * \file wasmtime/val.hh 3 */ 4 5 #ifndef WASMTIME_VAL_HH 6 #define WASMTIME_VAL_HH 7 8 #include <optional> 9 #include <wasmtime/gc.h> 10 #include <wasmtime/store.hh> 11 #include <wasmtime/types/val.hh> 12 #include <wasmtime/val.h> 13 14 namespace wasmtime { 15 16 class EqRef; 17 class StructRef; 18 class ArrayRef; 19 20 /** 21 * \brief Representation of a WebAssembly `externref` value. 22 * 23 * This class represents an value that cannot be forged by WebAssembly itself. 24 * All `ExternRef` values are guaranteed to be created by the host and its 25 * embedding. It's suitable to place private data structures in here which 26 * WebAssembly will not have access to, only other host functions will have 27 * access to them. 28 * 29 * Note that `ExternRef` values are rooted within a `Store` and must be manually 30 * unrooted via the `unroot` function. If this is not used then values will 31 * never be candidates for garbage collection. 32 */ 33 class ExternRef { 34 friend class Val; 35 36 wasmtime_externref_t val; 37 finalizer(void * ptr)38 static void finalizer(void *ptr) { 39 std::unique_ptr<std::any> _ptr(static_cast<std::any *>(ptr)); 40 } 41 42 public: 43 /// Creates a new `ExternRef` directly from its C-API representation. ExternRef(wasmtime_externref_t val)44 explicit ExternRef(wasmtime_externref_t val) : val(val) {} 45 46 /// Copy constructor to clone `other`. ExternRef(const ExternRef & other)47 ExternRef(const ExternRef &other) { 48 wasmtime_externref_clone(&other.val, &val); 49 } 50 51 /// Copy assignment to clone from `other`. operator =(const ExternRef & other)52 ExternRef &operator=(const ExternRef &other) { 53 wasmtime_externref_unroot(&val); 54 wasmtime_externref_clone(&other.val, &val); 55 return *this; 56 } 57 58 /// Move constructor to move the contents of `other`. ExternRef(ExternRef && other)59 ExternRef(ExternRef &&other) { 60 val = other.val; 61 wasmtime_externref_set_null(&other.val); 62 } 63 64 /// Move assignment to move the contents of `other`. operator =(ExternRef && other)65 ExternRef &operator=(ExternRef &&other) { 66 wasmtime_externref_unroot(&val); 67 val = other.val; 68 wasmtime_externref_set_null(&other.val); 69 return *this; 70 } 71 ~ExternRef()72 ~ExternRef() { wasmtime_externref_unroot(&val); } 73 74 /// Creates a new `externref` value from the provided argument. 75 /// 76 /// Note that `val` should be safe to send across threads and should own any 77 /// memory that it points to. Also note that `ExternRef` is similar to a 78 /// `std::shared_ptr` in that there can be many references to the same value. ExternRef(Store::Context cx,std::any val)79 explicit ExternRef(Store::Context cx, std::any val) { 80 void *ptr = std::make_unique<std::any>(val).release(); 81 bool ok = wasmtime_externref_new(cx.ptr, ptr, finalizer, &this->val); 82 if (!ok) { 83 fprintf(stderr, "failed to allocate a new externref"); 84 abort(); 85 } 86 } 87 88 /// Returns the underlying host data associated with this `ExternRef`. data(Store::Context cx)89 std::any &data(Store::Context cx) { 90 return *static_cast<std::any *>(wasmtime_externref_data(cx.ptr, &val)); 91 } 92 93 /// Consumes ownership of the underlying `wasmtime_externref_t` and returns 94 /// the result of `wasmtime_externref_to_raw`. take_raw(Store::Context cx)95 uint32_t take_raw(Store::Context cx) { 96 uint32_t ret = wasmtime_externref_to_raw(cx.capi(), &val); 97 wasmtime_externref_set_null(&val); 98 return ret; 99 } 100 101 /// Returns `wasmtime_externref_to_raw`. borrow_raw(Store::Context cx) const102 uint32_t borrow_raw(Store::Context cx) const { 103 return wasmtime_externref_to_raw(cx.capi(), &val); 104 } 105 }; 106 107 class EqRef; 108 109 /** 110 * \brief Representation of a WebAssembly `anyref` value. 111 */ 112 class AnyRef { 113 friend class Val; 114 115 wasmtime_anyref_t val; 116 117 public: 118 /// Creates a new `AnyRef` directly from its C-API representation. AnyRef(wasmtime_anyref_t val)119 explicit AnyRef(wasmtime_anyref_t val) : val(val) {} 120 121 /// Copy constructor to clone `other`. AnyRef(const AnyRef & other)122 AnyRef(const AnyRef &other) { wasmtime_anyref_clone(&other.val, &val); } 123 124 /// Copy assignment to clone from `other`. operator =(const AnyRef & other)125 AnyRef &operator=(const AnyRef &other) { 126 wasmtime_anyref_unroot(&val); 127 wasmtime_anyref_clone(&other.val, &val); 128 return *this; 129 } 130 131 /// Move constructor to move the contents of `other`. AnyRef(AnyRef && other)132 AnyRef(AnyRef &&other) { 133 val = other.val; 134 wasmtime_anyref_set_null(&other.val); 135 } 136 137 /// Move assignment to move the contents of `other`. operator =(AnyRef && other)138 AnyRef &operator=(AnyRef &&other) { 139 wasmtime_anyref_unroot(&val); 140 val = other.val; 141 wasmtime_anyref_set_null(&other.val); 142 return *this; 143 } 144 ~AnyRef()145 ~AnyRef() { wasmtime_anyref_unroot(&val); } 146 147 /// Creates a new `AnyRef` which is an `i31` with the given `value`, 148 /// truncated if the upper bit is set. i31(Store::Context cx,uint32_t value)149 static AnyRef i31(Store::Context cx, uint32_t value) { 150 wasmtime_anyref_t other; 151 wasmtime_anyref_from_i31(cx.ptr, value, &other); 152 return AnyRef(other); 153 } 154 155 /// Consumes ownership of the underlying `wasmtime_anyref_t` and returns the 156 /// result of `wasmtime_anyref_to_raw`. take_raw(Store::Context cx)157 uint32_t take_raw(Store::Context cx) { 158 uint32_t ret = wasmtime_anyref_to_raw(cx.capi(), &val); 159 wasmtime_anyref_set_null(&val); 160 return ret; 161 } 162 163 /// Returns `wasmtime_anyref_to_raw`. borrow_raw(Store::Context cx) const164 uint32_t borrow_raw(Store::Context cx) const { 165 return wasmtime_anyref_to_raw(cx.capi(), &val); 166 } 167 168 /// \brief If this is an `i31`, get the value zero-extended. u31(Store::Context cx) const169 std::optional<uint32_t> u31(Store::Context cx) const { 170 uint32_t ret = 0; 171 if (wasmtime_anyref_i31_get_u(cx.ptr, &val, &ret)) 172 return ret; 173 return std::nullopt; 174 } 175 176 /// \brief If this is an `i31`, get the value sign-extended. i31(Store::Context cx) const177 std::optional<int32_t> i31(Store::Context cx) const { 178 int32_t ret = 0; 179 if (wasmtime_anyref_i31_get_s(cx.ptr, &val, &ret)) 180 return ret; 181 return std::nullopt; 182 } 183 184 /// \brief Returns `true` if this anyref is an i31ref. is_i31(Store::Context cx) const185 bool is_i31(Store::Context cx) const { 186 return wasmtime_anyref_is_i31(cx.ptr, &val); 187 } 188 189 /// \brief Returns `true` if this anyref is an eqref. 190 inline bool is_eqref(Store::Context cx) const; 191 192 /// \brief Returns `true` if this anyref is a structref. 193 inline bool is_struct(Store::Context cx) const; 194 195 /// \brief Returns `true` if this anyref is an arrayref. 196 inline bool is_array(Store::Context cx) const; 197 198 /// \brief Downcast to eqref. Returns null eqref if not an eqref. 199 inline std::optional<EqRef> as_eqref(Store::Context cx) const; 200 201 /// \brief Downcast to structref. Returns null structref if not a structref. 202 inline std::optional<StructRef> as_struct(Store::Context cx) const; 203 204 /// \brief Downcast to arrayref. Returns null arrayref if not an arrayref. 205 inline std::optional<ArrayRef> as_array(Store::Context cx) const; 206 }; 207 208 /// \brief Container for the `v128` WebAssembly type. 209 struct V128 { 210 /// \brief The little-endian bytes of the `v128` value. 211 wasmtime_v128 v128; 212 213 /// \brief Creates a new zero-value `v128`. V128wasmtime::V128214 V128() : v128{} { memset(&v128[0], 0, sizeof(wasmtime_v128)); } 215 216 /// \brief Creates a new `V128` from its C API representation. V128wasmtime::V128217 V128(const wasmtime_v128 &v) : v128{} { 218 memcpy(&v128[0], &v[0], sizeof(wasmtime_v128)); 219 } 220 }; 221 222 class Func; 223 224 /** 225 * \brief Representation of a generic WebAssembly value. 226 * 227 * This is roughly equivalent to a tagged union of all possible WebAssembly 228 * values. This is later used as an argument with functions, globals, tables, 229 * etc. 230 * 231 * Note that a `Val` can represent owned GC pointers. In this case the `unroot` 232 * method must be used to ensure that they can later be garbage-collected. 233 */ 234 class Val { 235 friend class Global; 236 friend class Table; 237 friend class Func; 238 friend class Exn; 239 friend class StructRef; 240 friend class ArrayRef; 241 242 wasmtime_val_t val; 243 Val()244 Val() : val{} { 245 val.kind = WASMTIME_I32; 246 val.of.i32 = 0; 247 } Val(wasmtime_val_t val)248 Val(wasmtime_val_t val) : val(val) {} 249 250 public: 251 /// Creates a new `i32` WebAssembly value. Val(int32_t i32)252 Val(int32_t i32) : val{} { 253 val.kind = WASMTIME_I32; 254 val.of.i32 = i32; 255 } 256 /// Creates a new `i64` WebAssembly value. Val(int64_t i64)257 Val(int64_t i64) : val{} { 258 val.kind = WASMTIME_I64; 259 val.of.i64 = i64; 260 } 261 /// Creates a new `f32` WebAssembly value. Val(float f32)262 Val(float f32) : val{} { 263 val.kind = WASMTIME_F32; 264 val.of.f32 = f32; 265 } 266 /// Creates a new `f64` WebAssembly value. Val(double f64)267 Val(double f64) : val{} { 268 val.kind = WASMTIME_F64; 269 val.of.f64 = f64; 270 } 271 /// Creates a new `v128` WebAssembly value. Val(const V128 & v128)272 Val(const V128 &v128) : val{} { 273 val.kind = WASMTIME_V128; 274 memcpy(&val.of.v128[0], &v128.v128[0], sizeof(wasmtime_v128)); 275 } 276 /// Creates a new `funcref` WebAssembly value. 277 Val(std::optional<Func> func); 278 /// Creates a new `funcref` WebAssembly value which is not `ref.null func`. 279 Val(Func func); 280 /// Creates a new `externref` value. Val(std::optional<ExternRef> ptr)281 Val(std::optional<ExternRef> ptr) : val{} { 282 val.kind = WASMTIME_EXTERNREF; 283 if (ptr) { 284 val.of.externref = ptr->val; 285 wasmtime_externref_set_null(&ptr->val); 286 } else { 287 wasmtime_externref_set_null(&val.of.externref); 288 } 289 } 290 /// Creates a new `anyref` value. Val(std::optional<AnyRef> ptr)291 Val(std::optional<AnyRef> ptr) : val{} { 292 val.kind = WASMTIME_ANYREF; 293 if (ptr) { 294 val.of.anyref = ptr->val; 295 wasmtime_anyref_set_null(&ptr->val); 296 } else { 297 wasmtime_anyref_set_null(&val.of.anyref); 298 } 299 } 300 /// Creates a new `externref` WebAssembly value which is not `ref.null 301 /// extern`. 302 Val(ExternRef ptr); 303 /// Creates a new `anyref` WebAssembly value which is not `ref.null 304 /// any`. 305 Val(AnyRef ptr); 306 307 /// Copy constructor to clone `other`. Val(const Val & other)308 Val(const Val &other) { wasmtime_val_clone(&other.val, &val); } 309 310 /// Copy assignment to clone from `other`. operator =(const Val & other)311 Val &operator=(const Val &other) { 312 wasmtime_val_unroot(&val); 313 wasmtime_val_clone(&other.val, &val); 314 return *this; 315 } 316 317 /// Move constructor to move the contents of `other`. Val(Val && other)318 Val(Val &&other) { 319 val = other.val; 320 other.val.kind = WASMTIME_I32; 321 other.val.of.i32 = 0; 322 } 323 324 /// Move assignment to move the contents of `other`. operator =(Val && other)325 Val &operator=(Val &&other) { 326 wasmtime_val_unroot(&val); 327 val = other.val; 328 other.val.kind = WASMTIME_I32; 329 other.val.of.i32 = 0; 330 return *this; 331 } 332 333 /// Unroots the values in `val`, if any. ~Val()334 ~Val() { wasmtime_val_unroot(&val); } 335 336 /// Returns the kind of value that this value has. kind() const337 ValKind kind() const { 338 switch (val.kind) { 339 case WASMTIME_I32: 340 return ValKind::I32; 341 case WASMTIME_I64: 342 return ValKind::I64; 343 case WASMTIME_F32: 344 return ValKind::F32; 345 case WASMTIME_F64: 346 return ValKind::F64; 347 case WASMTIME_FUNCREF: 348 return ValKind::FuncRef; 349 case WASMTIME_EXTERNREF: 350 return ValKind::ExternRef; 351 case WASMTIME_ANYREF: 352 return ValKind::AnyRef; 353 case WASMTIME_EXNREF: 354 return ValKind::ExnRef; 355 case WASMTIME_V128: 356 return ValKind::V128; 357 } 358 std::abort(); 359 } 360 361 /// Returns the underlying `i32`, requires `kind() == KindI32` or aborts the 362 /// process. i32() const363 int32_t i32() const { 364 if (val.kind != WASMTIME_I32) { 365 std::abort(); 366 } 367 return val.of.i32; 368 } 369 370 /// Returns the underlying `i64`, requires `kind() == KindI64` or aborts the 371 /// process. i64() const372 int64_t i64() const { 373 if (val.kind != WASMTIME_I64) { 374 std::abort(); 375 } 376 return val.of.i64; 377 } 378 379 /// Returns the underlying `f32`, requires `kind() == KindF32` or aborts the 380 /// process. f32() const381 float f32() const { 382 if (val.kind != WASMTIME_F32) { 383 std::abort(); 384 } 385 return val.of.f32; 386 } 387 388 /// Returns the underlying `f64`, requires `kind() == KindF64` or aborts the 389 /// process. f64() const390 double f64() const { 391 if (val.kind != WASMTIME_F64) { 392 std::abort(); 393 } 394 return val.of.f64; 395 } 396 397 /// Returns the underlying `v128`, requires `kind() == KindV128` or aborts 398 /// the process. v128() const399 V128 v128() const { 400 if (val.kind != WASMTIME_V128) { 401 std::abort(); 402 } 403 return val.of.v128; 404 } 405 406 /// Returns the underlying `externref`, requires `kind() == KindExternRef` or 407 /// aborts the process. 408 /// 409 /// Note that `externref` is a nullable reference, hence the `optional` return 410 /// value. externref() const411 std::optional<ExternRef> externref() const { 412 if (val.kind != WASMTIME_EXTERNREF) { 413 std::abort(); 414 } 415 if (wasmtime_externref_is_null(&val.of.externref)) { 416 return std::nullopt; 417 } 418 wasmtime_externref_t other; 419 wasmtime_externref_clone(&val.of.externref, &other); 420 return ExternRef(other); 421 } 422 423 /// Returns the underlying `anyref`, requires `kind() == KindAnyRef` or 424 /// aborts the process. 425 /// 426 /// Note that `anyref` is a nullable reference, hence the `optional` return 427 /// value. anyref() const428 std::optional<AnyRef> anyref() const { 429 if (val.kind != WASMTIME_ANYREF) { 430 std::abort(); 431 } 432 if (wasmtime_anyref_is_null(&val.of.anyref)) { 433 return std::nullopt; 434 } 435 wasmtime_anyref_t other; 436 wasmtime_anyref_clone(&val.of.anyref, &other); 437 return AnyRef(other); 438 } 439 440 /// Returns the underlying `funcref`, requires `kind() == KindFuncRef` or 441 /// aborts the process. 442 /// 443 /// Note that `funcref` is a nullable reference, hence the `optional` return 444 /// value. 445 std::optional<Func> funcref() const; 446 }; 447 448 } // namespace wasmtime 449 450 // fill in `Func` constructors for `Val` 451 #include <wasmtime/func.hh> 452 453 #endif // WASMTIME_VAL_HH 454