Skip to content

Commit

Permalink
feat(compiler): introduce code section (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
clearloop authored Aug 8, 2023
1 parent b93a7f1 commit 6fb8cd3
Show file tree
Hide file tree
Showing 25 changed files with 334 additions and 38 deletions.
15 changes: 8 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace.package]
version = "0.1.0"
version = "0.1.1"
authors = ["clearloop"]
edition = "2021"
license = "GPL-3.0-only"
Expand Down Expand Up @@ -43,12 +43,12 @@ wasmparser = "0.107.0"
wat = "1.0.66"

# Local Dependencies.
zinkup = { path = "cli", version = "=0.1.0" }
opcodes = { package = "evm-opcodes", path = "codegen/opcodes", version = "=0.0.2" }
zingen = { path = "codegen", version = "=0.1.0" }
zinkc = { path = "compiler", version = "=0.1.0" }
zink = { path = "zink", version = "=0.1.0" }
zint = { path = "zint", version = "=0.1.0" }
zinkup = { path = "cli", version = "=0.1.1" }
opcodes = { package = "evm-opcodes", path = "codegen/opcodes", version = "=0.0.3", features = ["data"] }
zingen = { path = "codegen", version = "=0.1.1" }
zinkc = { path = "compiler", version = "=0.1.1" }
zink = { path = "zink", version = "=0.1.1" }
zint = { path = "zint", version = "=0.1.1" }

[profile]
dev = { panic = "abort"}
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ which will unlock all of the following features:
and `zinkc`, your contracts will have the smallest size with **strong performance** in EVM
bytecode at the end!

- **Compatible**: All of the `no_std` libraries in rust are your libraries, futhermore, you
can use your solidity contracts as part of your zink contracts and your zink contracts as
part of your solidty contracts :)
- **Compatible**: All of the `no_std` libraries in rust are your libraries, you can use your
solidity contracts as part of your zink contracts and your zink contracts as part of your
solidty contracts :)

- **Easy Debugging**: Developing your smart contracts with only one programming language!
zink will provide everything you need for developing your contracts officially based on the
Expand Down Expand Up @@ -77,7 +77,7 @@ GPL-3.0-only
[telegram-badge]: https://img.shields.io/badge/telegram-blue?logo=telegram
[telegram-group]: https://t.me/+6oZpbwxlVD81OGQ1
[version-badge]: https://img.shields.io/crates/v/zink
[version-link]: https://docs.rs/zink/latest/zink/
[version-link]: https://docs.rs/zink/latest/zinkc
[ci-badge]: https://img.shields.io/github/actions/workflow/status/clearloop/zink/main.yml
[ci-link]: https://github.com/clearloop/zink/actions/workflows/main.yml
[rustc-codegen]: https://doc.rust-lang.org/rustc/codegen-options/index.html
Expand Down
5 changes: 4 additions & 1 deletion codegen/opcodes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "evm-opcodes"
description = "Rust implementation of EVM opcode"
documentation = "https://docs.rs/evm-opcodes"
version = "0.0.2"
version = "0.0.3"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
Expand All @@ -11,3 +11,6 @@ repository.workspace = true

[dependencies]
paste.workspace = true

[features]
data = []
15 changes: 15 additions & 0 deletions codegen/opcodes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ macro_rules! opcodes {
/// Ethereum virtual machine opcode.
#[derive(Clone, Copy, Debug)]
pub enum $version {
#[cfg(feature = "data")]
/// No operation but provides a byte for serializing.
Data(u8),
$(
#[doc = concat!(" ", $desc)]
$name,
Expand All @@ -48,6 +51,8 @@ macro_rules! opcodes {
impl From<$version> for u8 {
fn from(version: $version) -> Self {
match version {
#[cfg(feature = "data")]
$version::Data(data) => data,
$(
$version::$name => $opcode,
)*
Expand All @@ -58,6 +63,8 @@ macro_rules! opcodes {
impl OpCode for $version {
fn group(&self) -> Group {
match self {
#[cfg(feature = "data")]
Self::Data(_) => Group::StopArithmetic,
$(
Self::$name => Group::$group,
)*
Expand All @@ -66,6 +73,8 @@ macro_rules! opcodes {

fn gas(&self) -> u16 {
match self {
#[cfg(feature = "data")]
Self::Data(_) => 0,
$(
Self::$name => $gas,
)*
Expand All @@ -74,6 +83,8 @@ macro_rules! opcodes {

fn since(&self) -> Upgrade {
match self {
#[cfg(feature = "data")]
Self::Data(_) => Upgrade::Shanghai,
$(
Self::$name => Upgrade::$since,
)*
Expand All @@ -82,6 +93,8 @@ macro_rules! opcodes {

fn stack_in(&self) -> u16 {
match self {
#[cfg(feature = "data")]
Self::Data(_) => 0,
$(
Self::$name => $input,
)*
Expand All @@ -90,6 +103,8 @@ macro_rules! opcodes {

fn stack_out(&self) -> u16 {
match self {
#[cfg(feature = "data")]
Self::Data(_) => 0,
$(
Self::$name => $output,
)*
Expand Down
92 changes: 92 additions & 0 deletions codegen/src/jump/code.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//! Table for the code section.

use opcodes::ShangHai as OpCode;
use std::collections::HashMap;

/// Code in code section.
#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub enum Func {
/// Run select.
Select,
}

impl Func {
/// Get the bytecode of the function.
pub fn bytecode(&self) -> Vec<u8> {
match self {
Self::Select => [
OpCode::JUMPDEST,
OpCode::POP,
OpCode::PUSH1,
OpCode::Data(0x06),
OpCode::ADD,
OpCode::JUMP,
],
}
.into_iter()
.map(|op| op.into())
.collect()
}
}

/// Code section for EVM.
#[derive(Default, Debug)]
pub struct Code {
offset: usize,
/// Function table.
funcs: HashMap<Func, usize>,
}

impl Code {
/// Create a new code section.
pub fn new() -> Self {
Self {
offset: 0,
funcs: HashMap::new(),
}
}

/// Get the functions in the code section.
pub fn funcs(&self) -> Vec<Func> {
self.funcs.keys().cloned().collect()
}

/// Shift the code section.
pub fn shift(&mut self, offset: u16) {
tracing::debug!("shift code section by 0x{:x} bytes.", offset);
let offset = offset as usize;
self.offset += offset;
self.funcs.values_mut().for_each(|pc| *pc += offset);
}

/// Add a function to the code section.
pub fn try_add_func(&mut self, func: Func) {
if self.funcs.contains_key(&func) {
return;
}

let bytecode = func.bytecode();
let len = bytecode.len();
self.funcs.insert(func, self.offset);
self.offset += len;
}

/// Get the current offset of the code section.
pub fn offset(&self) -> usize {
self.offset
}

/// Get the offset of a function.
pub fn offset_of(&self, func: &Func) -> Option<u16> {
self.funcs.get(func).and_then(|i| (*i).try_into().ok())
}

/// Get the bytecode of the code section.
pub fn finish(&self) -> Vec<u8> {
let mut code = Vec::new();
for func in self.funcs.keys() {
code.extend(func.bytecode());
}
code
}
}
27 changes: 24 additions & 3 deletions codegen/src/jump/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
//! Jump table implementation.

use crate::{Error, Result};
pub use code::{Code, Func};
use std::collections::BTreeMap;

mod code;
mod pc;
mod relocate;

Expand All @@ -14,6 +16,8 @@ pub enum Jump {
Label(u16),
/// Jump to function.
Func(u32),
/// External function.
ExtFunc(Func),
}

impl Jump {
Expand All @@ -30,13 +34,14 @@ pub struct JumpTable {
jump: BTreeMap<u16, Jump>,
/// Function table.
func: BTreeMap<u32, u16>,
/// Code section.
code: Code,
}

impl JumpTable {
/// Register a function.
pub fn call(&mut self, pc: u16, func: u32) -> Result<()> {
pub fn call(&mut self, pc: u16, func: u32) {
self.jump.insert(pc, Jump::Func(func));
Ok(())
}

/// Register program counter to the function table.
Expand All @@ -48,6 +53,17 @@ impl JumpTable {
Ok(())
}

/// Register program counter for code section.
pub fn code_offset(&mut self, offset: u16) {
self.code.shift(offset);
}

/// Register a external function.
pub fn ext(&mut self, pc: u16, func: Func) {
self.code.try_add_func(func);
self.jump.insert(pc, Jump::ExtFunc(func));
}

/// Register a label.
pub fn label(&mut self, pc: u16, label: u16) {
self.jump.insert(pc, Jump::Label(label));
Expand All @@ -74,14 +90,19 @@ impl JumpTable {
}
}

for func in table.code.funcs() {
self.code.try_add_func(func);
}

Ok(())
}

/// Get the target of a jump.
pub fn target(&self, jump: &Jump) -> Result<u16> {
pub fn target(&mut self, jump: &Jump) -> Result<u16> {
match jump {
Jump::Label(label) => Ok(*label),
Jump::Func(func) => Ok(*self.func.get(func).ok_or(Error::FuncNotFound(*func))?),
Jump::ExtFunc(ext) => Ok(self.code.offset_of(ext).ok_or(Error::ExtNotFound(*ext))?),
}
}
}
9 changes: 5 additions & 4 deletions codegen/src/jump/pc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ impl JumpTable {

/// Shift the target program counters.
pub fn shift_targets(&mut self) -> Result<()> {
self.jump.clone().keys().try_for_each(|pc| -> Result<()> {
self.shift_target(*pc, relocate::offset(*pc)?)?;
Ok(())
})
self.jump
.clone()
.keys()
.try_for_each(|pc| -> Result<()> { self.shift_target(*pc, relocate::offset(*pc)?) })
}

/// Shift the program counter of targets with given ptr and offset.
pub fn shift_target(&mut self, ptr: u16, offset: u16) -> Result<()> {
self.code.shift(offset);
self.shift_label_target(ptr, offset)?;
self.shift_func_target(ptr, offset)
}
Expand Down
Loading

0 comments on commit 6fb8cd3

Please sign in to comment.