Ver Fonte

Factor out burrow target

Signed-off-by: Sean Young <sean@mess.org>
Sean Young há 6 anos atrás
pai
commit
7f7fb61d61
4 ficheiros alterados com 139 adições e 99 exclusões
  1. 117 0
      src/emit/burrow.rs
  2. 20 97
      src/emit/mod.rs
  3. 1 1
      src/main.rs
  4. 1 1
      src/test.rs

+ 117 - 0
src/emit/burrow.rs

@@ -0,0 +1,117 @@
+
+use resolver;
+
+use inkwell::types::BasicTypeEnum;
+use inkwell::context::Context;
+use inkwell::module::Linkage;
+use inkwell::AddressSpace;
+
+use super::{TargetRuntime, Contract};
+
+pub struct BurrowTarget {
+}
+
+impl BurrowTarget {
+    pub fn build<'a>(context: &'a Context, contract: &'a resolver::Contract, filename: &'a str) -> Contract<'a> {
+        let mut c = Contract::new(context, contract, filename);
+        let b = BurrowTarget{};
+
+        // externals
+        b.declare_externals(&mut c);
+
+        c.emit_functions(&b);
+    
+        b.emit_constructor_dispatch(&c);
+        c.emit_function_dispatch(contract);
+
+        c
+    }
+
+    fn declare_externals(&self, contract: &mut Contract) {
+        let ret = contract.context.void_type();
+        let args: Vec<BasicTypeEnum> = vec![
+            contract.context.i32_type().into(),
+            contract.context.i8_type().ptr_type(AddressSpace::Generic).into(),
+            contract.context.i32_type().into(),
+        ];
+
+        let ftype = ret.fn_type(&args, false);
+        let func = contract.module.add_function("get_storage32", ftype, Some(Linkage::External));
+        contract.externals.insert("get_storage32".to_owned(), func);
+
+        let func = contract.module.add_function("set_storage32", ftype, Some(Linkage::External));
+        contract.externals.insert("set_storage32".to_owned(), func);
+    }
+
+    fn emit_constructor_dispatch(&self, contract: &Contract) {
+        // create start function
+        let ret = contract.context.void_type();
+        let ftype = ret.fn_type(&[contract.context.i32_type().ptr_type(AddressSpace::Generic).into()], false);
+        let function = contract.module.add_function("constructor", ftype, None);
+
+        let entry = contract.context.append_basic_block(function, "entry");
+
+        contract.builder.position_at_end(&entry);
+
+        // init our heap
+        contract.builder.build_call(
+            contract.module.get_function("__init_heap").unwrap(),
+            &[],
+            "");
+
+        if let Some(con) = contract.ns.constructors.get(0) {
+            let mut args = Vec::new();
+
+            let arg = function.get_first_param().unwrap().into_pointer_value();
+            let length = contract.builder.build_load(arg, "length");
+
+            // step over length
+            let args_ptr = unsafe {
+                contract.builder.build_gep(arg,
+                    &[contract.context.i32_type().const_int(1, false).into()],
+                    "args_ptr")
+            };
+
+            // insert abi decode
+            contract.emit_abi_decode(
+                function,
+                &mut args,
+                args_ptr,
+                length.into_int_value(),
+                con,
+            );
+
+            contract.builder.build_call(contract.constructors[0].value_ref, &args, "");
+        }
+
+        contract.builder.build_return(None);
+    }
+}
+
+impl TargetRuntime for BurrowTarget {
+    fn set_storage<'a>(&self, contract: &'a Contract, slot: u32, dest: inkwell::values::PointerValue<'a>) {
+        contract.builder.build_call(
+            contract.externals["set_storage32"],
+            &[
+                contract.context.i32_type().const_int(slot as u64, false).into(),
+                contract.builder.build_pointer_cast(dest,
+                    contract.context.i8_type().ptr_type(AddressSpace::Generic), "").into(),
+                dest.get_type().size_of().const_cast(
+                    contract.context.i32_type(), false).into()
+            ],
+            "");
+    }
+
+    fn get_storage<'a>(&self, contract: &'a Contract, slot: u32, dest: inkwell::values::PointerValue<'a>) {
+        contract.builder.build_call(
+            contract.externals["get_storage32"],
+            &[
+                contract.context.i32_type().const_int(slot as u64, false).into(),
+                contract.builder.build_pointer_cast(dest,
+                    contract.context.i8_type().ptr_type(AddressSpace::Generic), "").into(),
+                dest.get_type().size_of().const_cast(
+                    contract.context.i32_type(), false).into()
+            ],
+            "");
+    }
+}

+ 20 - 97
src/emit/mod.rs

@@ -24,6 +24,8 @@ use inkwell::IntPredicate;
 
 const WASMTRIPLE: &str = "wasm32-unknown-unknown-wasm";
 
+pub mod burrow;
+
 lazy_static::lazy_static! {
     static ref LLVM_INIT: () = {
         Target::initialize_webassembly(&Default::default());
@@ -42,6 +44,11 @@ struct Function<'a> {
     wasm_return: bool,
 }
 
+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>);
+}
+
 pub struct Contract<'a> {
     pub name: String,
     pub module: Module<'a>,
@@ -97,7 +104,7 @@ impl<'a> Contract<'a> {
         let intr = load_stdlib(&context);
         module.link_in_module(intr).unwrap();
 
-        let mut e = Contract {
+        Contract {
             name: contract.name.to_owned(),
             module: module,
             builder: context.create_builder(),
@@ -107,46 +114,24 @@ impl<'a> Contract<'a> {
             constructors: Vec::new(),
             functions: Vec::new(),
             externals: HashMap::new(),
-        };
-
-        // externals
-        e.declare_externals();
+        }
+    }
 
-        e.constructors = contract.constructors.iter()
-            .map(|func| e.emit_func(&format!("sol::constructor::{}", func.wasm_symbol(&contract)), func))
+    fn emit_functions(&mut self, runtime: &dyn TargetRuntime) {
+        self.constructors = self.ns.constructors.iter()
+            .map(|func| self.emit_func(&format!("sol::constructor::{}", func.wasm_symbol(&self.ns)), func, runtime))
             .collect();
 
-        for func in &contract.functions {
+        for func in &self.ns.functions {
             let name = if func.name != "" {
-                format!("sol::function::{}", func.wasm_symbol(&contract))
+                format!("sol::function::{}", func.wasm_symbol(&self.ns))
             } else {
                 "sol::fallback".to_owned()
             };
 
-            let f = e.emit_func(&name, func);
-            e.functions.push(f);
+            let f = self.emit_func(&name, func, runtime);
+            self.functions.push(f);
         }
-
-        e.emit_constructor_dispatch(contract);
-        e.emit_function_dispatch(contract);
-
-        e
-    }
-
-    fn declare_externals(&mut self) {
-        let ret = self.context.void_type();
-        let args: Vec<BasicTypeEnum> = vec![
-            self.context.i32_type().into(),
-            self.context.i8_type().ptr_type(AddressSpace::Generic).into(),
-            self.context.i32_type().into(),
-        ];
-
-        let ftype = ret.fn_type(&args, false);
-        let func = self.module.add_function("get_storage32", ftype, Some(Linkage::External));
-        self.externals.insert("get_storage32".to_owned(), func);
-
-        let func = self.module.add_function("set_storage32", ftype, Some(Linkage::External));
-        self.externals.insert("set_storage32".to_owned(), func);
     }
 
     fn expression(
@@ -240,50 +225,6 @@ impl<'a> Contract<'a> {
         }
     }
 
-    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");
-
-        self.builder.position_at_end(&entry);
-
-        // init our heap
-        self.builder.build_call(
-            self.module.get_function("__init_heap").unwrap(),
-            &[],
-            "");
-
-        if let Some(con) = contract.constructors.get(0) {
-            let mut args = Vec::new();
-
-            let arg = function.get_first_param().unwrap().into_pointer_value();
-            let length = self.builder.build_load(arg, "length");
-
-            // step over length
-            let args_ptr = unsafe {
-                self.builder.build_gep(arg,
-                    &[self.context.i32_type().const_int(1, false).into()],
-                    "args_ptr")
-            };
-
-            // insert abi decode
-            self.emit_abi_decode(
-                function,
-                &mut args,
-                args_ptr,
-                length.into_int_value(),
-                con,
-            );
-
-            self.builder.build_call(self.constructors[0].value_ref, &args, "");
-        }
-
-        self.builder.build_return(None);
-    }
-
     fn emit_function_dispatch(&self, contract: &resolver::Contract) {
         // create start function
         let ret = self.context.i32_type().ptr_type(AddressSpace::Generic);
@@ -679,7 +620,7 @@ impl<'a> Contract<'a> {
         self.builder.position_at_end(&decode_block);
     }
 
-    fn emit_func(&self, fname: &str, f: &resolver::FunctionDecl) -> Function<'a> {
+    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;
 
@@ -892,30 +833,12 @@ impl<'a> Contract<'a> {
                     cfg::Instr::GetStorage { local, storage } => {
                         let dest = w.vars[*local].value.into_pointer_value();
 
-                        self.builder.build_call(
-                            self.externals["get_storage32"],
-                            &[
-                                self.context.i32_type().const_int(*storage as u64, false).into(),
-                                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()
-                            ],
-                            "");
+                        runtime.get_storage(&self, *storage as u32, dest);
                     }
                     cfg::Instr::SetStorage { local, storage } => {
                         let dest = w.vars[*local].value.into_pointer_value();
 
-                        self.builder.build_call(
-                            self.externals["set_storage32"],
-                            &[
-                                self.context.i32_type().const_int(*storage as u64, false).into(),
-                                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()
-                            ],
-                            "");
+                        runtime.set_storage(&self, *storage as u32, dest);
                     }
                     cfg::Instr::Call { res, func, args } => {
                         let mut parms: Vec<BasicValueEnum> = Vec::new();

+ 1 - 1
src/main.rs

@@ -167,7 +167,7 @@ fn main() {
 
             let abi = contract.generate_abi();
 
-            let contract = emit::Contract::new(&context, contract, &filename);
+            let contract = emit::burrow::BurrowTarget::build(&context, contract, &filename);
 
             if let Some("llvm") = matches.value_of("EMIT") {
                 contract.dump_llvm(&output_file(&contract.name, "ll")).unwrap();

+ 1 - 1
src/test.rs

@@ -103,7 +103,7 @@ mod tests {
         let abi = contracts[0].generate_abi();
 
         // codegen
-        let contract = emit::Contract::new(ctx, &contracts[0], &"foo.sol");
+        let contract = emit::burrow::BurrowTarget::build(ctx, &contracts[0], &"foo.sol");
 
         let obj = contract.wasm("default").expect("llvm wasm emit should work");