Sfoglia il codice sorgente

Generate call function for substrate target

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 6 anni fa
parent
commit
e9bafb7c15
1 ha cambiato i file con 70 aggiunte e 36 eliminazioni
  1. 70 36
      src/emit/substrate.rs

+ 70 - 36
src/emit/substrate.rs

@@ -19,16 +19,53 @@ impl SubstrateTarget {
         let b = SubstrateTarget{};
 
         // externals
-        b.declare_externals(&mut c);
+        b.declare_externals(&c);
 
         c.emit_functions(&b);
-    
+
         b.emit_deploy(&c);
+        b.emit_call(&c);
 
         c
     }
 
-    fn declare_externals(&self, contract: &mut Contract) {
+    fn public_function_prelude<'a>(&self, contract: &'a Contract, function: FunctionValue) -> (PointerValue<'a>, IntValue<'a>) {
+        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(),
+            &[],
+            "");
+
+        // copy arguments from scratch buffer
+        let args_length = contract.builder.build_call(
+            contract.module.get_function("ext_scratch_size").unwrap(),
+            &[],
+            "scratch_size").try_as_basic_value().left().unwrap();
+
+        let args = contract.builder.build_call(
+            contract.module.get_function("__malloc").unwrap(),
+            &[args_length],
+            ""
+        ).try_as_basic_value().left().unwrap().into_pointer_value();
+
+        contract.builder.build_call(
+            contract.module.get_function("ext_scratch_read").unwrap(),
+            &[
+                args.into(),
+                contract.context.i32_type().const_zero().into(),
+                args_length.into(),
+            ],
+            ""
+        );
+
+        (args, args_length.into_int_value())
+    }
+
+    fn declare_externals(&self, contract: &Contract) {
         // Access to scratch buffer
         contract.module.add_function(
             "ext_scratch_size",
@@ -62,45 +99,42 @@ impl SubstrateTarget {
         let ftype = ret.fn_type(&[contract.context.i32_type().ptr_type(AddressSpace::Generic).into()], false);
         let function = contract.module.add_function("deploy", ftype, None);
 
-        let entry = contract.context.append_basic_block(function, "entry");
+        let fallback_block = contract.context.append_basic_block(function, "fallback");
 
-        contract.builder.position_at_end(&entry);
+        let (deploy_args, deploy_args_length) = self.public_function_prelude(contract, function);
 
-        // init our heap
-        contract.builder.build_call(
-            contract.module.get_function("__init_heap").unwrap(),
-            &[],
-            "");
-        
-        // copy arguments from scratch buffer
-        let deploy_args_length = contract.builder.build_call(
-            contract.module.get_function("ext_scratch_size").unwrap(),
-            &[],
-            "scratch_size").try_as_basic_value().left().unwrap();
-        
-        let deploy_args = contract.builder.build_call(
-            contract.module.get_function("__malloc").unwrap(),
-            &[deploy_args_length],
-            ""
-        ).try_as_basic_value().left().unwrap().into_pointer_value();
+        contract.emit_function_dispatch(&contract.ns.constructors, deploy_args, deploy_args_length, function, &fallback_block, self);
 
-        contract.builder.build_call(
-            contract.module.get_function("ext_scratch_read").unwrap(),
-            &[
-                deploy_args.into(),
-                contract.context.i32_type().const_zero().into(),
-                deploy_args_length.into(),
-            ],
-            ""
-        );
+        // emit fallback code
+        contract.builder.position_at_end(&fallback_block);
+        contract.builder.build_unreachable();
+    }
+
+    fn emit_call(&self, contract: &Contract) {
+        // create deploy 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("call", ftype, None);
 
         let fallback_block = contract.context.append_basic_block(function, "fallback");
 
-        contract.emit_function_dispatch(&contract.ns.constructors, deploy_args, deploy_args_length.into_int_value(), function, &fallback_block, self);
-        
+        let (call_args, call_args_length) = self.public_function_prelude(contract, function);
+
+        contract.emit_function_dispatch(&contract.ns.constructors, call_args, call_args_length, function, &fallback_block, self);
+
         // emit fallback code
         contract.builder.position_at_end(&fallback_block);
-        contract.builder.build_unreachable();
+
+        if let Some(fallback) = contract.ns.fallback_function() {
+            contract.builder.build_call(
+                contract.functions[fallback].value_ref,
+                &[],
+                "");
+
+            contract.builder.build_return(None);
+        } else {
+            contract.builder.build_unreachable();
+        }
     }
 }
 
@@ -147,7 +181,7 @@ impl TargetRuntime for SubstrateTarget {
             "correct_length");
 
         contract.builder.build_conditional_branch(is_ok, &decode_block, &wrong_length_block);
-    
+
         contract.builder.position_at_end(&decode_block);
 
         let mut argsdata = data;
@@ -234,7 +268,7 @@ impl TargetRuntime for SubstrateTarget {
 
             match ty {
                 ast::ElementaryTypeName::Bool => {
-                    contract.builder.build_store(argsdata, 
+                    contract.builder.build_store(argsdata,
                         contract.builder.build_int_cast(args[i].into_int_value(), contract.context.i8_type(), "bool")
                     );
                     arglen = 1;