Contract calls (#19)

This commit is contained in:
Cyrill Leutwiler
2024-06-01 20:48:20 +02:00
committed by GitHub
parent 532721f3be
commit 1ba806be1f
27 changed files with 540 additions and 929 deletions
+12 -107
View File
@@ -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