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