Skip to content

Commit

Permalink
add ReturnCallInternal instruction
Browse files Browse the repository at this point in the history
  • Loading branch information
Robbepop committed May 28, 2023
1 parent 98d3e4c commit ef6b5e6
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 14 deletions.
21 changes: 21 additions & 0 deletions crates/wasmi/src/engine/bytecode/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,29 @@ pub enum Instruction {
ConsumeFuel(BlockFuel),
Return(DropKeep),
ReturnIfNez(DropKeep),
/// Tail calls an internal (compiled) function.
///
/// # Note
///
/// This instruction can be used for calls to functions that are engine internal
/// (or compiled) and acts as an optimization for those common cases.
///
/// # Encoding
///
/// This [`Instruction`] must be followed by an [`Instruction::Return`] that
/// encodes the [`DropKeep`] parameter. Note that the [`Instruction::Return`]
/// only acts as a storage for the parameter of the [`Instruction::ReturnCall`]
/// and will never be executed by itself.
ReturnCallInternal(CompiledFunc),
/// Tail calling `func`.
///
/// # Note
///
/// Since [`Instruction::ReturnCallInternal`] should be used for all functions internal
/// (or compiled) to the engine this instruction should mainly be used for tail calling
/// imported functions. However, it is a general form that can technically be used
/// for both.
///
/// # Encoding
///
/// This [`Instruction`] must be followed by an [`Instruction::Return`] that
Expand Down
43 changes: 34 additions & 9 deletions crates/wasmi/src/engine/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
return Ok(WasmOutcome::Return);
}
}
Instr::ReturnCallInternal(compiled_func) => {
self.visit_return_call_internal(compiled_func)?
}
Instr::ReturnCall(func) => {
forward_call!(self.visit_return_call(func))
}
Expand Down Expand Up @@ -630,6 +633,29 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
}
}

/// Calls the given internal [`CompiledFunc`].
///
/// This also prepares the instruction pointer and stack pointer for
/// the function call so that the stack and execution state is synchronized
/// with the outer structures.
#[inline(always)]
fn call_func_internal(&mut self, func: CompiledFunc, kind: CallKind) -> Result<(), TrapCode> {
self.next_instr_at(match kind {
CallKind::Nested => 1,
CallKind::Tail => 2,
});
self.sync_stack_ptr();
if matches!(kind, CallKind::Nested) {
self.call_stack
.push(FuncFrame::new(self.ip, self.cache.instance()))?;
}
let header = self.code_map.header(func);
self.value_stack.prepare_wasm_call(header)?;
self.sp = self.value_stack.stack_ptr();
self.ip = self.code_map.instr_ptr(header.iref());
Ok(())
}

/// Returns to the caller.
///
/// This also modifies the stack as the caller would expect it
Expand Down Expand Up @@ -966,6 +992,13 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
self.next_instr()
}

#[inline(always)]
fn visit_return_call_internal(&mut self, compiled_func: CompiledFunc) -> Result<(), TrapCode> {
let drop_keep = self.fetch_drop_keep(1);
self.sp.drop_keep(drop_keep);
self.call_func_internal(compiled_func, CallKind::Tail)
}

#[inline(always)]
fn visit_return_call(&mut self, func_index: FuncIdx) -> Result<CallOutcome, TrapCode> {
let drop_keep = self.fetch_drop_keep(1);
Expand All @@ -987,15 +1020,7 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {

#[inline(always)]
fn visit_call_internal(&mut self, compiled_func: CompiledFunc) -> Result<(), TrapCode> {
self.next_instr();
self.sync_stack_ptr();
self.call_stack
.push(FuncFrame::new(self.ip, self.cache.instance()))?;
let header = self.code_map.header(compiled_func);
self.value_stack.prepare_wasm_call(header)?;
self.sp = self.value_stack.stack_ptr();
self.ip = self.code_map.instr_ptr(header.iref());
Ok(())
self.call_func_internal(compiled_func, CallKind::Nested)
}

#[inline(always)]
Expand Down
24 changes: 19 additions & 5 deletions crates/wasmi/src/engine/func_builder/translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1210,15 +1210,29 @@ impl<'a> VisitOperator<'a> for FuncTranslator<'a> {

fn visit_return_call(&mut self, func_idx: u32) -> Result<(), TranslationError> {
self.translate_if_reachable(|builder| {
let func = bytecode::FuncIdx::from(func_idx);
let func_type = builder.func_type_of(func_idx.into());
let drop_keep = builder.drop_keep_return_call(&func_type)?;
builder.bump_fuel_consumption(builder.fuel_costs().call)?;
builder.bump_fuel_consumption(builder.fuel_costs().fuel_for_drop_keep(drop_keep))?;
builder
.alloc
.inst_builder
.push_inst(Instruction::ReturnCall(func));
match builder.res.get_compiled_func(func_idx.into()) {
Some(compiled_func) => {
// Case: We are calling an internal function and can optimize
// this case by using the special instruction for it.
builder
.alloc
.inst_builder
.push_inst(Instruction::ReturnCallInternal(compiled_func));
}
None => {
// Case: We are calling an imported function and must use the
// general calling operator for it.
let func = bytecode::FuncIdx::from(func_idx);
builder
.alloc
.inst_builder
.push_inst(Instruction::ReturnCall(func));
}
}
builder
.alloc
.inst_builder
Expand Down

0 comments on commit ef6b5e6

Please sign in to comment.