mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-24 19:27:58 +00:00
@@ -6,9 +6,5 @@ fn main() {
|
||||
let bytecode = hex::decode(hexcode.trim()).unwrap();
|
||||
let instructions = bytecode.disassemble();
|
||||
|
||||
//for instruction in instructions.iter() {
|
||||
// println!("{instruction:?}");
|
||||
//}
|
||||
|
||||
Program::new(instructions).dot(BasicBlockFormatOption::ByteCode);
|
||||
Program::new(instructions).dot(BasicBlockFormatOption::Ir);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,14 @@ impl BasicBlock {
|
||||
writeln!(&mut acc, "{:?}", opcode.instruction).unwrap();
|
||||
acc
|
||||
}),
|
||||
BasicBlockFormatOption::Ir => {
|
||||
self.instructions
|
||||
.iter()
|
||||
.fold(String::new(), |mut acc, instruction| {
|
||||
writeln!(&mut acc, "{instruction}").unwrap();
|
||||
acc
|
||||
})
|
||||
}
|
||||
_ => String::new(),
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use evmil::bytecode::Instruction as EvmInstruction;
|
||||
use primitive_types::U256;
|
||||
use std::fmt::Write;
|
||||
|
||||
use crate::symbol::{Global, Symbol, SymbolTable, Type};
|
||||
|
||||
@@ -16,8 +17,8 @@ pub enum Instruction {
|
||||
/// `x = op y`
|
||||
UnaryAssign {
|
||||
x: Symbol,
|
||||
y: Symbol,
|
||||
operator: Operator,
|
||||
y: Symbol,
|
||||
},
|
||||
|
||||
/// `branch target`
|
||||
@@ -36,7 +37,7 @@ pub enum Instruction {
|
||||
Function {
|
||||
symbol: Global,
|
||||
x: Symbol,
|
||||
args: Vec<Symbol>,
|
||||
parameters: Vec<Symbol>,
|
||||
},
|
||||
|
||||
/// `x = y`
|
||||
@@ -49,6 +50,61 @@ pub enum Instruction {
|
||||
IndexedCopy { x: Symbol, y: Symbol, index: Symbol },
|
||||
}
|
||||
|
||||
impl Instruction {
|
||||
fn target_address(&self) -> Symbol {
|
||||
match self {
|
||||
Instruction::Copy { x, .. } => *x,
|
||||
Instruction::IndexedAssign { x, .. } => *x,
|
||||
Instruction::IndexedCopy { x, .. } => *x,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Instruction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::BinaryAssign { x, y, operator, z } => write!(f, "{x} = {y} {operator:?} {z}"),
|
||||
|
||||
Self::UnaryAssign { x, operator, y } => write!(f, "{x} = {operator:?} {y} "),
|
||||
|
||||
Self::UncoditionalBranch { target } => write!(f, "branch {target}"),
|
||||
|
||||
Self::ConditionalBranch { condition, target } => {
|
||||
write!(f, "if {condition} branch {target}")
|
||||
}
|
||||
|
||||
Self::Procedure { symbol, parameters } => write!(
|
||||
f,
|
||||
"{symbol:?}({})",
|
||||
parameters.iter().fold(String::new(), |mut acc, p| {
|
||||
write!(&mut acc, "{p}, ").unwrap();
|
||||
acc
|
||||
})
|
||||
),
|
||||
|
||||
Self::Function {
|
||||
symbol,
|
||||
x,
|
||||
parameters: args,
|
||||
} => write!(
|
||||
f,
|
||||
"{x} = {symbol:?}({})",
|
||||
args.iter().fold(String::new(), |mut acc, p| {
|
||||
write!(&mut acc, "{p}, ").unwrap();
|
||||
acc
|
||||
})
|
||||
),
|
||||
|
||||
Self::Copy { x, y } => write!(f, "{x} = {y}"),
|
||||
|
||||
Self::IndexedAssign { x, index, y } => write!(f, "{x}[{index}] = {y}"),
|
||||
|
||||
Self::IndexedCopy { x, y, index } => write!(f, "{x} = {y}[{index}]"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum Operator {
|
||||
Add,
|
||||
@@ -139,17 +195,6 @@ fn increment_stack_height(symbol_table: &mut SymbolTable) -> Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
impl Instruction {
|
||||
fn target_address(&self) -> Symbol {
|
||||
match self {
|
||||
Instruction::Copy { x, .. } => *x,
|
||||
Instruction::IndexedAssign { x, .. } => *x,
|
||||
Instruction::IndexedCopy { x, .. } => *x,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower an EVM instruction into corresponding 3AC instructions.
|
||||
pub fn translate(opcode: &EvmInstruction, symbol_table: &mut SymbolTable) -> Vec<Instruction> {
|
||||
use EvmInstruction::*;
|
||||
@@ -272,7 +317,7 @@ mod tests {
|
||||
|
||||
use crate::{
|
||||
instruction::Operator,
|
||||
symbol::{Global, Kind, Symbol, Type},
|
||||
symbol::{Address, Global, Kind, Symbol, Type},
|
||||
};
|
||||
|
||||
use super::Instruction;
|
||||
@@ -287,31 +332,37 @@ mod tests {
|
||||
let expected = vec![
|
||||
Instruction::IndexedAssign {
|
||||
x: Symbol {
|
||||
kind: Kind::Label(Global::Stack),
|
||||
address: Address::Label(Global::Stack),
|
||||
type_hint: Type::Word,
|
||||
kind: Global::Stack.kind(),
|
||||
},
|
||||
index: Symbol {
|
||||
kind: Kind::Label(Global::StackHeight),
|
||||
address: Address::Label(Global::StackHeight),
|
||||
type_hint: Type::Int(4),
|
||||
kind: Global::StackHeight.kind(),
|
||||
},
|
||||
y: Symbol {
|
||||
kind: Kind::Constant(U256::one()),
|
||||
address: Address::Constant(U256::one()),
|
||||
type_hint: Type::Bytes(1),
|
||||
kind: Kind::Value,
|
||||
},
|
||||
},
|
||||
Instruction::BinaryAssign {
|
||||
x: Symbol {
|
||||
kind: Kind::Label(Global::StackHeight),
|
||||
address: Address::Label(Global::StackHeight),
|
||||
type_hint: Type::Int(4),
|
||||
kind: Global::StackHeight.kind(),
|
||||
},
|
||||
y: Symbol {
|
||||
kind: Kind::Label(Global::StackHeight),
|
||||
address: Address::Label(Global::StackHeight),
|
||||
type_hint: Type::Int(4),
|
||||
kind: Global::StackHeight.kind(),
|
||||
},
|
||||
operator: Operator::Add,
|
||||
z: Symbol {
|
||||
kind: Kind::Constant(U256::one()),
|
||||
address: Address::Constant(U256::one()),
|
||||
type_hint: Type::Int(4),
|
||||
kind: Kind::Value,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
+66
-15
@@ -2,13 +2,23 @@ use indexmap::IndexSet;
|
||||
use primitive_types::U256;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum Kind {
|
||||
pub enum Address {
|
||||
Constant(U256),
|
||||
Temporary(usize),
|
||||
Label(Global),
|
||||
}
|
||||
|
||||
impl Kind {
|
||||
impl std::fmt::Display for Address {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Constant(value) => write!(f, "{value:02x}"),
|
||||
Self::Temporary(n) => write!(f, "tmp_{n}"),
|
||||
Self::Label(label) => write!(f, "{label:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Address {
|
||||
pub fn from_be_bytes(bytes: &[u8]) -> Self {
|
||||
Self::Constant(U256::from_big_endian(bytes))
|
||||
}
|
||||
@@ -16,8 +26,15 @@ impl Kind {
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct Symbol {
|
||||
pub kind: Kind,
|
||||
pub address: Address,
|
||||
pub type_hint: Type,
|
||||
pub kind: Kind,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Symbol {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "({}) {}", self.type_hint, self.address)
|
||||
}
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
@@ -27,11 +44,15 @@ impl Symbol {
|
||||
_ => Default::default(),
|
||||
};
|
||||
|
||||
Self::new(Kind::Label(symbol), type_hint)
|
||||
Self::new(Address::Label(symbol), type_hint, symbol.kind())
|
||||
}
|
||||
|
||||
fn new(kind: Kind, type_hint: Type) -> Self {
|
||||
Self { kind, type_hint }
|
||||
fn new(address: Address, type_hint: Type, kind: Kind) -> Self {
|
||||
Self {
|
||||
address,
|
||||
type_hint,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,30 +65,42 @@ pub enum Type {
|
||||
Bool,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Type {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Word => write!(f, "word"),
|
||||
Self::Int(size) => write!(f, "int{}", size * 8),
|
||||
Self::Bytes(size) => write!(f, "bytes{size}"),
|
||||
Self::Bool => write!(f, "bool"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn pointer() -> Self {
|
||||
Self::Int(4)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum Kind {
|
||||
Pointer,
|
||||
Value,
|
||||
Function,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum Global {
|
||||
/// Pointer
|
||||
Stack,
|
||||
/// Stack height variable
|
||||
StackHeight,
|
||||
|
||||
/// Pointer
|
||||
CallData,
|
||||
/// Pointer
|
||||
Memory,
|
||||
/// Pointer
|
||||
ReturnData,
|
||||
|
||||
/// Low level `memcpy` like function
|
||||
MemoryCopy,
|
||||
|
||||
// EVM
|
||||
// EVM runtime environment
|
||||
Sha3,
|
||||
Address,
|
||||
CallDataLoad,
|
||||
@@ -106,6 +139,16 @@ pub enum Global {
|
||||
Event,
|
||||
}
|
||||
|
||||
impl Global {
|
||||
pub fn kind(&self) -> Kind {
|
||||
match self {
|
||||
Self::Stack | Self::CallData | Self::Memory | Self::ReturnData => Kind::Pointer,
|
||||
Self::StackHeight => Kind::Value,
|
||||
_ => Kind::Function,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SymbolTable {
|
||||
symbols: IndexSet<Symbol>,
|
||||
@@ -121,14 +164,22 @@ impl SymbolTable {
|
||||
|
||||
pub fn temporary(&mut self, type_hint: Option<Type>) -> Symbol {
|
||||
let id = self.next();
|
||||
let symbol = Symbol::new(Kind::Temporary(id), type_hint.unwrap_or_default());
|
||||
let symbol = Symbol::new(
|
||||
Address::Temporary(id),
|
||||
type_hint.unwrap_or_default(),
|
||||
Kind::Value,
|
||||
);
|
||||
assert!(self.symbols.insert(symbol));
|
||||
|
||||
symbol
|
||||
}
|
||||
|
||||
pub fn constant(&mut self, value: U256, type_hint: Option<Type>) -> Symbol {
|
||||
let symbol = Symbol::new(Kind::Constant(value), type_hint.unwrap_or_default());
|
||||
let symbol = Symbol::new(
|
||||
Address::Constant(value),
|
||||
type_hint.unwrap_or_default(),
|
||||
Kind::Value,
|
||||
);
|
||||
self.symbols.insert(symbol);
|
||||
|
||||
symbol
|
||||
|
||||
Reference in New Issue
Block a user