use inkwell::{ builder::Builder, context::Context, module::Module, types::{BasicType, StructType}, values::{BasicValueEnum, PointerValue}, }; /// Creates a module that sets the PolkaVM minimum stack size to [`size`] if linked in. pub fn min_stack_size<'context>( context: &'context Context, module_name: &str, size: u32, ) -> Module<'context> { let module = context.create_module(module_name); module.set_inline_assembly(&format!( ".pushsection .polkavm_min_stack_size,\"\",@progbits .word {size} .popsection" )); module } /// Helper for building function calls with stack spilled arguments. /// - `pointer`: points to a struct of the packed argument struct type /// - `type`: the packed argument struct type /// - `arguments`: a correctly ordered list of the struct field values pub fn spill<'ctx>( builder: &Builder<'ctx>, pointer: PointerValue<'ctx>, r#type: StructType<'ctx>, arguments: &[BasicValueEnum<'ctx>], ) -> anyhow::Result<()> { for index in 0..r#type.get_field_types().len() { let field_pointer = builder.build_struct_gep( r#type, pointer, index as u32, &format!("spill_parameter_{}", index), )?; let field_value = arguments .get(index) .ok_or_else(|| anyhow::anyhow!("invalid index {index} for struct type {}", r#type))?; builder.build_store(field_pointer, *field_value)?; } Ok(()) } /// Returns a packed struct argument type for the `instantiate` API. pub fn instantiate(context: &Context) -> StructType { context.struct_type( &[ // code_hash_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), // ref_time_limit: u64, context.i64_type().as_basic_type_enum(), // proof_size_limit: u64, context.i64_type().as_basic_type_enum(), // deposit_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), // value_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), // input_data_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), // input_data_len: u32, context.i32_type().as_basic_type_enum(), // address_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), // output_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), // output_len_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), // salt_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), ], true, ) } /// Returns a packed struct argument type for the `call` API. pub fn call(context: &Context) -> StructType { context.struct_type( &[ // flags: u32, context.i32_type().as_basic_type_enum(), // address_ptr: context.ptr_type(Default::default()).as_basic_type_enum(), // ref_time_limit: u64, context.i64_type().as_basic_type_enum(), // proof_size_limit: u64, context.i64_type().as_basic_type_enum(), // deposit_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), // value_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), // input_data_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), // input_data_len: u32, context.i32_type().as_basic_type_enum(), // output_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), // output_len_ptr: u32, context.ptr_type(Default::default()).as_basic_type_enum(), ], true, ) }