|
|
@@ -24,7 +24,8 @@ use inkwell::IntPredicate;
|
|
|
|
|
|
const WASMTRIPLE: &str = "wasm32-unknown-unknown-wasm";
|
|
|
|
|
|
-pub mod burrow;
|
|
|
+mod burrow;
|
|
|
+mod substrate;
|
|
|
|
|
|
lazy_static::lazy_static! {
|
|
|
static ref LLVM_INIT: () = {
|
|
|
@@ -45,8 +46,28 @@ struct Function<'a> {
|
|
|
}
|
|
|
|
|
|
pub trait TargetRuntime {
|
|
|
+ //
|
|
|
fn set_storage<'a>(&self, contract: &'a Contract, slot: u32, dest: inkwell::values::PointerValue<'a>);
|
|
|
fn get_storage<'a>(&self, contract: &'a Contract, slot: u32, dest: inkwell::values::PointerValue<'a>);
|
|
|
+
|
|
|
+ fn abi_decode<'b>(
|
|
|
+ &self,
|
|
|
+ contract: &'b Contract,
|
|
|
+ function: FunctionValue,
|
|
|
+ args: &mut Vec<BasicValueEnum<'b>>,
|
|
|
+ data: PointerValue<'b>,
|
|
|
+ length: IntValue,
|
|
|
+ spec: &resolver::FunctionDecl,
|
|
|
+ );
|
|
|
+ fn abi_encode<'b>(
|
|
|
+ &self,
|
|
|
+ contract: &'b Contract,
|
|
|
+ args: &[BasicValueEnum<'b>],
|
|
|
+ spec: &resolver::FunctionDecl,
|
|
|
+ ) -> (PointerValue<'b>, IntValue<'b>);
|
|
|
+
|
|
|
+ fn return_empty_abi(&self, contract: &Contract);
|
|
|
+ fn return_abi<'b>(&self, contract: &'b Contract, data: PointerValue<'b>, length: IntValue);
|
|
|
}
|
|
|
|
|
|
pub struct Contract<'a> {
|
|
|
@@ -58,10 +79,16 @@ pub struct Contract<'a> {
|
|
|
ns: &'a resolver::Contract,
|
|
|
constructors: Vec<Function<'a>>,
|
|
|
functions: Vec<Function<'a>>,
|
|
|
- externals: HashMap<String, FunctionValue<'a>>,
|
|
|
}
|
|
|
|
|
|
impl<'a> Contract<'a> {
|
|
|
+ pub fn build(context: &'a Context, contract: &'a resolver::Contract, filename: &'a str) -> Self {
|
|
|
+ match contract.target {
|
|
|
+ resolver::Target::Burrow => burrow::BurrowTarget::build(context, contract, filename),
|
|
|
+ resolver::Target::Substrate => substrate::SubstrateTarget::build(context, contract, filename),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
pub fn wasm(&self, opt: &str) -> Result<Vec<u8>, String> {
|
|
|
let opt = match opt {
|
|
|
"none" => OptimizationLevel::None,
|
|
|
@@ -113,7 +140,6 @@ impl<'a> Contract<'a> {
|
|
|
ns: contract,
|
|
|
constructors: Vec::new(),
|
|
|
functions: Vec::new(),
|
|
|
- externals: HashMap::new(),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -225,401 +251,6 @@ impl<'a> Contract<'a> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fn emit_function_dispatch(&self, contract: &resolver::Contract) {
|
|
|
- // create start function
|
|
|
- let ret = self.context.i32_type().ptr_type(AddressSpace::Generic);
|
|
|
- let ftype = ret.fn_type(&[self.context.i32_type().ptr_type(AddressSpace::Generic).into()], false);
|
|
|
- let function = self.module.add_function("function", ftype, None);
|
|
|
-
|
|
|
- let entry = self.context.append_basic_block(function, "entry");
|
|
|
- let fallback_block = self.context.append_basic_block(function, "fallback");
|
|
|
- let switch_block = self.context.append_basic_block(function, "switch");
|
|
|
-
|
|
|
- self.builder.position_at_end(&entry);
|
|
|
-
|
|
|
- let arg = function.get_first_param().unwrap().into_pointer_value();
|
|
|
- let length = self.builder.build_load(arg, "length").into_int_value();
|
|
|
-
|
|
|
- let not_fallback = self.builder.build_int_compare(
|
|
|
- IntPredicate::UGE,
|
|
|
- length,
|
|
|
- self.context.i32_type().const_int(4, false).into(),
|
|
|
- "");
|
|
|
-
|
|
|
- self.builder.build_conditional_branch(not_fallback, &switch_block, &fallback_block);
|
|
|
-
|
|
|
- self.builder.position_at_end(&switch_block);
|
|
|
-
|
|
|
- let fid_ptr = unsafe {
|
|
|
- self.builder.build_gep(
|
|
|
- arg,
|
|
|
- &[self.context.i32_type().const_int(1, false).into()],
|
|
|
- "fid_ptr")
|
|
|
- };
|
|
|
-
|
|
|
- let fid = self.builder.build_load(fid_ptr, "fid");
|
|
|
-
|
|
|
- // pointer/size for abi decoding
|
|
|
- let args_ptr = unsafe {
|
|
|
- self.builder.build_gep(
|
|
|
- arg,
|
|
|
- &[self.context.i32_type().const_int(2, false).into()],
|
|
|
- "fid_ptr")
|
|
|
- };
|
|
|
-
|
|
|
- let args_len = self.builder.build_int_sub(
|
|
|
- length.into(),
|
|
|
- self.context.i32_type().const_int(4, false).into(),
|
|
|
- "args_len"
|
|
|
- );
|
|
|
-
|
|
|
- let nomatch = self.context.append_basic_block(function, "nomatch");
|
|
|
-
|
|
|
- self.builder.position_at_end(&nomatch);
|
|
|
-
|
|
|
- self.builder.build_unreachable();
|
|
|
-
|
|
|
- let mut cases = Vec::new();
|
|
|
-
|
|
|
- let mut fallback = None;
|
|
|
-
|
|
|
- for (i, f) in contract.functions.iter().enumerate() {
|
|
|
- match &f.visibility {
|
|
|
- ast::Visibility::Internal(_) | ast::Visibility::Private(_) => {
|
|
|
- continue;
|
|
|
- }
|
|
|
- _ => (),
|
|
|
- }
|
|
|
-
|
|
|
- if f.name == "" {
|
|
|
- fallback = Some(i);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- let res = keccak256(f.signature.as_bytes());
|
|
|
-
|
|
|
- let bb = self.context.append_basic_block(function, "");
|
|
|
- let id = u32::from_le_bytes([res[0], res[1], res[2], res[3]]);
|
|
|
-
|
|
|
- self.builder.position_at_end(&bb);
|
|
|
-
|
|
|
- let mut args = Vec::new();
|
|
|
-
|
|
|
- // insert abi decode
|
|
|
- self.emit_abi_decode(function, &mut args, args_ptr, args_len, f);
|
|
|
-
|
|
|
- let ret = self.builder.build_call(
|
|
|
- self.functions[i].value_ref,
|
|
|
- &args,
|
|
|
- "").try_as_basic_value().left();
|
|
|
-
|
|
|
- if f.returns.is_empty() {
|
|
|
- // return ABI of length 0
|
|
|
-
|
|
|
- // malloc 4 bytes
|
|
|
- let dest = self.builder.build_call(
|
|
|
- self.module.get_function("__malloc").unwrap(),
|
|
|
- &[self.context.i32_type().const_int(4, false).into()],
|
|
|
- ""
|
|
|
- ).try_as_basic_value().left().unwrap().into_pointer_value();
|
|
|
-
|
|
|
- self.builder.build_store(
|
|
|
- self.builder.build_pointer_cast(dest,
|
|
|
- self.context.i32_type().ptr_type(AddressSpace::Generic),
|
|
|
- ""),
|
|
|
- self.context.i32_type().const_zero());
|
|
|
-
|
|
|
- self.builder.build_return(Some(&dest));
|
|
|
- } else if self.functions[i].wasm_return {
|
|
|
- // malloc 36 bytes
|
|
|
- let dest = self.builder.build_call(
|
|
|
- self.module.get_function("__malloc").unwrap(),
|
|
|
- &[self.context.i32_type().const_int(36, false).into()],
|
|
|
- ""
|
|
|
- ).try_as_basic_value().left().unwrap().into_pointer_value();
|
|
|
-
|
|
|
- // write length
|
|
|
- self.builder.build_store(
|
|
|
- self.builder.build_pointer_cast(dest,
|
|
|
- self.context.i32_type().ptr_type(AddressSpace::Generic),
|
|
|
- ""),
|
|
|
- self.context.i32_type().const_int(32, false));
|
|
|
-
|
|
|
- // malloc returns u8*
|
|
|
- let abi_ptr = unsafe {
|
|
|
- self.builder.build_gep(
|
|
|
- dest,
|
|
|
- &[ self.context.i32_type().const_int(4, false).into()],
|
|
|
- "abi_ptr")
|
|
|
- };
|
|
|
-
|
|
|
- // insert abi decode
|
|
|
- let ty = match &f.returns[0].ty {
|
|
|
- resolver::TypeName::Elementary(e) => e,
|
|
|
- resolver::TypeName::Enum(n) => &self.ns.enums[*n].ty,
|
|
|
- resolver::TypeName::Noreturn => unreachable!(),
|
|
|
- };
|
|
|
-
|
|
|
- self.emit_abi_encode_single_val(&ty, abi_ptr, ret.unwrap().into_int_value());
|
|
|
-
|
|
|
- self.builder.build_return(Some(&dest));
|
|
|
- } else {
|
|
|
- // FIXME: abi encode all the arguments
|
|
|
- }
|
|
|
-
|
|
|
- cases.push((self.context.i32_type().const_int(id as u64, false), bb));
|
|
|
- }
|
|
|
-
|
|
|
- self.builder.position_at_end(&switch_block);
|
|
|
-
|
|
|
- let mut c = Vec::new();
|
|
|
-
|
|
|
- for (id, bb) in cases.iter() {
|
|
|
- c.push((*id, bb));
|
|
|
- }
|
|
|
-
|
|
|
- //let c = cases.into_iter().map(|(id, bb)| (id, &bb)).collect();
|
|
|
-
|
|
|
- self.builder.build_switch(
|
|
|
- fid.into_int_value(), &nomatch,
|
|
|
- &c);
|
|
|
-
|
|
|
- // FIXME: emit code for public contract variables
|
|
|
-
|
|
|
- // emit fallback code
|
|
|
- self.builder.position_at_end(&fallback_block);
|
|
|
-
|
|
|
- match fallback {
|
|
|
- Some(f) => {
|
|
|
- self.builder.build_call(
|
|
|
- self.functions[f].value_ref,
|
|
|
- &[],
|
|
|
- "");
|
|
|
-
|
|
|
- self.builder.build_return(None);
|
|
|
- }
|
|
|
- None => {
|
|
|
- self.builder.build_unreachable();
|
|
|
- },
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn emit_abi_encode_single_val(
|
|
|
- &self,
|
|
|
- ty: &ast::ElementaryTypeName,
|
|
|
- dest: PointerValue,
|
|
|
- val: IntValue,
|
|
|
- ) {
|
|
|
- match ty {
|
|
|
- ast::ElementaryTypeName::Bool => {
|
|
|
- // first clear
|
|
|
- let dest8 = self.builder.build_pointer_cast(dest,
|
|
|
- self.context.i8_type().ptr_type(AddressSpace::Generic),
|
|
|
- "destvoid");
|
|
|
-
|
|
|
- self.builder.build_call(
|
|
|
- self.module.get_function("__bzero8").unwrap(),
|
|
|
- &[ dest8.into(),
|
|
|
- self.context.i32_type().const_int(4, false).into() ],
|
|
|
- "");
|
|
|
-
|
|
|
- let value = self.builder.build_select(val,
|
|
|
- self.context.i8_type().const_int(1, false),
|
|
|
- self.context.i8_type().const_zero(),
|
|
|
- "bool_val");
|
|
|
-
|
|
|
- let dest = unsafe {
|
|
|
- self.builder.build_gep(
|
|
|
- dest8,
|
|
|
- &[ self.context.i32_type().const_int(31, false).into() ],
|
|
|
- "")
|
|
|
- };
|
|
|
-
|
|
|
- self.builder.build_store(dest, value);
|
|
|
- }
|
|
|
- ast::ElementaryTypeName::Int(8) | ast::ElementaryTypeName::Uint(8) => {
|
|
|
- let signval = if let ast::ElementaryTypeName::Int(8) = ty {
|
|
|
- let negative = self.builder.build_int_compare(IntPredicate::SLT,
|
|
|
- val, self.context.i8_type().const_zero(), "neg");
|
|
|
-
|
|
|
- self.builder.build_select(negative,
|
|
|
- self.context.i64_type().const_zero(),
|
|
|
- self.context.i64_type().const_int(std::u64::MAX, true),
|
|
|
- "val").into_int_value()
|
|
|
- } else {
|
|
|
- self.context.i64_type().const_zero()
|
|
|
- };
|
|
|
-
|
|
|
- let dest8 = self.builder.build_pointer_cast(dest,
|
|
|
- self.context.i8_type().ptr_type(AddressSpace::Generic),
|
|
|
- "destvoid");
|
|
|
-
|
|
|
- self.builder.build_call(
|
|
|
- self.module.get_function("__memset8").unwrap(),
|
|
|
- &[ dest8.into(), signval.into(),
|
|
|
- self.context.i32_type().const_int(4, false).into() ],
|
|
|
- "");
|
|
|
-
|
|
|
- let dest = unsafe {
|
|
|
- self.builder.build_gep(
|
|
|
- dest8,
|
|
|
- &[ self.context.i32_type().const_int(31, false).into() ],
|
|
|
- "")
|
|
|
- };
|
|
|
-
|
|
|
- self.builder.build_store(dest, val);
|
|
|
- }
|
|
|
- ast::ElementaryTypeName::Uint(n) | ast::ElementaryTypeName::Int(n) => {
|
|
|
- // first clear/set the upper bits
|
|
|
- if *n < 256 {
|
|
|
- let signval = if let ast::ElementaryTypeName::Int(8) = ty {
|
|
|
- let negative = self.builder.build_int_compare(IntPredicate::SLT,
|
|
|
- val, self.context.i8_type().const_zero(), "neg");
|
|
|
-
|
|
|
- self.builder.build_select(negative,
|
|
|
- self.context.i64_type().const_zero(),
|
|
|
- self.context.i64_type().const_int(std::u64::MAX, true),
|
|
|
- "val").into_int_value()
|
|
|
- } else {
|
|
|
- self.context.i64_type().const_zero()
|
|
|
- };
|
|
|
-
|
|
|
- let dest8 = self.builder.build_pointer_cast(dest,
|
|
|
- self.context.i8_type().ptr_type(AddressSpace::Generic),
|
|
|
- "destvoid");
|
|
|
-
|
|
|
- self.builder.build_call(
|
|
|
- self.module.get_function("__memset8").unwrap(),
|
|
|
- &[ dest8.into(), signval.into(),
|
|
|
- self.context.i32_type().const_int(4, false).into() ],
|
|
|
- "");
|
|
|
- }
|
|
|
-
|
|
|
- // no need to allocate space for each uint64
|
|
|
- // allocate enough for type
|
|
|
- let int_type = self.context.custom_width_int_type(*n as u32);
|
|
|
- let type_size = int_type.size_of();
|
|
|
-
|
|
|
- let store = self.builder.build_alloca(int_type, "stack");
|
|
|
-
|
|
|
- self.builder.build_store(store, val);
|
|
|
-
|
|
|
- self.builder.build_call(
|
|
|
- self.module.get_function("__leNtobe32").unwrap(),
|
|
|
- &[ self.builder.build_pointer_cast(store,
|
|
|
- self.context.i8_type().ptr_type(AddressSpace::Generic),
|
|
|
- "destvoid").into(),
|
|
|
- self.builder.build_pointer_cast(dest,
|
|
|
- self.context.i8_type().ptr_type(AddressSpace::Generic),
|
|
|
- "destvoid").into(),
|
|
|
- self.builder.build_int_truncate(type_size,
|
|
|
- self.context.i32_type(), "").into()
|
|
|
- ],
|
|
|
- "");
|
|
|
- }
|
|
|
- _ => unimplemented!(),
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn emit_abi_decode(
|
|
|
- &self,
|
|
|
- function: FunctionValue,
|
|
|
- args: &mut Vec<BasicValueEnum<'a>>,
|
|
|
- data: PointerValue<'a>,
|
|
|
- length: IntValue,
|
|
|
- spec: &resolver::FunctionDecl,
|
|
|
- ) {
|
|
|
- let mut data = data;
|
|
|
- let decode_block = self.context.append_basic_block(function, "abi_decode");
|
|
|
- let wrong_length_block = self.context.append_basic_block(function, "wrong_abi_length");
|
|
|
-
|
|
|
- let is_ok = self.builder.build_int_compare(IntPredicate::EQ, length,
|
|
|
- self.context.i32_type().const_int(32 * spec.params.len() as u64, false),
|
|
|
- "correct_length");
|
|
|
-
|
|
|
- self.builder.build_conditional_branch(is_ok, &decode_block, &wrong_length_block);
|
|
|
-
|
|
|
- self.builder.position_at_end(&decode_block);
|
|
|
-
|
|
|
- for arg in &spec.params {
|
|
|
- let ty = match &arg.ty {
|
|
|
- resolver::TypeName::Elementary(e) => e,
|
|
|
- resolver::TypeName::Enum(n) => &self.ns.enums[*n].ty,
|
|
|
- resolver::TypeName::Noreturn => unreachable!(),
|
|
|
- };
|
|
|
-
|
|
|
- args.push(match ty {
|
|
|
- ast::ElementaryTypeName::Bool => {
|
|
|
- // solidity checks all the 32 bytes for being non-zero; we will just look at the upper 8 bytes, else we would need four loads
|
|
|
- // which is unneeded (hopefully)
|
|
|
- // cast to 64 bit pointer
|
|
|
- let bool_ptr = self.builder.build_pointer_cast(data,
|
|
|
- self.context.i64_type().ptr_type(AddressSpace::Generic), "");
|
|
|
-
|
|
|
- let bool_ptr = unsafe {
|
|
|
- self.builder.build_gep(bool_ptr,
|
|
|
- &[ self.context.i32_type().const_int(3, false) ],
|
|
|
- "bool_ptr")
|
|
|
- };
|
|
|
-
|
|
|
- self.builder.build_int_compare(IntPredicate::EQ,
|
|
|
- self.builder.build_load(bool_ptr, "abi_bool").into_int_value(),
|
|
|
- self.context.i64_type().const_zero(), "bool").into()
|
|
|
- }
|
|
|
- ast::ElementaryTypeName::Uint(8) | ast::ElementaryTypeName::Int(8) => {
|
|
|
- let int8_ptr = self.builder.build_pointer_cast(data,
|
|
|
- self.context.i8_type().ptr_type(AddressSpace::Generic), "");
|
|
|
-
|
|
|
- let int8_ptr = unsafe {
|
|
|
- self.builder.build_gep(int8_ptr,
|
|
|
- &[ self.context.i32_type().const_int(31, false) ],
|
|
|
- "bool_ptr")
|
|
|
- };
|
|
|
-
|
|
|
- self.builder.build_load(int8_ptr, "abi_int8")
|
|
|
- }
|
|
|
- ast::ElementaryTypeName::Uint(n) | ast::ElementaryTypeName::Int(n) => {
|
|
|
- let int_type = self.context.custom_width_int_type(*n as u32);
|
|
|
- let type_size = int_type.size_of();
|
|
|
-
|
|
|
- let store = self.builder.build_alloca(int_type, "stack");
|
|
|
-
|
|
|
- self.builder.build_call(
|
|
|
- self.module.get_function("__be32toleN").unwrap(),
|
|
|
- &[
|
|
|
- self.builder.build_pointer_cast(data,
|
|
|
- self.context.i8_type().ptr_type(AddressSpace::Generic), "").into(),
|
|
|
- self.builder.build_pointer_cast(store,
|
|
|
- self.context.i8_type().ptr_type(AddressSpace::Generic), "").into(),
|
|
|
- self.builder.build_int_truncate(type_size,
|
|
|
- self.context.i32_type(), "size").into()
|
|
|
- ],
|
|
|
- ""
|
|
|
- );
|
|
|
-
|
|
|
- if *n <= 64 {
|
|
|
- self.builder.build_load(store, &format!("abi_int{}", *n))
|
|
|
- } else {
|
|
|
- store.into()
|
|
|
- }
|
|
|
- }
|
|
|
- _ => panic!(),
|
|
|
- });
|
|
|
-
|
|
|
- data = unsafe {
|
|
|
- self.builder.build_gep(data,
|
|
|
- &[ self.context.i32_type().const_int(8, false)],
|
|
|
- "data_next")
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- // FIXME: generate a call to revert/abort with some human readable error or error code
|
|
|
- self.builder.position_at_end(&wrong_length_block);
|
|
|
- self.builder.build_unreachable();
|
|
|
-
|
|
|
- self.builder.position_at_end(&decode_block);
|
|
|
- }
|
|
|
-
|
|
|
fn emit_func(&self, fname: &str, f: &resolver::FunctionDecl, runtime: &dyn TargetRuntime) -> Function<'a> {
|
|
|
let mut args: Vec<BasicTypeEnum> = Vec::new();
|
|
|
let mut wasm_return = false;
|
|
|
@@ -864,6 +495,109 @@ impl<'a> Contract<'a> {
|
|
|
wasm_return,
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ pub fn emit_function_dispatch(&self,
|
|
|
+ functions: &Vec<resolver::FunctionDecl>,
|
|
|
+ argsdata: inkwell::values::PointerValue,
|
|
|
+ argslen: inkwell::values::IntValue,
|
|
|
+ function: inkwell::values::FunctionValue,
|
|
|
+ fallback_block: &inkwell::basic_block::BasicBlock,
|
|
|
+ runtime: &dyn TargetRuntime) {
|
|
|
+ // create start function
|
|
|
+ let switch_block = self.context.append_basic_block(function, "switch");
|
|
|
+
|
|
|
+ let not_fallback = self.builder.build_int_compare(
|
|
|
+ IntPredicate::UGE,
|
|
|
+ argslen,
|
|
|
+ self.context.i32_type().const_int(4, false).into(),
|
|
|
+ "");
|
|
|
+
|
|
|
+ self.builder.build_conditional_branch(not_fallback, &switch_block, fallback_block);
|
|
|
+
|
|
|
+ self.builder.position_at_end(&switch_block);
|
|
|
+
|
|
|
+ let fid = self.builder.build_load(argsdata, "function_selector");
|
|
|
+
|
|
|
+ // step over the function selector
|
|
|
+ let argsdata = unsafe {
|
|
|
+ self.builder.build_gep(
|
|
|
+ argsdata,
|
|
|
+ &[self.context.i32_type().const_int(1, false).into()],
|
|
|
+ "fid_ptr")
|
|
|
+ };
|
|
|
+
|
|
|
+ let argslen = self.builder.build_int_sub(
|
|
|
+ argslen.into(),
|
|
|
+ self.context.i32_type().const_int(4, false).into(),
|
|
|
+ "argslen"
|
|
|
+ );
|
|
|
+
|
|
|
+ let nomatch = self.context.append_basic_block(function, "nomatch");
|
|
|
+
|
|
|
+ self.builder.position_at_end(&nomatch);
|
|
|
+
|
|
|
+ self.builder.build_unreachable();
|
|
|
+
|
|
|
+ let mut cases = Vec::new();
|
|
|
+
|
|
|
+ for (i, f) in functions.iter().enumerate() {
|
|
|
+ match &f.visibility {
|
|
|
+ ast::Visibility::Internal(_) | ast::Visibility::Private(_) => {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ _ => (),
|
|
|
+ }
|
|
|
+
|
|
|
+ if f.fallback {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ let res = keccak256(f.signature.as_bytes());
|
|
|
+
|
|
|
+ let bb = self.context.append_basic_block(function, "");
|
|
|
+ let id = u32::from_le_bytes([res[0], res[1], res[2], res[3]]);
|
|
|
+
|
|
|
+ self.builder.position_at_end(&bb);
|
|
|
+
|
|
|
+ let mut args = Vec::new();
|
|
|
+
|
|
|
+ // insert abi decode
|
|
|
+ runtime.abi_decode(&self, function, &mut args, argsdata, argslen, f);
|
|
|
+
|
|
|
+ let ret = self.builder.build_call(
|
|
|
+ self.functions[i].value_ref,
|
|
|
+ &args,
|
|
|
+ "").try_as_basic_value().left();
|
|
|
+
|
|
|
+ if f.returns.is_empty() {
|
|
|
+ // return ABI of length 0
|
|
|
+ runtime.return_empty_abi(&self);
|
|
|
+ } else if self.functions[i].wasm_return {
|
|
|
+ let (data, length) = runtime.abi_encode(&self, &[ ret.unwrap() ], &f);
|
|
|
+
|
|
|
+ runtime.return_abi(&self, data, length);
|
|
|
+ } else {
|
|
|
+ // FIXME: abi encode all the arguments
|
|
|
+ unimplemented!();
|
|
|
+ }
|
|
|
+
|
|
|
+ cases.push((self.context.i32_type().const_int(id as u64, false), bb));
|
|
|
+ }
|
|
|
+
|
|
|
+ self.builder.position_at_end(&switch_block);
|
|
|
+
|
|
|
+ let mut c = Vec::new();
|
|
|
+
|
|
|
+ for (id, bb) in cases.iter() {
|
|
|
+ c.push((*id, bb));
|
|
|
+ }
|
|
|
+
|
|
|
+ //let c = cases.into_iter().map(|(id, bb)| (id, &bb)).collect();
|
|
|
+
|
|
|
+ self.builder.build_switch(
|
|
|
+ fid.into_int_value(), &nomatch,
|
|
|
+ &c);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
impl ast::ElementaryTypeName {
|