Skip to content

Commit 5d4fea7

Browse files
committed
add return_call_internal execution handler
1 parent 4cbaa9c commit 5d4fea7

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ pub fn op_code_to_handler(code: OpCode) -> Handler {
342342
OpCode::CallInternal => exec::call_internal,
343343
OpCode::CallImported => exec::call_imported,
344344
OpCode::CallIndirect => exec::call_indirect,
345+
OpCode::ReturnCallInternal => exec::return_call_internal,
345346
// memory
346347
OpCode::MemorySize => exec::memory_size,
347348
OpCode::MemoryGrow => exec::memory_grow,

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,24 @@ pub fn call_indirect(
301301
dispatch!(state, callee_ip, sp, mem0, mem0_len, instance)
302302
}
303303

304+
pub fn return_call_internal(
305+
state: &mut VmState,
306+
ip: Ip,
307+
_sp: Sp,
308+
mem0: Mem0Ptr,
309+
mem0_len: Mem0Len,
310+
instance: NonNull<InstanceEntity>,
311+
) -> Done {
312+
let (_, crate::ir::decode::ReturnCallInternal { params, func }) = unsafe { decode_op(ip) };
313+
let func = EngineFunc::from(func);
314+
let (callee_ip, size) = compile_or_get_func!(state, func);
315+
let callee_sp = match state.stack.replace_frame(callee_ip, params, size, None) {
316+
Ok(sp) => sp,
317+
Err(trap) => done!(state, trap),
318+
};
319+
dispatch!(state, callee_ip, callee_sp, mem0, mem0_len, instance)
320+
}
321+
304322
pub fn r#return(
305323
state: &mut VmState,
306324
_ip: Ip,

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

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::{
22
core::{ReadAs, UntypedVal, WriteAs},
33
engine::{
44
executor::{handler::utils::extract_mem0, CodeMap},
5+
utils::unreachable_unchecked,
56
StackConfig,
67
},
78
errors::HostError,
@@ -251,6 +252,22 @@ impl Stack {
251252
};
252253
Some((ip, sp, mem0, mem0_len, instance))
253254
}
255+
256+
pub fn replace_frame(
257+
&mut self,
258+
callee_ip: Ip,
259+
callee_params: BoundedSlotSpan,
260+
callee_size: usize,
261+
callee_instance: Option<NonNull<InstanceEntity>>,
262+
) -> Result<Sp, TrapCode> {
263+
let params_start = usize::from(u16::from(callee_params.span().head()));
264+
let params_len = callee_params.len();
265+
let start = self.frames.replace(callee_ip, callee_instance)?;
266+
let sp = self
267+
.values
268+
.replace(start, callee_size, params_start, params_len)?;
269+
Ok(sp)
270+
}
254271
}
255272

256273
#[derive(Debug)]
@@ -302,6 +319,36 @@ impl ValueStack {
302319
let sp = self.sp(start);
303320
Ok(sp)
304321
}
322+
323+
fn replace(
324+
&mut self,
325+
start: usize,
326+
len_slots: usize,
327+
params_start: usize,
328+
params_len: u16,
329+
) -> Result<Sp, TrapCode> {
330+
debug_assert!(params_start <= len_slots);
331+
debug_assert!(params_start + usize::from(params_len) <= len_slots);
332+
if len_slots == 0 {
333+
return Ok(Sp::null());
334+
}
335+
let Some(end) = start.checked_add(len_slots) else {
336+
return Err(TrapCode::StackOverflow);
337+
};
338+
if end > self.max_height {
339+
return Err(TrapCode::StackOverflow);
340+
}
341+
self.cells.resize_with(end, UntypedVal::default);
342+
let Some(cells) = self.cells.get_mut(start..end) else {
343+
unsafe { unreachable_unchecked!() }
344+
};
345+
let params_end = params_start.wrapping_add(usize::from(params_len));
346+
cells.copy_within(params_start..params_end, 0);
347+
let locals_start = start.wrapping_add(usize::from(params_len));
348+
cells[locals_start..].fill_with(UntypedVal::default);
349+
let sp = self.sp(start);
350+
Ok(sp)
351+
}
305352
}
306353

307354
#[derive(Debug)]
@@ -384,6 +431,27 @@ impl CallStack {
384431
}
385432
Some((ip, start, popped.instance))
386433
}
434+
435+
fn replace(
436+
&mut self,
437+
callee_ip: Ip,
438+
instance: Option<NonNull<InstanceEntity>>,
439+
) -> Result<usize, TrapCode> {
440+
let Some(caller_frame) = self.frames.last_mut() else {
441+
unsafe { unreachable_unchecked!("missing caller frame on the call stack") }
442+
};
443+
let prev_instance = match instance {
444+
Some(instance) => self.instance.replace(instance),
445+
None => self.instance,
446+
};
447+
let start = caller_frame.start;
448+
*caller_frame = Frame {
449+
start,
450+
ip: callee_ip,
451+
instance: prev_instance,
452+
};
453+
Ok(start)
454+
}
387455
}
388456

389457
#[derive(Debug)]

0 commit comments

Comments
 (0)