Skip to content
This repository has been archived by the owner on Mar 20, 2024. It is now read-only.

Commit

Permalink
Handle entry functions with non-empty list of arguments (#260)
Browse files Browse the repository at this point in the history
  • Loading branch information
dmakarov authored Aug 1, 2023
1 parent bf4e4ec commit b6c4da7
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,72 @@ impl<'mm, 'up> ModuleContext<'mm, 'up> {
attrs
}

// This function extracts an entry function actual arguments from
// AccountInfo data field. The field is a byte array containing
// values of actual arguments in sequential order without gaps.
fn emit_entry_arguments(
&self,
fn_env: &mm::FunctionEnv,
accounts: &llvm::AnyValue,
) -> Vec<llvm::AnyValue> {
if fn_env.get_parameter_count() == 0 {
return vec![];
}
let llcx = self.llvm_cx;

let vec_ty = self.rtty_cx.get_llvm_type_for_move_native_vector();
let acc_vec_ptr =
self.llvm_builder
.getelementptr(*accounts, &vec_ty.as_struct_type(), 0, "acc_vec_ptr");
let acc_vec_ptr =
self.llvm_builder
.load(acc_vec_ptr, llcx.ptr_type(), "acc_vec_ptr_loaded");
let acc_ty = self.rtty_cx.get_llvm_type_for_solana_account_info();
let acc_data =
self.llvm_builder
.getelementptr(acc_vec_ptr, &acc_ty.as_struct_type(), 2, "acc_data");
let data_ty = self.rtty_cx.get_llvm_type_for_slice();
let acc_data_ptr =
self.llvm_builder
.getelementptr(acc_data, &data_ty.as_struct_type(), 0, "acc_data_ptr");
let acc_data_ptr =
self.llvm_builder
.load(acc_data_ptr, llcx.ptr_type(), "acc_data_ptr_loaded");
// Make a struct of fields with types corresponding to the
// entry function formal parameters. For reference
// parameters, use the type it refers to. The struct helps to
// compute offsets in acc_data slice for accessing actual
// argument values.
let ll_param_tys = fn_env
.get_parameter_types()
.iter()
.map(|mty| match mty {
mty::Type::Reference(_mu, mty) => self.to_llvm_type(mty, &[]),
_ => self.to_llvm_type(mty, &[]),
})
.collect::<Vec<_>>();
let arg_tys = llcx.get_anonymous_struct_type(ll_param_tys.as_slice());
let mut args = vec![];
for (ix, ty) in fn_env.get_parameter_types().iter().enumerate() {
let mut arg = self.llvm_builder.getelementptr(
acc_data_ptr,
&arg_tys.as_struct_type(),
ix,
"arg_ptr",
);
// All arguments are present in acc_data as values. If an
// entry function takes a reference parameter, pass the
// address of the corresponding element in the acc_data
// slice.
match ty {
mty::Type::Reference(_mu, _ty) => {}
_ => arg = self.llvm_builder.load(arg, ll_param_tys[ix], "arg"),
}
args.push(arg);
}
args
}

fn generate_global_str_slice(&self, s: &str) -> llvm::Global {
let llcx = &self.llvm_cx;

Expand Down Expand Up @@ -888,13 +954,9 @@ impl<'mm, 'up> ModuleContext<'mm, 'up> {
) -> (llvm::AnyValue, llvm::AnyValue, llvm::AnyValue) {
let llcx = self.llvm_cx;
let ll_sret = llcx.get_anonymous_struct_type(&[
llcx.get_anonymous_struct_type(&[llcx.ptr_type(), llcx.int_type(64)]),
self.rtty_cx.get_llvm_type_for_slice(),
llcx.ptr_type(),
llcx.get_anonymous_struct_type(&[
llcx.ptr_type(),
llcx.int_type(64),
llcx.int_type(64),
]),
self.rtty_cx.get_llvm_type_for_move_native_vector(),
]);
let params = self
.llvm_builder
Expand Down Expand Up @@ -966,13 +1028,11 @@ impl<'mm, 'up> ModuleContext<'mm, 'up> {
.as_any_value();

// Get inputs from the VM into proper data structures.
let (insn_data, _, _) =
let (insn_data, _, accounts) =
self.emit_rtcall_deserialize(ll_fn_solana_entrypoint.get_param(0).as_any_value());
// Make a str slice from instruction_data byte array returned
// from a call to deserialize
let str_slice_type = self
.llvm_cx
.get_anonymous_struct_type(&[self.llvm_cx.ptr_type(), self.llvm_cx.int_type(64)]);
let str_slice_type = self.rtty_cx.get_llvm_type_for_slice();
let insn_data_ptr = self.llvm_builder.getelementptr(
insn_data,
&str_slice_type.as_struct_type(),
Expand Down Expand Up @@ -1039,7 +1099,8 @@ impl<'mm, 'up> ModuleContext<'mm, 'up> {
self.llvm_builder.position_at_end(then_bb);
let fn_name = fun.llvm_symbol_name(&[]);
let ll_fun = self.fn_decls.get(&fn_name).unwrap();
let ret = self.llvm_builder.call(*ll_fun, &[]);
let params = self.emit_entry_arguments(&fun, &accounts);
let ret = self.llvm_builder.call(*ll_fun, &params);
self.llvm_builder.store(ret, retval);
self.llvm_builder.build_br(exit_bb);
self.llvm_builder.position_at_end(else_bb);
Expand All @@ -1052,5 +1113,9 @@ impl<'mm, 'up> ModuleContext<'mm, 'up> {
.load(retval, self.llvm_cx.int_type(64), "exit_code");
self.llvm_builder.build_return(ret);
ll_fn_solana_entrypoint.verify();

if log::max_level() >= log::LevelFilter::Debug {
self.llvm_module.dump();
}
}
}
21 changes: 21 additions & 0 deletions language/tools/move-mv-llvm-compiler/src/stackless/rttydesc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,27 @@ impl<'mm, 'up> RttyContext<'mm, 'up> {
llcx.get_anonymous_struct_type(&[llcx.ptr_type(), llcx.int_type(64), llcx.int_type(64)])
}

pub fn get_llvm_type_for_slice(&self) -> llvm::Type {
let llcx = &self.get_llvm_cx();
llcx.get_anonymous_struct_type(&[llcx.ptr_type(), llcx.int_type(64)])
}

pub fn get_llvm_type_for_solana_account_info(&self) -> llvm::Type {
// This struct is shared with move-native,
// where it is declared as `SolanaAccountinfo`.
let llcx = &self.get_llvm_cx();
llcx.get_anonymous_struct_type(&[
llcx.ptr_type(), // key
llcx.int_type(64), // lamports
self.get_llvm_type_for_slice(), // data
llcx.ptr_type(), // owner
llcx.int_type(64), // rent_epoch
llcx.int_type(1), // is_signer
llcx.int_type(1), // is_writable
llcx.int_type(1), // executable
])
}

pub fn get_llvm_type_for_address(&self) -> llvm::Type {
// Create a type `[N x i8]` (an account address) corresponding
// to `move_native::rt_types::MoveAddress`.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"program_id": "DozgQiYtGbdyniV2T74xMdmjZJvYDzoRFFqw7UR5MwPK",
"accounts": [
{
"key": "524HMdYYBy6TAn4dK5vCcjiTmT2sxV6Xoue5EXrz22Ca",
"owner": "BPFLoaderUpgradeab1e11111111111111111111111",
"is_signer": false,
"is_writable": true,
"lamports": 1000,
"data": [
59, 180, 10, 27, 53, 174, 68, 250, 182, 197, 64, 125, 20, 13, 245, 130, 63, 209, 147, 189, 65, 82, 20, 53, 37, 71, 8, 125, 94, 87, 32, 27,
23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
2, 3, 5, 7, 11, 13, 17, 19]
}
],
"instruction_data": [101, 110, 116, 114, 121, 95, 112, 111, 105, 110, 116, 95, 95, 116, 114, 97, 110, 115, 102, 101, 114]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// input entry-point04.json

// A phony `signer` module until we build `move-stdlib`.
module 0x500::signer {
native public fun borrow_address(acct: &signer): &address;

// Copies the address of the signer
public fun address_of(s: &signer): address {
*borrow_address(s)
}
}

module 0xa000::entry_point {
use 0x500::signer;

public entry fun bar(): u64 {
0
}

public entry fun foo(): u64 {
17
}

public entry fun transfer(
sender: &signer,
receiver: address,
amount: u64,
): u64
{
assert!(signer::address_of(sender) == @0x1b20575e7d08472535145241bd93d13f82f50d147d40c5b6fa44ae351b0ab43b, 0xf0000);
assert!(receiver == @0xada7a39d97958b89837f716d6b67656159534f4947433d3b352f2b29251f1d17, 0xf001);
assert!(amount == 0x13110d0b07050302, 0xf002);
0
}
}

0 comments on commit b6c4da7

Please sign in to comment.