Jelajahi Sumber

Make GetAddress return a pointer to an address (#1328)

Signed-off-by: Lucas Steuernagel <lucas.tnagel@gmail.com>
Lucas Steuernagel 2 tahun lalu
induk
melakukan
5c32df093b

+ 15 - 0
src/codegen/expression.rs

@@ -2170,6 +2170,21 @@ fn expr_builtin(
                 var_no: temp,
             }
         }
+        ast::Builtin::GetAddress => {
+            // In emit, GetAddress returns a pointer to the address
+            let codegen_expr = Expression::Builtin {
+                loc: *loc,
+                tys: vec![Type::Ref(Box::new(Type::Address(false)))],
+                kind: Builtin::GetAddress,
+                args: vec![],
+            };
+
+            Expression::Load {
+                loc: *loc,
+                ty: Type::Address(false),
+                expr: Box::new(codegen_expr),
+            }
+        }
         _ => {
             let arguments: Vec<Expression> = args
                 .iter()

+ 3 - 0
src/codegen/mod.rs

@@ -1720,6 +1720,9 @@ pub enum Builtin {
     Gasprice,
     BaseFee,
     PrevRandao,
+    /// GetAddress returns a pointer to the address. On Substrate, this pointer points to the
+    /// scratch buffer, to which many syscall write. We strongly recommend loading the pointer
+    /// before using on Substrate. This is not the case for Solana, though.
     GetAddress,
     ExtCodeSize,
     MinimumBalance,

+ 4 - 8
src/codegen/solana_deploy.rs

@@ -273,15 +273,11 @@ pub(super) fn solana_deploy(
                             loc: Loc::Codegen,
                             ty: Type::Struct(StructType::AccountMeta),
                             values: vec![
-                                Expression::GetRef {
+                                Expression::Builtin {
                                     loc: Loc::Codegen,
-                                    ty: Type::Address(false),
-                                    expr: Box::new(Expression::Builtin {
-                                        loc: Loc::Codegen,
-                                        tys: vec![Type::Address(false)],
-                                        kind: Builtin::GetAddress,
-                                        args: vec![],
-                                    }),
+                                    tys: vec![Type::Ref(Box::new(Type::Address(false)))],
+                                    kind: Builtin::GetAddress,
+                                    args: vec![],
                                 },
                                 Expression::BoolLiteral {
                                     loc: Loc::Codegen,

+ 15 - 2
src/codegen/yul/builtin.rs

@@ -154,7 +154,13 @@ pub(crate) fn process_builtin(
         }
 
         YulBuiltInFunction::Address => {
-            Expression::Builtin { loc: *loc, tys: vec![Type::Address(false)], kind: Builtin::GetAddress, args: vec![] }
+            let address_fetch = Expression::Builtin { loc: *loc, tys: vec![
+                Type::Ref(Box::new(Type::Address(false)))], kind: Builtin::GetAddress, args: vec![] };
+            Expression::Load {
+                loc: *loc,
+                ty: Type::Address(false),
+                expr: Box::new(address_fetch),
+            }
         }
 
         YulBuiltInFunction::Balance => {
@@ -163,7 +169,14 @@ pub(crate) fn process_builtin(
         }
 
         YulBuiltInFunction::SelfBalance => {
-            let addr = Expression::Builtin { loc: *loc, tys: vec![Type::Contract(contract_no)], kind: Builtin::GetAddress, args: vec![] };
+            let address_fetch = Expression::Builtin { loc: *loc, tys: vec![
+                Type::Ref(Box::new(Type::Contract(contract_no))),
+            ], kind: Builtin::GetAddress, args: vec![] };
+            let addr = Expression::Load {
+                loc: *loc,
+                ty: Type::Contract(contract_no),
+                expr: Box::new(address_fetch),
+            };
             Expression::Builtin { loc: *loc, tys: vec![Type::Value], kind: Builtin::Balance, args: vec![addr] }
         }
 

+ 3 - 6
src/emit/solana/target.rs

@@ -11,7 +11,8 @@ use crate::emit::{ContractArgs, TargetRuntime, Variable};
 use crate::sema::ast::{self, Namespace};
 use inkwell::types::{BasicType, BasicTypeEnum, IntType};
 use inkwell::values::{
-    ArrayValue, BasicMetadataValueEnum, BasicValueEnum, FunctionValue, IntValue, PointerValue,
+    ArrayValue, BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, IntValue,
+    PointerValue,
 };
 use inkwell::{AddressSpace, IntPredicate};
 use num_traits::ToPrimitive;
@@ -1707,11 +1708,7 @@ impl<'a> TargetRuntime<'a> for SolanaTarget {
                     "key_pointer",
                 );
 
-                binary.builder.build_load(
-                    binary.address_type(ns),
-                    key_pointer.into_pointer_value(),
-                    "key",
-                )
+                key_pointer.as_basic_value_enum()
             }
             codegen::Expression::Builtin {
                 kind: codegen::Builtin::ProgramId,

+ 5 - 3
src/emit/substrate/target.rs

@@ -11,6 +11,7 @@ use crate::sema::ast;
 use crate::sema::ast::{Function, Namespace, Type};
 use crate::{codegen, emit_context};
 use inkwell::types::{BasicType, BasicTypeEnum, IntType};
+use inkwell::values::BasicValue;
 use inkwell::values::{
     ArrayValue, BasicMetadataValueEnum, BasicValueEnum, FunctionValue, IntValue, PointerValue,
 };
@@ -1501,9 +1502,10 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                     "seal_address"
                 );
 
-                binary
-                    .builder
-                    .build_load(binary.address_type(ns), scratch_buf, "self_address")
+                // The scratch buffer is a global buffer which gets overwritten by many syscalls.
+                // Whenever an address is needed in the Substrate target, we strongly recommend
+                // to `Expression::Load` the return of GetAddress to work with GetAddress.
+                scratch_buf.as_basic_value_enum()
             }
             codegen::Expression::Builtin {
                 kind: codegen::Builtin::Balance,

+ 1 - 1
tests/codegen_testcases/solidity/borsh_encoding_simple_types.sol

@@ -22,7 +22,7 @@ contract EncodingTest {
 
         // CHECK: ty:bytes %abi_encoded.temp.55 = (alloc bytes len uint32 207)
 	    // CHECK: writebuffer buffer:%abi_encoded.temp.55 offset:uint32 0 value:%myAddr
-	    // CHECK: writebuffer buffer:%abi_encoded.temp.55 offset:uint32 32 value:(builtin GetAddress ())
+	    // CHECK: writebuffer buffer:%abi_encoded.temp.55 offset:uint32 32 value:(load (builtin GetAddress ()))
 	    // CHECK: writebuffer buffer:%abi_encoded.temp.55 offset:uint32 64 value:(arg #0)
 	    // CHECK: writebuffer buffer:%abi_encoded.temp.55 offset:uint32 65 value:uint8 1
 	    // CHECK: writebuffer buffer:%abi_encoded.temp.55 offset:uint32 66 value:uint16 2

+ 2 - 2
tests/codegen_testcases/solidity/scale.sol

@@ -5,7 +5,7 @@ contract ExternalFunctions {
 
     // BEGIN-CHECK: ExternalFunctions::ExternalFunctions::function::to_storage
     function to_storage() public {
-        // CHECK: ty:function(int32) external returns (uint64) storage %temp.4 = function(int32) external returns (uint64)(function(int32) external returns (uint64)(struct { hex"42761137", (builtin GetAddress ()) }))
+        // CHECK: ty:function(int32) external returns (uint64) storage %temp.4 = function(int32) external returns (uint64)(function(int32) external returns (uint64)(struct { hex"42761137", (load (builtin GetAddress ())) }))
         // CHECK: store storage slot(uint256 0) ty:function(int32) external returns (uint64) = %temp.4
         func = this.foo;
     }
@@ -49,7 +49,7 @@ contract ExternalFunctions {
         // CHECK: writebuffer buffer:%abi_encoded.temp.9 offset:uint32 0 value:hex"f503f5fe"
         // CHECK: writebuffer buffer:%abi_encoded.temp.9 offset:uint32 4 value:(load (struct function(int32) external returns (uint64)(%temp.8) field 1))
         // CHECK: writebuffer buffer:%abi_encoded.temp.9 offset:uint32 36 value:(load (struct function(int32) external returns (uint64)(%temp.8) field 0))
-        // CHECK: _ = external call::regular address:(builtin GetAddress ()) payload:%abi_encoded.temp.9 value:uint128 0 gas:uint64 0 accounts: seeds:
+        // CHECK: _ = external call::regular address:(load (builtin GetAddress ())) payload:%abi_encoded.temp.9 value:uint128 0 gas:uint64 0 accounts: seeds: contract|function:(0, 3)
         this.bar(func);
     }
 }

+ 2 - 2
tests/codegen_testcases/yul/evm_builtin.sol

@@ -8,13 +8,13 @@ contract Testing {
             // CHECK: ty:uint256 %a = (zext uint256 (builtin Gasleft ()))
             let a := gas()
 
-            // CHECK: ty:uint256 %b = (sext uint256 uint160((builtin GetAddress ())))
+            // CHECK: (sext uint256 uint160((load (builtin GetAddress ()))))
             let b := address()
 
             // CHECK: ty:uint256 %c = (sext uint256 (builtin Balance (address((trunc uint160 (arg #0))))))
             let c := balance(arg1)
 
-            // CHECK: ty:uint256 %d = (sext uint256 (builtin Balance ((builtin GetAddress ()))))
+            // CHECK: ty:uint256 %d = (sext uint256 (builtin Balance ((load (builtin GetAddress ())))))
             let d := selfbalance()
 
             // CHECK: ty:uint256 %e = (sext uint256 uint160((builtin Sender ())))