mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-22 02:07:55 +00:00
the revive call function
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
Reference in New Issue
Block a user