From 25cd4adb10f79fb1ee00ed09fc46bfabe71ab5cb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 20 Aug 2025 09:50:56 -0700 Subject: [PATCH] Deduplicate some more GC functions Use the `async` version from sync API entrypoints to deduplicate the implementation. --- .../src/runtime/gc/enabled/arrayref.rs | 31 ++++------------ .../wasmtime/src/runtime/gc/enabled/exnref.rs | 27 +++----------- .../src/runtime/gc/enabled/externref.rs | 35 ++----------------- .../src/runtime/gc/enabled/structref.rs | 21 +++-------- crates/wasmtime/src/runtime/store/gc.rs | 33 ----------------- 5 files changed, 18 insertions(+), 129 deletions(-) diff --git a/crates/wasmtime/src/runtime/gc/enabled/arrayref.rs b/crates/wasmtime/src/runtime/gc/enabled/arrayref.rs index c79e8dde0835..c229e2583c72 100644 --- a/crates/wasmtime/src/runtime/gc/enabled/arrayref.rs +++ b/crates/wasmtime/src/runtime/gc/enabled/arrayref.rs @@ -2,7 +2,7 @@ use crate::runtime::vm::VMGcRef; use crate::store::StoreId; -use crate::vm::{VMArrayRef, VMGcHeader}; +use crate::vm::{self, VMArrayRef, VMGcHeader}; use crate::{AnyRef, FieldType}; use crate::{ ArrayType, AsContext, AsContextMut, EqRef, GcHeapOutOfMemory, GcRefImpl, GcRootIndex, HeapType, @@ -297,18 +297,9 @@ impl ArrayRef { elem: &Val, len: u32, ) -> Result> { - Self::_new(store.as_context_mut().0, allocator, elem, len) - } - - pub(crate) fn _new( - store: &mut StoreOpaque, - allocator: &ArrayRefPre, - elem: &Val, - len: u32, - ) -> Result> { - store.retry_after_gc((), |store, ()| { - Self::new_from_iter(store, allocator, RepeatN(elem, len)) - }) + let store = store.as_context_mut().0; + assert!(!store.async_support()); + vm::assert_ready(Self::_new_async(store, allocator, elem, len)) } /// Asynchronously allocate a new `array` of the given length, with every @@ -454,17 +445,9 @@ impl ArrayRef { allocator: &ArrayRefPre, elems: &[Val], ) -> Result> { - Self::_new_fixed(store.as_context_mut().0, allocator, elems) - } - - pub(crate) fn _new_fixed( - store: &mut StoreOpaque, - allocator: &ArrayRefPre, - elems: &[Val], - ) -> Result> { - store.retry_after_gc((), |store, ()| { - Self::new_from_iter(store, allocator, elems.iter()) - }) + let store = store.as_context_mut().0; + assert!(!store.async_support()); + vm::assert_ready(Self::_new_fixed_async(store, allocator, elems)) } /// Asynchronously allocate a new `array` containing the given elements. diff --git a/crates/wasmtime/src/runtime/gc/enabled/exnref.rs b/crates/wasmtime/src/runtime/gc/enabled/exnref.rs index 3e650cfe39a6..fe2afc998c94 100644 --- a/crates/wasmtime/src/runtime/gc/enabled/exnref.rs +++ b/crates/wasmtime/src/runtime/gc/enabled/exnref.rs @@ -2,7 +2,7 @@ use crate::runtime::vm::VMGcRef; use crate::store::StoreId; -use crate::vm::{VMExnRef, VMGcHeader}; +use crate::vm::{self, VMExnRef, VMGcHeader}; use crate::{ AsContext, AsContextMut, GcRefImpl, GcRootIndex, HeapType, ManuallyRooted, RefType, Result, Rooted, Val, ValRaw, ValType, WasmTy, @@ -205,23 +205,9 @@ impl ExnRef { tag: &Tag, fields: &[Val], ) -> Result> { - Self::_new(store.as_context_mut().0, allocator, tag, fields) - } - - pub(crate) fn _new( - store: &mut StoreOpaque, - allocator: &ExnRefPre, - tag: &Tag, - fields: &[Val], - ) -> Result> { - assert!( - !store.async_support(), - "use `ExnRef::new_async` with asynchronous stores" - ); - Self::type_check_tag_and_fields(store, allocator, tag, fields)?; - store.retry_after_gc((), |store, ()| { - Self::new_unchecked(store, allocator, tag, fields) - }) + let store = store.as_context_mut().0; + assert!(!store.async_support()); + vm::assert_ready(Self::_new_async(store, allocator, tag, fields)) } /// Asynchronously allocate a new exception object and get a @@ -262,17 +248,12 @@ impl ExnRef { Self::_new_async(store.as_context_mut().0, allocator, tag, fields).await } - #[cfg(feature = "async")] pub(crate) async fn _new_async( store: &mut StoreOpaque, allocator: &ExnRefPre, tag: &Tag, fields: &[Val], ) -> Result> { - assert!( - store.async_support(), - "use `ExnRef::new` with synchronous stores" - ); Self::type_check_tag_and_fields(store, allocator, tag, fields)?; store .retry_after_gc_async((), |store, ()| { diff --git a/crates/wasmtime/src/runtime/gc/enabled/externref.rs b/crates/wasmtime/src/runtime/gc/enabled/externref.rs index 1f74a2c19684..2c98a773b01c 100644 --- a/crates/wasmtime/src/runtime/gc/enabled/externref.rs +++ b/crates/wasmtime/src/runtime/gc/enabled/externref.rs @@ -2,7 +2,7 @@ use super::{AnyRef, RootedGcRefImpl}; use crate::prelude::*; -use crate::runtime::vm::VMGcRef; +use crate::runtime::vm::{self, VMGcRef}; use crate::{ AsContextMut, GcHeapOutOfMemory, GcRefImpl, GcRootIndex, HeapType, ManuallyRooted, RefType, Result, Rooted, StoreContext, StoreContextMut, ValRaw, ValType, WasmTy, @@ -215,36 +215,8 @@ impl ExternRef { T: 'static + Any + Send + Sync, { let ctx = context.as_context_mut().0; - Self::_new(ctx, value) - } - - pub(crate) fn _new(store: &mut StoreOpaque, value: T) -> Result> - where - T: 'static + Any + Send + Sync, - { - // Allocate the box once, regardless how many gc-and-retry attempts we - // make. - let value: Box = Box::new(value); - - let gc_ref = store - .retry_after_gc(value, |store, value| { - store - .require_gc_store_mut()? - .alloc_externref(value) - .context("unrecoverable error when allocating new `externref`")? - .map_err(|(x, n)| GcHeapOutOfMemory::new(x, n).into()) - }) - // Translate the `GcHeapOutOfMemory`'s inner value from the boxed - // trait object into `T`. - .map_err( - |e| match e.downcast::>>() { - Ok(oom) => oom.map_inner(|x| *x.downcast::().unwrap()).into(), - Err(e) => e, - }, - )?; - - let mut ctx = AutoAssertNoGc::new(store); - Ok(Self::from_cloned_gc_ref(&mut ctx, gc_ref.into())) + assert!(!ctx.async_support()); + vm::assert_ready(Self::_new_async(ctx, value)) } /// Asynchronously allocates a new `ExternRef` wrapping the given value. @@ -331,7 +303,6 @@ impl ExternRef { Self::_new_async(ctx, value).await } - #[cfg(feature = "async")] pub(crate) async fn _new_async( store: &mut StoreOpaque, value: T, diff --git a/crates/wasmtime/src/runtime/gc/enabled/structref.rs b/crates/wasmtime/src/runtime/gc/enabled/structref.rs index 603d59b7f8b9..da8cee81f886 100644 --- a/crates/wasmtime/src/runtime/gc/enabled/structref.rs +++ b/crates/wasmtime/src/runtime/gc/enabled/structref.rs @@ -2,7 +2,7 @@ use crate::runtime::vm::VMGcRef; use crate::store::StoreId; -use crate::vm::{VMGcHeader, VMStructRef}; +use crate::vm::{self, VMGcHeader, VMStructRef}; use crate::{AnyRef, FieldType}; use crate::{ AsContext, AsContextMut, EqRef, GcHeapOutOfMemory, GcRefImpl, GcRootIndex, HeapType, @@ -231,22 +231,9 @@ impl StructRef { allocator: &StructRefPre, fields: &[Val], ) -> Result> { - Self::_new(store.as_context_mut().0, allocator, fields) - } - - pub(crate) fn _new( - store: &mut StoreOpaque, - allocator: &StructRefPre, - fields: &[Val], - ) -> Result> { - assert!( - !store.async_support(), - "use `StructRef::new_async` with asynchronous stores" - ); - Self::type_check_fields(store, allocator, fields)?; - store.retry_after_gc((), |store, ()| { - Self::new_unchecked(store, allocator, fields) - }) + let store = store.as_context_mut().0; + assert!(!store.async_support()); + vm::assert_ready(Self::_new_async(store, allocator, fields)) } /// Asynchronously allocate a new `struct` and get a reference to it. diff --git a/crates/wasmtime/src/runtime/store/gc.rs b/crates/wasmtime/src/runtime/store/gc.rs index 1ca8613a98f5..7eb4b6287b98 100644 --- a/crates/wasmtime/src/runtime/store/gc.rs +++ b/crates/wasmtime/src/runtime/store/gc.rs @@ -165,39 +165,6 @@ impl StoreOpaque { } } - /// Attempt an allocation, if it fails due to GC OOM, then do a GC and - /// retry. - pub(crate) fn retry_after_gc( - &mut self, - value: T, - alloc_func: impl Fn(&mut Self, T) -> Result, - ) -> Result - where - T: Send + Sync + 'static, - { - assert!( - !self.async_support(), - "use the `*_async` versions of methods when async is configured" - ); - vm::assert_ready(self.ensure_gc_store())?; - match alloc_func(self, value) { - Ok(x) => Ok(x), - Err(e) => match e.downcast::>() { - Ok(oom) => { - let (value, oom) = oom.take_inner(); - // SAFETY: FIXME(#11409) - unsafe { - vm::assert_ready( - self.gc_unsafe_get_limiter(None, Some(oom.bytes_needed())), - ); - } - alloc_func(self, value) - } - Err(e) => Err(e), - }, - } - } - /// Attempt an allocation, if it fails due to GC OOM, then do a GC and /// retry. pub(crate) async fn retry_after_gc_async(