Skip to content

Commit 348a0da

Browse files
authored
Optimize calls and fix bug with Instance preservation of cross-instance calls (#1878)
* push inst to call stack only if it differs * fix bug with return_call[_indirect] cross-instance calls * add cross-instance-calls.wast Wasmi test cases
1 parent 526bc88 commit 348a0da

3 files changed

Lines changed: 31 additions & 13 deletions

File tree

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,8 +413,12 @@ execution_handler! {
413413
let wasm_func = func.func_body();
414414
let callee_instance = *func.instance();
415415
let callee_instance = resolve_instance(state.store, &callee_instance).into();
416+
let changed_instance = match callee_instance != instance {
417+
true => Some(callee_instance),
418+
false => None,
419+
};
416420
let (callee_ip, callee_sp) =
417-
return_call_wasm(state, params, wasm_func, Some(instance))?;
421+
return_call_wasm(state, params, wasm_func, changed_instance)?;
418422
(callee_ip, callee_sp, callee_instance)
419423
}
420424
FuncEntity::Host(host_func) => {
@@ -457,8 +461,12 @@ execution_handler! {
457461
let wasm_func = func.func_body();
458462
let callee_instance = *func.instance();
459463
let callee_instance: Inst = resolve_instance(state.store, &callee_instance).into();
464+
let changed_instance = match callee_instance != instance {
465+
true => Some(callee_instance),
466+
false => None,
467+
};
460468
let (callee_ip, callee_sp) =
461-
return_call_wasm(state, params, wasm_func, Some(instance))?;
469+
return_call_wasm(state, params, wasm_func, changed_instance)?;
462470
(callee_ip, callee_sp, callee_instance)
463471
}
464472
FuncEntity::Host(host_func) => {

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

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,8 +1225,8 @@ impl CallStack {
12251225
None => debug_assert!(self.frames.is_empty()),
12261226
}
12271227
let prev_instance = match instance {
1228-
Some(instance) => self.instance.replace(instance),
1229-
None => self.instance,
1228+
Some(instance) if self.instance != Some(instance) => self.instance.replace(instance),
1229+
_ => None,
12301230
};
12311231
let params_offset = usize::from(u16::from(callee_params.span().head()));
12321232
let start = self.top_start().add(params_offset)?;
@@ -1253,21 +1253,30 @@ impl CallStack {
12531253
}
12541254

12551255
/// Adjusts `self` for a function tail call.
1256+
///
1257+
/// # Note
1258+
///
1259+
/// - If `instance` is `Some` it refers to the _callee_ instance of the tail call
1260+
/// which is required to be different from the currently used instance.
1261+
/// - If `instance` is `None` the callee shares the currently used instance.
12561262
#[inline(always)]
12571263
fn replace(&mut self, callee_ip: Ip, instance: Option<Inst>) -> Result<SpOffset, TrapCode> {
12581264
let Some(caller_frame) = self.frames.last_mut() else {
12591265
unsafe { unreachable_unchecked!("missing caller frame on the call stack") }
12601266
};
1261-
let prev_instance = match instance {
1262-
Some(instance) => self.instance.replace(instance),
1263-
None => self.instance,
1264-
};
12651267
let start = caller_frame.start;
1266-
*caller_frame = Frame {
1267-
start,
1268-
ip: callee_ip,
1269-
instance: prev_instance,
1270-
};
1268+
caller_frame.ip = callee_ip;
1269+
if let Some(callee_instance) = instance {
1270+
debug_assert!(self.instance != Some(callee_instance));
1271+
// The replaced frame's restoration obligation is carried over unchanged.
1272+
// However, if the replaced frame has no such obligation yet, its caller
1273+
// runs in the currently used instance which must be restored when the
1274+
// new frame returns since the callee continues in a different instance.
1275+
if caller_frame.instance.is_none() {
1276+
caller_frame.instance = self.instance;
1277+
}
1278+
self.instance = Some(callee_instance);
1279+
}
12711280
Ok(start)
12721281
}
12731282
}

crates/wast/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ macro_rules! foreach_test {
200200
fn wasmi_audit("wasmi/tests/audit");
201201
fn wasmi_call("wasmi/tests/call");
202202
fn wasmi_call_indirect("wasmi/tests/call-indirect");
203+
fn wasmi_cross_instance_calls("wasmi/tests/cross-instance-calls");
203204
fn wasmi_return_call("wasmi/tests/return-call");
204205
fn wasmi_return_call_indirect("wasmi/tests/return-call-indirect");
205206
fn wasmi_global_set("wasmi/tests/global-set");

0 commit comments

Comments
 (0)