the revive call function

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
This commit is contained in:
Cyrill Leutwiler
2025-07-04 12:31:25 +02:00
parent 3204b61ea0
commit 0685df37a1
4 changed files with 151 additions and 56 deletions
+1
View File
@@ -33,6 +33,7 @@ pub use self::polkavm::context::function::runtime::bitwise::Sar as PolkaVMSarFun
pub use self::polkavm::context::function::runtime::bitwise::Shl as PolkaVMShlFunction;
pub use self::polkavm::context::function::runtime::bitwise::Shr as PolkaVMShrFunction;
pub use self::polkavm::context::function::runtime::bitwise::Xor as PolkaVMXorFunction;
pub use self::polkavm::context::function::runtime::call::Call as PolkaVMCall;
pub use self::polkavm::context::function::runtime::call::CallReentrancyProtector as PolkaVMCallReentrancyProtector;
pub use self::polkavm::context::function::runtime::deploy_code::DeployCode as PolkaVMDeployCodeFunction;
pub use self::polkavm::context::function::runtime::entry::Entry as PolkaVMEntryFunction;
@@ -4,6 +4,7 @@ use inkwell::values::BasicValue;
use crate::polkavm::context::runtime::RuntimeFunction;
use crate::polkavm::context::Context;
use crate::polkavm::context::Pointer;
use crate::polkavm::Dependency;
use crate::polkavm::WriteLLVM;
@@ -125,3 +126,132 @@ where
<Self as RuntimeFunction<_>>::emit(&self, context)
}
}
/// Implements the CALL operator according to the EVM specification.
///
/// # Arguments:
/// - The address value.
/// - The value value.
/// - The input offset.
/// - The input length.
/// - The output offset.
/// - The output length.
/// - The deposit limit pointer.
/// - The call flags.
///
/// # Returns:
/// - The success value (as xlen)
pub struct Call;
impl<D> RuntimeFunction<D> for Call
where
D: Dependency + Clone,
{
const NAME: &'static str = "__revive_call";
fn r#type<'ctx>(context: &Context<'ctx, D>) -> inkwell::types::FunctionType<'ctx> {
context.register_type().fn_type(
&[
context.word_type().into(),
context.word_type().into(),
context.xlen_type().into(),
context.xlen_type().into(),
context.xlen_type().into(),
context.xlen_type().into(),
context.llvm().ptr_type(Default::default()).into(),
context.xlen_type().into(),
],
false,
)
}
fn emit_body<'ctx>(
&self,
context: &mut Context<'ctx, D>,
) -> anyhow::Result<Option<inkwell::values::BasicValueEnum<'ctx>>> {
let address = Self::paramater(context, 0).into_int_value();
let value = Self::paramater(context, 1).into_int_value();
let input_offset = Self::paramater(context, 2).into_int_value();
let input_length = Self::paramater(context, 3).into_int_value();
let output_offset = Self::paramater(context, 4).into_int_value();
let output_length = Self::paramater(context, 5).into_int_value();
let depsit_limit_pointer = Self::paramater(context, 6).into_pointer_value();
let flags = Self::paramater(context, 7).into_int_value();
let address_pointer = context.build_address_argument_store(address)?;
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
context.build_store(value_pointer, value)?;
let input_pointer = context.build_heap_gep(input_offset, input_length)?;
let output_pointer = context.build_heap_gep(output_offset, output_length)?;
let output_length_pointer =
context.build_alloca_at_entry(context.xlen_type(), "output_length");
context.build_store(output_length_pointer, output_length)?;
let flags_and_callee = revive_runtime_api::calling_convention::pack_hi_lo_reg(
context.builder(),
context.llvm(),
flags,
address_pointer.to_int(context),
"address_and_callee",
)?;
let deposit_limit_pointer = Pointer::new(
context.word_type(),
Default::default(),
depsit_limit_pointer,
);
let deposit_and_value = revive_runtime_api::calling_convention::pack_hi_lo_reg(
context.builder(),
context.llvm(),
deposit_limit_pointer.to_int(context),
value_pointer.to_int(context),
"deposit_and_value",
)?;
let input_data = revive_runtime_api::calling_convention::pack_hi_lo_reg(
context.builder(),
context.llvm(),
input_length,
input_pointer.to_int(context),
"input_data",
)?;
let output_data = revive_runtime_api::calling_convention::pack_hi_lo_reg(
context.builder(),
context.llvm(),
output_length_pointer.to_int(context),
output_pointer.to_int(context),
"output_data",
)?;
let name = revive_runtime_api::polkavm_imports::CALL;
let success = context
.build_runtime_call(
name,
&[
flags_and_callee.into(),
context.register_type().const_all_ones().into(),
context.register_type().const_all_ones().into(),
deposit_and_value.into(),
input_data.into(),
output_data.into(),
],
)
.unwrap_or_else(|| panic!("{name} should return a value"))
.into_int_value();
Ok(Some(success.into()))
}
}
impl<D> WriteLLVM<D> for Call
where
D: Dependency + Clone,
{
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::declare(self, context)
}
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
<Self as RuntimeFunction<_>>::emit(&self, context)
}
}
+18 -56
View File
@@ -6,7 +6,7 @@ use crate::polkavm::context::argument::Argument;
use crate::polkavm::context::runtime::RuntimeFunction;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::PolkaVMCallReentrancyProtector;
use crate::{PolkaVMCall, PolkaVMCallReentrancyProtector};
const STATIC_CALL_FLAG: u32 = 0b0001_0000;
const REENTRANT_CALL_FLAG: u32 = 0b0000_1000;
@@ -28,6 +28,9 @@ pub fn call<'ctx, D>(
where
D: Dependency + Clone,
{
let input_offset = context.safe_truncate_int_to_xlen(input_offset)?;
let output_offset = context.safe_truncate_int_to_xlen(output_offset)?;
let input_length = context.safe_truncate_int_to_xlen(input_length)?;
let output_length = context.safe_truncate_int_to_xlen(output_length)?;
@@ -47,64 +50,23 @@ where
)?
};
let address_pointer = context.build_address_argument_store(address)?;
let value = value.unwrap_or_else(|| context.word_const(0));
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
context.build_store(value_pointer, value)?;
let input_offset = context.safe_truncate_int_to_xlen(input_offset)?;
let output_offset = context.safe_truncate_int_to_xlen(output_offset)?;
let input_pointer = context.build_heap_gep(input_offset, input_length)?;
let output_pointer = context.build_heap_gep(output_offset, output_length)?;
let output_length_pointer = context.build_alloca_at_entry(context.xlen_type(), "output_length");
context.build_store(output_length_pointer, output_length)?;
let flags_and_callee = revive_runtime_api::calling_convention::pack_hi_lo_reg(
context.builder(),
context.llvm(),
flags,
address_pointer.to_int(context),
"address_and_callee",
)?;
let deposit_and_value = revive_runtime_api::calling_convention::pack_hi_lo_reg(
context.builder(),
context.llvm(),
deposit_limit_pointer.to_int(context),
value_pointer.to_int(context),
"deposit_and_value",
)?;
let input_data = revive_runtime_api::calling_convention::pack_hi_lo_reg(
context.builder(),
context.llvm(),
input_length,
input_pointer.to_int(context),
"input_data",
)?;
let output_data = revive_runtime_api::calling_convention::pack_hi_lo_reg(
context.builder(),
context.llvm(),
output_length_pointer.to_int(context),
output_pointer.to_int(context),
"output_data",
)?;
let name = revive_runtime_api::polkavm_imports::CALL;
let name = <PolkaVMCall as RuntimeFunction<D>>::NAME;
let declaration = <PolkaVMCall as RuntimeFunction<D>>::declaration(context);
let arguments = &[
address.into(),
value.into(),
input_offset.into(),
input_length.into(),
output_offset.into(),
output_length.into(),
deposit_limit_pointer.value.into(),
flags.into(),
];
let success = context
.build_runtime_call(
name,
&[
flags_and_callee.into(),
context.register_type().const_all_ones().into(),
context.register_type().const_all_ones().into(),
deposit_and_value.into(),
input_data.into(),
output_data.into(),
],
)
.unwrap_or_else(|| panic!("{name} should return a value"))
.build_call(declaration, arguments, "call")
.unwrap_or_else(|| panic!("revive runtime function {name} should return a value"))
.into_int_value();
let is_success = context.builder().build_int_compare(
@@ -220,6 +220,7 @@ where
revive_llvm_context::PolkaVMSarFunction.declare(context)?;
revive_llvm_context::PolkaVMByteFunction.declare(context)?;
revive_llvm_context::PolkaVMCall.declare(context)?;
revive_llvm_context::PolkaVMCallReentrancyProtector.declare(context)?;
revive_llvm_context::PolkaVMSbrkFunction.declare(context)?;
@@ -287,6 +288,7 @@ where
revive_llvm_context::PolkaVMSarFunction.into_llvm(context)?;
revive_llvm_context::PolkaVMByteFunction.into_llvm(context)?;
revive_llvm_context::PolkaVMCall.into_llvm(context)?;
revive_llvm_context::PolkaVMCallReentrancyProtector.into_llvm(context)?;
revive_llvm_context::PolkaVMSbrkFunction.into_llvm(context)?;