1 //! Unboxed 31-bit integers.
2 //!
3 //! Note that ideally, we would just re-export `wasmtime_runtime::I31` here, but
4 //! in order to get doc comments with example code that shows the use of `I31`
5 //! with typed functions and such, we need to wrap it in a newtype.
6 
7 use crate::runtime::vm::{VMGcRef, ValRaw};
8 use crate::{
9     HeapType, RefType, Result, ValType, WasmTy,
10     store::{AutoAssertNoGc, StoreOpaque},
11 };
12 use core::fmt;
13 use core::mem::MaybeUninit;
14 
15 /// A 31-bit integer.
16 ///
17 /// Represents WebAssembly's `(ref i31)` and `(ref null i31)` (aka `i31ref`)
18 /// references.
19 ///
20 /// You can convert this into any of the `(ref i31)` supertypes such as `(ref
21 /// eq)` or `(ref any)`, and their nullable equivalents. After conversion, the
22 /// resulting reference does not actually point at a GC object in the heap,
23 /// instead it is a 31-bit integer that is stored unboxed/inline in the
24 /// reference itself.
25 ///
26 /// # Example
27 ///
28 /// ```
29 /// # use wasmtime::*;
30 /// # fn _foo() -> Result<()> {
31 /// // Enable the Wasm GC proposal for Wasm to use i31 references.
32 /// let mut config = Config::new();
33 /// config.wasm_gc(true);
34 ///
35 /// let engine = Engine::new(&config)?;
36 /// let mut store = Store::new(&engine, ());
37 ///
38 /// // A Wasm module that exports a function that increments an i31.
39 /// let module = Module::new(&engine, r#"
40 ///     (module
41 ///         (func (export "inc_i31") (param (ref i31)) (result (ref i31))
42 ///             local.get 0
43 ///             i31.get_u
44 ///             i32.const 1
45 ///             i32.add
46 ///             ref.i31
47 ///         )
48 /// "#)?;
49 ///
50 /// // Instantiate the module.
51 /// let instance = Instance::new(&mut store, &module, &[])?;
52 ///
53 /// // Get the exported `inc_i31` function.
54 /// let inc_i31 = instance.get_func(&mut store, "inc_i31").unwrap();
55 ///
56 /// // Call the function using the untyped functions API, meaning we need to
57 /// // pack our `I31` argument into an `AnyRef` that is packed into a `Val`, and
58 /// // then we need to do the opposite unpacking to extract the result.
59 /// let i31 = I31::wrapping_u32(0x1234);
60 /// let anyref = AnyRef::from_i31(&mut store, i31);
61 /// let val = Val::AnyRef(Some(anyref));
62 /// let mut results = [Val::null_any_ref()];
63 /// inc_i31.call(&mut store, &[val], &mut results)?;
64 /// let nullable_anyref = results[0].unwrap_anyref();
65 /// let anyref = nullable_anyref.unwrap();
66 /// let i31 = anyref.unwrap_i31(&store)?;
67 /// assert_eq!(i31.get_u32(), 0x1235);
68 ///
69 /// // Alternatively, we can use the typed function API to make this all a lot
70 /// // more ergonomic.
71 /// let inc_i31 = inc_i31.typed::<I31, I31>(&mut store)?;
72 /// let i31 = I31::wrapping_u32(0x5678);
73 /// let result = inc_i31.call(&mut store, i31)?;
74 /// assert_eq!(result.get_u32(), 0x5679);
75 /// # Ok(())
76 /// # }
77 /// ```
78 #[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
79 pub struct I31(crate::runtime::vm::I31);
80 
81 impl fmt::Debug for I31 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result82     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83         f.debug_struct("I31")
84             .field("as_u32", &self.get_u32())
85             .field("as_i32", &self.get_i32())
86             .finish()
87     }
88 }
89 
90 impl From<crate::runtime::vm::I31> for I31 {
91     #[inline]
from(value: crate::runtime::vm::I31) -> Self92     fn from(value: crate::runtime::vm::I31) -> Self {
93         Self(value)
94     }
95 }
96 
97 impl From<I31> for crate::runtime::vm::I31 {
98     #[inline]
from(value: I31) -> Self99     fn from(value: I31) -> Self {
100         value.0
101     }
102 }
103 
104 impl I31 {
105     /// Get this `wasmtime::I31`'s internal `crate::runtime::vm::I31`.
runtime_i31(self) -> crate::runtime::vm::I31106     pub(crate) fn runtime_i31(self) -> crate::runtime::vm::I31 {
107         self.0
108     }
109 
110     /// Construct a new `I31` from the given unsigned value.
111     ///
112     /// Returns `None` if the value does not fit in the bottom 31 bits.
113     ///
114     /// # Example
115     ///
116     /// ```
117     /// # use wasmtime::*;
118     /// // This value does not fit into 31 bits.
119     /// assert!(I31::new_u32(0x8000_0000).is_none());
120     ///
121     /// // This value does fit into 31 bits.
122     /// let x = I31::new_u32(5).unwrap();
123     /// assert_eq!(x.get_u32(), 5);
124     /// ```
125     #[inline]
new_u32(value: u32) -> Option<Self>126     pub fn new_u32(value: u32) -> Option<Self> {
127         crate::runtime::vm::I31::new_u32(value).map(Self)
128     }
129 
130     /// Construct a new `I31` from the given signed value.
131     ///
132     /// Returns `None` if the value does not fit in the bottom 31 bits.
133     ///
134     /// # Example
135     ///
136     /// ```
137     /// # use wasmtime::*;
138     /// // This value does not fit into 31 bits.
139     /// assert!(I31::new_i32(-2147483648).is_none());
140     ///
141     /// // This value does fit into 31 bits.
142     /// let x = I31::new_i32(-5).unwrap();
143     /// assert_eq!(x.get_i32(), -5);
144     /// ```
145     #[inline]
new_i32(value: i32) -> Option<Self>146     pub fn new_i32(value: i32) -> Option<Self> {
147         crate::runtime::vm::I31::new_i32(value).map(Self)
148     }
149 
150     /// Construct a new `I31` from the given unsigned value.
151     ///
152     /// If the value doesn't fit in the bottom 31 bits, it is wrapped such that
153     /// the wrapped value does.
154     ///
155     /// # Example
156     ///
157     /// ```
158     /// # use wasmtime::*;
159     /// // Values that fit in 31 bits are preserved.
160     /// let x = I31::wrapping_u32(5);
161     /// assert_eq!(x.get_u32(), 5);
162     ///
163     /// // Values that do not fit in 31 bits are wrapped to 31 bits.
164     /// let y = I31::wrapping_u32(0xffff_ffff);
165     /// assert_eq!(y.get_u32(), 0x7fff_ffff);
166     /// ```
167     #[inline]
wrapping_u32(value: u32) -> Self168     pub fn wrapping_u32(value: u32) -> Self {
169         Self(crate::runtime::vm::I31::wrapping_u32(value))
170     }
171 
172     /// Construct a new `I31` from the given signed value.
173     ///
174     /// If the value doesn't fit in the bottom 31 bits, it is wrapped such that
175     /// the wrapped value does.
176     ///
177     /// # Example
178     ///
179     /// ```
180     /// # use wasmtime::*;
181     /// // Values that fit in 31 bits are preserved.
182     /// let x = I31::wrapping_i32(-5);
183     /// assert_eq!(x.get_i32(), -5);
184     ///
185     /// // Values that do not fit in 31 bits are wrapped to 31 bits.
186     /// let y = I31::wrapping_i32(-1073741825); // 0xbfffffff
187     /// assert_eq!(y.get_i32(), 1073741823);    // 0x3fffffff
188     /// ```
189     #[inline]
wrapping_i32(value: i32) -> Self190     pub fn wrapping_i32(value: i32) -> Self {
191         Self(crate::runtime::vm::I31::wrapping_i32(value))
192     }
193 
194     /// Get this `I31`'s value as an unsigned integer.
195     ///
196     /// # Example
197     ///
198     /// ```
199     /// # use wasmtime::*;
200     /// let x = I31::new_i32(-1).unwrap();
201     /// assert_eq!(x.get_u32(), 0x7fff_ffff);
202     /// ```
203     #[inline]
get_u32(&self) -> u32204     pub fn get_u32(&self) -> u32 {
205         self.0.get_u32()
206     }
207 
208     /// Get this `I31`'s value as a signed integer.
209     ///
210     /// # Example
211     ///
212     /// ```
213     /// # use wasmtime::*;
214     /// let x = I31::new_u32(0x7fff_ffff).unwrap();
215     /// assert_eq!(x.get_i32(), -1);
216     /// ```
217     #[inline]
get_i32(&self) -> i32218     pub fn get_i32(&self) -> i32 {
219         self.0.get_i32()
220     }
221 }
222 
223 unsafe impl WasmTy for I31 {
224     #[inline]
valtype() -> ValType225     fn valtype() -> ValType {
226         ValType::Ref(RefType::new(false, HeapType::I31))
227     }
228 
229     #[inline]
compatible_with_store(&self, _store: &StoreOpaque) -> bool230     fn compatible_with_store(&self, _store: &StoreOpaque) -> bool {
231         true
232     }
233 
dynamic_concrete_type_check( &self, _store: &StoreOpaque, _nullable: bool, _actual: &HeapType, ) -> Result<()>234     fn dynamic_concrete_type_check(
235         &self,
236         _store: &StoreOpaque,
237         _nullable: bool,
238         _actual: &HeapType,
239     ) -> Result<()> {
240         unreachable!()
241     }
242 
store(self, _store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>243     fn store(self, _store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
244         let gc_ref = VMGcRef::from_i31(self.into()).as_raw_u32();
245         ptr.write(ValRaw::anyref(gc_ref));
246         Ok(())
247     }
248 
load(_store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self249     unsafe fn load(_store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
250         let raw = ptr.get_anyref();
251         let gc_ref = VMGcRef::from_raw_u32(raw).expect("non-null");
252         gc_ref.unwrap_i31().into()
253     }
254 }
255 
256 unsafe impl WasmTy for Option<I31> {
257     #[inline]
valtype() -> ValType258     fn valtype() -> ValType {
259         ValType::Ref(RefType::new(true, HeapType::I31))
260     }
261 
262     #[inline]
compatible_with_store(&self, _store: &StoreOpaque) -> bool263     fn compatible_with_store(&self, _store: &StoreOpaque) -> bool {
264         true
265     }
266 
dynamic_concrete_type_check( &self, _store: &StoreOpaque, _nullable: bool, _actual: &HeapType, ) -> Result<()>267     fn dynamic_concrete_type_check(
268         &self,
269         _store: &StoreOpaque,
270         _nullable: bool,
271         _actual: &HeapType,
272     ) -> Result<()> {
273         unreachable!()
274     }
275 
store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>276     fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
277         match self {
278             Some(i) => i.store(store, ptr),
279             None => {
280                 ptr.write(ValRaw::anyref(0));
281                 Ok(())
282             }
283         }
284     }
285 
load(_store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self286     unsafe fn load(_store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
287         let raw = ptr.get_anyref();
288         let gc_ref = VMGcRef::from_raw_u32(raw)?;
289         Some(I31(gc_ref.unwrap_i31()))
290     }
291 }
292