Browse Source

Support literal initializer for string/bytes

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 5 năm trước cách đây
mục cha
commit
a464b74b4c

+ 1 - 7
src/emit/ewasm.rs

@@ -242,16 +242,10 @@ impl EwasmTarget {
         // the deploy code should return the runtime wasm code
         let runtime_code = contract.emit_global_string("runtime_code", runtime, true);
 
-        let runtime_ptr = contract.builder.build_pointer_cast(
-            contract.globals[runtime_code].as_pointer_value(),
-            contract.context.i8_type().ptr_type(AddressSpace::Generic),
-            "runtime_code",
-        );
-
         contract.builder.build_call(
             contract.module.get_function("finish").unwrap(),
             &[
-                runtime_ptr.into(),
+                runtime_code.into(),
                 contract
                     .context
                     .i32_type()

+ 18 - 11
src/emit/mod.rs

@@ -19,7 +19,7 @@ use inkwell::targets::{CodeModel, FileType, RelocMode, Target, TargetTriple};
 use inkwell::types::BasicTypeEnum;
 use inkwell::types::{BasicType, IntType, StringRadix};
 use inkwell::values::{
-    ArrayValue, BasicValueEnum, FunctionValue, GlobalValue, IntValue, PhiValue, PointerValue,
+    ArrayValue, BasicValueEnum, FunctionValue, IntValue, PhiValue, PointerValue,
 };
 use inkwell::AddressSpace;
 use inkwell::IntPredicate;
@@ -104,7 +104,6 @@ pub struct Contract<'a> {
     ns: &'a resolver::Contract,
     constructors: Vec<FunctionValue<'a>>,
     functions: Vec<FunctionValue<'a>>,
-    globals: Vec<GlobalValue<'a>>,
 }
 
 impl<'a> Contract<'a> {
@@ -191,13 +190,12 @@ impl<'a> Contract<'a> {
             ns: contract,
             constructors: Vec::new(),
             functions: Vec::new(),
-            globals: Vec::new(),
         }
     }
 
     /// Creates global string in the llvm module with initializer
     ///
-    fn emit_global_string(&mut self, name: &str, data: &[u8], constant: bool) -> usize {
+    fn emit_global_string(&self, name: &str, data: &[u8], constant: bool) -> PointerValue<'a> {
         let ty = self.context.i8_type().array_type(data.len() as u32);
 
         let gv = self
@@ -212,11 +210,11 @@ impl<'a> Contract<'a> {
             gv.set_constant(true);
         }
 
-        let last = self.globals.len();
-
-        self.globals.push(gv);
-
-        last
+        self.builder.build_pointer_cast(
+            gv.as_pointer_value(),
+            self.context.i8_type().ptr_type(AddressSpace::Generic),
+            name,
+        )
     }
 
     /// Emit a loop from `from` to `to`. The closure exists to insert the body of the loop; the closure
@@ -1052,7 +1050,7 @@ impl<'a> Contract<'a> {
 
                 array.into()
             }
-            Expression::AllocDynamicArray(_, ty, size) => {
+            Expression::AllocDynamicArray(_, ty, size, init) => {
                 let elem = ty.array_deref();
 
                 let size = self
@@ -1065,10 +1063,19 @@ impl<'a> Contract<'a> {
                     .unwrap()
                     .const_cast(self.context.i32_type(), false);
 
+                let init = match init {
+                    None => self
+                        .context
+                        .i8_type()
+                        .ptr_type(AddressSpace::Generic)
+                        .const_null(),
+                    Some(s) => self.emit_global_string("const_string", s, false),
+                };
+
                 self.builder
                     .build_call(
                         self.module.get_function("vector_new").unwrap(),
-                        &[size.into(), elem_size.into()],
+                        &[size.into(), elem_size.into(), init.into()],
                         "",
                     )
                     .try_as_basic_value()

+ 11 - 1
src/resolver/cfg.rs

@@ -2,6 +2,7 @@ use num_bigint::BigInt;
 use std::collections::HashMap;
 use std::collections::HashSet;
 use std::collections::LinkedList;
+use std::str;
 
 use hex;
 use output;
@@ -318,11 +319,20 @@ impl ControlFlowGraph {
             Expression::Complement(_, e) => format!("~{}", self.expr_to_string(ns, e)),
             Expression::UnaryMinus(_, e) => format!("-{}", self.expr_to_string(ns, e)),
             Expression::Poison => "☠".to_string(),
-            Expression::AllocDynamicArray(_, ty, size) => format!(
+            Expression::AllocDynamicArray(_, ty, size, None) => format!(
                 "(alloc {} len {})",
                 ty.to_string(ns),
                 self.expr_to_string(ns, size)
             ),
+            Expression::AllocDynamicArray(_, ty, size, Some(init)) => format!(
+                "(alloc {} {} {})",
+                ty.to_string(ns),
+                self.expr_to_string(ns, size),
+                match str::from_utf8(init) {
+                    Ok(s) => format!("\"{}\"", s.to_owned()),
+                    Err(_) => format!("hex\"{}\"", hex::encode(init)),
+                }
+            ),
             Expression::DynamicArrayLength(_, a) => {
                 format!("(array {} len)", self.expr_to_string(ns, a))
             }

+ 13 - 4
src/resolver/expression.rs

@@ -70,7 +70,7 @@ pub enum Expression {
     ArraySubscript(Loc, Box<Expression>, Box<Expression>),
     StructMember(Loc, Box<Expression>, usize),
 
-    AllocDynamicArray(Loc, resolver::Type, Box<Expression>),
+    AllocDynamicArray(Loc, resolver::Type, Box<Expression>, Option<Vec<u8>>),
     DynamicArrayLength(Loc, Box<Expression>),
     DynamicArraySubscript(Loc, Box<Expression>, resolver::Type, Box<Expression>),
 
@@ -128,7 +128,7 @@ impl Expression {
             | Expression::ArraySubscript(loc, _, _)
             | Expression::StructMember(loc, _, _)
             | Expression::Or(loc, _, _)
-            | Expression::AllocDynamicArray(loc, _, _)
+            | Expression::AllocDynamicArray(loc, _, _, _)
             | Expression::DynamicArrayLength(loc, _)
             | Expression::DynamicArraySubscript(loc, _, _, _)
             | Expression::Keccak256(loc, _)
@@ -225,7 +225,7 @@ impl Expression {
             Expression::DynamicArraySubscript(_, l, _, r) | Expression::ArraySubscript(_, l, r) => {
                 l.reads_contract_storage() || r.reads_contract_storage()
             }
-            Expression::AllocDynamicArray(_, _, s) => s.reads_contract_storage(),
+            Expression::AllocDynamicArray(_, _, s, _) => s.reads_contract_storage(),
             Expression::DynamicArrayLength(_, s) => s.reads_contract_storage(),
             Expression::StructMember(_, s, _) => s.reads_contract_storage(),
             Expression::Keccak256(_, e) => e.reads_contract_storage(),
@@ -526,6 +526,15 @@ pub fn cast(
                 Ok(Expression::BytesLiteral(*loc, bs))
             };
         }
+        (&Expression::BytesLiteral(loc, ref init), _, &resolver::Type::DynamicBytes)
+        | (&Expression::BytesLiteral(loc, ref init), _, &resolver::Type::String) => {
+            return Ok(Expression::AllocDynamicArray(
+                loc,
+                to_conv,
+                Box::new(Expression::NumberLiteral(loc, 32, BigInt::from(init.len()))),
+                Some(init.clone()),
+            ));
+        }
         _ => (),
     };
 
@@ -2557,7 +2566,7 @@ fn new(
     };
 
     Ok((
-        Expression::AllocDynamicArray(*loc, ty.clone(), Box::new(size)),
+        Expression::AllocDynamicArray(*loc, ty.clone(), Box::new(size), None),
         ty,
     ))
 }

+ 1 - 0
src/resolver/mod.rs

@@ -248,6 +248,7 @@ impl Type {
         match self {
             Type::Array(_, _) => true,
             Type::Struct(_) => true,
+            Type::String | Type::DynamicBytes => true,
             _ => false,
         }
     }

BIN
stdlib/stdlib.bc


+ 22 - 2
stdlib/stdlib.c

@@ -393,11 +393,31 @@ struct vector
 	uint8_t data[];
 };
 
-__attribute__((visibility("hidden"))) struct vector *vector_new(uint32_t members, uint32_t size)
+__attribute__((visibility("hidden"))) struct vector *vector_new(uint32_t members, uint32_t size, uint8_t *initial)
 {
-	struct vector *v = __malloc(sizeof(*v) + members * size);
+	struct vector *v;
+	size_t size_array = members * size;
+
+	v = __malloc(sizeof(*v) + size_array);
 	v->len = members;
 	v->size = members;
 
+	uint8_t *data = v->data;
+
+	if (initial)
+	{
+		do
+		{
+			*data++ = *initial++;
+		} while (size_array--);
+	}
+	else
+	{
+		do
+		{
+			*data++ = 0;
+		} while (size_array--);
+	}
+
 	return v;
 }

+ 22 - 4
tests/substrate_strings/mod.rs

@@ -113,11 +113,11 @@ fn more_tests() {
         r##"
         contract foo {
             function ref_test(bytes n) private {
-                    n[1] = 102;
+                n[1] = 102;
 
-                    n = new bytes(10);
-                    // new reference
-                    n[1] = 104;
+                n = new bytes(10);
+                // new reference
+                n[1] = 104;
             }
 
             function test() public {
@@ -137,4 +137,22 @@ fn more_tests() {
     );
 
     runtime.function(&mut store, "test", Vec::new());
+
+    let (runtime, mut store) = build_solidity(
+        r##"
+        contract foo {
+            function test() public {
+                bytes s = "ABCD";
+
+                assert(s.length == 4);
+
+                s[0] = 0x41;
+                s[1] = 0x42;
+                s[2] = 0x43;
+                s[3] = 0x44;
+            }
+        }"##,
+    );
+
+    runtime.function(&mut store, "test", Vec::new());
 }