Skip to content

Commit 5319622

Browse files
authored
Refactor ThinPtr + executor's instance access APIs (#2020)
* move ThinPtr<InstanceEntity> around * reformat docs * rename AnyHandleAndEntity::typed_{ref,mut} -> as_typed_{ref,mut} * add AnyHandleAndEntity::into_typed_ptr method * return NonNull instead of refs in ThinPtr getters * add required HandleAndEntity<T>::map_entity * add TODO for HandleAndEntity::entity method * re-export HandleAndEntity crate-wide * remove unused lifetime annotations * privately re-export DataSegment handle from crate root * re-design executor Inst access API * take PrunedStore instead of StoreInner for lifetime * take &mut PrunedStore in fetch_default_memory_bytes for its lifetime * apply some clippy suggestions * add todo safety comments to executor * add more todo safety comments in executor * move safety comment to where it belongs * update/fix safety comments * update and improve docs for the new traits * add new or todo safety comments * update docs about `this` usage * update safety docss * remove HandleAndEntity::map_entity utility * drop incorrect todo item * mark into_typed_ptr unsafe * remove outdated todo comment * add missing safety comments
1 parent d737d7f commit 5319622

9 files changed

Lines changed: 291 additions & 224 deletions

File tree

crates/wasmi/src/engine/executor/handler/args.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ impl Args {
152152

153153
/// Returns the bytes of the default memory at index 0.
154154
#[inline]
155-
pub fn fetch_default_memory_bytes<'a>(&mut self) -> &'a mut [u8] {
155+
pub fn fetch_default_memory_bytes<'a>(&mut self, _state: &'a mut VmState) -> &'a mut [u8] {
156156
state::mem0_bytes::<'a>(self.mem0_ptr, self.mem0_len)
157157
}
158158

@@ -166,7 +166,10 @@ impl Args {
166166
where
167167
Inst: LoadEntity<Addr, Entity = MemoryEntity>,
168168
{
169-
self.instance.load(state.store.inner_mut(), addr)
169+
// SAFETY: `addr` stems from a Wasmi IR operator and thus addresses a memory entry of
170+
// `self.instance` whose cache was warmed at instantiation. The `state` borrow
171+
// scopes the returned reference.
172+
unsafe { self.instance.load_entity_mut(state.store, addr) }
170173
}
171174

172175
/// Returns an exclusive reference to the global at `index`.
@@ -179,7 +182,10 @@ impl Args {
179182
where
180183
Inst: LoadEntity<Addr, Entity = GlobalEntity>,
181184
{
182-
self.instance.load(state.store.inner_mut(), addr)
185+
// SAFETY: `addr` stems from a Wasmi IR operator and thus addresses a global entry of
186+
// `self.instance` whose cache was warmed at instantiation. The `state` borrow
187+
// scopes the returned reference.
188+
unsafe { self.instance.load_entity_mut(state.store, addr) }
183189
}
184190

185191
/// Returns an exclusive reference to the table at `index`.
@@ -192,7 +198,10 @@ impl Args {
192198
where
193199
Inst: LoadEntity<Addr, Entity = TableEntity>,
194200
{
195-
self.instance.load(state.store.inner_mut(), addr)
201+
// SAFETY: `addr` stems from a Wasmi IR operator and thus addresses a table entry of
202+
// `self.instance` whose cache was warmed at instantiation. The `state` borrow
203+
// scopes the returned reference.
204+
unsafe { self.instance.load_entity_mut(state.store, addr) }
196205
}
197206

198207
/// Returns an exclusive reference to the element segment at `index`.
@@ -205,7 +214,10 @@ impl Args {
205214
where
206215
Inst: LoadEntity<Addr, Entity = ElementSegmentEntity>,
207216
{
208-
self.instance.load(state.store.inner_mut(), addr)
217+
// SAFETY: `addr` stems from a Wasmi IR operator and thus addresses an element segment
218+
// entry of `self.instance` whose cache was warmed at instantiation. The `state`
219+
// borrow scopes the returned reference.
220+
unsafe { self.instance.load_entity_mut(state.store, addr) }
209221
}
210222

211223
/// Returns an exclusive reference to the data segment at `index`.
@@ -218,7 +230,10 @@ impl Args {
218230
where
219231
Inst: LoadEntity<Addr, Entity = DataSegmentEntity>,
220232
{
221-
self.instance.load(state.store.inner_mut(), addr)
233+
// SAFETY: `addr` stems from a Wasmi IR operator and thus addresses a data segment entry
234+
// of `self.instance` whose cache was warmed at instantiation. The `state` borrow
235+
// scopes the returned reference.
236+
unsafe { self.instance.load_entity_mut(state.store, addr) }
222237
}
223238

224239
/// Reloads the data pointer and length of the default memory at index 0 from `state`.

crates/wasmi/src/engine/executor/handler/exec.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use super::{
1111
Args,
1212
dispatch::Done,
1313
state::{Freg32, Freg64, Inst, Ip, Ireg, Mem0Len, Mem0Ptr, Sp, VmState},
14-
utils::fetch_func,
1514
};
1615
#[cfg(feature = "simd")]
1716
use crate::V128;
@@ -25,7 +24,7 @@ use crate::{
2524
Control,
2625
dispatch::Break,
2726
state::DoneReason,
28-
utils::{self, GetValue, IntoControl as _},
27+
utils::{self, GetValue, IntoControl as _, LoadEntity, LoadHandle as _},
2928
},
3029
utils::unreachable_unchecked,
3130
},
@@ -405,7 +404,7 @@ execution_handler! {
405404
delta,
406405
} = unsafe { args.decode_op() };
407406
let delta: u64 = args.get(delta);
408-
let memref = utils::fetch_memory(instance, memory);
407+
let memref = unsafe { instance.load_handle(memory) };
409408
let return_value = match state.store.grow_memory(&memref, delta) {
410409
Ok(return_value) => {
411410
// The `memory.grow` operation might have invalidated the cached
@@ -419,7 +418,8 @@ execution_handler! {
419418
Err(StoreError::External(
420419
MemoryError::OutOfBoundsGrowth | MemoryError::OutOfSystemMemory,
421420
)) => {
422-
let memory_ty = utils::resolve_memory(state.store, &memref).ty();
421+
let memory = unsafe { instance.load_entity_mut(state.store, memory) };
422+
let memory_ty = memory.ty();
423423
match memory_ty.is_64() {
424424
true => u64::MAX,
425425
false => u64::from(u32::MAX),
@@ -480,8 +480,8 @@ execution_handler! {
480480
memory_copy_within(state, &mut args, ip, dst_memory, dst_index, src_index, len)?;
481481
dispatch!(state, args)
482482
}
483-
let src_ptr = unsafe { utils::load_memory_ptr(instance, src_memory) };
484-
let mut dst_ptr = unsafe { utils::load_memory_ptr(instance, dst_memory) };
483+
let src_ptr = unsafe { instance.load_entity_ptr(src_memory) };
484+
let mut dst_ptr = unsafe { instance.load_entity_ptr(dst_memory) };
485485
if src_ptr == dst_ptr {
486486
// Distinct memory indices can still resolve to the same store entity (e.g. the same
487487
// memory imported under two names), so branch on the resolved entity before forming
@@ -520,7 +520,7 @@ fn memory_copy_within(
520520
len: usize,
521521
) -> Control<(), Break> {
522522
// SAFETY: `args.instance` is live and warmed up; `memory` is the only entity accessed here.
523-
let memory = unsafe { utils::load_memory_ptr(args.instance, dst_memory).as_mut() };
523+
let memory = unsafe { args.instance.load_entity_ptr(dst_memory).as_mut() };
524524
let fuel = state.store.inner_mut().fuel_mut();
525525
// These accesses just perform the bounds checks required by the Wasm spec.
526526
utils::memory_slice(memory, src_index, len).into_control()?;
@@ -562,7 +562,7 @@ execution_handler! {
562562
trap!(TrapCode::MemoryOutOfBounds)
563563
};
564564
// SAFETY: `instance` is live and warmed up; `memory` is the only entity accessed here.
565-
let memory = unsafe { utils::load_memory_ptr(instance, memory).as_mut() };
565+
let memory = unsafe { instance.load_entity_ptr(memory).as_mut() };
566566
let fuel = state.store.inner_mut().fuel_mut();
567567
let slice = utils::memory_slice_mut(memory, dst, len).into_control()?;
568568
consume_fuel!(state, ip, args, fuel, |costs| costs.fuel_for_copying_values::<u8>(len as u64));
@@ -605,8 +605,8 @@ execution_handler! {
605605
};
606606
// SAFETY: `instance` is live and warmed up. `memory` and `data` live in different
607607
// arenas, so their references are to distinct entities and cannot alias.
608-
let memory = unsafe { utils::load_memory_ptr(instance, memory).as_mut() };
609-
let data = unsafe { utils::load_data_ptr(instance, data).as_ref() };
608+
let memory = unsafe { instance.load_entity_ptr(memory).as_mut() };
609+
let data = unsafe { instance.load_entity_ptr(data).as_ref() };
610610
let fuel = state.store.inner_mut().fuel_mut();
611611
let memory = utils::memory_slice_mut(memory, dst_index, len).into_control()?;
612612
let Some(data) = data
@@ -680,13 +680,13 @@ execution_handler! {
680680
delta,
681681
value,
682682
} = unsafe { args.decode_op() };
683-
let table = utils::fetch_table(instance, table);
683+
let table_ref = unsafe { instance.load_handle(table) };
684684
let delta = args.get(delta);
685685
let value = args.get(value);
686-
let return_value = match state.store.grow_table(&table, delta, value) {
686+
let return_value = match state.store.grow_table(&table_ref, delta, value) {
687687
Ok(return_value) => return_value,
688688
Err(StoreError::External(TableError::GrowOutOfBounds | TableError::OutOfSystemMemory)) => {
689-
let table = utils::resolve_table(state.store, &table);
689+
let table = unsafe { instance.load_entity_mut(state.store, table) };
690690
match table.ty().is_64() {
691691
true => u64::MAX,
692692
false => u64::from(u32::MAX),
@@ -733,8 +733,8 @@ execution_handler! {
733733
let dst: u64 = args.get(dst);
734734
let src: u64 = args.get(src);
735735
let len: u64 = args.get(len);
736-
let src_ptr = unsafe { utils::load_table_ptr(instance, src_table) };
737-
let mut dst_ptr = unsafe { utils::load_table_ptr(instance, dst_table) };
736+
let src_ptr = unsafe { instance.load_entity_ptr(src_table) };
737+
let mut dst_ptr = unsafe { instance.load_entity_ptr(dst_table) };
738738
// Distinct table indices can still resolve to the same store entity (e.g. the same table
739739
// imported under two names), so branch on the resolved entity, not just the index.
740740
let result = if src_ptr == dst_ptr {
@@ -791,7 +791,7 @@ execution_handler! {
791791
let len: u64 = args.get(len);
792792
let value: RawRef = args.get(value);
793793
// SAFETY: `instance` is live and warmed up; `table` is the only entity accessed here.
794-
let table = unsafe { utils::load_table_ptr(instance, table).as_mut() };
794+
let table = unsafe { instance.load_entity_ptr(table).as_mut() };
795795
let fuel = state.store.inner_mut().fuel_mut();
796796
if let Err(error) = table.fill_raw(dst, value, len, Some(fuel)) {
797797
let trap_code = match error {
@@ -834,8 +834,8 @@ execution_handler! {
834834
let len: u32 = args.get(len);
835835
// SAFETY: `args.instance` is live and warmed up. `table` and `elem` live in different
836836
// arenas, so their references are to distinct entities and cannot alias.
837-
let table = unsafe { utils::load_table_ptr(args.instance, table).as_mut() };
838-
let element = unsafe { utils::load_elem_ptr(args.instance, elem).as_ref() };
837+
let table = unsafe { args.instance.load_entity_ptr(table).as_mut() };
838+
let element = unsafe { args.instance.load_entity_ptr(elem).as_ref() };
839839
let fuel = state.store.inner_mut().fuel_mut();
840840
if let Err(error) = table.init(element.as_ref(), dst, src, len, Some(fuel)) {
841841
let trap_code = match error {
@@ -961,7 +961,7 @@ execution_handler! {
961961
) -> Done = {
962962
let mut args = Args::from_parts(ip, sp, mem0, mem0_len, instance, ireg, freg32, freg64);
963963
let crate::ir::decode::RefFunc { func, result } = unsafe { args.decode_op() };
964-
let func = fetch_func(instance, func);
964+
let func = unsafe { instance.load_handle(func) };
965965
let Some(rawref) = func.unwrap_raw(&*state.store) else {
966966
unsafe { unreachable_unchecked!("store mismatch with: {func:?}") }
967967
};

crates/wasmi/src/engine/executor/handler/exec/macros.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ macro_rules! handler_load_mem0_offset16 {
200200
} = unsafe { args.decode_op() };
201201
let ptr = args.get(ptr);
202202
let offset = args.get(offset);
203-
let bytes = args.fetch_default_memory_bytes();
203+
let bytes = args.fetch_default_memory_bytes(state);
204204
let loaded = $load(bytes, ptr, u64::from(offset)).into_control()?;
205205
args.set(result, loaded);
206206
dispatch!(state, args)
@@ -268,7 +268,7 @@ macro_rules! handler_store_mem0_offset16 {
268268
let ptr = args.get(ptr);
269269
let offset = args.get(offset);
270270
let value: $hint = args.get(value);
271-
let bytes = args.fetch_default_memory_bytes();
271+
let bytes = args.fetch_default_memory_bytes(state);
272272
$store(bytes, ptr, u64::from(offset), value.into()).into_control()?;
273273
dispatch!(state, args)
274274
}

crates/wasmi/src/engine/executor/handler/exec/simd.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ macro_rules! handler_store_lane_mem0_offset16_ss {
540540
let ptr = args.get(ptr);
541541
let offset = args.get(offset);
542542
let value = args.get(value);
543-
let bytes = args.fetch_default_memory_bytes();
543+
let bytes = args.fetch_default_memory_bytes(state);
544544
$eval(bytes, ptr, u64::from(offset), value, lane).into_control()?;
545545
dispatch!(state, args)
546546
}

0 commit comments

Comments
 (0)