|
|
@@ -31,25 +31,26 @@ lazy_static::lazy_static! {
|
|
|
}
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
-struct Variable {
|
|
|
- value: BasicValueEnum,
|
|
|
+struct Variable<'a> {
|
|
|
+ value: BasicValueEnum<'a>,
|
|
|
stack: bool,
|
|
|
}
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
-struct Function {
|
|
|
- value_ref: FunctionValue,
|
|
|
+struct Function<'a> {
|
|
|
+ value_ref: FunctionValue<'a>,
|
|
|
wasm_return: bool,
|
|
|
}
|
|
|
|
|
|
pub struct Contract<'a> {
|
|
|
pub name: String,
|
|
|
- pub module: Module,
|
|
|
+ pub module: Module<'a>,
|
|
|
+ builder: Builder<'a>,
|
|
|
+ context: &'a Context,
|
|
|
target: Target,
|
|
|
- context: Context,
|
|
|
ns: &'a resolver::Contract,
|
|
|
- functions: Vec<Function>,
|
|
|
- externals: HashMap<String, FunctionValue>,
|
|
|
+ functions: Vec<Function<'a>>,
|
|
|
+ externals: HashMap<String, FunctionValue<'a>>,
|
|
|
}
|
|
|
|
|
|
impl<'a> Contract<'a> {
|
|
|
@@ -82,20 +83,23 @@ impl<'a> Contract<'a> {
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
- pub fn new(contract: &'a resolver::Contract, filename: &str) -> Self {
|
|
|
+ pub fn new(context: &'a Context, contract: &'a resolver::Contract, filename: &'a str) -> Self {
|
|
|
lazy_static::initialize(&LLVM_INIT);
|
|
|
|
|
|
let target = Target::from_triple(WASMTRIPLE).unwrap();
|
|
|
- let context = Context::create();
|
|
|
let module = context.create_module(&contract.name);
|
|
|
+
|
|
|
module.set_target(&target);
|
|
|
module.set_source_file_name(filename);
|
|
|
|
|
|
- let builder = context.create_builder();
|
|
|
+ // stdlib
|
|
|
+ let intr = load_stdlib(&context);
|
|
|
+ module.link_in_module(intr).unwrap();
|
|
|
|
|
|
let mut e = Contract {
|
|
|
name: contract.name.to_owned(),
|
|
|
module: module,
|
|
|
+ builder: context.create_builder(),
|
|
|
target: target,
|
|
|
context: context,
|
|
|
ns: contract,
|
|
|
@@ -103,21 +107,15 @@ impl<'a> Contract<'a> {
|
|
|
externals: HashMap::new(),
|
|
|
};
|
|
|
|
|
|
- // stdlib
|
|
|
- let intr = load_stdlib(&e.context);
|
|
|
-
|
|
|
- e.module.link_in_module(intr).unwrap();
|
|
|
-
|
|
|
// externals
|
|
|
e.declare_externals();
|
|
|
|
|
|
for func in &contract.functions {
|
|
|
- let f = e.emit_func(func, &builder);
|
|
|
- e.functions.push(f);
|
|
|
+ e.emit_func(func);
|
|
|
}
|
|
|
|
|
|
- e.emit_constructor_dispatch(contract, &builder);
|
|
|
- e.emit_function_dispatch(contract, &builder);
|
|
|
+ e.emit_constructor_dispatch(contract);
|
|
|
+ e.emit_function_dispatch(contract);
|
|
|
|
|
|
e
|
|
|
}
|
|
|
@@ -140,10 +138,9 @@ impl<'a> Contract<'a> {
|
|
|
|
|
|
fn expression(
|
|
|
&self,
|
|
|
- builder: &Builder,
|
|
|
e: &cfg::Expression,
|
|
|
- vartab: &Vec<Variable>,
|
|
|
- ) -> IntValue {
|
|
|
+ vartab: &Vec<Variable<'a>>,
|
|
|
+ ) -> IntValue<'a> {
|
|
|
match e {
|
|
|
cfg::Expression::NumberLiteral(bits, n) => {
|
|
|
let ty = self.context.custom_width_int_type(*bits as _);
|
|
|
@@ -152,77 +149,77 @@ impl<'a> Contract<'a> {
|
|
|
ty.const_int_from_string(&s, StringRadix::Decimal).unwrap()
|
|
|
}
|
|
|
cfg::Expression::Add(l, r) => {
|
|
|
- let left = self.expression(builder, l, vartab);
|
|
|
- let right = self.expression(builder, r, vartab);
|
|
|
+ let left = self.expression(l, vartab);
|
|
|
+ let right = self.expression(r, vartab);
|
|
|
|
|
|
- builder.build_int_add(left, right, "")
|
|
|
+ self.builder.build_int_add(left, right, "")
|
|
|
}
|
|
|
cfg::Expression::Subtract(l, r) => {
|
|
|
- let left = self.expression(builder, l, vartab);
|
|
|
- let right = self.expression(builder, r, vartab);
|
|
|
+ let left = self.expression(l, vartab);
|
|
|
+ let right = self.expression(r, vartab);
|
|
|
|
|
|
- builder.build_int_sub(left, right, "")
|
|
|
+ self.builder.build_int_sub(left, right, "")
|
|
|
}
|
|
|
cfg::Expression::Multiply(l, r) => {
|
|
|
- let left = self.expression(builder, l, vartab);
|
|
|
- let right = self.expression(builder, r, vartab);
|
|
|
+ let left = self.expression(l, vartab);
|
|
|
+ let right = self.expression(r, vartab);
|
|
|
|
|
|
- builder.build_int_mul(left, right, "")
|
|
|
+ self.builder.build_int_mul(left, right, "")
|
|
|
}
|
|
|
cfg::Expression::UDivide(l, r) => {
|
|
|
- let left = self.expression(builder, l, vartab);
|
|
|
- let right = self.expression(builder, r, vartab);
|
|
|
+ let left = self.expression(l, vartab);
|
|
|
+ let right = self.expression(r, vartab);
|
|
|
|
|
|
- builder.build_int_unsigned_div(left, right, "")
|
|
|
+ self.builder.build_int_unsigned_div(left, right, "")
|
|
|
}
|
|
|
cfg::Expression::SDivide(l, r) => {
|
|
|
- let left = self.expression(builder, l, vartab);
|
|
|
- let right = self.expression(builder, r, vartab);
|
|
|
+ let left = self.expression(l, vartab);
|
|
|
+ let right = self.expression(r, vartab);
|
|
|
|
|
|
- builder.build_int_signed_div(left, right, "")
|
|
|
+ self.builder.build_int_signed_div(left, right, "")
|
|
|
}
|
|
|
cfg::Expression::Equal(l, r) => {
|
|
|
- let left = self.expression(builder, l, vartab);
|
|
|
- let right = self.expression(builder, r, vartab);
|
|
|
+ let left = self.expression(l, vartab);
|
|
|
+ let right = self.expression(r, vartab);
|
|
|
|
|
|
- builder.build_int_compare(IntPredicate::EQ, left, right, "")
|
|
|
+ self.builder.build_int_compare(IntPredicate::EQ, left, right, "")
|
|
|
}
|
|
|
cfg::Expression::More(l, r) => {
|
|
|
- let left = self.expression(builder, l, vartab);
|
|
|
- let right = self.expression(builder, r, vartab);
|
|
|
+ let left = self.expression(l, vartab);
|
|
|
+ let right = self.expression(r, vartab);
|
|
|
|
|
|
- builder.build_int_compare(IntPredicate::SGT, left, right, "")
|
|
|
+ self.builder.build_int_compare(IntPredicate::SGT, left, right, "")
|
|
|
}
|
|
|
cfg::Expression::Less(l, r) => {
|
|
|
- let left = self.expression(builder, l, vartab);
|
|
|
- let right = self.expression(builder, r, vartab);
|
|
|
+ let left = self.expression(l, vartab);
|
|
|
+ let right = self.expression(r, vartab);
|
|
|
|
|
|
- builder.build_int_compare(IntPredicate::SLT, left, right, "")
|
|
|
+ self.builder.build_int_compare(IntPredicate::SLT, left, right, "")
|
|
|
}
|
|
|
cfg::Expression::Variable(_, s) => {
|
|
|
if vartab[*s].stack {
|
|
|
- builder.build_load(vartab[*s].value.into_pointer_value(), "").into_int_value()
|
|
|
+ self.builder.build_load(vartab[*s].value.into_pointer_value(), "").into_int_value()
|
|
|
} else {
|
|
|
vartab[*s].value.into_int_value()
|
|
|
}
|
|
|
}
|
|
|
cfg::Expression::ZeroExt(t, e) => {
|
|
|
- let e = self.expression(builder, e, vartab);
|
|
|
+ let e = self.expression(e, vartab);
|
|
|
let ty = t.LLVMType(self.ns, &self.context);
|
|
|
|
|
|
- builder.build_int_z_extend(e, ty, "")
|
|
|
+ self.builder.build_int_z_extend(e, ty, "")
|
|
|
}
|
|
|
cfg::Expression::SignExt(t, e) => {
|
|
|
- let e = self.expression(builder, e, vartab);
|
|
|
+ let e = self.expression(e, vartab);
|
|
|
let ty = t.LLVMType(self.ns, &self.context);
|
|
|
|
|
|
- builder.build_int_s_extend(e, ty, "")
|
|
|
+ self.builder.build_int_s_extend(e, ty, "")
|
|
|
}
|
|
|
cfg::Expression::Trunc(t, e) => {
|
|
|
- let e = self.expression(builder, e, vartab);
|
|
|
+ let e = self.expression(e, vartab);
|
|
|
let ty = t.LLVMType(self.ns, &self.context);
|
|
|
|
|
|
- builder.build_int_truncate(e, ty, "")
|
|
|
+ self.builder.build_int_truncate(e, ty, "")
|
|
|
}
|
|
|
_ => {
|
|
|
panic!("expression not implemented");
|
|
|
@@ -230,18 +227,18 @@ impl<'a> Contract<'a> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fn emit_constructor_dispatch(&self, contract: &resolver::Contract, builder: &Builder) {
|
|
|
+ fn emit_constructor_dispatch(&self, contract: &resolver::Contract) {
|
|
|
// create start function
|
|
|
let ret = self.context.void_type();
|
|
|
let ftype = ret.fn_type(&[self.context.i32_type().ptr_type(AddressSpace::Generic).into()], false);
|
|
|
let function = self.module.add_function("constructor", ftype, None);
|
|
|
|
|
|
- let entry = self.context.append_basic_block(&function, "entry");
|
|
|
+ let entry = self.context.append_basic_block(function, "entry");
|
|
|
|
|
|
- builder.position_at_end(&entry);
|
|
|
+ self.builder.position_at_end(&entry);
|
|
|
|
|
|
// init our heap
|
|
|
- builder.build_call(
|
|
|
+ self.builder.build_call(
|
|
|
self.module.get_function("__init_heap").unwrap(),
|
|
|
&[],
|
|
|
"");
|
|
|
@@ -250,84 +247,83 @@ impl<'a> Contract<'a> {
|
|
|
let mut args = Vec::new();
|
|
|
|
|
|
let arg = function.get_first_param().unwrap().into_pointer_value();
|
|
|
- let length = builder.build_load(arg, "length");
|
|
|
+ let length = self.builder.build_load(arg, "length");
|
|
|
|
|
|
// step over length
|
|
|
let args_ptr = unsafe {
|
|
|
- builder.build_gep(arg,
|
|
|
+ self.builder.build_gep(arg,
|
|
|
&[self.context.i32_type().const_int(1, false).into()],
|
|
|
"args_ptr")
|
|
|
};
|
|
|
|
|
|
// insert abi decode
|
|
|
self.emit_abi_decode(
|
|
|
- builder,
|
|
|
- &function,
|
|
|
+ function,
|
|
|
&mut args,
|
|
|
args_ptr,
|
|
|
length.into_int_value(),
|
|
|
&contract.functions[n],
|
|
|
);
|
|
|
|
|
|
- builder.build_call(self.functions[n].value_ref, &args, "");
|
|
|
+ self.builder.build_call(self.functions[n].value_ref, &args, "");
|
|
|
}
|
|
|
|
|
|
- builder.build_return(None);
|
|
|
+ self.builder.build_return(None);
|
|
|
}
|
|
|
|
|
|
- fn emit_function_dispatch(&self, contract: &resolver::Contract, builder: &Builder) {
|
|
|
+ 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 = self.context.append_basic_block(&function, "fallback");
|
|
|
- let switch = self.context.append_basic_block(&function, "switch");
|
|
|
+ let entry = self.context.append_basic_block(function, "entry");
|
|
|
+ let fallback = self.context.append_basic_block(function, "fallback");
|
|
|
+ let switch = self.context.append_basic_block(function, "switch");
|
|
|
|
|
|
- builder.position_at_end(&entry);
|
|
|
+ self.builder.position_at_end(&entry);
|
|
|
|
|
|
let arg = function.get_first_param().unwrap().into_pointer_value();
|
|
|
- let length = builder.build_load(arg, "length").into_int_value();
|
|
|
+ let length = self.builder.build_load(arg, "length").into_int_value();
|
|
|
|
|
|
- let not_fallback = builder.build_int_compare(
|
|
|
+ let not_fallback = self.builder.build_int_compare(
|
|
|
IntPredicate::UGE,
|
|
|
length,
|
|
|
self.context.i32_type().const_int(4, false).into(),
|
|
|
"");
|
|
|
|
|
|
- builder.build_conditional_branch(not_fallback, &switch, &fallback);
|
|
|
+ self.builder.build_conditional_branch(not_fallback, &switch, &fallback);
|
|
|
|
|
|
- builder.position_at_end(&switch);
|
|
|
+ self.builder.position_at_end(&switch);
|
|
|
|
|
|
let fid_ptr = unsafe {
|
|
|
- builder.build_gep(
|
|
|
+ self.builder.build_gep(
|
|
|
arg,
|
|
|
&[self.context.i32_type().const_int(1, false).into()],
|
|
|
"fid_ptr")
|
|
|
};
|
|
|
|
|
|
- let fid = builder.build_load(fid_ptr, "fid");
|
|
|
+ let fid = self.builder.build_load(fid_ptr, "fid");
|
|
|
|
|
|
// pointer/size for abi decoding
|
|
|
let args_ptr = unsafe {
|
|
|
- builder.build_gep(
|
|
|
+ self.builder.build_gep(
|
|
|
arg,
|
|
|
&[self.context.i32_type().const_int(2, false).into()],
|
|
|
"fid_ptr")
|
|
|
};
|
|
|
|
|
|
- let args_len = builder.build_int_sub(
|
|
|
+ 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");
|
|
|
+ let nomatch = self.context.append_basic_block(function, "nomatch");
|
|
|
|
|
|
- builder.position_at_end(&nomatch);
|
|
|
+ self.builder.position_at_end(&nomatch);
|
|
|
|
|
|
- builder.build_unreachable();
|
|
|
+ self.builder.build_unreachable();
|
|
|
|
|
|
let mut cases = Vec::new();
|
|
|
|
|
|
@@ -346,17 +342,17 @@ impl<'a> Contract<'a> {
|
|
|
|
|
|
let res = keccak256(f.sig.as_bytes());
|
|
|
|
|
|
- let bb = self.context.append_basic_block(&function, "");
|
|
|
+ let bb = self.context.append_basic_block(function, "");
|
|
|
let id = u32::from_le_bytes([res[0], res[1], res[2], res[3]]);
|
|
|
|
|
|
- builder.position_at_end(&bb);
|
|
|
+ self.builder.position_at_end(&bb);
|
|
|
|
|
|
let mut args = Vec::new();
|
|
|
|
|
|
// insert abi decode
|
|
|
- self.emit_abi_decode(builder, &function, &mut args, args_ptr, args_len, f);
|
|
|
+ self.emit_abi_decode(function, &mut args, args_ptr, args_len, f);
|
|
|
|
|
|
- let ret = builder.build_call(
|
|
|
+ let ret = self.builder.build_call(
|
|
|
self.functions[i].value_ref,
|
|
|
&args,
|
|
|
"").try_as_basic_value().left();
|
|
|
@@ -365,37 +361,37 @@ impl<'a> Contract<'a> {
|
|
|
// return ABI of length 0
|
|
|
|
|
|
// malloc 4 bytes
|
|
|
- let dest = builder.build_call(
|
|
|
+ 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();
|
|
|
|
|
|
- builder.build_store(
|
|
|
- builder.build_pointer_cast(dest,
|
|
|
+ self.builder.build_store(
|
|
|
+ self.builder.build_pointer_cast(dest,
|
|
|
self.context.i32_type().ptr_type(AddressSpace::Generic),
|
|
|
""),
|
|
|
self.context.i32_type().const_zero());
|
|
|
|
|
|
- builder.build_return(Some(&dest));
|
|
|
+ self.builder.build_return(Some(&dest));
|
|
|
} else if self.functions[i].wasm_return {
|
|
|
// malloc 36 bytes
|
|
|
- let dest = builder.build_call(
|
|
|
+ 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
|
|
|
- builder.build_store(
|
|
|
- builder.build_pointer_cast(dest,
|
|
|
+ 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 {
|
|
|
- builder.build_gep(
|
|
|
+ self.builder.build_gep(
|
|
|
dest,
|
|
|
&[ self.context.i32_type().const_int(4, false).into()],
|
|
|
"abi_ptr")
|
|
|
@@ -408,9 +404,9 @@ impl<'a> Contract<'a> {
|
|
|
resolver::TypeName::Noreturn => unreachable!(),
|
|
|
};
|
|
|
|
|
|
- self.emit_abi_encode_single_val(builder, &ty, abi_ptr, ret.unwrap().into_int_value());
|
|
|
+ self.emit_abi_encode_single_val(&ty, abi_ptr, ret.unwrap().into_int_value());
|
|
|
|
|
|
- builder.build_return(Some(&dest));
|
|
|
+ self.builder.build_return(Some(&dest));
|
|
|
} else {
|
|
|
// FIXME: abi encode all the arguments
|
|
|
}
|
|
|
@@ -418,7 +414,7 @@ impl<'a> Contract<'a> {
|
|
|
cases.push((self.context.i32_type().const_int(id as u64, false), bb));
|
|
|
}
|
|
|
|
|
|
- builder.position_at_end(&switch);
|
|
|
+ self.builder.position_at_end(&switch);
|
|
|
|
|
|
let mut c = Vec::new();
|
|
|
|
|
|
@@ -428,33 +424,32 @@ impl<'a> Contract<'a> {
|
|
|
|
|
|
//let c = cases.into_iter().map(|(id, bb)| (id, &bb)).collect();
|
|
|
|
|
|
- builder.build_switch(
|
|
|
+ self.builder.build_switch(
|
|
|
fid.into_int_value(), &nomatch,
|
|
|
&c);
|
|
|
|
|
|
// FIXME: emit code for public contract variables
|
|
|
|
|
|
// emit fallback code
|
|
|
- builder.position_at_end(&fallback);
|
|
|
+ self.builder.position_at_end(&fallback);
|
|
|
|
|
|
match contract.fallback_function() {
|
|
|
Some(n) => {
|
|
|
- builder.build_call(
|
|
|
+ self.builder.build_call(
|
|
|
self.functions[n].value_ref,
|
|
|
&[],
|
|
|
"");
|
|
|
|
|
|
- builder.build_return(None);
|
|
|
+ self.builder.build_return(None);
|
|
|
}
|
|
|
None => {
|
|
|
- builder.build_unreachable();
|
|
|
+ self.builder.build_unreachable();
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
|
|
|
fn emit_abi_encode_single_val(
|
|
|
&self,
|
|
|
- builder: &Builder,
|
|
|
ty: &ast::ElementaryTypeName,
|
|
|
dest: PointerValue,
|
|
|
val: IntValue,
|
|
|
@@ -462,36 +457,36 @@ impl<'a> Contract<'a> {
|
|
|
match ty {
|
|
|
ast::ElementaryTypeName::Bool => {
|
|
|
// first clear
|
|
|
- let dest8 = builder.build_pointer_cast(dest,
|
|
|
+ let dest8 = self.builder.build_pointer_cast(dest,
|
|
|
self.context.i8_type().ptr_type(AddressSpace::Generic),
|
|
|
"destvoid");
|
|
|
|
|
|
- builder.build_call(
|
|
|
+ self.builder.build_call(
|
|
|
self.module.get_function("__bzero8").unwrap(),
|
|
|
&[ dest8.into(),
|
|
|
self.context.i32_type().const_int(4, false).into() ],
|
|
|
"");
|
|
|
|
|
|
- let value = builder.build_select(val,
|
|
|
+ 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 {
|
|
|
- builder.build_gep(
|
|
|
+ self.builder.build_gep(
|
|
|
dest8,
|
|
|
&[ self.context.i32_type().const_int(31, false).into() ],
|
|
|
"")
|
|
|
};
|
|
|
|
|
|
- builder.build_store(dest, value);
|
|
|
+ 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 = builder.build_int_compare(IntPredicate::SLT,
|
|
|
+ let negative = self.builder.build_int_compare(IntPredicate::SLT,
|
|
|
val, self.context.i8_type().const_zero(), "neg");
|
|
|
|
|
|
- builder.build_select(negative,
|
|
|
+ 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()
|
|
|
@@ -499,33 +494,33 @@ impl<'a> Contract<'a> {
|
|
|
self.context.i64_type().const_zero()
|
|
|
};
|
|
|
|
|
|
- let dest8 = builder.build_pointer_cast(dest,
|
|
|
+ let dest8 = self.builder.build_pointer_cast(dest,
|
|
|
self.context.i8_type().ptr_type(AddressSpace::Generic),
|
|
|
"destvoid");
|
|
|
|
|
|
- builder.build_call(
|
|
|
+ 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 {
|
|
|
- builder.build_gep(
|
|
|
+ self.builder.build_gep(
|
|
|
dest8,
|
|
|
&[ self.context.i32_type().const_int(31, false).into() ],
|
|
|
"")
|
|
|
};
|
|
|
|
|
|
- builder.build_store(dest, val);
|
|
|
+ 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 = builder.build_int_compare(IntPredicate::SLT,
|
|
|
+ let negative = self.builder.build_int_compare(IntPredicate::SLT,
|
|
|
val, self.context.i8_type().const_zero(), "neg");
|
|
|
|
|
|
- builder.build_select(negative,
|
|
|
+ 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()
|
|
|
@@ -533,11 +528,11 @@ impl<'a> Contract<'a> {
|
|
|
self.context.i64_type().const_zero()
|
|
|
};
|
|
|
|
|
|
- let dest8 = builder.build_pointer_cast(dest,
|
|
|
+ let dest8 = self.builder.build_pointer_cast(dest,
|
|
|
self.context.i8_type().ptr_type(AddressSpace::Generic),
|
|
|
"destvoid");
|
|
|
|
|
|
- builder.build_call(
|
|
|
+ self.builder.build_call(
|
|
|
self.module.get_function("__memset8").unwrap(),
|
|
|
&[ dest8.into(), signval.into(),
|
|
|
self.context.i32_type().const_int(4, false).into() ],
|
|
|
@@ -549,19 +544,19 @@ impl<'a> Contract<'a> {
|
|
|
let int_type = self.context.custom_width_int_type(*n as u32);
|
|
|
let type_size = int_type.size_of();
|
|
|
|
|
|
- let store = builder.build_alloca(int_type, "stack");
|
|
|
+ let store = self.builder.build_alloca(int_type, "stack");
|
|
|
|
|
|
- builder.build_store(store, val);
|
|
|
+ self.builder.build_store(store, val);
|
|
|
|
|
|
- builder.build_call(
|
|
|
+ self.builder.build_call(
|
|
|
self.module.get_function("__leNtobe32").unwrap(),
|
|
|
- &[ builder.build_pointer_cast(store,
|
|
|
+ &[ self.builder.build_pointer_cast(store,
|
|
|
self.context.i8_type().ptr_type(AddressSpace::Generic),
|
|
|
"destvoid").into(),
|
|
|
- builder.build_pointer_cast(dest,
|
|
|
+ self.builder.build_pointer_cast(dest,
|
|
|
self.context.i8_type().ptr_type(AddressSpace::Generic),
|
|
|
"destvoid").into(),
|
|
|
- builder.build_int_truncate(type_size,
|
|
|
+ self.builder.build_int_truncate(type_size,
|
|
|
self.context.i32_type(), "").into()
|
|
|
],
|
|
|
"");
|
|
|
@@ -572,10 +567,9 @@ impl<'a> Contract<'a> {
|
|
|
|
|
|
fn emit_abi_decode(
|
|
|
&self,
|
|
|
- builder: &Builder,
|
|
|
- function: &FunctionValue,
|
|
|
- args: &mut Vec<BasicValueEnum>,
|
|
|
- data: PointerValue,
|
|
|
+ function: FunctionValue,
|
|
|
+ args: &mut Vec<BasicValueEnum<'a>>,
|
|
|
+ data: PointerValue<'a>,
|
|
|
length: IntValue,
|
|
|
spec: &resolver::FunctionDecl,
|
|
|
) {
|
|
|
@@ -583,13 +577,13 @@ impl<'a> Contract<'a> {
|
|
|
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 = builder.build_int_compare(IntPredicate::EQ, 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");
|
|
|
|
|
|
- builder.build_conditional_branch(is_ok, &decode_block, &wrong_length_block);
|
|
|
+ self.builder.build_conditional_branch(is_ok, &decode_block, &wrong_length_block);
|
|
|
|
|
|
- builder.position_at_end(&decode_block);
|
|
|
+ self.builder.position_at_end(&decode_block);
|
|
|
|
|
|
for arg in &spec.params {
|
|
|
let ty = match &arg.ty {
|
|
|
@@ -603,52 +597,52 @@ impl<'a> Contract<'a> {
|
|
|
// 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 = builder.build_pointer_cast(data,
|
|
|
+ let bool_ptr = self.builder.build_pointer_cast(data,
|
|
|
self.context.i64_type().ptr_type(AddressSpace::Generic), "");
|
|
|
|
|
|
let bool_ptr = unsafe {
|
|
|
- builder.build_gep(bool_ptr,
|
|
|
+ self.builder.build_gep(bool_ptr,
|
|
|
&[ self.context.i32_type().const_int(3, false) ],
|
|
|
"bool_ptr")
|
|
|
};
|
|
|
|
|
|
- builder.build_int_compare(IntPredicate::EQ,
|
|
|
- builder.build_load(bool_ptr, "abi_bool").into_int_value(),
|
|
|
+ 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 = builder.build_pointer_cast(data,
|
|
|
+ let int8_ptr = self.builder.build_pointer_cast(data,
|
|
|
self.context.i8_type().ptr_type(AddressSpace::Generic), "");
|
|
|
|
|
|
let int8_ptr = unsafe {
|
|
|
- builder.build_gep(int8_ptr,
|
|
|
+ self.builder.build_gep(int8_ptr,
|
|
|
&[ self.context.i32_type().const_int(31, false) ],
|
|
|
"bool_ptr")
|
|
|
};
|
|
|
|
|
|
- builder.build_load(int8_ptr, "abi_int8")
|
|
|
+ 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 = builder.build_alloca(int_type, "stack");
|
|
|
+ let store = self.builder.build_alloca(int_type, "stack");
|
|
|
|
|
|
- builder.build_call(
|
|
|
+ self.builder.build_call(
|
|
|
self.module.get_function("__be32toleN").unwrap(),
|
|
|
&[
|
|
|
- builder.build_pointer_cast(data,
|
|
|
+ self.builder.build_pointer_cast(data,
|
|
|
self.context.i8_type().ptr_type(AddressSpace::Generic), "").into(),
|
|
|
- builder.build_pointer_cast(store,
|
|
|
+ self.builder.build_pointer_cast(store,
|
|
|
self.context.i8_type().ptr_type(AddressSpace::Generic), "").into(),
|
|
|
- builder.build_int_truncate(type_size,
|
|
|
+ self.builder.build_int_truncate(type_size,
|
|
|
self.context.i32_type(), "size").into()
|
|
|
],
|
|
|
""
|
|
|
);
|
|
|
|
|
|
if *n <= 64 {
|
|
|
- builder.build_load(store, &format!("abi_int{}", *n))
|
|
|
+ self.builder.build_load(store, &format!("abi_int{}", *n))
|
|
|
} else {
|
|
|
store.into()
|
|
|
}
|
|
|
@@ -657,20 +651,20 @@ impl<'a> Contract<'a> {
|
|
|
});
|
|
|
|
|
|
data = unsafe {
|
|
|
- builder.build_gep(data,
|
|
|
+ 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
|
|
|
- builder.position_at_end(&wrong_length_block);
|
|
|
- builder.build_unreachable();
|
|
|
+ self.builder.position_at_end(&wrong_length_block);
|
|
|
+ self.builder.build_unreachable();
|
|
|
|
|
|
- builder.position_at_end(&decode_block);
|
|
|
+ self.builder.position_at_end(&decode_block);
|
|
|
}
|
|
|
|
|
|
- fn emit_func(&self, f: &resolver::FunctionDecl, builder: &Builder) -> Function {
|
|
|
+ fn emit_func(&mut self, f: &resolver::FunctionDecl) {
|
|
|
let mut args: Vec<BasicTypeEnum> = Vec::new();
|
|
|
let mut wasm_return = false;
|
|
|
|
|
|
@@ -683,6 +677,8 @@ impl<'a> Contract<'a> {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ // FIXME: Substrate can have multiple overloaded constructors
|
|
|
+ // FIXME: Solidity can have multiple overloaded functions by the same name
|
|
|
let fname = if f.constructor {
|
|
|
"sol::__constructor".to_string()
|
|
|
} else if let Some(ref name) = f.name {
|
|
|
@@ -695,7 +691,7 @@ impl<'a> Contract<'a> {
|
|
|
wasm_return = true;
|
|
|
f.returns[0].ty.LLVMType(self.ns, &self.context).fn_type(&args, false)
|
|
|
} else {
|
|
|
- // add return
|
|
|
+ // add return values
|
|
|
for p in &f.returns {
|
|
|
args.push(p.ty.LLVMType(self.ns, &self.context).ptr_type(AddressSpace::Generic).into());
|
|
|
}
|
|
|
@@ -710,14 +706,14 @@ impl<'a> Contract<'a> {
|
|
|
};
|
|
|
|
|
|
// recurse through basic blocks
|
|
|
- struct BasicBlock {
|
|
|
+ struct BasicBlock<'a> {
|
|
|
bb: inkwell::basic_block::BasicBlock,
|
|
|
- phis: HashMap<usize, PhiValue>,
|
|
|
+ phis: HashMap<usize, PhiValue<'a>>,
|
|
|
}
|
|
|
|
|
|
- struct Work {
|
|
|
+ struct Work<'b> {
|
|
|
bb_no: usize,
|
|
|
- vars: Vec<Variable>,
|
|
|
+ vars: Vec<Variable<'b>>,
|
|
|
}
|
|
|
|
|
|
let mut blocks: HashMap<usize, BasicBlock> = HashMap::new();
|
|
|
@@ -726,16 +722,16 @@ impl<'a> Contract<'a> {
|
|
|
let cfg_bb: &cfg::BasicBlock = &cfg.bb[bb_no];
|
|
|
let mut phis = HashMap::new();
|
|
|
|
|
|
- let bb = self.context.append_basic_block(&function, &cfg_bb.name);
|
|
|
+ let bb = self.context.append_basic_block(function, &cfg_bb.name);
|
|
|
|
|
|
- builder.position_at_end(&bb);
|
|
|
+ self.builder.position_at_end(&bb);
|
|
|
|
|
|
if let Some(ref cfg_phis) = cfg_bb.phis {
|
|
|
for v in cfg_phis {
|
|
|
// FIXME: no phis needed for stack based vars
|
|
|
let ty = cfg.vars[*v].ty.LLVMType(self.ns, &self.context);
|
|
|
|
|
|
- phis.insert(*v, builder.build_phi(ty, &cfg.vars[*v].id.name).into());
|
|
|
+ phis.insert(*v, self.builder.build_phi(ty, &cfg.vars[*v].id.name).into());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -759,7 +755,7 @@ impl<'a> Contract<'a> {
|
|
|
}
|
|
|
cfg::Storage::Local | cfg::Storage::Contract(_) => {
|
|
|
vars.push(Variable {
|
|
|
- value: builder.build_alloca(
|
|
|
+ value: self.builder.build_alloca(
|
|
|
v.ty.LLVMType(self.ns, &self.context), &v.id.name).into(),
|
|
|
stack: true,
|
|
|
});
|
|
|
@@ -785,7 +781,7 @@ impl<'a> Contract<'a> {
|
|
|
let ll_bb = {
|
|
|
let bb = blocks.get(&w.bb_no).unwrap();
|
|
|
|
|
|
- builder.position_at_end(&bb.bb);
|
|
|
+ self.builder.position_at_end(&bb.bb);
|
|
|
|
|
|
for (v, phi) in bb.phis.iter() {
|
|
|
w.vars[*v].value = (*phi).as_basic_value();
|
|
|
@@ -800,26 +796,26 @@ impl<'a> Contract<'a> {
|
|
|
w.vars[*res].value = function.get_nth_param(*arg as u32).unwrap().into();
|
|
|
}
|
|
|
cfg::Instr::Return { value } if value.is_empty() => {
|
|
|
- builder.build_return(None);
|
|
|
+ self.builder.build_return(None);
|
|
|
},
|
|
|
cfg::Instr::Return { value } if wasm_return => {
|
|
|
- let retval = self.expression(builder, &value[0], &w.vars);
|
|
|
- builder.build_return(Some(&retval));
|
|
|
+ let retval = self.expression(&value[0], &w.vars);
|
|
|
+ self.builder.build_return(Some(&retval));
|
|
|
}
|
|
|
cfg::Instr::Return { value } => {
|
|
|
let returns_offset = f.params.len();
|
|
|
for (i, val) in value.iter().enumerate() {
|
|
|
let arg = function.get_nth_param((returns_offset + i) as u32).unwrap();
|
|
|
- let retval = self.expression(builder, val, &w.vars);
|
|
|
+ let retval = self.expression(val, &w.vars);
|
|
|
|
|
|
- builder.build_store(arg.into_pointer_value(), retval);
|
|
|
+ self.builder.build_store(arg.into_pointer_value(), retval);
|
|
|
}
|
|
|
- builder.build_return(None);
|
|
|
+ self.builder.build_return(None);
|
|
|
}
|
|
|
cfg::Instr::Set { res, expr } => {
|
|
|
- let value_ref = self.expression(builder, expr, &w.vars);
|
|
|
+ let value_ref = self.expression(expr, &w.vars);
|
|
|
if w.vars[*res].stack {
|
|
|
- builder.build_store(w.vars[*res].value.into_pointer_value(), value_ref);
|
|
|
+ self.builder.build_store(w.vars[*res].value.into_pointer_value(), value_ref);
|
|
|
} else {
|
|
|
w.vars[*res].value = value_ref.into();
|
|
|
}
|
|
|
@@ -839,15 +835,15 @@ impl<'a> Contract<'a> {
|
|
|
phi.add_incoming(&[ (&w.vars[*v].value, &ll_bb) ]);
|
|
|
}
|
|
|
|
|
|
- builder.position_at_end(&ll_bb);
|
|
|
- builder.build_unconditional_branch(&bb.bb);
|
|
|
+ self.builder.position_at_end(&ll_bb);
|
|
|
+ self.builder.build_unconditional_branch(&bb.bb);
|
|
|
}
|
|
|
cfg::Instr::BranchCond {
|
|
|
cond,
|
|
|
true_,
|
|
|
false_,
|
|
|
} => {
|
|
|
- let cond = self.expression(builder, cond, &w.vars);
|
|
|
+ let cond = self.expression(cond, &w.vars);
|
|
|
|
|
|
let bb_true = {
|
|
|
if !blocks.contains_key(&true_) {
|
|
|
@@ -885,17 +881,17 @@ impl<'a> Contract<'a> {
|
|
|
bb.bb
|
|
|
};
|
|
|
|
|
|
- builder.position_at_end(&ll_bb);
|
|
|
- builder.build_conditional_branch(cond, &bb_true, &bb_false);
|
|
|
+ self.builder.position_at_end(&ll_bb);
|
|
|
+ self.builder.build_conditional_branch(cond, &bb_true, &bb_false);
|
|
|
}
|
|
|
cfg::Instr::GetStorage { local, storage } => {
|
|
|
let dest = w.vars[*local].value.into_pointer_value();
|
|
|
|
|
|
- builder.build_call(
|
|
|
+ self.builder.build_call(
|
|
|
self.externals["get_storage32"],
|
|
|
&[
|
|
|
self.context.i32_type().const_int(*storage as u64, false).into(),
|
|
|
- builder.build_pointer_cast(dest,
|
|
|
+ self.builder.build_pointer_cast(dest,
|
|
|
self.context.i8_type().ptr_type(AddressSpace::Generic), "").into(),
|
|
|
dest.get_type().size_of().const_cast(
|
|
|
self.context.i32_type(), false).into()
|
|
|
@@ -905,11 +901,11 @@ impl<'a> Contract<'a> {
|
|
|
cfg::Instr::SetStorage { local, storage } => {
|
|
|
let dest = w.vars[*local].value.into_pointer_value();
|
|
|
|
|
|
- builder.build_call(
|
|
|
+ self.builder.build_call(
|
|
|
self.externals["set_storage32"],
|
|
|
&[
|
|
|
self.context.i32_type().const_int(*storage as u64, false).into(),
|
|
|
- builder.build_pointer_cast(dest,
|
|
|
+ self.builder.build_pointer_cast(dest,
|
|
|
self.context.i8_type().ptr_type(AddressSpace::Generic), "").into(),
|
|
|
dest.get_type().size_of().const_cast(
|
|
|
self.context.i32_type(), false).into()
|
|
|
@@ -920,10 +916,10 @@ impl<'a> Contract<'a> {
|
|
|
let mut parms: Vec<BasicValueEnum> = Vec::new();
|
|
|
|
|
|
for a in args {
|
|
|
- parms.push(self.expression(builder, &a, &w.vars).into());
|
|
|
+ parms.push(self.expression(&a, &w.vars).into());
|
|
|
}
|
|
|
|
|
|
- let ret = builder.build_call(
|
|
|
+ let ret = self.builder.build_call(
|
|
|
self.functions[*func].value_ref,
|
|
|
&parms, "").try_as_basic_value().left().unwrap();
|
|
|
|
|
|
@@ -935,16 +931,16 @@ impl<'a> Contract<'a> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- Function {
|
|
|
+ self.functions.push(Function {
|
|
|
value_ref: function,
|
|
|
wasm_return,
|
|
|
- }
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl ast::ElementaryTypeName {
|
|
|
#[allow(non_snake_case)]
|
|
|
- fn LLVMType(&self, context: &Context) -> IntType {
|
|
|
+ fn LLVMType<'a>(&self, context: &'a Context) -> IntType<'a> {
|
|
|
match self {
|
|
|
ast::ElementaryTypeName::Bool => context.bool_type(),
|
|
|
ast::ElementaryTypeName::Int(n) |
|
|
|
@@ -971,7 +967,7 @@ impl ast::ElementaryTypeName {
|
|
|
|
|
|
impl resolver::TypeName {
|
|
|
#[allow(non_snake_case)]
|
|
|
- fn LLVMType(&self, ns: &resolver::Contract, context: &Context) -> IntType {
|
|
|
+ fn LLVMType<'a>(&self, ns: &resolver::Contract, context: &'a Context) -> IntType<'a> {
|
|
|
match self {
|
|
|
resolver::TypeName::Elementary(e) => e.LLVMType(context),
|
|
|
resolver::TypeName::Enum(n) => ns.enums[*n].ty.LLVMType(context),
|
|
|
@@ -993,5 +989,5 @@ static STDLIB_IR: &'static [u8] = include_bytes!("../../stdlib/stdlib.bc");
|
|
|
fn load_stdlib(context: &Context) -> Module {
|
|
|
let memory = MemoryBuffer::create_from_memory_range(STDLIB_IR, "stdlib");
|
|
|
|
|
|
- Module::parse_bitcode_from_buffer_in_context(&memory, context).unwrap()
|
|
|
+ Module::parse_bitcode_from_buffer(&memory, context).unwrap()
|
|
|
}
|