mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-30 15:17:58 +00:00
Contract calls (#19)
This commit is contained in:
@@ -1,57 +1,68 @@
|
||||
//! Runtime API import and export symbols.
|
||||
|
||||
/// The contract deploy export.
|
||||
pub static CALL: &str = "call";
|
||||
pub mod exports {
|
||||
/// The contract deploy export.
|
||||
pub static CALL: &str = "call";
|
||||
|
||||
/// The contract call export.
|
||||
pub static DEPLOY: &str = "deploy";
|
||||
/// The contract call export.
|
||||
pub static DEPLOY: &str = "deploy";
|
||||
|
||||
/// All exported symbols.
|
||||
/// Useful for configuring common attributes and linkage.
|
||||
pub static EXPORTS: [&str; 2] = [CALL, DEPLOY];
|
||||
/// All exported symbols.
|
||||
/// Useful for configuring common attributes and linkage.
|
||||
pub static EXPORTS: [&str; 2] = [CALL, DEPLOY];
|
||||
}
|
||||
|
||||
pub static ADDRESS: &str = "address";
|
||||
pub mod imports {
|
||||
pub static ADDRESS: &str = "address";
|
||||
|
||||
pub static BLOCK_NUMBER: &str = "block_number";
|
||||
pub static BLOCK_NUMBER: &str = "block_number";
|
||||
|
||||
pub static CALLER: &str = "caller";
|
||||
pub static CALL: &str = "seal_call";
|
||||
|
||||
pub static CODE_SIZE: &str = "code_size";
|
||||
pub static CALLER: &str = "caller";
|
||||
|
||||
pub static DEPOSIT_EVENT: &str = "deposit_event";
|
||||
pub static CODE_SIZE: &str = "code_size";
|
||||
|
||||
pub static GET_STORAGE: &str = "get_storage";
|
||||
pub static DEPOSIT_EVENT: &str = "deposit_event";
|
||||
|
||||
pub static HASH_KECCAK_256: &str = "hash_keccak_256";
|
||||
pub static GET_STORAGE: &str = "get_storage";
|
||||
|
||||
pub static INPUT: &str = "input";
|
||||
pub static HASH_KECCAK_256: &str = "hash_keccak_256";
|
||||
|
||||
pub static INSTANTIATE: &str = "instantiate";
|
||||
pub static INPUT: &str = "input";
|
||||
|
||||
pub static NOW: &str = "now";
|
||||
pub static INSTANTIATE: &str = "instantiate";
|
||||
|
||||
pub static RETURN: &str = "seal_return";
|
||||
pub static NOW: &str = "now";
|
||||
|
||||
pub static SET_STORAGE: &str = "set_storage";
|
||||
pub static RETURN: &str = "seal_return";
|
||||
|
||||
pub static VALUE_TRANSFERRED: &str = "value_transferred";
|
||||
pub static RETURNDATACOPY: &str = "returndatacopy";
|
||||
|
||||
/// All imported runtime API symbols..
|
||||
/// Useful for configuring common attributes and linkage.
|
||||
pub static IMPORTS: [&str; 12] = [
|
||||
ADDRESS,
|
||||
BLOCK_NUMBER,
|
||||
CALLER,
|
||||
DEPOSIT_EVENT,
|
||||
GET_STORAGE,
|
||||
HASH_KECCAK_256,
|
||||
INPUT,
|
||||
INSTANTIATE,
|
||||
NOW,
|
||||
RETURN,
|
||||
SET_STORAGE,
|
||||
VALUE_TRANSFERRED,
|
||||
];
|
||||
pub static SET_STORAGE: &str = "set_storage";
|
||||
|
||||
pub static VALUE_TRANSFERRED: &str = "value_transferred";
|
||||
|
||||
/// All imported runtime API symbols.
|
||||
/// Useful for configuring common attributes and linkage.
|
||||
pub static IMPORTS: [&str; 15] = [
|
||||
ADDRESS,
|
||||
BLOCK_NUMBER,
|
||||
CALL,
|
||||
CALLER,
|
||||
CODE_SIZE,
|
||||
DEPOSIT_EVENT,
|
||||
GET_STORAGE,
|
||||
HASH_KECCAK_256,
|
||||
INPUT,
|
||||
INSTANTIATE,
|
||||
NOW,
|
||||
RETURN,
|
||||
RETURNDATACOPY,
|
||||
SET_STORAGE,
|
||||
VALUE_TRANSFERRED,
|
||||
];
|
||||
}
|
||||
|
||||
/// PolkaVM __sbrk API symbol to extend the heap memory.
|
||||
pub static SBRK: &str = "__sbrk";
|
||||
|
||||
@@ -11,11 +11,6 @@ use crate::polkavm::context::function::Function;
|
||||
/// The functions are automatically linked to the LLVM implementations if the signatures match.
|
||||
#[derive(Debug)]
|
||||
pub struct LLVMRuntime<'ctx> {
|
||||
/// The LLVM personality function, used for exception handling.
|
||||
pub personality: FunctionDeclaration<'ctx>,
|
||||
/// The LLVM exception throwing function.
|
||||
pub cxa_throw: FunctionDeclaration<'ctx>,
|
||||
|
||||
/// The corresponding LLVM runtime function.
|
||||
pub shl: FunctionDeclaration<'ctx>,
|
||||
/// The corresponding LLVM runtime function.
|
||||
@@ -37,29 +32,6 @@ pub struct LLVMRuntime<'ctx> {
|
||||
/// The corresponding LLVM runtime function.
|
||||
pub sha3: FunctionDeclaration<'ctx>,
|
||||
|
||||
/// The corresponding LLVM runtime function.
|
||||
pub system_request: FunctionDeclaration<'ctx>,
|
||||
|
||||
/// The corresponding LLVM runtime function.
|
||||
//pub far_call: FunctionDeclaration<'ctx>,
|
||||
/// The corresponding LLVM runtime function.
|
||||
pub far_call_byref: FunctionDeclaration<'ctx>,
|
||||
|
||||
/// The corresponding LLVM runtime function.
|
||||
pub static_call: FunctionDeclaration<'ctx>,
|
||||
/// The corresponding LLVM runtime function.
|
||||
pub static_call_byref: FunctionDeclaration<'ctx>,
|
||||
|
||||
/// The corresponding LLVM runtime function.
|
||||
pub delegate_call: FunctionDeclaration<'ctx>,
|
||||
/// The corresponding LLVM runtime function.
|
||||
pub delegate_call_byref: FunctionDeclaration<'ctx>,
|
||||
|
||||
/// The corresponding LLVM runtime function.
|
||||
pub mimic_call: FunctionDeclaration<'ctx>,
|
||||
/// The corresponding LLVM runtime function.
|
||||
pub mimic_call_byref: FunctionDeclaration<'ctx>,
|
||||
|
||||
/// The corresponding LLVM runtime function.
|
||||
pub r#return: FunctionDeclaration<'ctx>,
|
||||
/// The corresponding LLVM runtime function.
|
||||
@@ -139,30 +111,6 @@ impl<'ctx> LLVMRuntime<'ctx> {
|
||||
module: &inkwell::module::Module<'ctx>,
|
||||
optimizer: &Optimizer,
|
||||
) -> Self {
|
||||
let personality = Self::declare(
|
||||
module,
|
||||
Self::FUNCTION_PERSONALITY,
|
||||
llvm.i32_type().fn_type(&[], false),
|
||||
None,
|
||||
);
|
||||
|
||||
let cxa_throw = Self::declare(
|
||||
module,
|
||||
Self::FUNCTION_CXA_THROW,
|
||||
llvm.void_type().fn_type(
|
||||
vec![
|
||||
llvm.ptr_type(AddressSpace::Stack.into())
|
||||
.as_basic_type_enum()
|
||||
.into();
|
||||
3
|
||||
]
|
||||
.as_slice(),
|
||||
false,
|
||||
),
|
||||
Some(inkwell::module::Linkage::External),
|
||||
);
|
||||
Function::set_cxa_throw_attributes(llvm, cxa_throw);
|
||||
|
||||
let shl = Self::declare(
|
||||
module,
|
||||
Self::FUNCTION_SHL,
|
||||
@@ -288,138 +236,6 @@ impl<'ctx> LLVMRuntime<'ctx> {
|
||||
false,
|
||||
);
|
||||
|
||||
let system_request = Self::declare(
|
||||
module,
|
||||
Self::FUNCTION_SYSTEM_REQUEST,
|
||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
||||
.fn_type(
|
||||
vec![
|
||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
||||
.as_basic_type_enum()
|
||||
.into(),
|
||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
||||
.as_basic_type_enum()
|
||||
.into(),
|
||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
||||
.as_basic_type_enum()
|
||||
.into(),
|
||||
llvm.ptr_type(AddressSpace::Stack.into())
|
||||
.as_basic_type_enum()
|
||||
.into(),
|
||||
]
|
||||
.as_slice(),
|
||||
false,
|
||||
),
|
||||
Some(inkwell::module::Linkage::External),
|
||||
);
|
||||
Function::set_default_attributes(llvm, system_request, optimizer);
|
||||
|
||||
let external_call_arguments: Vec<inkwell::types::BasicMetadataTypeEnum> = vec![
|
||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
||||
.as_basic_type_enum()
|
||||
.into();
|
||||
crate::polkavm::context::function::runtime::entry::Entry::MANDATORY_ARGUMENTS_COUNT
|
||||
+ crate::polkavm::EXTRA_ABI_DATA_SIZE
|
||||
];
|
||||
let mut mimic_call_arguments = external_call_arguments.clone();
|
||||
mimic_call_arguments.push(
|
||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
||||
.as_basic_type_enum()
|
||||
.into(),
|
||||
);
|
||||
|
||||
let mut external_call_arguments_by_ref: Vec<inkwell::types::BasicMetadataTypeEnum> = vec![
|
||||
llvm.ptr_type(AddressSpace::Generic.into())
|
||||
.as_basic_type_enum()
|
||||
.into(),
|
||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
||||
.as_basic_type_enum()
|
||||
.into(),
|
||||
];
|
||||
external_call_arguments_by_ref.extend::<Vec<inkwell::types::BasicMetadataTypeEnum>>(vec![
|
||||
llvm.custom_width_int_type(
|
||||
revive_common::BIT_LENGTH_WORD as u32
|
||||
)
|
||||
.as_basic_type_enum()
|
||||
.into();
|
||||
crate::polkavm::EXTRA_ABI_DATA_SIZE
|
||||
]);
|
||||
let mut mimic_call_arguments_by_ref = external_call_arguments_by_ref.clone();
|
||||
mimic_call_arguments_by_ref.push(
|
||||
llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
|
||||
.as_basic_type_enum()
|
||||
.into(),
|
||||
);
|
||||
|
||||
let external_call_result_type = llvm
|
||||
.struct_type(
|
||||
&[
|
||||
llvm.ptr_type(AddressSpace::Generic.into())
|
||||
.as_basic_type_enum(),
|
||||
llvm.bool_type().as_basic_type_enum(),
|
||||
],
|
||||
false,
|
||||
)
|
||||
.as_basic_type_enum();
|
||||
|
||||
//let far_call = Self::declare(
|
||||
// module,
|
||||
// Self::FUNCTION_FARCALL,
|
||||
// external_call_result_type.fn_type(external_call_arguments.as_slice(), false),
|
||||
// Some(inkwell::module::Linkage::External),
|
||||
//);
|
||||
//Function::set_default_attributes(llvm, far_call, optimizer);
|
||||
let static_call = Self::declare(
|
||||
module,
|
||||
Self::FUNCTION_STATICCALL,
|
||||
external_call_result_type.fn_type(external_call_arguments.as_slice(), false),
|
||||
Some(inkwell::module::Linkage::External),
|
||||
);
|
||||
Function::set_default_attributes(llvm, static_call, optimizer);
|
||||
let delegate_call = Self::declare(
|
||||
module,
|
||||
Self::FUNCTION_DELEGATECALL,
|
||||
external_call_result_type.fn_type(external_call_arguments.as_slice(), false),
|
||||
Some(inkwell::module::Linkage::External),
|
||||
);
|
||||
Function::set_default_attributes(llvm, delegate_call, optimizer);
|
||||
let mimic_call = Self::declare(
|
||||
module,
|
||||
Self::FUNCTION_MIMICCALL,
|
||||
external_call_result_type.fn_type(mimic_call_arguments.as_slice(), false),
|
||||
Some(inkwell::module::Linkage::External),
|
||||
);
|
||||
Function::set_default_attributes(llvm, mimic_call, optimizer);
|
||||
|
||||
let far_call_byref = Self::declare(
|
||||
module,
|
||||
Self::FUNCTION_FARCALL_BYREF,
|
||||
external_call_result_type.fn_type(external_call_arguments_by_ref.as_slice(), false),
|
||||
Some(inkwell::module::Linkage::External),
|
||||
);
|
||||
Function::set_default_attributes(llvm, far_call_byref, optimizer);
|
||||
let static_call_byref = Self::declare(
|
||||
module,
|
||||
Self::FUNCTION_STATICCALL_BYREF,
|
||||
external_call_result_type.fn_type(external_call_arguments_by_ref.as_slice(), false),
|
||||
Some(inkwell::module::Linkage::External),
|
||||
);
|
||||
Function::set_default_attributes(llvm, static_call_byref, optimizer);
|
||||
let delegate_call_byref = Self::declare(
|
||||
module,
|
||||
Self::FUNCTION_DELEGATECALL_BYREF,
|
||||
external_call_result_type.fn_type(external_call_arguments_by_ref.as_slice(), false),
|
||||
Some(inkwell::module::Linkage::External),
|
||||
);
|
||||
Function::set_default_attributes(llvm, delegate_call_byref, optimizer);
|
||||
let mimic_call_byref = Self::declare(
|
||||
module,
|
||||
Self::FUNCTION_MIMICCALL_BYREF,
|
||||
external_call_result_type.fn_type(mimic_call_arguments_by_ref.as_slice(), false),
|
||||
Some(inkwell::module::Linkage::External),
|
||||
);
|
||||
Function::set_default_attributes(llvm, mimic_call_byref, optimizer);
|
||||
|
||||
let r#return = Self::declare(
|
||||
module,
|
||||
Self::FUNCTION_RETURN,
|
||||
@@ -454,9 +270,6 @@ impl<'ctx> LLVMRuntime<'ctx> {
|
||||
Function::set_default_attributes(llvm, revert, optimizer);
|
||||
|
||||
Self {
|
||||
personality,
|
||||
cxa_throw,
|
||||
|
||||
shl,
|
||||
shr,
|
||||
sar,
|
||||
@@ -469,18 +282,6 @@ impl<'ctx> LLVMRuntime<'ctx> {
|
||||
|
||||
sha3,
|
||||
|
||||
system_request,
|
||||
|
||||
//far_call,
|
||||
static_call,
|
||||
delegate_call,
|
||||
mimic_call,
|
||||
|
||||
far_call_byref,
|
||||
static_call_byref,
|
||||
delegate_call_byref,
|
||||
mimic_call_byref,
|
||||
|
||||
r#return,
|
||||
revert,
|
||||
}
|
||||
@@ -506,42 +307,4 @@ impl<'ctx> LLVMRuntime<'ctx> {
|
||||
value.set_linkage(inkwell::module::Linkage::External);
|
||||
FunctionDeclaration::new(value.get_type(), value).into()
|
||||
}
|
||||
|
||||
/// Modifies the external call function with `is_byref` and `is_system` modifiers.
|
||||
pub fn modify(
|
||||
&self,
|
||||
function: FunctionDeclaration<'ctx>,
|
||||
is_byref: bool,
|
||||
) -> anyhow::Result<FunctionDeclaration<'ctx>> {
|
||||
let modified = if
|
||||
/*function == self.far_call {
|
||||
match is_byref {
|
||||
false => self.far_call,
|
||||
true => self.far_call_byref,
|
||||
}
|
||||
} else if */
|
||||
function == self.static_call {
|
||||
match is_byref {
|
||||
false => self.static_call,
|
||||
true => self.static_call_byref,
|
||||
}
|
||||
} else if function == self.delegate_call {
|
||||
match is_byref {
|
||||
false => self.delegate_call,
|
||||
true => self.delegate_call_byref,
|
||||
}
|
||||
} else if function == self.mimic_call {
|
||||
match is_byref {
|
||||
false => self.mimic_call,
|
||||
true => self.mimic_call_byref,
|
||||
}
|
||||
} else {
|
||||
anyhow::bail!(
|
||||
"Cannot modify an external call function `{}`",
|
||||
function.value.get_name().to_string_lossy()
|
||||
);
|
||||
};
|
||||
|
||||
Ok(modified)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
//! The `default_call` function.
|
||||
|
||||
use inkwell::types::BasicType;
|
||||
|
||||
use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
|
||||
use crate::polkavm::context::function::llvm_runtime::LLVMRuntime;
|
||||
use crate::polkavm::context::function::Function;
|
||||
use crate::polkavm::context::Context;
|
||||
use crate::polkavm::Dependency;
|
||||
use crate::polkavm::WriteLLVM;
|
||||
|
||||
/// The `default_call` function.
|
||||
/// Generates a default contract call, if the `msg.value` is zero.
|
||||
#[derive(Debug)]
|
||||
pub struct DefaultCall {
|
||||
/// The name of the inner function used for the low-level call.
|
||||
inner_name: String,
|
||||
/// The function name with the low-level function name as an element.
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
impl DefaultCall {
|
||||
/// The gas argument index.
|
||||
pub const ARGUMENT_INDEX_GAS: usize = 0;
|
||||
|
||||
/// The address argument index.
|
||||
pub const ARGUMENT_INDEX_ADDRESS: usize = 1;
|
||||
|
||||
/// The input offset argument index.
|
||||
pub const ARGUMENT_INDEX_INPUT_OFFSET: usize = 2;
|
||||
|
||||
/// The input length argument index.
|
||||
pub const ARGUMENT_INDEX_INPUT_LENGTH: usize = 3;
|
||||
|
||||
/// The output offset argument index.
|
||||
pub const ARGUMENT_INDEX_OUTPUT_OFFSET: usize = 4;
|
||||
|
||||
/// The output length argument index.
|
||||
pub const ARGUMENT_INDEX_OUTPUT_LENGTH: usize = 5;
|
||||
|
||||
/// A shortcut constructor.
|
||||
pub fn new(call_function: FunctionDeclaration) -> Self {
|
||||
let inner_name = call_function.value.get_name().to_string_lossy().to_string();
|
||||
let name = Self::name(call_function);
|
||||
|
||||
Self { inner_name, name }
|
||||
}
|
||||
|
||||
/// Returns the function name.
|
||||
pub fn name(call_function: FunctionDeclaration) -> String {
|
||||
let suffix = match call_function.value.get_name().to_string_lossy() {
|
||||
name if name == LLVMRuntime::FUNCTION_FARCALL => "far",
|
||||
name if name == LLVMRuntime::FUNCTION_STATICCALL => "static",
|
||||
name if name == LLVMRuntime::FUNCTION_DELEGATECALL => "delegate",
|
||||
name => panic!("Invalid low-level call inner function `{name}`"),
|
||||
};
|
||||
format!("__default_{suffix}_call")
|
||||
}
|
||||
|
||||
/// Returns the low-level call function.
|
||||
fn inner_function<'ctx, D>(&self, context: &Context<'ctx, D>) -> FunctionDeclaration<'ctx>
|
||||
where
|
||||
D: Dependency + Clone,
|
||||
{
|
||||
match self.inner_name.as_str() {
|
||||
//name if name == LLVMRuntime::FUNCTION_FARCALL => context.llvm_runtime().far_call,
|
||||
name if name == LLVMRuntime::FUNCTION_STATICCALL => context.llvm_runtime().static_call,
|
||||
name if name == LLVMRuntime::FUNCTION_DELEGATECALL => {
|
||||
context.llvm_runtime().delegate_call
|
||||
}
|
||||
name => panic!("Invalid low-level call inner function `{name}`"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> WriteLLVM<D> for DefaultCall
|
||||
where
|
||||
D: Dependency + Clone,
|
||||
{
|
||||
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
|
||||
let function_type = context.function_type(
|
||||
vec![
|
||||
context.word_type().as_basic_type_enum(),
|
||||
context.word_type().as_basic_type_enum(),
|
||||
context.word_type().as_basic_type_enum(),
|
||||
context.word_type().as_basic_type_enum(),
|
||||
context.word_type().as_basic_type_enum(),
|
||||
context.word_type().as_basic_type_enum(),
|
||||
],
|
||||
1,
|
||||
false,
|
||||
);
|
||||
let function = context.add_function(
|
||||
self.name.as_str(),
|
||||
function_type,
|
||||
1,
|
||||
Some(inkwell::module::Linkage::Private),
|
||||
)?;
|
||||
Function::set_frontend_runtime_attributes(
|
||||
context.llvm,
|
||||
function.borrow().declaration(),
|
||||
&context.optimizer,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
|
||||
context.set_current_function(self.name.as_str())?;
|
||||
|
||||
/*
|
||||
let gas = context
|
||||
.current_function()
|
||||
.borrow()
|
||||
.get_nth_param(Self::ARGUMENT_INDEX_GAS)
|
||||
.into_int_value();
|
||||
let address = context
|
||||
.current_function()
|
||||
.borrow()
|
||||
.get_nth_param(Self::ARGUMENT_INDEX_ADDRESS)
|
||||
.into_int_value();
|
||||
let input_offset = context
|
||||
.current_function()
|
||||
.borrow()
|
||||
.get_nth_param(Self::ARGUMENT_INDEX_INPUT_OFFSET)
|
||||
.into_int_value();
|
||||
let input_length = context
|
||||
.current_function()
|
||||
.borrow()
|
||||
.get_nth_param(Self::ARGUMENT_INDEX_INPUT_LENGTH)
|
||||
.into_int_value();
|
||||
let output_offset = context
|
||||
.current_function()
|
||||
.borrow()
|
||||
.get_nth_param(Self::ARGUMENT_INDEX_OUTPUT_OFFSET)
|
||||
.into_int_value();
|
||||
let output_length = context
|
||||
.current_function()
|
||||
.borrow()
|
||||
.get_nth_param(Self::ARGUMENT_INDEX_OUTPUT_LENGTH)
|
||||
.into_int_value();
|
||||
*/
|
||||
context.set_basic_block(context.current_function().borrow().entry_block());
|
||||
|
||||
let status_code_result_pointer = context.build_alloca(
|
||||
context.word_type(),
|
||||
"contract_call_result_status_code_pointer",
|
||||
);
|
||||
/*
|
||||
context.build_store(status_code_result_pointer, context.field_const(0));
|
||||
|
||||
let abi_data = crate::polkavm::utils::abi_data(
|
||||
context,
|
||||
input_offset,
|
||||
input_length,
|
||||
Some(gas),
|
||||
AddressSpace::Heap,
|
||||
false,
|
||||
)?
|
||||
.into_int_value();
|
||||
|
||||
let result = context
|
||||
.build_call(
|
||||
self.inner_function(context),
|
||||
crate::polkavm::utils::external_call_arguments(
|
||||
context,
|
||||
abi_data.as_basic_value_enum(),
|
||||
address,
|
||||
vec![],
|
||||
None,
|
||||
)
|
||||
.as_slice(),
|
||||
"contract_call_external",
|
||||
)
|
||||
.expect("IntrinsicFunction always returns a flag");
|
||||
|
||||
let result_abi_data = context
|
||||
.builder()
|
||||
.build_extract_value(
|
||||
result.into_struct_value(),
|
||||
0,
|
||||
"contract_call_external_result_abi_data",
|
||||
)
|
||||
.expect("Always exists");
|
||||
let result_abi_data_pointer = Pointer::new(
|
||||
context.byte_type(),
|
||||
AddressSpace::Generic,
|
||||
result_abi_data.into_pointer_value(),
|
||||
);
|
||||
let result_abi_data_casted = result_abi_data_pointer.cast(context.field_type());
|
||||
|
||||
let result_status_code_boolean = context
|
||||
.builder()
|
||||
.build_extract_value(
|
||||
result.into_struct_value(),
|
||||
1,
|
||||
"contract_call_external_result_status_code_boolean",
|
||||
)
|
||||
.expect("Always exists");
|
||||
let result_status_code = context.builder().build_int_z_extend_or_bit_cast(
|
||||
result_status_code_boolean.into_int_value(),
|
||||
context.field_type(),
|
||||
"contract_call_external_result_status_code",
|
||||
)?;
|
||||
context.build_store(status_code_result_pointer, result_status_code);
|
||||
|
||||
let source = result_abi_data_casted;
|
||||
|
||||
let destination = Pointer::new_with_offset(
|
||||
context,
|
||||
AddressSpace::Heap,
|
||||
context.byte_type(),
|
||||
output_offset,
|
||||
"contract_call_destination",
|
||||
);
|
||||
|
||||
context.build_memcpy_return_data(
|
||||
context.intrinsics().memory_copy_from_generic,
|
||||
destination,
|
||||
source,
|
||||
output_length,
|
||||
"contract_call_memcpy_from_child",
|
||||
);
|
||||
|
||||
context.write_abi_pointer(
|
||||
result_abi_data_pointer,
|
||||
crate::polkavm::GLOBAL_RETURN_DATA_POINTER,
|
||||
);
|
||||
context.write_abi_data_size(
|
||||
result_abi_data_pointer,
|
||||
crate::polkavm::GLOBAL_RETURN_DATA_SIZE,
|
||||
);
|
||||
*/
|
||||
context.build_unconditional_branch(context.current_function().borrow().return_block());
|
||||
|
||||
context.set_basic_block(context.current_function().borrow().return_block());
|
||||
let status_code_result =
|
||||
context.build_load(status_code_result_pointer, "contract_call_status_code")?;
|
||||
context.build_return(Some(&status_code_result));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -153,7 +153,7 @@ impl Entry {
|
||||
context.integer_const(crate::polkavm::XLEN, Self::MAX_CALLDATA_SIZE as u64),
|
||||
)?;
|
||||
context.build_runtime_call(
|
||||
runtime_api::INPUT,
|
||||
runtime_api::imports::INPUT,
|
||||
&[input_pointer_casted.into(), length_pointer_casted.into()],
|
||||
);
|
||||
|
||||
@@ -215,11 +215,11 @@ impl Entry {
|
||||
.ok_or_else(|| anyhow::anyhow!("Contract runtime code not found"))?;
|
||||
|
||||
context.set_basic_block(deploy_code_call_block);
|
||||
context.build_invoke(deploy_code.borrow().declaration, &[], "deploy_code_call");
|
||||
context.build_call(deploy_code.borrow().declaration, &[], "deploy_code_call");
|
||||
context.build_unconditional_branch(context.current_function().borrow().return_block());
|
||||
|
||||
context.set_basic_block(runtime_code_call_block);
|
||||
context.build_invoke(runtime_code.borrow().declaration, &[], "runtime_code_call");
|
||||
context.build_call(runtime_code.borrow().declaration, &[], "runtime_code_call");
|
||||
context.build_unconditional_branch(context.current_function().borrow().return_block());
|
||||
|
||||
Ok(())
|
||||
@@ -235,7 +235,7 @@ where
|
||||
let entry_function_type = context.function_type(entry_arguments, 0, false);
|
||||
context.add_function(Runtime::FUNCTION_ENTRY, entry_function_type, 0, None)?;
|
||||
|
||||
for symbol in runtime_api::EXPORTS {
|
||||
for symbol in runtime_api::exports::EXPORTS {
|
||||
context.declare_extern_function(symbol)?;
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ where
|
||||
true,
|
||||
);
|
||||
|
||||
context.set_current_function(runtime_api::DEPLOY)?;
|
||||
context.set_current_function(runtime_api::exports::DEPLOY)?;
|
||||
context.set_basic_block(context.current_function().borrow().entry_block());
|
||||
|
||||
assert!(context
|
||||
@@ -268,7 +268,7 @@ where
|
||||
context.set_basic_block(context.current_function().borrow().return_block);
|
||||
context.build_unreachable();
|
||||
|
||||
context.set_current_function(runtime_api::CALL)?;
|
||||
context.set_current_function(runtime_api::exports::CALL)?;
|
||||
context.set_basic_block(context.current_function().borrow().entry_block());
|
||||
|
||||
assert!(context
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
//! The front-end runtime functions.
|
||||
|
||||
pub mod default_call;
|
||||
pub mod deploy_code;
|
||||
pub mod entry;
|
||||
pub mod runtime_code;
|
||||
|
||||
use crate::polkavm::context::address_space::AddressSpace;
|
||||
use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
|
||||
use crate::polkavm::context::Context;
|
||||
use crate::polkavm::Dependency;
|
||||
use crate::polkavm::WriteLLVM;
|
||||
|
||||
use self::default_call::DefaultCall;
|
||||
|
||||
/// The front-end runtime functions.
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -35,40 +28,4 @@ impl Runtime {
|
||||
pub fn new(_address_space: AddressSpace) -> Self {
|
||||
Self { _address_space }
|
||||
}
|
||||
|
||||
/// Returns the corresponding runtime function.
|
||||
pub fn default_call<'ctx, D>(
|
||||
context: &Context<'ctx, D>,
|
||||
call_function: FunctionDeclaration<'ctx>,
|
||||
) -> FunctionDeclaration<'ctx>
|
||||
where
|
||||
D: Dependency + Clone,
|
||||
{
|
||||
context
|
||||
.get_function(DefaultCall::name(call_function).as_str())
|
||||
.expect("Always exists")
|
||||
.borrow()
|
||||
.declaration()
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> WriteLLVM<D> for Runtime
|
||||
where
|
||||
D: Dependency + Clone,
|
||||
{
|
||||
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
|
||||
//DefaultCall::new(context.llvm_runtime().far_call).declare(context)?;
|
||||
DefaultCall::new(context.llvm_runtime().static_call).declare(context)?;
|
||||
DefaultCall::new(context.llvm_runtime().delegate_call).declare(context)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()> {
|
||||
//DefaultCall::new(context.llvm_runtime().far_call).into_llvm(context)?;
|
||||
DefaultCall::new(context.llvm_runtime().static_call).into_llvm(context)?;
|
||||
DefaultCall::new(context.llvm_runtime().delegate_call).into_llvm(context)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ where
|
||||
)
|
||||
.expect("the PolkaVM guest API module should be linkable");
|
||||
|
||||
for export in runtime_api::EXPORTS {
|
||||
for export in runtime_api::exports::EXPORTS {
|
||||
module
|
||||
.get_function(export)
|
||||
.expect("should be declared")
|
||||
@@ -151,7 +151,7 @@ where
|
||||
);
|
||||
}
|
||||
|
||||
for import in runtime_api::IMPORTS {
|
||||
for import in runtime_api::imports::IMPORTS {
|
||||
module
|
||||
.get_function(import)
|
||||
.expect("should be declared")
|
||||
@@ -433,8 +433,6 @@ where
|
||||
let entry_block = self.llvm.append_basic_block(value, "entry");
|
||||
let return_block = self.llvm.append_basic_block(value, "return");
|
||||
|
||||
value.set_personality_function(self.llvm_runtime.personality.value);
|
||||
|
||||
let r#return = match return_values_length {
|
||||
0 => FunctionReturn::none(),
|
||||
1 => {
|
||||
@@ -705,7 +703,7 @@ where
|
||||
.build_stack_parameter(revive_common::BIT_LENGTH_WORD, "storage_value_pointer");
|
||||
|
||||
self.build_runtime_call(
|
||||
runtime_api::GET_STORAGE,
|
||||
runtime_api::imports::GET_STORAGE,
|
||||
&[
|
||||
storage_key_pointer_casted.into(),
|
||||
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
||||
@@ -809,7 +807,7 @@ where
|
||||
.build_store(storage_value_pointer.value, storage_value_value)?;
|
||||
|
||||
self.build_runtime_call(
|
||||
runtime_api::SET_STORAGE,
|
||||
runtime_api::imports::SET_STORAGE,
|
||||
&[
|
||||
storage_key_pointer_casted.into(),
|
||||
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
||||
@@ -957,106 +955,6 @@ where
|
||||
call_site_value.try_as_basic_value().left()
|
||||
}
|
||||
|
||||
/// Builds an invoke.
|
||||
/// Is defaulted to a call if there is no global exception handler.
|
||||
pub fn build_invoke(
|
||||
&self,
|
||||
function: FunctionDeclaration<'ctx>,
|
||||
arguments: &[inkwell::values::BasicValueEnum<'ctx>],
|
||||
name: &str,
|
||||
) -> Option<inkwell::values::BasicValueEnum<'ctx>> {
|
||||
if !self
|
||||
.functions
|
||||
.contains_key(Function::ZKSYNC_NEAR_CALL_ABI_EXCEPTION_HANDLER)
|
||||
{
|
||||
return self.build_call(function, arguments, name);
|
||||
}
|
||||
|
||||
let return_pointer = if let Some(r#type) = function.r#type.get_return_type() {
|
||||
let pointer = self.build_alloca(r#type, "invoke_return_pointer");
|
||||
self.build_store(pointer, r#type.const_zero()).unwrap();
|
||||
Some(pointer)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let success_block = self.append_basic_block("invoke_success_block");
|
||||
let catch_block = self.append_basic_block("invoke_catch_block");
|
||||
let current_block = self.basic_block();
|
||||
|
||||
self.set_basic_block(catch_block);
|
||||
let landing_pad_type = self.structure_type(&[
|
||||
self.llvm()
|
||||
.ptr_type(AddressSpace::Stack.into())
|
||||
.as_basic_type_enum(),
|
||||
self.integer_type(revive_common::BIT_LENGTH_X32)
|
||||
.as_basic_type_enum(),
|
||||
]);
|
||||
self.builder
|
||||
.build_landing_pad(
|
||||
landing_pad_type,
|
||||
self.llvm_runtime.personality.value,
|
||||
&[self
|
||||
.llvm()
|
||||
.ptr_type(AddressSpace::Stack.into())
|
||||
.const_zero()
|
||||
.as_basic_value_enum()],
|
||||
false,
|
||||
"invoke_catch_landing",
|
||||
)
|
||||
.unwrap();
|
||||
crate::polkavm::utils::throw(self);
|
||||
|
||||
self.set_basic_block(current_block);
|
||||
let call_site_value = self
|
||||
.builder
|
||||
.build_indirect_invoke(
|
||||
function.r#type,
|
||||
function.value.as_global_value().as_pointer_value(),
|
||||
arguments,
|
||||
success_block,
|
||||
catch_block,
|
||||
name,
|
||||
)
|
||||
.unwrap();
|
||||
self.modify_call_site_value(arguments, call_site_value, function);
|
||||
|
||||
self.set_basic_block(success_block);
|
||||
if let (Some(return_pointer), Some(mut return_value)) =
|
||||
(return_pointer, call_site_value.try_as_basic_value().left())
|
||||
{
|
||||
if let Some(return_type) = function.r#type.get_return_type() {
|
||||
if return_type.is_pointer_type() {
|
||||
return_value = self
|
||||
.builder()
|
||||
.build_int_to_ptr(
|
||||
return_value.into_int_value(),
|
||||
return_type.into_pointer_type(),
|
||||
format!("{name}_invoke_return_pointer_casted").as_str(),
|
||||
)
|
||||
.unwrap()
|
||||
.as_basic_value_enum();
|
||||
}
|
||||
}
|
||||
self.build_store(return_pointer, return_value).unwrap();
|
||||
}
|
||||
return_pointer.map(|pointer| self.build_load(pointer, "invoke_result").unwrap())
|
||||
}
|
||||
|
||||
/// Builds an invoke of local call covered with an exception handler.
|
||||
/// Yul does not the exception handling, so the user can declare a special handling function
|
||||
/// called (see constant `ZKSYNC_NEAR_CALL_ABI_EXCEPTION_HANDLER`. If the enclosed function
|
||||
/// panics, the control flow will be transferred to the exception handler.
|
||||
pub fn build_invoke_near_call_abi(
|
||||
&self,
|
||||
_function: FunctionDeclaration<'ctx>,
|
||||
_arguments: Vec<inkwell::values::BasicValueEnum<'ctx>>,
|
||||
_name: &str,
|
||||
) -> Option<inkwell::values::BasicValueEnum<'ctx>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Builds a memory copy call.
|
||||
/// Sets the alignment to `1`, since all non-stack memory pages have such alignment.
|
||||
pub fn build_memcpy(
|
||||
&self,
|
||||
@@ -1132,7 +1030,7 @@ where
|
||||
)?;
|
||||
|
||||
self.build_runtime_call(
|
||||
runtime_api::RETURN,
|
||||
runtime_api::imports::RETURN,
|
||||
&[flags.into(), offset_pointer.into(), length_pointer.into()],
|
||||
);
|
||||
self.build_unreachable();
|
||||
@@ -1396,6 +1294,13 @@ where
|
||||
self.llvm.custom_width_int_type(crate::polkavm::XLEN as u32)
|
||||
}
|
||||
|
||||
/// Returns the register witdh sized type.
|
||||
pub fn sentinel_pointer(&self) -> inkwell::values::PointerValue<'ctx> {
|
||||
self.xlen_type()
|
||||
.const_all_ones()
|
||||
.const_to_pointer(self.llvm().ptr_type(Default::default()))
|
||||
}
|
||||
|
||||
/// Returns the runtime value width sized type.
|
||||
pub fn value_type(&self) -> inkwell::types::IntType<'ctx> {
|
||||
self.llvm
|
||||
|
||||
@@ -3,17 +3,104 @@
|
||||
use inkwell::values::BasicValue;
|
||||
|
||||
use crate::polkavm::context::argument::Argument;
|
||||
use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
|
||||
use crate::polkavm::context::Context;
|
||||
use crate::polkavm::Dependency;
|
||||
use crate::polkavm_const::runtime_api;
|
||||
|
||||
static STATIC_CALL_FLAG: u32 = 0b0001_0000;
|
||||
|
||||
/// Translates a contract call.
|
||||
/// If the `simulation_address` is specified, the call is substituted with another instruction
|
||||
/// according to the specification.
|
||||
///
|
||||
/// If the `simulation_address` is specified, the call is
|
||||
/// substituted with another instruction according to the specification.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn default<'ctx, D>(
|
||||
pub fn call<'ctx, D>(
|
||||
context: &mut Context<'ctx, D>,
|
||||
gas: inkwell::values::IntValue<'ctx>,
|
||||
address: inkwell::values::IntValue<'ctx>,
|
||||
value: Option<inkwell::values::IntValue<'ctx>>,
|
||||
input_offset: inkwell::values::IntValue<'ctx>,
|
||||
input_length: inkwell::values::IntValue<'ctx>,
|
||||
output_offset: inkwell::values::IntValue<'ctx>,
|
||||
output_length: inkwell::values::IntValue<'ctx>,
|
||||
_constants: Vec<Option<num::BigUint>>,
|
||||
static_call: bool,
|
||||
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
|
||||
where
|
||||
D: Dependency + Clone,
|
||||
{
|
||||
let address_pointer = context.build_alloca(context.word_type(), "address_ptr");
|
||||
context.build_store(address_pointer, address)?;
|
||||
|
||||
let value_pointer = if let Some(value) = value {
|
||||
let value_pointer = context.build_alloca(context.value_type(), "value");
|
||||
context.build_store(value_pointer, value)?;
|
||||
value_pointer.value
|
||||
} else {
|
||||
context.sentinel_pointer()
|
||||
};
|
||||
|
||||
let input_offset = context.safe_truncate_int_to_xlen(input_offset)?;
|
||||
let input_length = context.safe_truncate_int_to_xlen(input_length)?;
|
||||
let output_offset = context.safe_truncate_int_to_xlen(output_offset)?;
|
||||
let output_length = context.safe_truncate_int_to_xlen(output_length)?;
|
||||
|
||||
let gas = context
|
||||
.builder()
|
||||
.build_int_truncate(gas, context.integer_type(64), "gas")?;
|
||||
|
||||
let flags = if static_call { STATIC_CALL_FLAG } else { 0 };
|
||||
|
||||
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.get_global(crate::polkavm::GLOBAL_RETURN_DATA_SIZE)?;
|
||||
context.build_store(output_length_pointer.into(), output_length)?;
|
||||
|
||||
let argument_pointer = pallet_contracts_pvm_llapi::calling_convention::Spill::new(
|
||||
context.builder(),
|
||||
pallet_contracts_pvm_llapi::calling_convention::call(context.llvm()),
|
||||
"call_arguments",
|
||||
)?
|
||||
.next(context.xlen_type().const_int(flags as u64, false))?
|
||||
.next(address_pointer.value)?
|
||||
.next(gas)?
|
||||
.skip()
|
||||
.next(context.sentinel_pointer())?
|
||||
.next(value_pointer)?
|
||||
.next(input_pointer.value)?
|
||||
.next(input_length)?
|
||||
.next(output_pointer.value)?
|
||||
.next(output_length_pointer.value)?
|
||||
.done();
|
||||
|
||||
let name = runtime_api::imports::CALL;
|
||||
let arguments = context.builder().build_ptr_to_int(
|
||||
argument_pointer,
|
||||
context.xlen_type(),
|
||||
"argument_pointer",
|
||||
)?;
|
||||
let success = context
|
||||
.build_runtime_call(name, &[arguments.into()])
|
||||
.unwrap_or_else(|| panic!("{name} should return a value"))
|
||||
.into_int_value();
|
||||
|
||||
let is_success = context.builder().build_int_compare(
|
||||
inkwell::IntPredicate::EQ,
|
||||
success,
|
||||
context.xlen_type().const_zero(),
|
||||
"is_success",
|
||||
)?;
|
||||
|
||||
Ok(context
|
||||
.builder()
|
||||
.build_int_z_extend(is_success, context.word_type(), "success")?
|
||||
.as_basic_value_enum())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn delegate_call<'ctx, D>(
|
||||
_context: &mut Context<'ctx, D>,
|
||||
_function: FunctionDeclaration<'ctx>,
|
||||
_gas: inkwell::values::IntValue<'ctx>,
|
||||
_address: inkwell::values::IntValue<'ctx>,
|
||||
_value: Option<inkwell::values::IntValue<'ctx>>,
|
||||
@@ -26,68 +113,7 @@ pub fn default<'ctx, D>(
|
||||
where
|
||||
D: Dependency + Clone,
|
||||
{
|
||||
todo!();
|
||||
|
||||
/*
|
||||
let ordinary_block = context.append_basic_block("contract_call_ordinary_block");
|
||||
let join_block = context.append_basic_block("contract_call_join_block");
|
||||
|
||||
let result_pointer = context.build_alloca(context.field_type(), "contract_call_result_pointer");
|
||||
context.build_store(result_pointer, context.field_const(0));
|
||||
|
||||
context.builder().build_switch(
|
||||
address,
|
||||
ordinary_block,
|
||||
&[(
|
||||
context.field_const(zkevm_opcode_defs::ADDRESS_IDENTITY.into()),
|
||||
identity_block,
|
||||
)],
|
||||
)?;
|
||||
|
||||
{
|
||||
context.set_basic_block(identity_block);
|
||||
let result = identity(context, output_offset, input_offset, output_length)?;
|
||||
context.build_store(result_pointer, result);
|
||||
context.build_unconditional_branch(join_block);
|
||||
}
|
||||
|
||||
context.set_basic_block(ordinary_block);
|
||||
let result = if let Some(value) = value {
|
||||
default_wrapped(
|
||||
context,
|
||||
function,
|
||||
gas,
|
||||
value,
|
||||
address,
|
||||
input_offset,
|
||||
input_length,
|
||||
output_offset,
|
||||
output_length,
|
||||
)?
|
||||
} else {
|
||||
let function = Runtime::default_call(context, function);
|
||||
context
|
||||
.build_call(
|
||||
function,
|
||||
&[
|
||||
gas.as_basic_value_enum(),
|
||||
address.as_basic_value_enum(),
|
||||
input_offset.as_basic_value_enum(),
|
||||
input_length.as_basic_value_enum(),
|
||||
output_offset.as_basic_value_enum(),
|
||||
output_length.as_basic_value_enum(),
|
||||
],
|
||||
"default_call",
|
||||
)
|
||||
.expect("Always exists")
|
||||
};
|
||||
context.build_store(result_pointer, result);
|
||||
context.build_unconditional_branch(join_block);
|
||||
|
||||
context.set_basic_block(join_block);
|
||||
let result = context.build_load(result_pointer, "contract_call_result");
|
||||
Ok(result)
|
||||
*/
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Translates the Yul `linkersymbol` instruction.
|
||||
|
||||
@@ -58,7 +58,7 @@ where
|
||||
"block_timestamp_output",
|
||||
);
|
||||
context.build_runtime_call(
|
||||
runtime_api::BLOCK_NUMBER,
|
||||
runtime_api::imports::BLOCK_NUMBER,
|
||||
&[
|
||||
output_pointer.to_int(context).into(),
|
||||
output_length_pointer.to_int(context).into(),
|
||||
@@ -83,7 +83,7 @@ where
|
||||
"block_timestamp_output",
|
||||
);
|
||||
context.build_runtime_call(
|
||||
runtime_api::NOW,
|
||||
runtime_api::imports::NOW,
|
||||
&[
|
||||
output_pointer.to_int(context).into(),
|
||||
output_length_pointer.to_int(context).into(),
|
||||
@@ -174,7 +174,7 @@ where
|
||||
let (output_pointer, output_length_pointer) =
|
||||
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "address_output");
|
||||
context.build_runtime_call(
|
||||
runtime_api::ADDRESS,
|
||||
runtime_api::imports::ADDRESS,
|
||||
&[
|
||||
output_pointer.to_int(context).into(),
|
||||
output_length_pointer.to_int(context).into(),
|
||||
@@ -197,7 +197,7 @@ where
|
||||
let (output_pointer, output_length_pointer) =
|
||||
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "caller_output");
|
||||
context.build_runtime_call(
|
||||
runtime_api::CALLER,
|
||||
runtime_api::imports::CALLER,
|
||||
&[
|
||||
output_pointer.to_int(context).into(),
|
||||
output_length_pointer.to_int(context).into(),
|
||||
|
||||
@@ -56,11 +56,7 @@ where
|
||||
|
||||
let (address_pointer, address_length_pointer) =
|
||||
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "address_pointer");
|
||||
|
||||
let sentinel = context
|
||||
.xlen_type()
|
||||
.const_all_ones()
|
||||
.const_to_pointer(context.llvm().ptr_type(Default::default()));
|
||||
context.build_store(address_pointer, context.word_const(0))?;
|
||||
|
||||
let argument_pointer = pallet_contracts_pvm_llapi::calling_convention::Spill::new(
|
||||
context.builder(),
|
||||
@@ -70,14 +66,14 @@ where
|
||||
.next(code_hash_pointer.value)?
|
||||
.skip()
|
||||
.skip()
|
||||
.next(sentinel)?
|
||||
.next(context.sentinel_pointer())?
|
||||
.next(value_pointer.value)?
|
||||
.next(input_data_pointer.value)?
|
||||
.next(input_length)?
|
||||
.next(address_pointer.value)?
|
||||
.next(address_length_pointer.value)?
|
||||
.next(sentinel)?
|
||||
.next(sentinel)?
|
||||
.next(context.sentinel_pointer())?
|
||||
.next(context.sentinel_pointer())?
|
||||
.next(salt_pointer.value)?
|
||||
.next(
|
||||
context
|
||||
@@ -86,14 +82,13 @@ where
|
||||
)?
|
||||
.done();
|
||||
|
||||
context.builder().build_direct_call(
|
||||
context.runtime_api_method(runtime_api::INSTANTIATE),
|
||||
context.build_runtime_call(
|
||||
runtime_api::imports::INSTANTIATE,
|
||||
&[context
|
||||
.builder()
|
||||
.build_ptr_to_int(argument_pointer, context.xlen_type(), "argument_pointer")?
|
||||
.into()],
|
||||
"create2",
|
||||
)?;
|
||||
);
|
||||
|
||||
context.build_load_word(
|
||||
address_pointer,
|
||||
|
||||
@@ -19,7 +19,7 @@ where
|
||||
let output_pointer = context.build_alloca(context.word_type(), "output_pointer");
|
||||
|
||||
context.build_runtime_call(
|
||||
runtime_api::HASH_KECCAK_256,
|
||||
runtime_api::imports::HASH_KECCAK_256,
|
||||
&[
|
||||
input_pointer.to_int(context).into(),
|
||||
length_casted.into(),
|
||||
|
||||
@@ -26,7 +26,7 @@ where
|
||||
let (output_pointer, output_length_pointer) =
|
||||
context.build_stack_parameter(revive_common::BIT_LENGTH_VALUE, "value_transferred_output");
|
||||
context.build_runtime_call(
|
||||
runtime_api::VALUE_TRANSFERRED,
|
||||
runtime_api::imports::VALUE_TRANSFERRED,
|
||||
&[
|
||||
output_pointer.to_int(context).into(),
|
||||
output_length_pointer.to_int(context).into(),
|
||||
|
||||
@@ -75,7 +75,7 @@ where
|
||||
]
|
||||
};
|
||||
|
||||
let _ = context.build_runtime_call(runtime_api::DEPOSIT_EVENT, &arguments);
|
||||
let _ = context.build_runtime_call(runtime_api::imports::DEPOSIT_EVENT, &arguments);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -23,8 +23,11 @@ where
|
||||
"address_pointer",
|
||||
)?;
|
||||
let value = context
|
||||
.build_runtime_call(runtime_api::CODE_SIZE, &[address_pointer_casted.into()])
|
||||
.unwrap_or_else(|| panic!("{} should return a value", runtime_api::CODE_SIZE))
|
||||
.build_runtime_call(
|
||||
runtime_api::imports::CODE_SIZE,
|
||||
&[address_pointer_casted.into()],
|
||||
)
|
||||
.unwrap_or_else(|| panic!("{} should return a value", runtime_api::imports::CODE_SIZE))
|
||||
.into_int_value();
|
||||
|
||||
Ok(context
|
||||
|
||||
@@ -4,6 +4,7 @@ use inkwell::values::BasicValue;
|
||||
|
||||
use crate::polkavm::context::Context;
|
||||
use crate::polkavm::Dependency;
|
||||
use crate::polkavm_const::runtime_api;
|
||||
|
||||
/// Translates the return data size.
|
||||
pub fn size<'ctx, D>(
|
||||
@@ -38,54 +39,16 @@ where
|
||||
let destination_offset = context.safe_truncate_int_to_xlen(destination_offset)?;
|
||||
let size = context.safe_truncate_int_to_xlen(size)?;
|
||||
|
||||
let block_copy = context.append_basic_block("copy_block");
|
||||
let block_trap = context.append_basic_block("trap_block");
|
||||
let block_check_out_of_bounds = context.append_basic_block("check_out_of_bounds_block");
|
||||
let is_overflow = context.builder().build_int_compare(
|
||||
inkwell::IntPredicate::UGT,
|
||||
source_offset,
|
||||
context.builder().build_int_sub(
|
||||
context.xlen_type().const_all_ones(),
|
||||
size,
|
||||
"offset_plus_size_max_value",
|
||||
)?,
|
||||
"is_returndata_size_out_of_bounds",
|
||||
let destination_offset = context.builder().build_ptr_to_int(
|
||||
context.build_heap_gep(destination_offset, size)?.value,
|
||||
context.xlen_type(),
|
||||
"destination_offset",
|
||||
)?;
|
||||
context.build_conditional_branch(is_overflow, block_trap, block_check_out_of_bounds)?;
|
||||
|
||||
context.set_basic_block(block_check_out_of_bounds);
|
||||
let is_out_of_bounds = context.builder().build_int_compare(
|
||||
inkwell::IntPredicate::UGT,
|
||||
context.builder().build_int_add(
|
||||
source_offset,
|
||||
context
|
||||
.get_global_value(crate::polkavm::GLOBAL_RETURN_DATA_SIZE)?
|
||||
.into_int_value(),
|
||||
"returndata_end_pointer",
|
||||
)?,
|
||||
context
|
||||
.xlen_type()
|
||||
.const_int(crate::PolkaVMEntryFunction::MAX_CALLDATA_SIZE as u64, false),
|
||||
"is_return_data_copy_overflow",
|
||||
)?;
|
||||
context.build_conditional_branch(is_out_of_bounds, block_trap, block_copy)?;
|
||||
context.build_runtime_call(
|
||||
runtime_api::imports::RETURNDATACOPY,
|
||||
&[destination_offset.into(), source_offset.into(), size.into()],
|
||||
);
|
||||
|
||||
context.set_basic_block(block_trap);
|
||||
context.build_call(context.intrinsics().trap, &[], "invalid_returndata_copy");
|
||||
context.build_unreachable();
|
||||
|
||||
context.set_basic_block(block_copy);
|
||||
context.build_memcpy(
|
||||
context.build_heap_gep(destination_offset, size)?,
|
||||
context.build_gep(
|
||||
context
|
||||
.get_global(crate::polkavm::GLOBAL_RETURN_DATA_POINTER)?
|
||||
.into(),
|
||||
&[context.xlen_type().const_zero(), source_offset],
|
||||
context.byte_type(),
|
||||
"source_offset_gep",
|
||||
),
|
||||
size,
|
||||
"return_data_copy_memcpy_from_return_data",
|
||||
)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
use inkwell::values::BasicValue;
|
||||
|
||||
use crate::polkavm::context::address_space::AddressSpace;
|
||||
use crate::polkavm::context::function::llvm_runtime::LLVMRuntime;
|
||||
use crate::polkavm::context::Context;
|
||||
use crate::polkavm::Dependency;
|
||||
|
||||
@@ -40,23 +39,6 @@ where
|
||||
Ok(result.into_int_value())
|
||||
}
|
||||
|
||||
/// Generates an exception.
|
||||
pub fn throw<D>(context: &Context<D>)
|
||||
where
|
||||
D: Dependency + Clone,
|
||||
{
|
||||
context.build_call(
|
||||
context.llvm_runtime().cxa_throw,
|
||||
&[context
|
||||
.llvm()
|
||||
.ptr_type(AddressSpace::Stack.into())
|
||||
.get_undef()
|
||||
.as_basic_value_enum(); 3],
|
||||
LLVMRuntime::FUNCTION_CXA_THROW,
|
||||
);
|
||||
context.build_unreachable();
|
||||
}
|
||||
|
||||
/// Returns the full list of arguments for an external call.
|
||||
/// Performs the extra ABI data padding and adds the mimic call extra argument.
|
||||
pub fn external_call_arguments<'ctx, D>(
|
||||
|
||||
Reference in New Issue
Block a user