Skip to content

Commit b465e6c

Browse files
committed
Don't assume a GcStore is allocated when creating an AnyRef from a raw i31ref
And also don't force the allocation of a `GcStore` when converting an `AnyRef` that happens to be an `i31ref` into its raw representation.
1 parent a731e91 commit b465e6c

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

crates/wasmtime/src/runtime/gc/enabled/anyref.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,11 @@ impl AnyRef {
278278
// (Not actually memory unsafe since we have indexed GC heaps.)
279279
pub(crate) fn _from_raw(store: &mut AutoAssertNoGc, raw: u32) -> Option<Rooted<Self>> {
280280
let gc_ref = VMGcRef::from_raw_u32(raw)?;
281-
let gc_ref = store.unwrap_gc_store_mut().clone_gc_ref(&gc_ref);
281+
let gc_ref = if gc_ref.is_i31() {
282+
gc_ref.copy_i31()
283+
} else {
284+
store.unwrap_gc_store_mut().clone_gc_ref(&gc_ref)
285+
};
282286
Some(Self::from_cloned_gc_ref(store, gc_ref))
283287
}
284288

@@ -331,7 +335,11 @@ impl AnyRef {
331335

332336
pub(crate) unsafe fn _to_raw(&self, store: &mut AutoAssertNoGc<'_>) -> Result<u32> {
333337
let gc_ref = self.inner.try_clone_gc_ref(store)?;
334-
let raw = store.gc_store_mut()?.expose_gc_ref_to_wasm(gc_ref);
338+
let raw = if gc_ref.is_i31() {
339+
gc_ref.as_raw_non_zero_u32()
340+
} else {
341+
store.gc_store_mut()?.expose_gc_ref_to_wasm(gc_ref)
342+
};
335343
Ok(raw.get())
336344
}
337345

tests/all/i31ref.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,24 @@ fn always_pop_i31ref_lifo_roots() -> Result<()> {
1919

2020
Ok(())
2121
}
22+
23+
#[test]
24+
fn i31ref_to_raw_round_trip() -> Result<()> {
25+
let mut config = Config::new();
26+
config.wasm_function_references(true);
27+
config.wasm_gc(true);
28+
29+
let engine = Engine::new(&config)?;
30+
let mut store = Store::new(&engine, ());
31+
32+
// Should be able to round trip an `i31ref` to its raw representation and
33+
// back again even though we have not forced the allocation of the `GcStore`
34+
// yet.
35+
let anyref = AnyRef::from_i31(&mut store, I31::wrapping_u32(42));
36+
let raw = unsafe { anyref.to_raw(&mut store)? };
37+
let anyref = unsafe { AnyRef::from_raw(&mut store, raw).expect("should be non-null") };
38+
assert!(anyref.is_i31(&store)?);
39+
assert_eq!(anyref.as_i31(&store)?.unwrap().get_u32(), 42);
40+
41+
Ok(())
42+
}

0 commit comments

Comments
 (0)