Skip to content

Commit 4dd1fad

Browse files
authored
Drop T: 'static bounds from wasmi::Store again (#1507)
* try to drop T:'static from wasmi::Store * turn RestorePrunedWrapper into v-table This resolves T:'static issues with call_host_func but unfortunately not with store_inner_and_resource_limiter getter. * add Copy for RestorePrunedWrapper * use &self in RestorePrunedWrapper methods * add more explicit lifetimes to PrunedStore::store_inner_and_resource_limiter_ref * remove commented out code * use infered lifetimes in store_inner_and_resource_limiter_ref * remove unnecesary for<'a> * add some #[inline] annotations * redesign RestorePrunedWrapper API * rename RestorePrunedWrapper -> PrunedStoreVTable * replace commented out code with just code * add docs * drop T:'static bounds from Store
1 parent 059c3d7 commit 4dd1fad

File tree

5 files changed

+143
-64
lines changed

5 files changed

+143
-64
lines changed

crates/wasmi/src/engine/executor/instrs/memory.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::{Executor, InstructionPtr};
22
use crate::{
3-
core::{MemoryError, ResourceLimiterRef, TrapCode},
3+
core::{MemoryError, TrapCode},
44
engine::{utils::unreachable_unchecked, ResumableOutOfFuelError},
55
ir::{
66
index::{Data, Memory},
@@ -76,8 +76,7 @@ impl Executor<'_> {
7676
delta: Reg,
7777
) -> Result<(), Error> {
7878
let delta: u64 = self.get_register_as(delta);
79-
let (store, mut resource_limiter) = store.store_inner_and_resource_limiter_ref();
80-
self.execute_memory_grow_impl(store, result, delta, &mut resource_limiter)
79+
self.execute_memory_grow_impl(store, result, delta)
8180
}
8281

8382
/// Executes an [`Instruction::MemoryGrowImm`].
@@ -87,41 +86,38 @@ impl Executor<'_> {
8786
result: Reg,
8887
delta: Const32<u64>,
8988
) -> Result<(), Error> {
90-
let (store, mut resource_limiter) = store.store_inner_and_resource_limiter_ref();
9189
let delta = u64::from(delta);
92-
self.execute_memory_grow_impl(store, result, delta, &mut resource_limiter)
90+
self.execute_memory_grow_impl(store, result, delta)
9391
}
9492

9593
/// Executes a generic `memory.grow` instruction.
9694
#[inline(never)]
97-
fn execute_memory_grow_impl<'store>(
95+
fn execute_memory_grow_impl(
9896
&mut self,
99-
store: &'store mut StoreInner,
97+
store: &mut PrunedStore,
10098
result: Reg,
10199
delta: u64,
102-
resource_limiter: &mut ResourceLimiterRef<'store>,
103100
) -> Result<(), Error> {
104101
let memory = self.fetch_memory_index(1);
105102
if delta == 0 {
106103
// Case: growing by 0 pages means there is nothing to do
107-
self.execute_memory_size_impl(store, result, memory);
104+
self.execute_memory_size_impl(store.inner(), result, memory);
108105
return self.try_next_instr_at(2);
109106
}
110107
let memory = self.get_memory(memory);
111-
let (memory, fuel) = store.resolve_memory_and_fuel_mut(&memory);
112-
let return_value = memory.grow(delta, Some(fuel), resource_limiter);
113-
let return_value = match return_value {
108+
let return_value = match store.grow_memory(&memory, delta) {
114109
Ok(return_value) => {
115110
// The `memory.grow` operation might have invalidated the cached
116111
// linear memory so we need to reset it in order for the cache to
117112
// reload in case it is used again.
118113
//
119114
// Safety: the instance has not changed thus calling this is valid.
120-
unsafe { self.cache.update_memory(store) };
115+
unsafe { self.cache.update_memory(store.inner_mut()) };
121116
return_value
122117
}
123118
Err(MemoryError::OutOfBoundsGrowth | MemoryError::OutOfSystemMemory) => {
124-
match memory.ty().is_64() {
119+
let memory_ty = store.inner().resolve_memory(&memory).ty();
120+
match memory_ty.is_64() {
125121
true => u64::MAX,
126122
false => u64::from(u32::MAX),
127123
}

crates/wasmi/src/engine/executor/instrs/table.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::{Executor, InstructionPtr};
22
use crate::{
3-
core::{ResourceLimiterRef, Table as CoreTable, TableError, TrapCode},
3+
core::{Table as CoreTable, TableError, TrapCode},
44
engine::{utils::unreachable_unchecked, ResumableOutOfFuelError},
55
ir::{
66
index::{Elem, Table},
@@ -294,8 +294,7 @@ impl Executor<'_> {
294294
value: Reg,
295295
) -> Result<(), Error> {
296296
let delta: u64 = self.get_register_as(delta);
297-
let (store, mut resource_limiter) = store.store_inner_and_resource_limiter_ref();
298-
self.execute_table_grow_impl(store, result, delta, value, &mut resource_limiter)
297+
self.execute_table_grow_impl(store, result, delta, value)
299298
}
300299

301300
/// Executes an [`Instruction::TableGrowImm`].
@@ -307,34 +306,31 @@ impl Executor<'_> {
307306
value: Reg,
308307
) -> Result<(), Error> {
309308
let delta: u64 = delta.into();
310-
let (store, mut resource_limiter) = store.store_inner_and_resource_limiter_ref();
311-
self.execute_table_grow_impl(store, result, delta, value, &mut resource_limiter)
309+
self.execute_table_grow_impl(store, result, delta, value)
312310
}
313311

314312
/// Executes a generic `table.grow` instruction.
315313
#[inline(never)]
316-
fn execute_table_grow_impl<'store>(
314+
fn execute_table_grow_impl(
317315
&mut self,
318-
store: &'store mut StoreInner,
316+
store: &mut PrunedStore,
319317
result: Reg,
320318
delta: u64,
321319
value: Reg,
322-
resource_limiter: &mut ResourceLimiterRef<'store>,
323320
) -> Result<(), Error> {
324321
let table_index = self.fetch_table_index(1);
325322
if delta == 0 {
326323
// Case: growing by 0 elements means there is nothing to do
327-
self.execute_table_size_impl(store, result, table_index);
324+
self.execute_table_size_impl(store.inner(), result, table_index);
328325
return self.try_next_instr_at(2);
329326
}
330327
let table = self.get_table(table_index);
331328
let value = self.get_register(value);
332-
let (table, fuel) = store.resolve_table_and_fuel_mut(&table);
333-
let return_value = table.grow_untyped(delta, value, Some(fuel), resource_limiter);
334-
let return_value = match return_value {
329+
let return_value = match store.grow_table(&table, delta, value) {
335330
Ok(return_value) => return_value,
336331
Err(TableError::GrowOutOfBounds | TableError::OutOfSystemMemory) => {
337-
match table.ty().is_64() {
332+
let table_ty = store.inner().resolve_table(&table).ty();
333+
match table_ty.is_64() {
338334
true => u64::MAX,
339335
false => u64::from(u32::MAX),
340336
}

crates/wasmi/src/store/mod.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
mod context;
22
mod inner;
33
mod pruned;
4+
mod typeid;
45

5-
use self::pruned::RestorePrunedWrapper;
6+
use self::pruned::PrunedStoreVTable;
67
pub use self::{
78
context::{AsContext, AsContextMut, StoreContext, StoreContextMut},
89
inner::{StoreInner, Stored},
@@ -41,27 +42,27 @@ pub struct Store<T> {
4142
/// restored `T` matches the original `T` of the `store`.
4243
id: TypeId,
4344
/// Used to restore a [`PrunedStore`] to a [`Store<T>`].
44-
restore_pruned: RestorePrunedWrapper,
45+
restore_pruned: PrunedStoreVTable,
4546
}
4647

4748
impl<T> Default for Store<T>
4849
where
49-
T: Default + 'static,
50+
T: Default,
5051
{
5152
fn default() -> Self {
5253
let engine = Engine::default();
5354
Self::new(&engine, T::default())
5455
}
5556
}
5657

57-
impl<T: 'static> Store<T> {
58+
impl<T> Store<T> {
5859
/// Creates a new store.
5960
pub fn new(engine: &Engine, data: T) -> Self {
6061
Self {
6162
inner: StoreInner::new(engine),
6263
typed: TypedStoreInner::new(data),
63-
id: TypeId::of::<T>(),
64-
restore_pruned: RestorePrunedWrapper::new::<T>(),
64+
id: typeid::of::<T>(),
65+
restore_pruned: PrunedStoreVTable::new::<T>(),
6566
}
6667
}
6768
}

crates/wasmi/src/store/pruned.rs

Lines changed: 84 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
use super::{CallHooks, FuncInOut, HostFuncEntity, ResourceLimiterRef, StoreInner};
2-
use crate::{core::hint, CallHook, Error, Instance, Store};
1+
use super::{typeid, CallHooks, FuncInOut, HostFuncEntity, StoreInner};
2+
use crate::{
3+
core::{hint, MemoryError, TableError, UntypedVal},
4+
CallHook,
5+
Error,
6+
Instance,
7+
Memory,
8+
Store,
9+
Table,
10+
};
311
use core::{
4-
any::{type_name, TypeId},
12+
any::type_name,
513
fmt::{self, Debug},
614
mem,
715
};
@@ -15,25 +23,31 @@ use crate::Engine;
1523
/// works for [`Store`].
1624
#[allow(clippy::type_complexity)]
1725
#[derive(Copy, Clone)]
18-
pub struct RestorePrunedWrapper {
26+
pub struct PrunedStoreVTable {
1927
/// Calls the given [`HostFuncEntity`] with the `params` and `results` on `instance`.
2028
///
2129
/// # Errors
2230
///
2331
/// If the called host function returned an error.
2432
call_host_func: fn(
25-
/* store: */ &mut PrunedStore,
26-
/* func: */ &HostFuncEntity,
27-
/* instance: */ Option<&Instance>,
28-
/* params_results:*/ FuncInOut,
29-
/* call_hooks: */ CallHooks,
33+
store: &mut PrunedStore,
34+
func: &HostFuncEntity,
35+
instance: Option<&Instance>,
36+
params_results: FuncInOut,
37+
call_hooks: CallHooks,
3038
) -> Result<(), Error>,
31-
/// Returns an exclusive reference to [`StoreInner`] and a [`ResourceLimiterRef`].
32-
store_inner_and_resource_limiter_ref:
33-
fn(&mut PrunedStore) -> (&mut StoreInner, ResourceLimiterRef<'_>),
39+
/// Grows `memory` by `delta` pages.
40+
grow_memory: fn(&mut PrunedStore, memory: &Memory, delta: u64) -> Result<u64, MemoryError>,
41+
/// Grows `table` by `delta` items filling with `init`.
42+
grow_table: fn(
43+
&mut PrunedStore,
44+
table: &Table,
45+
delta: u64,
46+
init: UntypedVal,
47+
) -> Result<u64, TableError>,
3448
}
35-
impl RestorePrunedWrapper {
36-
pub fn new<T: 'static>() -> Self {
49+
impl PrunedStoreVTable {
50+
pub fn new<T>() -> Self {
3751
Self {
3852
call_host_func: |pruned: &mut PrunedStore,
3953
func: &HostFuncEntity,
@@ -51,15 +65,29 @@ impl RestorePrunedWrapper {
5165
}
5266
Ok(())
5367
},
54-
store_inner_and_resource_limiter_ref: |pruned: &mut PrunedStore| {
55-
pruned
56-
.restore_or_panic::<T>()
57-
.store_inner_and_resource_limiter_ref()
68+
grow_memory: |pruned: &mut PrunedStore,
69+
memory: &Memory,
70+
delta: u64|
71+
-> Result<u64, MemoryError> {
72+
let store: &mut Store<T> = pruned.restore_or_panic();
73+
let (store, mut resource_limiter) = store.store_inner_and_resource_limiter_ref();
74+
let (memory, fuel) = store.resolve_memory_and_fuel_mut(memory);
75+
memory.grow(delta, Some(fuel), &mut resource_limiter)
76+
},
77+
grow_table: |pruned: &mut PrunedStore,
78+
table: &Table,
79+
delta: u64,
80+
init: UntypedVal|
81+
-> Result<u64, TableError> {
82+
let store: &mut Store<T> = pruned.restore_or_panic();
83+
let (store, mut resource_limiter) = store.store_inner_and_resource_limiter_ref();
84+
let (table, fuel) = store.resolve_table_and_fuel_mut(table);
85+
table.grow_untyped(delta, init, Some(fuel), &mut resource_limiter)
5886
},
5987
}
6088
}
6189
}
62-
impl RestorePrunedWrapper {
90+
impl PrunedStoreVTable {
6391
#[inline]
6492
fn call_host_func(
6593
&self,
@@ -73,14 +101,27 @@ impl RestorePrunedWrapper {
73101
}
74102

75103
#[inline]
76-
fn store_inner_and_resource_limiter_ref<'a>(
104+
fn grow_memory(
105+
&self,
106+
pruned: &mut PrunedStore,
107+
memory: &Memory,
108+
delta: u64,
109+
) -> Result<u64, MemoryError> {
110+
(self.grow_memory)(pruned, memory, delta)
111+
}
112+
113+
#[inline]
114+
fn grow_table(
77115
&self,
78-
pruned: &'a mut PrunedStore,
79-
) -> (&'a mut StoreInner, ResourceLimiterRef<'a>) {
80-
(self.store_inner_and_resource_limiter_ref)(pruned)
116+
pruned: &mut PrunedStore,
117+
table: &Table,
118+
delta: u64,
119+
init: UntypedVal,
120+
) -> Result<u64, TableError> {
121+
(self.grow_table)(pruned, table, delta, init)
81122
}
82123
}
83-
impl Debug for RestorePrunedWrapper {
124+
impl Debug for PrunedStoreVTable {
84125
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85126
write!(f, "RestorePrunedWrapper")
86127
}
@@ -155,23 +196,35 @@ impl PrunedStore {
155196
)
156197
}
157198

158-
/// Returns an exclusive reference to [`StoreInner`] and a [`ResourceLimiterRef`].
199+
/// Grows the [`Memory`] by `delta` pages and returns the result.
200+
#[inline]
201+
pub fn grow_memory(&mut self, memory: &Memory, delta: u64) -> Result<u64, MemoryError> {
202+
self.pruned
203+
.restore_pruned
204+
.clone()
205+
.grow_memory(self, memory, delta)
206+
}
207+
208+
/// Grows the [`Table`] by `delta` items and returns the result.
159209
#[inline]
160-
pub fn store_inner_and_resource_limiter_ref(
210+
pub fn grow_table(
161211
&mut self,
162-
) -> (&mut StoreInner, ResourceLimiterRef) {
212+
table: &Table,
213+
delta: u64,
214+
init: UntypedVal,
215+
) -> Result<u64, TableError> {
163216
self.pruned
164217
.restore_pruned
165218
.clone()
166-
.store_inner_and_resource_limiter_ref(self)
219+
.grow_table(self, table, delta, init)
167220
}
168221

169222
/// Restores `self` to a proper [`Store<T>`] if possible.
170223
///
171224
/// # Panics
172225
///
173226
/// If the `T` of the resulting [`Store<T>`] does not match the given `T`.
174-
fn restore_or_panic<T: 'static>(&mut self) -> &mut Store<T> {
227+
fn restore_or_panic<T>(&mut self) -> &mut Store<T> {
175228
let Ok(store) = self.restore() else {
176229
panic!(
177230
"failed to convert `PrunedStore` back into `Store<{}>`",
@@ -187,8 +240,8 @@ impl PrunedStore {
187240
///
188241
/// If the `T` of the resulting [`Store<T>`] does not match the given `T`.
189242
#[inline]
190-
fn restore<T: 'static>(&mut self) -> Result<&mut Store<T>, PrunedStoreError> {
191-
if hint::unlikely(TypeId::of::<T>() != self.pruned.id) {
243+
fn restore<T>(&mut self) -> Result<&mut Store<T>, PrunedStoreError> {
244+
if hint::unlikely(typeid::of::<T>() != self.pruned.id) {
192245
return Err(PrunedStoreError);
193246
}
194247
let store = {

crates/wasmi/src/store/typeid.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use core::{any::TypeId, marker::PhantomData, mem};
2+
3+
/// Returns the [`TypeId`] of `T`.
4+
///
5+
/// # Note
6+
///
7+
/// - `T` does _not_ need to be `'static` for this to work.
8+
/// - This uses a trick copied from the [`typeid` crate](https://docs.rs/typeid) by [dtolnay](https://github.com/dtolnay).
9+
#[must_use]
10+
#[inline(always)]
11+
pub fn of<T>() -> TypeId
12+
where
13+
T: ?Sized,
14+
{
15+
trait NonStaticAny {
16+
fn get_type_id(&self) -> TypeId
17+
where
18+
Self: 'static;
19+
}
20+
impl<T: ?Sized> NonStaticAny for PhantomData<T> {
21+
#[inline(always)]
22+
fn get_type_id(&self) -> TypeId
23+
where
24+
Self: 'static,
25+
{
26+
TypeId::of::<T>()
27+
}
28+
}
29+
let phantom_data = PhantomData::<T>;
30+
NonStaticAny::get_type_id(unsafe {
31+
mem::transmute::<&dyn NonStaticAny, &(dyn NonStaticAny + 'static)>(&phantom_data)
32+
})
33+
}

0 commit comments

Comments
 (0)