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/store.hh> 10 #include <wasmtime/types/val.hh> 11 #include <wasmtime/val.h> 12 13 namespace wasmtime { 14 15 /** 16 * \brief Representation of a WebAssembly `externref` value. 17 * 18 * This class represents an value that cannot be forged by WebAssembly itself. 19 * All `ExternRef` values are guaranteed to be created by the host and its 20 * embedding. It's suitable to place private data structures in here which 21 * WebAssembly will not have access to, only other host functions will have 22 * access to them. 23 * 24 * Note that `ExternRef` values are rooted within a `Store` and must be manually 25 * unrooted via the `unroot` function. If this is not used then values will 26 * never be candidates for garbage collection. 27 */ 28 class ExternRef { 29 friend class Val; 30 31 wasmtime_externref_t val; 32 33 static void finalizer(void *ptr) { 34 std::unique_ptr<std::any> _ptr(static_cast<std::any *>(ptr)); 35 } 36 37 public: 38 /// Creates a new `ExternRef` directly from its C-API representation. 39 explicit ExternRef(wasmtime_externref_t val) : val(val) {} 40 41 /// Creates a new `externref` value from the provided argument. 42 /// 43 /// Note that `val` should be safe to send across threads and should own any 44 /// memory that it points to. Also note that `ExternRef` is similar to a 45 /// `std::shared_ptr` in that there can be many references to the same value. 46 template <typename T> explicit ExternRef(Store::Context cx, T val) { 47 void *ptr = std::make_unique<std::any>(std::move(val)).release(); 48 bool ok = wasmtime_externref_new(cx.ptr, ptr, finalizer, &this->val); 49 if (!ok) { 50 fprintf(stderr, "failed to allocate a new externref"); 51 abort(); 52 } 53 } 54 55 /// Creates a new `ExternRef` which is separately rooted from this one. 56 ExternRef clone(Store::Context cx) { 57 wasmtime_externref_t other; 58 wasmtime_externref_clone(cx.ptr, &val, &other); 59 return ExternRef(other); 60 } 61 62 /// Returns the underlying host data associated with this `ExternRef`. 63 std::any &data(Store::Context cx) { 64 return *static_cast<std::any *>(wasmtime_externref_data(cx.ptr, &val)); 65 } 66 67 /// Unroots this value from the context provided, enabling a future GC to 68 /// collect the internal object if there are no more references. 69 void unroot(Store::Context cx) { wasmtime_externref_unroot(cx.ptr, &val); } 70 71 /// Returns the raw underlying C API value. 72 /// 73 /// This class still retains ownership of the pointer. 74 const wasmtime_externref_t *raw() const { return &val; } 75 }; 76 77 /** 78 * \brief Representation of a WebAssembly `anyref` value. 79 */ 80 class AnyRef { 81 friend class Val; 82 83 wasmtime_anyref_t val; 84 85 public: 86 /// Creates a new `AnyRef` directly from its C-API representation. 87 explicit AnyRef(wasmtime_anyref_t val) : val(val) {} 88 89 /// Creates a new `AnyRef` which is an `i31` with the given `value`, 90 /// truncated if the upper bit is set. 91 static AnyRef i31(Store::Context cx, uint32_t value) { 92 wasmtime_anyref_t other; 93 wasmtime_anyref_from_i31(cx.ptr, value, &other); 94 return AnyRef(other); 95 } 96 97 /// Creates a new `AnyRef` which is separately rooted from this one. 98 AnyRef clone(Store::Context cx) { 99 wasmtime_anyref_t other; 100 wasmtime_anyref_clone(cx.ptr, &val, &other); 101 return AnyRef(other); 102 } 103 104 /// Unroots this value from the context provided, enabling a future GC to 105 /// collect the internal object if there are no more references. 106 void unroot(Store::Context cx) { wasmtime_anyref_unroot(cx.ptr, &val); } 107 108 /// Returns the raw underlying C API value. 109 /// 110 /// This class still retains ownership of the pointer. 111 const wasmtime_anyref_t *raw() const { return &val; } 112 113 /// \brief If this is an `i31`, get the value zero-extended. 114 std::optional<uint32_t> u31(Store::Context cx) const { 115 uint32_t ret = 0; 116 if (wasmtime_anyref_i31_get_u(cx.ptr, &val, &ret)) 117 return ret; 118 return std::nullopt; 119 } 120 121 /// \brief If this is an `i31`, get the value sign-extended. 122 std::optional<int32_t> i31(Store::Context cx) const { 123 int32_t ret = 0; 124 if (wasmtime_anyref_i31_get_s(cx.ptr, &val, &ret)) 125 return ret; 126 return std::nullopt; 127 } 128 }; 129 130 /// \brief Container for the `v128` WebAssembly type. 131 struct V128 { 132 /// \brief The little-endian bytes of the `v128` value. 133 wasmtime_v128 v128; 134 135 /// \brief Creates a new zero-value `v128`. 136 V128() : v128{} { memset(&v128[0], 0, sizeof(wasmtime_v128)); } 137 138 /// \brief Creates a new `V128` from its C API representation. 139 V128(const wasmtime_v128 &v) : v128{} { 140 memcpy(&v128[0], &v[0], sizeof(wasmtime_v128)); 141 } 142 }; 143 144 class Func; 145 146 /** 147 * \brief Representation of a generic WebAssembly value. 148 * 149 * This is roughly equivalent to a tagged union of all possible WebAssembly 150 * values. This is later used as an argument with functions, globals, tables, 151 * etc. 152 * 153 * Note that a `Val` can represent owned GC pointers. In this case the `unroot` 154 * method must be used to ensure that they can later be garbage-collected. 155 */ 156 class Val { 157 friend class Global; 158 friend class Table; 159 friend class Func; 160 161 wasmtime_val_t val; 162 163 Val() : val{} { 164 val.kind = WASMTIME_I32; 165 val.of.i32 = 0; 166 } 167 Val(wasmtime_val_t val) : val(val) {} 168 169 public: 170 /// Creates a new `i32` WebAssembly value. 171 Val(int32_t i32) : val{} { 172 val.kind = WASMTIME_I32; 173 val.of.i32 = i32; 174 } 175 /// Creates a new `i64` WebAssembly value. 176 Val(int64_t i64) : val{} { 177 val.kind = WASMTIME_I64; 178 val.of.i64 = i64; 179 } 180 /// Creates a new `f32` WebAssembly value. 181 Val(float f32) : val{} { 182 val.kind = WASMTIME_F32; 183 val.of.f32 = f32; 184 } 185 /// Creates a new `f64` WebAssembly value. 186 Val(double f64) : val{} { 187 val.kind = WASMTIME_F64; 188 val.of.f64 = f64; 189 } 190 /// Creates a new `v128` WebAssembly value. 191 Val(const V128 &v128) : val{} { 192 val.kind = WASMTIME_V128; 193 memcpy(&val.of.v128[0], &v128.v128[0], sizeof(wasmtime_v128)); 194 } 195 /// Creates a new `funcref` WebAssembly value. 196 Val(std::optional<Func> func); 197 /// Creates a new `funcref` WebAssembly value which is not `ref.null func`. 198 Val(Func func); 199 /// Creates a new `externref` value. 200 Val(std::optional<ExternRef> ptr) : val{} { 201 val.kind = WASMTIME_EXTERNREF; 202 if (ptr) { 203 val.of.externref = ptr->val; 204 } else { 205 wasmtime_externref_set_null(&val.of.externref); 206 } 207 } 208 /// Creates a new `anyref` value. 209 Val(std::optional<AnyRef> ptr) : val{} { 210 val.kind = WASMTIME_ANYREF; 211 if (ptr) { 212 val.of.anyref = ptr->val; 213 } else { 214 wasmtime_anyref_set_null(&val.of.anyref); 215 } 216 } 217 /// Creates a new `externref` WebAssembly value which is not `ref.null 218 /// extern`. 219 Val(ExternRef ptr); 220 /// Creates a new `anyref` WebAssembly value which is not `ref.null 221 /// any`. 222 Val(AnyRef ptr); 223 224 /// Returns the kind of value that this value has. 225 ValKind kind() const { 226 switch (val.kind) { 227 case WASMTIME_I32: 228 return ValKind::I32; 229 case WASMTIME_I64: 230 return ValKind::I64; 231 case WASMTIME_F32: 232 return ValKind::F32; 233 case WASMTIME_F64: 234 return ValKind::F64; 235 case WASMTIME_FUNCREF: 236 return ValKind::FuncRef; 237 case WASMTIME_EXTERNREF: 238 return ValKind::ExternRef; 239 case WASMTIME_ANYREF: 240 return ValKind::AnyRef; 241 case WASMTIME_V128: 242 return ValKind::V128; 243 } 244 std::abort(); 245 } 246 247 /// Returns the underlying `i32`, requires `kind() == KindI32` or aborts the 248 /// process. 249 int32_t i32() const { 250 if (val.kind != WASMTIME_I32) { 251 std::abort(); 252 } 253 return val.of.i32; 254 } 255 256 /// Returns the underlying `i64`, requires `kind() == KindI64` or aborts the 257 /// process. 258 int64_t i64() const { 259 if (val.kind != WASMTIME_I64) { 260 std::abort(); 261 } 262 return val.of.i64; 263 } 264 265 /// Returns the underlying `f32`, requires `kind() == KindF32` or aborts the 266 /// process. 267 float f32() const { 268 if (val.kind != WASMTIME_F32) { 269 std::abort(); 270 } 271 return val.of.f32; 272 } 273 274 /// Returns the underlying `f64`, requires `kind() == KindF64` or aborts the 275 /// process. 276 double f64() const { 277 if (val.kind != WASMTIME_F64) { 278 std::abort(); 279 } 280 return val.of.f64; 281 } 282 283 /// Returns the underlying `v128`, requires `kind() == KindV128` or aborts 284 /// the process. 285 V128 v128() const { 286 if (val.kind != WASMTIME_V128) { 287 std::abort(); 288 } 289 return val.of.v128; 290 } 291 292 /// Returns the underlying `externref`, requires `kind() == KindExternRef` or 293 /// aborts the process. 294 /// 295 /// Note that `externref` is a nullable reference, hence the `optional` return 296 /// value. 297 std::optional<ExternRef> externref(Store::Context cx) const { 298 if (val.kind != WASMTIME_EXTERNREF) { 299 std::abort(); 300 } 301 if (wasmtime_externref_is_null(&val.of.externref)) { 302 return std::nullopt; 303 } 304 wasmtime_externref_t other; 305 wasmtime_externref_clone(cx.ptr, &val.of.externref, &other); 306 return ExternRef(other); 307 } 308 309 /// Returns the underlying `anyref`, requires `kind() == KindAnyRef` or 310 /// aborts the process. 311 /// 312 /// Note that `anyref` is a nullable reference, hence the `optional` return 313 /// value. 314 std::optional<AnyRef> anyref(Store::Context cx) const { 315 if (val.kind != WASMTIME_ANYREF) { 316 std::abort(); 317 } 318 if (wasmtime_anyref_is_null(&val.of.anyref)) { 319 return std::nullopt; 320 } 321 wasmtime_anyref_t other; 322 wasmtime_anyref_clone(cx.ptr, &val.of.anyref, &other); 323 return AnyRef(other); 324 } 325 326 /// Returns the underlying `funcref`, requires `kind() == KindFuncRef` or 327 /// aborts the process. 328 /// 329 /// Note that `funcref` is a nullable reference, hence the `optional` return 330 /// value. 331 std::optional<Func> funcref() const; 332 333 /// Unroots any GC references this `Val` points to within the `cx` provided. 334 void unroot(Store::Context cx) { wasmtime_val_unroot(cx.ptr, &val); } 335 }; 336 337 } // namespace wasmtime 338 339 // fill in `Func` constructors for `Val` 340 #include <wasmtime/func.hh> 341 342 #endif // WASMTIME_VAL_HH 343