use crate::{
wasm::{HostFunc, ToLSBytes},
Error, Function, Result,
};
use anyhow::anyhow;
use opcodes::Cancun as OpCode;
impl Function {
pub fn _call_indirect(
&mut self,
_type_index: u32,
_table_index: u32,
_table_byte: u8,
) -> Result<()> {
todo!()
}
pub fn _call(&mut self, index: u32) -> Result<()> {
if self.env.is_external(index) {
panic!("External functions could not be called internally");
}
if self.env.imports.len() as u32 > index {
self.call_imported(index)
} else {
self.call_internal(index)
}
}
fn call_internal(&mut self, index: u32) -> Result<()> {
if self.env.index == Some(index) {
return Err(anyhow!(
"Recursion is no longer supported in this version. See https://github.com/zink-lang/zink/issues/248"
).into());
}
tracing::debug!("Calling internal function: index={index}");
let reserved = self.env.slots.get(&index).unwrap_or(&0);
let (params, results) = self.env.funcs.get(&index).unwrap_or(&(0, 0));
self.masm.increment_sp(1)?;
for i in (0..*params).rev() {
tracing::trace!("Storing local at {} for function {index}", i + reserved);
self.masm.push(&((i + reserved) * 0x20).to_ls_bytes())?;
self.masm._mstore()?;
}
let return_pc = self.masm.pc() + 2;
self.table.label(self.masm.pc(), return_pc);
self.masm._jumpdest()?;
self.table.call(self.masm.pc(), index); self.masm._jump()?;
self.masm._jumpdest()?;
self.masm.increment_sp(*results as u16)?;
Ok(())
}
fn call_imported(&mut self, index: u32) -> Result<()> {
let func = *self
.env
.imports
.get(&index)
.ok_or(Error::ImportedFuncNotFound(index))?;
tracing::trace!("Calling imported function, index={index}, func={func:?}");
match func {
HostFunc::Evm(OpCode::LOG0) => self.log(0),
HostFunc::Evm(OpCode::LOG1) => self.log(1),
HostFunc::Evm(OpCode::LOG2) => self.log(2),
HostFunc::Evm(OpCode::LOG3) => self.log(3),
HostFunc::Evm(OpCode::LOG4) => self.log(4),
HostFunc::Evm(op) => self.masm.emit_op(op),
HostFunc::U256MAX => self.masm.push(&[255; 32]),
HostFunc::Revert(count) => self.revert(count),
HostFunc::NoOp | HostFunc::Label(_) => Ok(()),
_ => {
tracing::error!("Unsupported host function {func:?}");
Err(Error::UnsupportedHostFunc(func))
}
}
}
}