diff --git a/Cargo.lock b/Cargo.lock index 74d20fb1..6eecd7f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,7 +76,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn", ] [[package]] @@ -132,7 +132,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.38", + "syn", ] [[package]] @@ -899,24 +899,25 @@ dependencies = [ [[package]] name = "magnus" -version = "0.5.5" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b7a37670bc433d081ef5846d5589381fabd8d3410ad3b59faa6b1b4c9c3cbce" +checksum = "4778544796676e8428e9c622460ebf284bea52d8b10db3aeb449d8b5e61b3a13" dependencies = [ "magnus-macros", "rb-sys", "rb-sys-env", + "seq-macro", ] [[package]] name = "magnus-macros" -version = "0.4.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cc17af1d45442c011aa579d727ec6cff8a69aea8a6bbad26736e7112d749bfb" +checksum = "5968c820e2960565f647819f5928a42d6e874551cab9d88d75e3e0660d7f71e3" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -1153,7 +1154,7 @@ dependencies = [ "quote", "regex", "shell-words", - "syn 2.0.38", + "syn", ] [[package]] @@ -1269,6 +1270,12 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +[[package]] +name = "seq-macro" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b44e8fc93a14e66336d230954dda83d18b4605ccace8fe09bc7514a71ad0bc" + [[package]] name = "serde" version = "1.0.190" @@ -1286,7 +1293,7 @@ checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn", ] [[package]] @@ -1372,17 +1379,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.38" @@ -1433,7 +1429,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn", ] [[package]] @@ -1496,7 +1492,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn", ] [[package]] @@ -1640,7 +1636,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn", "wasm-bindgen-shared", ] @@ -1662,7 +1658,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1780,7 +1776,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.38", + "syn", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser", @@ -1993,7 +1989,7 @@ checksum = "73190422af3b408daa3c791f97f50c62509746c09de934d69dae602c65809663" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn", ] [[package]] @@ -2122,7 +2118,7 @@ dependencies = [ "proc-macro2", "quote", "shellexpand", - "syn 2.0.38", + "syn", "witx", ] @@ -2134,7 +2130,7 @@ checksum = "56981968f26952a527f78cf3aeb5ac436db82d3be1682a217a1835754fa50f51" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn", "wiggle-generate", ] @@ -2298,7 +2294,7 @@ checksum = "772666c41fb6dceaf520b564b962d738a8e1a83b41bd48945f50837aed78bb1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn", ] [[package]] diff --git a/ext/Cargo.toml b/ext/Cargo.toml index ccbb5a55..26439283 100644 --- a/ext/Cargo.toml +++ b/ext/Cargo.toml @@ -17,7 +17,7 @@ winch = ["wasmtime/winch"] [dependencies] lazy_static = "1.4.0" -magnus = { version = "0.5.5", features = ["rb-sys-interop"] } +magnus = { version = "0.6", features = ["rb-sys", "deprecated-send-sync-value"] } rb-sys = { version = "*", default-features = false, features = [ "stable-api-compiled-fallback", ] } diff --git a/ext/src/helpers/symbol_enum.rs b/ext/src/helpers/symbol_enum.rs index ba09a694..f52960ee 100644 --- a/ext/src/helpers/symbol_enum.rs +++ b/ext/src/helpers/symbol_enum.rs @@ -1,5 +1,5 @@ use super::static_id::StaticId; -use magnus::{exception::arg_error, Error, Symbol, TryConvert, Value}; +use magnus::{exception::arg_error, prelude::*, Error, Symbol, TryConvert, Value}; use std::fmt::Display; /// Represents an enum as a set of Symbols (using `StaticId`). diff --git a/ext/src/lib.rs b/ext/src/lib.rs index 3aeef351..36a8a646 100644 --- a/ext/src/lib.rs +++ b/ext/src/lib.rs @@ -1,4 +1,4 @@ -use magnus::Error; +use magnus::{Error, Ruby}; mod helpers; mod ruby_api; @@ -12,10 +12,10 @@ pub(crate) use ruby_api::*; rb_sys::set_global_tracking_allocator!(); #[magnus::init] -pub fn init() -> Result<(), Error> { +pub fn init(ruby: &Ruby) -> Result<(), Error> { #[cfg(ruby_gte_3_0)] unsafe { rb_sys::rb_ext_ractor_safe(true); } - ruby_api::init() + ruby_api::init(ruby) } diff --git a/ext/src/ruby_api/caller.rs b/ext/src/ruby_api/caller.rs index b6eb0bdb..84d7da25 100644 --- a/ext/src/ruby_api/caller.rs +++ b/ext/src/ruby_api/caller.rs @@ -66,7 +66,7 @@ impl<'a> Caller<'a> { /// @def export(name) /// @see Instance#export pub fn export(rb_self: Obj>, name: RString) -> Result>, Error> { - let caller = rb_self.get(); + let caller = rb_self; let inner = caller.handle.get_mut()?; if let Some(export) = inner.get_export(unsafe { name.as_str() }?) { diff --git a/ext/src/ruby_api/config.rs b/ext/src/ruby_api/config.rs index 78a936f1..d61289ac 100644 --- a/ext/src/ruby_api/config.rs +++ b/ext/src/ruby_api/config.rs @@ -4,6 +4,7 @@ use crate::{define_rb_intern, helpers::SymbolEnum}; use lazy_static::lazy_static; use magnus::{ exception::{arg_error, type_error}, + prelude::*, r_hash::ForEach, Error, RHash, Symbol, TryConvert, Value, }; @@ -165,8 +166,7 @@ impl TryFrom for String { impl TryFrom for Option { type Error = magnus::Error; fn try_from(value: ConfigEntry) -> Result { - let val: Option = value.1.try_convert().map_err(|_| value.invalid_type())?; - Ok(val) + >::try_convert(value.1).map_err(|_| value.invalid_type()) } } diff --git a/ext/src/ruby_api/convert.rs b/ext/src/ruby_api/convert.rs index a9990631..dd7ccc70 100644 --- a/ext/src/ruby_api/convert.rs +++ b/ext/src/ruby_api/convert.rs @@ -1,6 +1,6 @@ use crate::{define_rb_intern, err, error, helpers::SymbolEnum}; use lazy_static::lazy_static; -use magnus::{Error, IntoValue, RArray, Symbol, TryConvert, TypedData, Value}; +use magnus::{prelude::*, Error, IntoValue, RArray, Ruby, Symbol, TryConvert, TypedData, Value}; use wasmtime::{ExternRef, Val, ValType}; use super::{func::Func, global::Global, memory::Memory, store::StoreContextValue, table::Table}; @@ -99,18 +99,18 @@ unsafe impl Send for ExternRefValue {} unsafe impl Sync for ExternRefValue {} pub trait ToExtern { - fn to_extern(&self) -> Result; + fn to_extern(&self, ruby: &Ruby) -> Result; } impl ToExtern for Value { - fn to_extern(&self) -> Result { - if self.is_kind_of(Func::class()) { + fn to_extern(&self, ruby: &Ruby) -> Result { + if self.is_kind_of(Func::class(ruby)) { Ok(<&Func>::try_convert(*self)?.into()) - } else if self.is_kind_of(Memory::class()) { + } else if self.is_kind_of(Memory::class(ruby)) { Ok(<&Memory>::try_convert(*self)?.into()) - } else if self.is_kind_of(Table::class()) { + } else if self.is_kind_of(Table::class(ruby)) { Ok(<&Table>::try_convert(*self)?.into()) - } else if self.is_kind_of(Global::class()) { + } else if self.is_kind_of(Global::class(ruby)) { Ok(<&Global>::try_convert(*self)?.into()) } else { Err(Error::new( diff --git a/ext/src/ruby_api/engine.rs b/ext/src/ruby_api/engine.rs index 3aa1da5d..d3ac7ed9 100644 --- a/ext/src/ruby_api/engine.rs +++ b/ext/src/ruby_api/engine.rs @@ -4,8 +4,8 @@ use super::{ }; use crate::error; use magnus::{ - class, function, memoize, method, scan_args, typed_data::Obj, value::Id, Error, Module, Object, - RHash, RString, TryConvert, Value, + class, function, method, prelude::*, scan_args, typed_data::Obj, value::LazyId, Error, Module, + Object, RHash, RString, Ruby, TryConvert, Value, }; use std::{ collections::hash_map::DefaultHasher, @@ -178,15 +178,16 @@ impl Engine { /// then serialized modules from one engine can be deserialized by the /// other. /// @return [String] The hex formatted string that can be used to check precompiled module compatibility. - pub fn precompile_compatibility_key(rb_self: Obj) -> Result { - let ivar_id = *memoize!(Id: Id::new("precompile_compatibility_key")); + pub fn precompile_compatibility_key(ruby: &Ruby, rb_self: Obj) -> Result { + static ID: LazyId = LazyId::new("precompile_compatibility_key"); + let ivar_id = LazyId::get_inner_with(&ID, ruby); if let Ok(cached) = rb_self.ivar_get::<_, RString>(ivar_id) { return Ok(cached); } let mut hasher = DefaultHasher::new(); - let engine = rb_self.get().inner.clone(); + let engine = rb_self.inner.clone(); engine.precompile_compatibility_hash().hash(&mut hasher); let hex_encoded = format!("{:x}", hasher.finish()); let key = RString::new(&hex_encoded); diff --git a/ext/src/ruby_api/errors.rs b/ext/src/ruby_api/errors.rs index 5895ecb4..52bcc655 100644 --- a/ext/src/ruby_api/errors.rs +++ b/ext/src/ruby_api/errors.rs @@ -1,42 +1,33 @@ use crate::ruby_api::root; -use magnus::{gc, Error}; -use magnus::{memoize, ExceptionClass, Module}; +use magnus::{value::Lazy, Error, ExceptionClass, Module, Ruby}; /// Base error class for all Wasmtime errors. pub fn base_error() -> ExceptionClass { - *memoize!(ExceptionClass: { - let err = root().const_get("Error").unwrap(); - gc::register_mark_object(err); - err - }) + static ERR: Lazy = Lazy::new(|_| root().const_get("Error").unwrap()); + let ruby = Ruby::get().unwrap(); + ruby.get_inner(&ERR) } /// Raised when failing to convert the return value of a Ruby-backed Func to /// Wasm types. pub fn result_error() -> ExceptionClass { - *memoize!(ExceptionClass: { - let err = root().const_get("ResultError").unwrap(); - gc::register_mark_object(err); - err - }) + static ERR: Lazy = Lazy::new(|_| root().const_get("ResultError").unwrap()); + let ruby = Ruby::get().unwrap(); + ruby.get_inner(&ERR) } /// Raised when converting an {Extern} to its concrete type fails. pub fn conversion_error() -> ExceptionClass { - *memoize!(ExceptionClass: { - let err = root().const_get("ConversionError").unwrap(); - gc::register_mark_object(err); - err - }) + static ERR: Lazy = Lazy::new(|_| root().const_get("ConversionError").unwrap()); + let ruby = Ruby::get().unwrap(); + ruby.get_inner(&ERR) } /// Raised when a WASI program terminates early by calling +exit+. pub fn wasi_exit_error() -> ExceptionClass { - *memoize!(ExceptionClass: { - let err = root().const_get("WasiExit").unwrap(); - gc::register_mark_object(err); - err - }) + static ERR: Lazy = Lazy::new(|_| root().const_get("WasiExit").unwrap()); + let ruby = Ruby::get().unwrap(); + ruby.get_inner(&ERR) } #[macro_export] diff --git a/ext/src/ruby_api/externals.rs b/ext/src/ruby_api/externals.rs index e22a5d65..e3c4416c 100644 --- a/ext/src/ruby_api/externals.rs +++ b/ext/src/ruby_api/externals.rs @@ -4,8 +4,8 @@ use super::{ }; use crate::{conversion_err, not_implemented}; use magnus::{ - class, gc, method, rb_sys::AsRawValue, typed_data::Obj, DataTypeFunctions, Error, Module, - RClass, TypedData, Value, + class, gc::Marker, method, prelude::*, rb_sys::AsRawValue, typed_data::Obj, DataTypeFunctions, + Error, Module, RClass, Ruby, TypedData, Value, }; /// @yard @@ -28,12 +28,12 @@ pub enum Extern<'a> { } impl DataTypeFunctions for Extern<'_> { - fn mark(&self) { + fn mark(&self, marker: &Marker) { match self { - Extern::Func(f) => gc::mark(*f), - Extern::Global(g) => gc::mark(*g), - Extern::Memory(m) => gc::mark(*m), - Extern::Table(t) => gc::mark(*t), + Extern::Func(f) => marker.mark(*f), + Extern::Global(g) => marker.mark(*g), + Extern::Memory(m) => marker.mark(*m), + Extern::Table(t) => marker.mark(*t), } } } @@ -44,20 +44,20 @@ impl Extern<'_> { /// Returns the exported function or raises a `{ConversionError}` when the export is not a /// function. /// @return [Func] The exported function. - pub fn to_func(rb_self: Obj) -> Result { - match rb_self.get() { + pub fn to_func(ruby: &Ruby, rb_self: Obj) -> Result { + match *rb_self { Extern::Func(f) => Ok(f.as_value()), - _ => conversion_err!(Self::inner_class(rb_self), Func::class()), + _ => conversion_err!(Self::inner_class(rb_self), Func::class(ruby)), } } /// @yard /// Returns the exported global or raises a `{ConversionError}` when the export is not a global. /// @return [Global] The exported global. - pub fn to_global(rb_self: Obj) -> Result { - match rb_self.get() { + pub fn to_global(ruby: &Ruby, rb_self: Obj) -> Result { + match *rb_self { Extern::Global(g) => Ok(g.as_value()), - _ => conversion_err!(Self::inner_class(rb_self), Global::class()), + _ => conversion_err!(Self::inner_class(rb_self), Global::class(ruby)), } } @@ -65,27 +65,25 @@ impl Extern<'_> { /// Returns the exported memory or raises a `{ConversionError}` when the export is not a /// memory. /// @return [Memory] The exported memory. - pub fn to_memory(rb_self: Obj) -> Result { - match rb_self.get() { + pub fn to_memory(ruby: &Ruby, rb_self: Obj) -> Result { + match *rb_self { Extern::Memory(m) => Ok(m.as_value()), - _ => conversion_err!(Self::inner_class(rb_self), Memory::class()), + _ => conversion_err!(Self::inner_class(rb_self), Memory::class(ruby)), } } /// @yard /// Returns the exported table or raises a `{ConversionError}` when the export is not a table. /// @return [Table] The exported table. - pub fn to_table(rb_self: Obj) -> Result { - match rb_self.get() { + pub fn to_table(ruby: &Ruby, rb_self: Obj) -> Result { + match *rb_self { Extern::Table(t) => Ok(t.as_value()), - _ => conversion_err!(Self::inner_class(rb_self), Table::class()), + _ => conversion_err!(Self::inner_class(rb_self), Table::class(ruby)), } } pub fn inspect(rb_self: Obj) -> Result { - let rs_self = rb_self.get(); - - let inner_string: String = match rs_self { + let inner_string: String = match *rb_self { Extern::Func(f) => f.inspect(), Extern::Global(g) => g.inspect(), Extern::Memory(m) => m.inspect(), @@ -100,7 +98,7 @@ impl Extern<'_> { } fn inner_class(rb_self: Obj) -> RClass { - match rb_self.get() { + match *rb_self { Extern::Func(f) => f.class(), Extern::Global(g) => g.class(), Extern::Memory(m) => m.class(), diff --git a/ext/src/ruby_api/func.rs b/ext/src/ruby_api/func.rs index edd6c15c..c1d1802b 100644 --- a/ext/src/ruby_api/func.rs +++ b/ext/src/ruby_api/func.rs @@ -7,8 +7,9 @@ use super::{ }; use crate::Caller; use magnus::{ - block::Proc, class, function, method, prelude::*, scan_args::scan_args, typed_data::Obj, - DataTypeFunctions, Error, IntoValue, Object, RArray, TypedData, Value, + block::Proc, class, function, gc::Marker, method, prelude::*, scan_args::scan_args, + typed_data::Obj, value::Opaque, DataTypeFunctions, Error, IntoValue, Object, RArray, Ruby, + TypedData, Value, }; use wasmtime::{Caller as CallerImpl, Func as FuncImpl, Val}; @@ -16,7 +17,7 @@ use wasmtime::{Caller as CallerImpl, Func as FuncImpl, Val}; /// @rename Wasmtime::Func /// Represents a WebAssembly Function /// @see https://docs.rs/wasmtime/latest/wasmtime/struct.Func.html Wasmtime's Rust doc -#[derive(Debug, TypedData)] +#[derive(TypedData)] #[magnus( class = "Wasmtime::Func", size, @@ -30,21 +31,11 @@ pub struct Func<'a> { } impl DataTypeFunctions for Func<'_> { - fn mark(&self) { - self.store.mark() + fn mark(&self, marker: &Marker) { + self.store.mark(marker) } } -// Wraps a Proc to satisfy wasmtime::Func's Send+Sync requirements. This is safe -// to do as long as (1) we hold the GVL when whe execute the proc and (2) we do -// not have multiple threads running at once (e.g. with Wasm thread proposal). -#[repr(transparent)] -struct ShareableProc(Proc); -unsafe impl Send for ShareableProc {} -unsafe impl Sync for ShareableProc {} - -unsafe impl Send for Func<'_> {} - impl<'a> Func<'a> { /// @yard /// @@ -84,13 +75,12 @@ impl<'a> Func<'a> { let args = scan_args::<(Obj, RArray, RArray), (), (), (), (), Proc>(args)?; let (wrapped_store, params, results) = args.required; let callable = args.block; - let store = wrapped_store.get(); - store.retain(callable.as_value()); + wrapped_store.retain(callable.as_value()); - let context = store.context_mut(); + let context = wrapped_store.context_mut(); let ty = wasmtime::FuncType::new(params.to_val_type_vec()?, results.to_val_type_vec()?); - let func_closure = make_func_closure(&ty, callable); + let func_closure = make_func_closure(&ty, callable.into()); let inner = wasmtime::Func::new(context, ty, func_closure); Ok(Self { @@ -208,11 +198,10 @@ macro_rules! result_error { pub fn make_func_closure( ty: &wasmtime::FuncType, - callable: Proc, + callable: Opaque, ) -> impl Fn(CallerImpl<'_, StoreData>, &[Val], &mut [Val]) -> anyhow::Result<()> + Send + Sync + 'static { let ty = ty.to_owned(); - let callable = ShareableProc(callable); // The error handling here is a bit tricky. We want to return a Ruby exception, // but doing so directly can easily cause an early Ruby GC and segfault. So to @@ -233,11 +222,12 @@ pub fn make_func_closure( rparams.push(rparam).unwrap(); } - let callable = callable.0; + let ruby = Ruby::get().unwrap(); + let callable = ruby.get_inner(callable); match (callable.call(unsafe { rparams.as_slice() }), results.len()) { (Ok(_proc_result), 0) => { - wrapped_caller.get().expire(); + wrapped_caller.expire(); Ok(()) } (Ok(proc_result), n) => { @@ -245,7 +235,7 @@ pub fn make_func_closure( let Ok(proc_result) = RArray::to_ary(proc_result) else { return result_error!( store_context, - wrapped_caller.get(), + wrapped_caller, format!("could not convert {} to results array", callable) ); }; @@ -253,7 +243,7 @@ pub fn make_func_closure( if proc_result.len() != results.len() { return result_error!( store_context, - wrapped_caller.get(), + wrapped_caller, format!( "wrong number of results (given {}, expected {}) in {}", proc_result.len(), @@ -274,18 +264,18 @@ pub fn make_func_closure( Err(e) => { return result_error!( store_context, - wrapped_caller.get(), + wrapped_caller, format!("invalid result at index {i}: {e} in {callable}") ); } } } - wrapped_caller.get().expire(); + wrapped_caller.expire(); Ok(()) } (Err(e), _) => { - caller_error!(store_context, wrapped_caller.get(), e) + caller_error!(store_context, wrapped_caller, e) } } } diff --git a/ext/src/ruby_api/global.rs b/ext/src/ruby_api/global.rs index 2a4f07d5..bfd6c0ef 100644 --- a/ext/src/ruby_api/global.rs +++ b/ext/src/ruby_api/global.rs @@ -5,8 +5,8 @@ use super::{ }; use crate::error; use magnus::{ - class, function, method, prelude::*, typed_data::Obj, DataTypeFunctions, Error, Object, Symbol, - TypedData, Value, + class, function, gc::Marker, method, prelude::*, typed_data::Obj, DataTypeFunctions, Error, + Object, Symbol, TypedData, Value, }; use wasmtime::{Extern, Global as GlobalImpl, GlobalType, Mutability}; @@ -14,7 +14,7 @@ use wasmtime::{Extern, Global as GlobalImpl, GlobalType, Mutability}; /// @rename Wasmtime::Global /// Represents a WebAssembly global. /// @see https://docs.rs/wasmtime/latest/wasmtime/struct.Global.html Wasmtime's Rust doc -#[derive(Debug, TypedData)] +#[derive(TypedData)] #[magnus(class = "Wasmtime::Global", free_immediately, mark, unsafe_generics)] pub struct Global<'a> { store: StoreContextValue<'a>, @@ -22,8 +22,8 @@ pub struct Global<'a> { } impl DataTypeFunctions for Global<'_> { - fn mark(&self) { - self.store.mark() + fn mark(&self, marker: &Marker) { + self.store.mark(marker) } } @@ -56,9 +56,8 @@ impl<'a> Global<'a> { ) -> Result { let wasm_type = value_type.to_val_type()?; let wasm_default = default.to_wasm_val(wasm_type.clone())?; - let store = s.get(); let inner = GlobalImpl::new( - store.context_mut(), + s.context_mut(), GlobalType::new(wasm_type, mutability), wasm_default, ) @@ -96,7 +95,7 @@ impl<'a> Global<'a> { /// @def type /// @return [Symbol] The Wasm type of the global‘s content. pub fn type_(&self) -> Result { - self.ty().map(|ty| ty.content().clone().to_sym()) + self.ty().map(|ty| (ty.content()).clone().to_sym()) } /// @yard diff --git a/ext/src/ruby_api/instance.rs b/ext/src/ruby_api/instance.rs index 11558bf7..ba1c5360 100644 --- a/ext/src/ruby_api/instance.rs +++ b/ext/src/ruby_api/instance.rs @@ -7,8 +7,8 @@ use super::{ }; use crate::err; use magnus::{ - class, function, gc, method, prelude::*, scan_args, typed_data::Obj, DataTypeFunctions, Error, - Object, RArray, RHash, RString, TryConvert, TypedData, Value, + class, function, gc::Marker, method, prelude::*, scan_args, typed_data::Obj, DataTypeFunctions, + Error, Object, RArray, RHash, RString, Ruby, TryConvert, TypedData, Value, }; use wasmtime::{Extern, Instance as InstanceImpl, StoreContextMut}; @@ -25,8 +25,8 @@ pub struct Instance { unsafe impl Send for Instance {} impl DataTypeFunctions for Instance { - fn mark(&self) { - gc::mark(self.store) + fn mark(&self, marker: &Marker) { + marker.mark(self.store) } } @@ -38,12 +38,11 @@ impl Instance { /// @param imports [Array] /// The module's import, in orders that that they show up in the module. /// @return [Instance] - pub fn new(args: &[Value]) -> Result { + pub fn new(ruby: &Ruby, args: &[Value]) -> Result { let args = scan_args::scan_args::<(Obj, &Module), (Option,), (), (), (), ()>(args)?; let (wrapped_store, module) = args.required; - let store = wrapped_store.get(); - let mut context = store.context_mut(); + let mut context = wrapped_store.context_mut(); let imports = args .optional .0 @@ -56,7 +55,7 @@ impl Instance { // SAFETY: arr won't get gc'd (it's on the stack) and we don't mutate it. for import in unsafe { arr.as_slice() } { context.data_mut().retain(*import); - imports.push(import.to_extern()?); + imports.push(import.to_extern(ruby)?); } imports } @@ -88,8 +87,7 @@ impl Instance { /// @def exports /// @return [Hash{String => Extern}] pub fn exports(&self) -> Result { - let store = self.store.get(); - let mut ctx = store.context_mut(); + let mut ctx = self.store.context_mut(); let hash = RHash::new(); for export in self.inner.exports(&mut ctx) { @@ -111,10 +109,9 @@ impl Instance { /// @param name [String] /// @return [Extern, nil] The export if it exists, nil otherwise. pub fn export(&self, str: RString) -> Result, Error> { - let store = self.store.get(); let export = self .inner - .get_export(store.context_mut(), unsafe { str.as_str()? }); + .get_export(self.store.context_mut(), unsafe { str.as_str()? }); match export { Some(export) => export.wrap_wasmtime_type(self.store.into()).map(Some), None => Ok(None), @@ -138,8 +135,7 @@ impl Instance { ) })?)?; - let store = self.store.get(); - let func = self.get_func(store.context_mut(), unsafe { name.as_str()? })?; + let func = self.get_func(self.store.context_mut(), unsafe { name.as_str()? })?; Func::invoke(&self.store.into(), &func, &args[1..]) } diff --git a/ext/src/ruby_api/linker.rs b/ext/src/ruby_api/linker.rs index 5c0df693..0d92b5f0 100644 --- a/ext/src/ruby_api/linker.rs +++ b/ext/src/ruby_api/linker.rs @@ -11,8 +11,9 @@ use super::{ }; use crate::{define_rb_intern, err, error}; use magnus::{ - block::Proc, class, function, gc, method, prelude::*, scan_args, scan_args::scan_args, - typed_data::Obj, DataTypeFunctions, Error, Object, RArray, RHash, RString, TypedData, Value, + block::Proc, class, function, gc::Marker, method, prelude::*, scan_args, scan_args::scan_args, + typed_data::Obj, DataTypeFunctions, Error, Object, RArray, RHash, RString, Ruby, TypedData, + Value, }; use std::cell::RefCell; use wasmtime::Linker as LinkerImpl; @@ -34,8 +35,8 @@ pub struct Linker { unsafe impl Send for Linker {} impl DataTypeFunctions for Linker { - fn mark(&self) { - gc::mark_slice(self.refs.borrow().as_slice()); + fn mark(&self, marker: &Marker) { + marker.mark_slice(self.refs.borrow().as_slice()); } } @@ -100,15 +101,17 @@ impl Linker { /// @param item [Func, Memory] The item to define. /// @return [void] pub fn define( - &self, + ruby: &Ruby, + rb_self: &Self, store: &Store, module: RString, name: RString, item: Value, ) -> Result<(), Error> { - let item = item.to_extern()?; + let item = item.to_extern(ruby)?; - self.inner + rb_self + .inner .borrow_mut() .define( store.context(), @@ -138,7 +141,7 @@ impl Linker { let (module, name, params, results) = args.required; let callable = args.block; let ty = wasmtime::FuncType::new(params.to_val_type_vec()?, results.to_val_type_vec()?); - let func_closure = func::make_func_closure(&ty, callable); + let func_closure = func::make_func_closure(&ty, callable.into()); self.refs.borrow_mut().push(callable.as_value()); @@ -168,13 +171,12 @@ impl Linker { module: RString, name: RString, ) -> Result, Error> { - let store = s.get(); - let ext = - self.inner - .borrow() - .get(store.context_mut(), unsafe { module.as_str() }?, unsafe { - name.as_str()? - }); + let ext = self + .inner + .borrow() + .get(s.context_mut(), unsafe { module.as_str() }?, unsafe { + name.as_str()? + }); match ext { None => Ok(None), @@ -273,9 +275,7 @@ impl Linker { /// @param mod [Module] /// @return [Instance] pub fn instantiate(&self, s: Obj, module: &Module) -> Result { - let store = s.get(); - - if self.has_wasi && !store.context().data().has_wasi_ctx() { + if self.has_wasi && !s.context().data().has_wasi_ctx() { return err!( "Store is missing WASI configuration.\n\n\ When using `wasi: true`, the Store given to\n\ @@ -287,10 +287,10 @@ impl Linker { self.inner .borrow_mut() - .instantiate(store.context_mut(), module.get()) + .instantiate(s.context_mut(), module.get()) .map_err(|e| StoreContextValue::from(s).handle_wasm_error(e)) .map(|instance| { - self.refs.borrow().iter().for_each(|val| store.retain(*val)); + self.refs.borrow().iter().for_each(|val| s.retain(*val)); Instance::from_inner(s, instance) }) } @@ -302,11 +302,9 @@ impl Linker { /// @param mod [String] Module name /// @return [Func] pub fn get_default(&self, s: Obj, module: RString) -> Result { - let store = s.get(); - self.inner .borrow() - .get_default(store.context_mut(), unsafe { module.as_str() }?) + .get_default(s.context_mut(), unsafe { module.as_str() }?) .map(|func| Func::from_inner(s.into(), func)) .map_err(|e| error!("{}", e)) } diff --git a/ext/src/ruby_api/memory.rs b/ext/src/ruby_api/memory.rs index 0694158c..0802aea6 100644 --- a/ext/src/ruby_api/memory.rs +++ b/ext/src/ruby_api/memory.rs @@ -7,8 +7,8 @@ use super::{ }; use crate::{define_rb_intern, error}; use magnus::{ - class, function, method, r_string::RString, scan_args, typed_data::Obj, DataTypeFunctions, - Error, Module as _, Object, TypedData, Value, + class, function, gc::Marker, method, r_string::RString, scan_args, typed_data::Obj, + DataTypeFunctions, Error, Module as _, Object, Ruby, TypedData, Value, }; use rb_sys::tracking_allocator::ManuallyTracked; @@ -24,7 +24,7 @@ define_rb_intern!( /// @rename Wasmtime::Memory /// Represents a WebAssembly memory. /// @see https://docs.rs/wasmtime/latest/wasmtime/struct.Memory.html Wasmtime's Rust doc -#[derive(Debug, TypedData)] +#[derive(TypedData)] #[magnus(class = "Wasmtime::Memory", free_immediately, mark, unsafe_generics)] pub struct Memory<'a> { store: StoreContextValue<'a>, @@ -32,8 +32,8 @@ pub struct Memory<'a> { } impl DataTypeFunctions for Memory<'_> { - fn mark(&self) { - self.store.mark() + fn mark(&self, marker: &Marker) { + self.store.mark(marker) } } unsafe impl Send for Memory<'_> {} @@ -54,12 +54,11 @@ impl<'a> Memory<'a> { let (s,) = args.required; let (min,) = kw.required; let (max,) = kw.optional; - let store = s.get(); let memtype = wasmtime::MemoryType::new(min, max); - let inner = MemoryImpl::new(store.context_mut(), memtype).map_err(|e| error!("{}", e))?; - let memsize = inner.data_size(store.context_mut()); + let inner = MemoryImpl::new(s.context_mut(), memtype).map_err(|e| error!("{}", e))?; + let memsize = inner.data_size(s.context_mut()); Ok(Self { store: s.into(), @@ -223,7 +222,7 @@ impl From<&Memory<'_>> for Extern { } } -pub fn init() -> Result<(), Error> { +pub fn init(ruby: &Ruby) -> Result<(), Error> { let class = root().define_class("Memory", class::object())?; class.define_singleton_method("new", function!(Memory::new, -1))?; class.define_method("min_size", method!(Memory::min_size, 0))?; @@ -236,7 +235,7 @@ pub fn init() -> Result<(), Error> { class.define_method("data_size", method!(Memory::data_size, 0))?; class.define_method("read_unsafe_slice", method!(Memory::read_unsafe_slice, 2))?; - unsafe_slice::init()?; + unsafe_slice::init(ruby)?; Ok(()) } diff --git a/ext/src/ruby_api/memory/unsafe_slice.rs b/ext/src/ruby_api/memory/unsafe_slice.rs index ef2be2d9..69c7dd50 100644 --- a/ext/src/ruby_api/memory/unsafe_slice.rs +++ b/ext/src/ruby_api/memory/unsafe_slice.rs @@ -1,13 +1,15 @@ use crate::{define_rb_intern, error, root, Memory}; use magnus::{ - class, gc, method, + class, + gc::Marker, + method, rb_sys::{AsRawId, AsRawValue, FromRawValue}, typed_data::Obj, - value::IntoId, - DataTypeFunctions, Error, Module as _, TryConvert, TypedData, Value, + value::{IntoId, Lazy, Opaque}, + Class, DataTypeFunctions, Error, Module as _, Ruby, TryConvert, TypedData, Value, }; #[cfg(ruby_gte_3_0)] -use magnus::{class::object, memoize, require, RClass, RModule}; +use magnus::{class::object, require, RClass, RModule}; use rb_sys::{rb_ivar_set, rb_obj_freeze, rb_str_new_static}; #[cfg(ruby_gte_3_0)] use rb_sys::{ @@ -24,7 +26,7 @@ use std::ops::Range; /// The returned {UnsafeSlice} lazily reads the underlying memory, meaning that /// the actual pointer to the string buffer is not materialzed until /// {UnsafeSlice#to_str} is called. -#[derive(Debug, TypedData)] +#[derive(TypedData)] #[magnus( class = "Wasmtime::Memory::UnsafeSlice", free_immediately, @@ -39,8 +41,8 @@ pub struct UnsafeSlice<'a> { define_rb_intern!(IVAR_NAME => "__slice__",); impl DataTypeFunctions for UnsafeSlice<'_> { - fn mark(&self) { - self.memory.mark() + fn mark(&self, marker: &Marker) { + self.memory.mark(marker) } } @@ -66,13 +68,9 @@ impl<'a> UnsafeSlice<'a> { /// @return [Fiddle::MemoryView] Memory view of the slice. #[cfg(ruby_gte_3_0)] pub fn to_memory_view(rb_self: Obj) -> Result { - let klass = *memoize!(RClass: { - let c = fiddle_memory_view_class().unwrap(); - gc::register_mark_object(c); - c - }); - - klass.new_instance((rb_self,)) + static CLASS: Lazy = Lazy::new(|_| fiddle_memory_view_class().unwrap()); + let ruby = Ruby::get().unwrap(); + ruby.get_inner(&CLASS).new_instance((rb_self,)) } /// @yard @@ -81,7 +79,7 @@ impl<'a> UnsafeSlice<'a> { /// @def to_str /// @return [String] Binary +String+ of the memory. pub fn to_str(rb_self: Obj) -> Result { - let raw_slice = rb_self.get().get_raw_slice()?; + let raw_slice = rb_self.get_raw_slice()?; let id = IVAR_NAME.into_id(); let rstring = unsafe { let val = rb_str_new_static(raw_slice.as_ptr() as _, raw_slice.len() as _); @@ -101,8 +99,8 @@ impl<'a> UnsafeSlice<'a> { } #[cfg(ruby_gte_3_0)] - fn register_memory_view() -> Result<(), Error> { - let class = Self::class(); + fn register_memory_view(ruby: &Ruby) -> Result<(), Error> { + let class = Self::class(ruby); static ENTRY: rb_memory_view_entry_t = rb_memory_view_entry_t { get_func: Some(UnsafeSlice::initialize_memory_view), @@ -127,7 +125,6 @@ impl<'a> UnsafeSlice<'a> { let Ok(memory) = >::try_convert(obj) else { return false; }; - let memory = memory.get(); let Ok(raw_slice) = memory.get_raw_slice() else { return false; }; @@ -142,31 +139,29 @@ impl<'a> UnsafeSlice<'a> { let Ok(memory) = >::try_convert(obj) else { return false; }; - let memory = memory.get(); - memory.get_raw_slice().is_ok() } } /// A guard that ensures that a memory slice is not invalidated by resizing -#[derive(Debug)] pub struct MemoryGuard<'a> { - memory: Obj>, + memory: Opaque>>, original_size: u64, } impl<'a> MemoryGuard<'a> { pub fn new(memory: Obj>) -> Result { - let original_size = memory.get().size()?; + let original_size = memory.size()?; Ok(Self { - memory, + memory: memory.into(), original_size, }) } pub fn get(&self) -> Result<&Memory<'a>, Error> { - let mem = self.memory.get(); + let ruby = Ruby::get().unwrap(); + let mem = ruby.get_inner_ref(&self.memory); if mem.size()? != self.original_size { Err(error!("memory slice was invalidated by resize")) @@ -175,12 +170,12 @@ impl<'a> MemoryGuard<'a> { } } - pub fn mark(&self) { - gc::mark(self.memory) + pub fn mark(&self, marker: &Marker) { + marker.mark(self.memory) } } -pub fn init() -> Result<(), Error> { +pub fn init(ruby: &Ruby) -> Result<(), Error> { let parent = root().define_class("Memory", class::object())?; let class = parent.define_class("UnsafeSlice", class::object())?; @@ -188,7 +183,7 @@ pub fn init() -> Result<(), Error> { #[cfg(ruby_gte_3_0)] if require("fiddle").is_ok() && fiddle_memory_view_class().is_some() { - UnsafeSlice::register_memory_view()?; + UnsafeSlice::register_memory_view(ruby)?; class.define_method("to_memory_view", method!(UnsafeSlice::to_memory_view, 0))?; } diff --git a/ext/src/ruby_api/mod.rs b/ext/src/ruby_api/mod.rs index c678b90a..4339f754 100644 --- a/ext/src/ruby_api/mod.rs +++ b/ext/src/ruby_api/mod.rs @@ -2,7 +2,7 @@ #![allow(rustdoc::invalid_html_tags)] #![allow(rustdoc::bare_urls)] #![allow(rustdoc::invalid_rust_codeblocks)] -use magnus::{define_module, function, memoize, Error, RModule, RString}; +use magnus::{function, value::Lazy, Error, RModule, RString, Ruby}; mod caller; mod config; @@ -36,7 +36,9 @@ pub use wasi_ctx_builder::WasiCtxBuilder; /// The "Wasmtime" Ruby module. pub fn root() -> RModule { - *memoize!(RModule: define_module("Wasmtime").unwrap()) + static ROOT: Lazy = Lazy::new(|ruby| ruby.define_module("Wasmtime").unwrap()); + let ruby = Ruby::get().unwrap(); + ruby.get_inner(&ROOT) } // This Struct is a placeholder for documentation, so that we can hang methods @@ -57,7 +59,7 @@ impl Wasmtime { } } -pub fn init() -> Result<(), Error> { +pub fn init(ruby: &Ruby) -> Result<(), Error> { let wasmtime = root(); wasmtime.define_module_function("wat2wasm", function!(Wasmtime::wat2wasm, 1))?; @@ -70,7 +72,7 @@ pub fn init() -> Result<(), Error> { instance::init()?; func::init()?; caller::init()?; - memory::init()?; + memory::init(ruby)?; linker::init()?; externals::init()?; wasi_ctx_builder::init()?; diff --git a/ext/src/ruby_api/params.rs b/ext/src/ruby_api/params.rs index cbfbbdb5..6cc9d46c 100644 --- a/ext/src/ruby_api/params.rs +++ b/ext/src/ruby_api/params.rs @@ -1,5 +1,5 @@ use super::convert::ToWasmVal; -use magnus::{exception::arg_error, Error, ExceptionClass, Value}; +use magnus::{error::ErrorType, exception::arg_error, Error, Value}; use static_assertions::assert_eq_size; use wasmtime::{FuncType, ValType}; @@ -22,12 +22,12 @@ impl Param { fn to_wasmtime_val(&self) -> Result { self.val .to_wasm_val(self.ty.clone()) - .map_err(|error| match error { - Error::Error(class, msg) => { - Error::new(class, format!("{} (param at index {})", msg, self.index)) + .map_err(|error| match error.error_type() { + ErrorType::Error(class, msg) => { + Error::new(*class, format!("{} (param at index {})", msg, self.index)) } - Error::Exception(exception) => Error::new( - ExceptionClass::from_value(exception.class().into()).unwrap_or_else(arg_error), + ErrorType::Exception(exception) => Error::new( + exception.exception_class(), format!("{} (param at index {})", exception, self.index), ), _ => error, diff --git a/ext/src/ruby_api/store.rs b/ext/src/ruby_api/store.rs index 02c95638..83e1dfdd 100644 --- a/ext/src/ruby_api/store.rs +++ b/ext/src/ruby_api/store.rs @@ -3,8 +3,12 @@ use super::{caller::Caller, engine::Engine, root, trap::Trap, wasi_ctx_builder:: use crate::{define_rb_intern, error}; use magnus::Class; use magnus::{ - class, function, gc, method, scan_args, typed_data::Obj, DataTypeFunctions, Error, IntoValue, - Module, Object, TypedData, Value, + class, function, + gc::{Compactor, Marker}, + method, scan_args, + typed_data::Obj, + value::Opaque, + DataTypeFunctions, Error, IntoValue, Module, Object, Ruby, TypedData, Value, }; use std::cell::UnsafeCell; use std::convert::TryFrom; @@ -47,43 +51,25 @@ impl StoreData { self.last_error.take() } - pub fn mark(&self) { - gc::mark_movable(&self.user_data); + pub fn mark(&self, marker: &Marker) { + marker.mark_movable(self.user_data); if let Some(ref error) = self.last_error { - match error { - Error::Error(klass, _msg) => { - gc::mark_movable(*klass); - } - Error::Exception(obj) => { - gc::mark_movable(*obj); - } - Error::Jump(_) => {} + if let Some(val) = error.value() { + marker.mark(val); } } for value in self.refs.iter() { - gc::mark_movable(value); + marker.mark_movable(*value); } } - pub fn compact(&mut self) { - self.user_data = gc::location(self.user_data); + pub fn compact(&mut self, compactor: &Compactor) { + self.user_data = compactor.location(self.user_data); for value in self.refs.iter_mut() { - *value = gc::location(*value); - } - - if let Some(ref mut error) = self.last_error { - match error { - Error::Error(klass, _msg) => { - *klass = gc::location(*klass); - } - Error::Exception(obj) => { - *obj = gc::location(*obj); - } - Error::Jump(_) => {} - } + *value = compactor.location(*value); } } } @@ -98,12 +84,12 @@ pub struct Store { } impl DataTypeFunctions for Store { - fn mark(&self) { - self.context().data().mark(); + fn mark(&self, marker: &Marker) { + self.context().data().mark(marker); } - fn compact(&self) { - self.context_mut().data_mut().compact(); + fn compact(&self, compactor: &Compactor) { + self.context_mut().data_mut().compact(compactor); } } @@ -127,7 +113,7 @@ impl Store { /// /// @example /// store = Wasmtime::Store.new(Wasmtime::Engine.new, {}) - pub fn new(args: &[Value]) -> Result { + pub fn new(ruby: &Ruby, args: &[Value]) -> Result { let args = scan_args::scan_args::<(&Engine,), (Option,), (), (), _, ()>(args)?; let kw = scan_args::get_kwargs::<_, (), (Option<&WasiCtxBuilder>,), ()>( args.keywords, @@ -139,7 +125,7 @@ impl Store { let user_data = user_data.unwrap_or_else(|| ().into_value()); let wasi = match kw.optional.0 { None => None, - Some(wasi_ctx_builder) => Some(wasi_ctx_builder.build_context()?), + Some(wasi_ctx_builder) => Some(wasi_ctx_builder.build_context(ruby)?), }; let eng = engine.get(); @@ -234,28 +220,28 @@ impl Store { /// A wrapper around a Ruby Value that has a store context. /// Used in places where both Store or Caller can be used. -#[derive(Debug, Clone, Copy)] +#[derive(Clone, Copy)] pub enum StoreContextValue<'a> { - Store(Obj), - Caller(Obj>), + Store(Opaque>), + Caller(Opaque>>), } impl<'a> From> for StoreContextValue<'a> { fn from(store: Obj) -> Self { - StoreContextValue::Store(store) + StoreContextValue::Store(store.into()) } } impl<'a> From>> for StoreContextValue<'a> { fn from(caller: Obj>) -> Self { - StoreContextValue::Caller(caller) + StoreContextValue::Caller(caller.into()) } } impl<'a> StoreContextValue<'a> { - pub fn mark(&self) { + pub fn mark(&self, marker: &Marker) { match self { - Self::Store(store) => gc::mark(*store), + Self::Store(store) => marker.mark(*store), Self::Caller(_) => { // The Caller is on the stack while it's "live". Right before the end of a host call, // we remove the Caller form the Ruby object, thus there is no need to mark. @@ -264,24 +250,31 @@ impl<'a> StoreContextValue<'a> { } pub fn context(&self) -> Result, Error> { + let ruby = Ruby::get().unwrap(); match self { - Self::Store(store) => Ok(store.get().context()), - Self::Caller(caller) => caller.get().context(), + Self::Store(store) => Ok(ruby.get_inner_ref(store).context()), + Self::Caller(caller) => ruby.get_inner_ref(caller).context(), } } pub fn context_mut(&self) -> Result, Error> { + let ruby = Ruby::get().unwrap(); match self { - Self::Store(store) => Ok(store.get().context_mut()), - Self::Caller(caller) => caller.get().context_mut(), + Self::Store(store) => Ok(ruby.get_inner_ref(store).context_mut()), + Self::Caller(caller) => ruby.get_inner_ref(caller).context_mut(), } } pub fn set_last_error(&self, error: Error) { + let ruby = Ruby::get().unwrap(); match self { - Self::Store(store) => store.get().context_mut().data_mut().set_error(error), + Self::Store(store) => ruby + .get_inner(*store) + .context_mut() + .data_mut() + .set_error(error), Self::Caller(caller) => { - if let Ok(mut context) = caller.get().context_mut() { + if let Ok(mut context) = ruby.get_inner(*caller).context_mut() { context.data_mut().set_error(error); } } @@ -296,10 +289,7 @@ impl<'a> StoreContextValue<'a> { } else { Trap::try_from(error) .map(|trap| trap.into()) - .unwrap_or_else(|error| match error.downcast::() { - Ok(e) => e, - Err(e) => error!("{}", e), - }) + .unwrap_or_else(|e| error!("{}", e)) } } @@ -309,9 +299,14 @@ impl<'a> StoreContextValue<'a> { } fn take_last_error(&self) -> Result, Error> { + let ruby = Ruby::get().unwrap(); match self { - Self::Store(store) => Ok(store.get().take_last_error()), - Self::Caller(caller) => Ok(caller.get().context_mut()?.data_mut().take_error()), + Self::Store(store) => Ok(ruby.get_inner(*store).take_last_error()), + Self::Caller(caller) => Ok(ruby + .get_inner(*caller) + .context_mut()? + .data_mut() + .take_error()), } } } diff --git a/ext/src/ruby_api/table.rs b/ext/src/ruby_api/table.rs index 2add03f8..cd1ac001 100644 --- a/ext/src/ruby_api/table.rs +++ b/ext/src/ruby_api/table.rs @@ -5,8 +5,8 @@ use super::{ }; use crate::{define_rb_intern, error}; use magnus::{ - class, function, method, prelude::*, scan_args, typed_data::Obj, DataTypeFunctions, Error, - IntoValue, Object, Symbol, TypedData, Value, + class, function, gc::Marker, method, prelude::*, scan_args, typed_data::Obj, DataTypeFunctions, + Error, IntoValue, Object, Symbol, TypedData, Value, }; use wasmtime::{Extern, Table as TableImpl, TableType}; @@ -19,7 +19,7 @@ define_rb_intern!( /// @rename Wasmtime::Table /// Represents a WebAssembly table. /// @see https://docs.rs/wasmtime/latest/wasmtime/struct.Table.html Wasmtime's Rust doc -#[derive(Debug, TypedData)] +#[derive(TypedData)] #[magnus(class = "Wasmtime::Table", free_immediately, mark, unsafe_generics)] pub struct Table<'a> { store: StoreContextValue<'a>, @@ -27,8 +27,8 @@ pub struct Table<'a> { } impl DataTypeFunctions for Table<'_> { - fn mark(&self) { - self.store.mark() + fn mark(&self, marker: &Marker) { + self.store.mark(marker) } } @@ -50,12 +50,11 @@ impl<'a> Table<'a> { let (s, value_type, default) = args.required; let (min,) = kw.required; let (max,) = kw.optional; - let store = s.get(); let wasm_type = value_type.to_val_type()?; let wasm_default = default.to_wasm_val(wasm_type.clone())?; let inner = TableImpl::new( - store.context_mut(), + s.context_mut(), TableType::new(wasm_type, min, max), wasm_default, ) diff --git a/ext/src/ruby_api/trap.rs b/ext/src/ruby_api/trap.rs index 48ea3515..8b3e3c33 100644 --- a/ext/src/ruby_api/trap.rs +++ b/ext/src/ruby_api/trap.rs @@ -3,12 +3,15 @@ use std::convert::TryFrom; use crate::ruby_api::{errors::base_error, root}; use magnus::Error; use magnus::{ - memoize, method, prelude::*, rb_sys::AsRawValue, typed_data::Obj, DataTypeFunctions, - ExceptionClass, IntoValue, Symbol, TypedData, + method, prelude::*, rb_sys::AsRawValue, typed_data::Obj, value::Lazy, DataTypeFunctions, + ExceptionClass, IntoValue, Ruby, Symbol, TypedData, }; pub fn trap_error() -> ExceptionClass { - *memoize!(ExceptionClass: root().define_error("Trap", base_error()).unwrap()) + static ERR: Lazy = + Lazy::new(|_| root().define_error("Trap", base_error()).unwrap()); + let ruby = Ruby::get().unwrap(); + ruby.get_inner(&ERR) } macro_rules! trap_const { @@ -77,12 +80,10 @@ impl Trap { } pub fn inspect(rb_self: Obj) -> Result { - let rs_self = rb_self.get(); - Ok(format!( "#", rb_self.as_raw(), - rs_self.code()?.into_value().inspect() + rb_self.code()?.into_value().inspect() )) } } diff --git a/ext/src/ruby_api/wasi_ctx_builder.rs b/ext/src/ruby_api/wasi_ctx_builder.rs index a4edf989..8dcc53d9 100644 --- a/ext/src/ruby_api/wasi_ctx_builder.rs +++ b/ext/src/ruby_api/wasi_ctx_builder.rs @@ -1,8 +1,8 @@ use super::root; use crate::error; use magnus::{ - class, function, gc, method, typed_data::Obj, DataTypeFunctions, Error, Module, Object, RArray, - RHash, RString, TryConvert, TypedData, + class, function, gc::Marker, method, typed_data::Obj, value::Opaque, DataTypeFunctions, Error, + Module, Object, RArray, RHash, RString, Ruby, TryConvert, TypedData, }; use std::cell::RefCell; use std::{fs::File, path::PathBuf}; @@ -10,29 +10,29 @@ use wasi_common::pipe::ReadPipe; enum ReadStream { Inherit, - Path(RString), - String(RString), + Path(Opaque), + String(Opaque), } impl ReadStream { - pub fn mark(&self) { + pub fn mark(&self, marker: &Marker) { match self { Self::Inherit => (), - Self::Path(s) => gc::mark(*s), - Self::String(s) => gc::mark(*s), + Self::Path(s) => marker.mark(*s), + Self::String(s) => marker.mark(*s), } } } enum WriteStream { Inherit, - Path(RString), + Path(Opaque), } impl WriteStream { - pub fn mark(&self) { + pub fn mark(&self, marker: &Marker) { match self { Self::Inherit => (), - Self::Path(v) => gc::mark(*v), + Self::Path(v) => marker.mark(*v), } } } @@ -42,26 +42,26 @@ struct WasiCtxBuilderInner { stdin: Option, stdout: Option, stderr: Option, - env: Option, - args: Option, + env: Option>, + args: Option>, } impl WasiCtxBuilderInner { - pub fn mark(&self) { + pub fn mark(&self, marker: &Marker) { if let Some(v) = self.stdin.as_ref() { - v.mark(); + v.mark(marker); } if let Some(v) = self.stdout.as_ref() { - v.mark(); + v.mark(marker); } if let Some(v) = self.stderr.as_ref() { - v.mark(); + v.mark(marker); } if let Some(v) = self.env.as_ref() { - gc::mark(*v); + marker.mark(*v); } if let Some(v) = self.args.as_ref() { - gc::mark(*v); + marker.mark(*v); } } } @@ -81,8 +81,8 @@ pub struct WasiCtxBuilder { } impl DataTypeFunctions for WasiCtxBuilder { - fn mark(&self) { - self.inner.borrow().mark(); + fn mark(&self, marker: &Marker) { + self.inner.borrow().mark(marker); } } @@ -101,7 +101,7 @@ impl WasiCtxBuilder { /// Inherit stdin from the current Ruby process. /// @return [WasiCtxBuilder] +self+ pub fn inherit_stdin(rb_self: RbSelf) -> RbSelf { - let mut inner = rb_self.get().inner.borrow_mut(); + let mut inner = rb_self.inner.borrow_mut(); inner.stdin = Some(ReadStream::Inherit); rb_self } @@ -112,8 +112,8 @@ impl WasiCtxBuilder { /// @def set_stdin_file(path) /// @return [WasiCtxBuilder] +self+ pub fn set_stdin_file(rb_self: RbSelf, path: RString) -> RbSelf { - let mut inner = rb_self.get().inner.borrow_mut(); - inner.stdin = Some(ReadStream::Path(path)); + let mut inner = rb_self.inner.borrow_mut(); + inner.stdin = Some(ReadStream::Path(path.into())); rb_self } @@ -123,8 +123,8 @@ impl WasiCtxBuilder { /// @def set_stdin_string(content) /// @return [WasiCtxBuilder] +self+ pub fn set_stdin_string(rb_self: RbSelf, content: RString) -> RbSelf { - let mut inner = rb_self.get().inner.borrow_mut(); - inner.stdin = Some(ReadStream::String(content)); + let mut inner = rb_self.inner.borrow_mut(); + inner.stdin = Some(ReadStream::String(content.into())); rb_self } @@ -132,7 +132,7 @@ impl WasiCtxBuilder { /// Inherit stdout from the current Ruby process. /// @return [WasiCtxBuilder] +self+ pub fn inherit_stdout(rb_self: RbSelf) -> RbSelf { - let mut inner = rb_self.get().inner.borrow_mut(); + let mut inner = rb_self.inner.borrow_mut(); inner.stdout = Some(WriteStream::Inherit); rb_self } @@ -144,8 +144,8 @@ impl WasiCtxBuilder { /// @def set_stdout_file(path) /// @return [WasiCtxBuilder] +self+ pub fn set_stdout_file(rb_self: RbSelf, path: RString) -> RbSelf { - let mut inner = rb_self.get().inner.borrow_mut(); - inner.stdout = Some(WriteStream::Path(path)); + let mut inner = rb_self.inner.borrow_mut(); + inner.stdout = Some(WriteStream::Path(path.into())); rb_self } @@ -153,7 +153,7 @@ impl WasiCtxBuilder { /// Inherit stderr from the current Ruby process. /// @return [WasiCtxBuilder] +self+ pub fn inherit_stderr(rb_self: RbSelf) -> RbSelf { - let mut inner = rb_self.get().inner.borrow_mut(); + let mut inner = rb_self.inner.borrow_mut(); inner.stderr = Some(WriteStream::Inherit); rb_self } @@ -165,8 +165,8 @@ impl WasiCtxBuilder { /// @def set_stderr_file(path) /// @return [WasiCtxBuilder] +self+ pub fn set_stderr_file(rb_self: RbSelf, path: RString) -> RbSelf { - let mut inner = rb_self.get().inner.borrow_mut(); - inner.stderr = Some(WriteStream::Path(path)); + let mut inner = rb_self.inner.borrow_mut(); + inner.stderr = Some(WriteStream::Path(path.into())); rb_self } @@ -176,8 +176,8 @@ impl WasiCtxBuilder { /// @def set_env(env) /// @return [WasiCtxBuilder] +self+ pub fn set_env(rb_self: RbSelf, env: RHash) -> RbSelf { - let mut inner = rb_self.get().inner.borrow_mut(); - inner.env = Some(env); + let mut inner = rb_self.inner.borrow_mut(); + inner.env = Some(env.into()); rb_self } @@ -187,22 +187,24 @@ impl WasiCtxBuilder { /// @def set_argv(args) /// @return [WasiCtxBuilder] +self+ pub fn set_argv(rb_self: RbSelf, argv: RArray) -> RbSelf { - let mut inner = rb_self.get().inner.borrow_mut(); - inner.args = Some(argv); + let mut inner = rb_self.inner.borrow_mut(); + inner.args = Some(argv.into()); rb_self } - pub fn build_context(&self) -> Result { + pub fn build_context(&self, ruby: &Ruby) -> Result { let mut builder = wasmtime_wasi::WasiCtxBuilder::new(); let inner = self.inner.borrow(); if let Some(stdin) = inner.stdin.as_ref() { match stdin { ReadStream::Inherit => builder.inherit_stdin(), - ReadStream::Path(path) => builder.stdin(file_r(*path).map(wasi_file)?), + ReadStream::Path(path) => { + builder.stdin(file_r(ruby.get_inner(*path)).map(wasi_file)?) + } ReadStream::String(input) => { // SAFETY: &[u8] copied before calling in to Ruby, no GC can happen before. - let pipe = ReadPipe::from(unsafe { input.as_slice() }); + let pipe = ReadPipe::from(unsafe { ruby.get_inner(*input).as_slice() }); builder.stdin(Box::new(pipe)) } }; @@ -211,20 +213,24 @@ impl WasiCtxBuilder { if let Some(stdout) = inner.stdout.as_ref() { match stdout { WriteStream::Inherit => builder.inherit_stdout(), - WriteStream::Path(path) => builder.stdout(file_w(*path).map(wasi_file)?), + WriteStream::Path(path) => { + builder.stdout(file_w(ruby.get_inner(*path)).map(wasi_file)?) + } }; } if let Some(stderr) = inner.stderr.as_ref() { match stderr { WriteStream::Inherit => builder.inherit_stderr(), - WriteStream::Path(path) => builder.stderr(file_w(*path).map(wasi_file)?), + WriteStream::Path(path) => { + builder.stderr(file_w(ruby.get_inner(*path)).map(wasi_file)?) + } }; } if let Some(args) = inner.args.as_ref() { // SAFETY: no gc can happen nor do we write to `args`. - for item in unsafe { args.as_slice() } { + for item in unsafe { ruby.get_inner(*args).as_slice() } { let arg = RString::try_convert(*item)?; // SAFETY: &str copied before calling in to Ruby, no GC can happen before. let arg = unsafe { arg.as_str() }?; @@ -233,7 +239,7 @@ impl WasiCtxBuilder { } if let Some(env_hash) = inner.env.as_ref() { - let env_vec: Vec<(String, String)> = env_hash.to_vec()?; + let env_vec: Vec<(String, String)> = ruby.get_inner(*env_hash).to_vec()?; builder.envs(&env_vec).map_err(|e| error!("{}", e))?; }