diff --git a/codegen/src/abi.rs b/codegen/src/abi.rs index 5b8362071..aa39b7822 100644 --- a/codegen/src/abi.rs +++ b/codegen/src/abi.rs @@ -92,6 +92,7 @@ macro_rules! offset { offset! { (usize, 8), + (u64, 8), (i64, 8), (i32, 4), (u32, 4), diff --git a/codegen/src/asm.rs b/codegen/src/asm.rs index 392fb86e7..f1c5f876d 100644 --- a/codegen/src/asm.rs +++ b/codegen/src/asm.rs @@ -97,7 +97,7 @@ impl Assembler { /// Mock the stack input and output for checking /// the stack usages. pub fn emit_op(&mut self, opcode: OpCode) -> Result<()> { - tracing::trace!("stack length: {:?}", self.sp); + // tracing::trace!("stack length: {:?}", self.sp); tracing::trace!("emit opcode: {:?}", opcode); self.decrement_sp(opcode.stack_in() as u8)?; self.emit(opcode.into()); diff --git a/codegen/src/codegen.rs b/codegen/src/codegen.rs index ab0f684df..5729874dd 100644 --- a/codegen/src/codegen.rs +++ b/codegen/src/codegen.rs @@ -59,7 +59,7 @@ impl CodeGen { // STACK: PC + params codegen.masm.increment_sp(1 + params_count)?; codegen.masm._jumpdest()?; - codegen.masm.shift_pc(params_count, true)?; + codegen.masm.shift_stack(params_count, true)?; } Ok(codegen) diff --git a/codegen/src/dispatcher.rs b/codegen/src/dispatcher.rs index a47b51ea8..0410a41a3 100644 --- a/codegen/src/dispatcher.rs +++ b/codegen/src/dispatcher.rs @@ -1,6 +1,8 @@ //! Code generator for EVM dispatcher. -use crate::{code::ExtFunc, DataSet, Error, Exports, Imports, JumpTable, MacroAssembler, Result}; +use crate::{ + code::ExtFunc, DataSet, Error, Exports, Imports, JumpTable, MacroAssembler, Result, ToLSBytes, +}; use std::{ collections::BTreeMap, ops::{Deref, DerefMut}, @@ -179,15 +181,14 @@ impl<'d> Dispatcher<'d> { } /// Emit return of ext function. - fn ext_return(&mut self, func: u32) -> Result<()> { - let sig = self - .funcs - .get(&func) - .ok_or(Error::FuncNotFound(func))? - .sig()?; - + fn ext_return(&mut self, sig: &FuncType) -> Result<()> { + self.asm.increment_sp(1)?; let asm = self.asm.clone(); - self.asm.main_return(sig.results())?; + + { + self.asm.main_return(sig.results())?; + } + let bytecode = { let jumpdest = vec![0x5b]; let ret = self.asm.buffer()[asm.buffer().len()..].to_vec(); @@ -204,6 +205,52 @@ impl<'d> Dispatcher<'d> { Ok(()) } + // Process to the selected function. + // + // 1. drop selector. + // 2. load calldata to stack. + // 3. jump to the callee function. + fn process(&mut self, sig: &FuncType) -> Result<()> { + self.asm.increment_sp(1)?; + let asm = self.asm.clone(); + let len = sig.params().len() as u8; + + { + // TODO: check the safety of this. + // + // [ callee, ret, selector ] -> [ selector, callee, ret ] + self.asm.shift_stack(2, false)?; + // [ selector, callee, ret ] -> [ callee, ret ] + self.asm._drop()?; + // [ callee, ret ] -> [ param * len, callee, ret ] + for p in (0..len).rev() { + let offset = 4 + p * 32; + self.asm.push(&offset.to_ls_bytes())?; + self.asm._calldataload()?; + } + + // [ param * len, callee, ret ] -> [ ret, param * len, callee ] + self.asm.shift_stack(len + 1, false)?; + // [ ret, param * len, callee ] -> [ callee, ret, param * len ] + self.asm.shift_stack(len + 1, false)?; + self.asm._jump()?; + } + + let bytecode = { + let jumpdest = vec![0x5b]; + let ret = self.asm.buffer()[asm.buffer().len()..].to_vec(); + [jumpdest, ret].concat() + }; + *self.asm = asm; + let ret = ExtFunc { + bytecode, + stack_in: len, + stack_out: 1, + }; + self.table.ext(self.asm.pc_offset(), ret); + Ok(()) + } + /// Emit selector to buffer. fn emit_selector(&mut self, selector: &Function<'_>, last: bool) -> Result<()> { let abi = self.load_abi(selector)?; @@ -216,27 +263,40 @@ impl<'d> Dispatcher<'d> { ); let func = self.query_func(&abi.name)?; + let sig = self + .funcs + .get(&func) + .ok_or(Error::FuncNotFound(func))? + .sig()?; // Jump to the end of the current function. // // TODO: detect the bytes of the position. (#157) - self.asm.increment_sp(1)?; - self.ext_return(func)?; + self.ext_return(&sig)?; + + // Prepare the `PC` of the callee function. + { + // TODO: remove this (#160) + self.asm._jumpdest()?; + self.asm.increment_sp(1)?; + self.table.call(self.asm.pc_offset(), func); + } if !last { - self.asm._dup2()?; + self.asm._dup3()?; } else { - self.asm._swap1()?; + self.asm._swap2()?; } self.asm.push(&selector_bytes)?; self.asm._eq()?; - self.asm.increment_sp(1)?; - - self.table.call(self.asm.pc_offset(), func); + self.process(&sig)?; self.asm._jumpi()?; if !last { + // drop the PC of the previous callee function. + self.asm._drop()?; + // drop the PC of the previous callee function preprocessor. self.asm._drop()?; } diff --git a/codegen/src/import.rs b/codegen/src/import.rs index 001c245be..a44eb6789 100644 --- a/codegen/src/import.rs +++ b/codegen/src/import.rs @@ -4,7 +4,7 @@ use std::{ ops::{Deref, DerefMut}, }; -use crate::{Error, MacroAssembler, Result}; +use crate::{Error, Result}; /// EVM built-in function. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] @@ -61,14 +61,6 @@ impl Func { _ => 0, } } - - /// Pre-processing for the function. - pub fn prelude(&self, masm: &mut MacroAssembler) -> Result<()> { - match self { - Self::Sstore => masm._swap1(), - _ => Ok(()), - } - } } impl TryFrom<(&str, &str)> for Func { diff --git a/codegen/src/masm/mod.rs b/codegen/src/masm/mod.rs index b273712d3..1dc995765 100644 --- a/codegen/src/masm/mod.rs +++ b/codegen/src/masm/mod.rs @@ -193,7 +193,7 @@ impl MacroAssembler { /// Shift the program counter to the bottom or the top of the /// parameters. This is used by the callee function for jumping /// back to the caller function. - pub fn shift_pc(&mut self, count: u8, from_top: bool) -> Result<()> { + pub fn shift_stack(&mut self, count: u8, from_top: bool) -> Result<()> { let mut swaps = 0; if from_top { diff --git a/codegen/src/masm/ret.rs b/codegen/src/masm/ret.rs index 811e519e1..2c9626289 100644 --- a/codegen/src/masm/ret.rs +++ b/codegen/src/masm/ret.rs @@ -46,7 +46,7 @@ impl MacroAssembler { } // TODO: handle the length of results > u8::MAX. - self.shift_pc(len, false)?; + self.shift_stack(len, false)?; self._jump() } } diff --git a/codegen/src/visitor/call.rs b/codegen/src/visitor/call.rs index 63feb97a7..fea2c2083 100644 --- a/codegen/src/visitor/call.rs +++ b/codegen/src/visitor/call.rs @@ -60,8 +60,6 @@ impl CodeGen { .get(&index) .ok_or(Error::ImportedFuncNotFound(index))?; - func.prelude(&mut self.masm)?; - match func { Func::Sstore => self.masm._sstore(), Func::Sload => self.masm._sload(), diff --git a/compiler/tests/storage.rs b/compiler/tests/storage.rs index cd596f223..f73190ceb 100644 --- a/compiler/tests/storage.rs +++ b/compiler/tests/storage.rs @@ -45,19 +45,19 @@ fn basic() -> Result<()> { #[test] fn dispatcher() -> Result<()> { - let _bytecode = common::load_with_dispatcher("storage", "dispatcher")?; + let bytecode = common::load_with_dispatcher("storage", "dispatcher")?; // TODO: testing set (#122) - // { - // let key = 0; - // let value = 42; - // let mut selector = zabi::selector(b"set(i32)").to_vec(); - // selector = [selector, 42.to_bytes32().to_vec()].concat(); - // let info = EVM::run(&bytecode, &selector); - // assert_eq!(info.instr, InstructionResult::Return); - // assert_eq!(info.ret, []); - // assert_eq!(info.storage.get(&U256::from(key)), Some(&U256::from(value))); - // } + { + let key = 0; + let value = 42; + let mut selector = zabi::selector(b"set(i32)").to_vec(); + selector = [selector, 42.to_bytes32().to_vec()].concat(); + let info = EVM::run(&bytecode, &selector); + assert_eq!(info.instr, InstructionResult::Return); + assert_eq!(info.ret, []); + assert_eq!(info.storage.get(&U256::from(key)), Some(&U256::from(value))); + } // let info = EVM::run(&bytecode, &42.to_bytes32()); diff --git a/compiler/wat/storage/basic.wat b/compiler/wat/storage/basic.wat index 61b9c8633..d9428db01 100644 --- a/compiler/wat/storage/basic.wat +++ b/compiler/wat/storage/basic.wat @@ -4,8 +4,8 @@ (import "evm" "sstore" (func (;0;) (type 1))) (import "evm" "sload" (func (;1;) (type 0))) (func (;2;) (type 0) (param i32) (result i32) - i32.const 0 local.get 0 + i32.const 0 call 0 i32.const 0 call 1)) diff --git a/compiler/wat/storage/dispatcher.wat b/compiler/wat/storage/dispatcher.wat index 5c502a408..b5c0ce792 100644 --- a/compiler/wat/storage/dispatcher.wat +++ b/compiler/wat/storage/dispatcher.wat @@ -9,8 +9,8 @@ (import "zinkc" "emit_abi" (func (;2;) (type 1))) (import "env" "memory" (memory (;0;) 17)) (func (;3;) (type 2) (param i32) (result i32) - i32.const 0 local.get 0 + i32.const 0 call 0 i32.const 0 call 1) @@ -19,8 +19,8 @@ i32.const 34 call 2) (func (;5;) (type 3) (param i32) - i32.const 0 local.get 0 + i32.const 0 call 0) (func (;6;) (type 0) i32.const 1048610 diff --git a/compiler/wat/storage/load.wat b/compiler/wat/storage/load.wat index 88ca518e2..efcbafe07 100644 --- a/compiler/wat/storage/load.wat +++ b/compiler/wat/storage/load.wat @@ -4,8 +4,8 @@ (import "evm" "sload" (func (;0;) (type 0))) (import "evm" "sstore" (func (;1;) (type 1))) (func (type 0) (param i32) (result i32) - i32.const 0 local.get 0 + i32.const 0 call 1 i32.const 0 call 0)) diff --git a/compiler/wat/storage/store.wat b/compiler/wat/storage/store.wat index b263c01bd..c17e935c1 100644 --- a/compiler/wat/storage/store.wat +++ b/compiler/wat/storage/store.wat @@ -2,7 +2,7 @@ (type (;0;) (func (param i32 i32))) (import "evm" "sstore" (func (;0;) (type 0))) (func (param i32) - i32.const 0 local.get 0 + i32.const 0 call 0) ) diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 4e75d5bba..0fc9552e5 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -9,21 +9,6 @@ dependencies = [ "zink", ] -[[package]] -name = "atomic-polyfill" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" -dependencies = [ - "critical-section", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "block-buffer" version = "0.10.4" @@ -33,12 +18,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "cobs" version = "0.2.3" @@ -54,12 +33,6 @@ dependencies = [ "libc", ] -[[package]] -name = "critical-section" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" - [[package]] name = "crypto-common" version = "0.1.6" @@ -103,29 +76,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "heapless" -version = "0.7.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin", - "stable_deref_trait", -] - [[package]] name = "hex" version = "0.4.3" @@ -154,16 +104,6 @@ version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.1.0" @@ -179,7 +119,6 @@ checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" dependencies = [ "cobs", "embedded-io", - "heapless", "serde", ] @@ -201,27 +140,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" - [[package]] name = "serde" version = "1.0.189" @@ -252,21 +170,6 @@ dependencies = [ "keccak", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "storage" version = "0.1.0" diff --git a/zink/codegen/src/storage.rs b/zink/codegen/src/storage.rs index e2b1a204c..17629612b 100644 --- a/zink/codegen/src/storage.rs +++ b/zink/codegen/src/storage.rs @@ -45,7 +45,7 @@ pub fn parse(input: ItemType) -> TokenStream { fn set(value: #variable_type) { unsafe { - zink::ffi::evm::sstore(Self::STORAGE_KEY, value); + zink::ffi::evm::sstore(value, Self::STORAGE_KEY); } } } @@ -61,6 +61,6 @@ mod tests { #[test] fn parse_test() { let expr: ItemType = syn::parse_str("pub type Counter = i32;").unwrap(); - assert_eq!(parse(expr).to_string().as_str(), "struct Counter ; impl zink :: Storage < i32 > for Counter { const STORAGE_KEY : i32 = 0i32 ; fn get () -> i32 { unsafe { zink :: ffi :: evm :: sload (Self :: STORAGE_KEY) } } fn set (value : i32) { unsafe { zink :: ffi :: evm :: sstore (Self :: STORAGE_KEY , value) ; } } }"); + assert_eq!(parse(expr).to_string().as_str(), "struct Counter ; impl zink :: Storage < i32 > for Counter { const STORAGE_KEY : i32 = 0i32 ; fn get () -> i32 { unsafe { zink :: ffi :: evm :: sload (Self :: STORAGE_KEY) } } fn set (value : i32) { unsafe { zink :: ffi :: evm :: sstore (value , Self :: STORAGE_KEY) ; } } }"); } } diff --git a/zink/src/ffi/evm.rs b/zink/src/ffi/evm.rs index fadd7582e..09af6e9ec 100644 --- a/zink/src/ffi/evm.rs +++ b/zink/src/ffi/evm.rs @@ -9,7 +9,7 @@ extern "C" { // i32 -> 8 bytes /// Store a value in the storage - pub fn sstore(key: i32, value: i32); + pub fn sstore(value: i32, key: i32); /// Load a value from the storage pub fn sload(key: i32) -> i32;