1use crate::{Buffer, Error, Result};
6use opcodes::{for_each_cancun_operator, Cancun as OpCode, OpCode as _};
7
8const MAX_STACK_SIZE: u16 = 1024;
9
10#[derive(Default, Clone, Debug)]
12pub struct Assembler {
13 buffer: Buffer,
15 gas: u128,
21 pub mp: usize,
23 pub sp: u16,
25}
26
27impl Assembler {
28 pub fn buffer(&self) -> &[u8] {
30 &self.buffer
31 }
32
33 pub fn buffer_mut(&mut self) -> &mut Buffer {
35 &mut self.buffer
36 }
37
38 pub fn increment_gas(&mut self, gas: u128) {
42 self.gas += gas;
43 }
44
45 pub fn increment_sp(&mut self, items: u16) -> Result<()> {
47 if items == 0 {
48 return Ok(());
49 }
50
51 tracing::trace!(
52 "increment stack pointer {}.add({items}) -> {}",
53 self.sp,
54 self.sp + items
55 );
56 self.sp = self
57 .sp
58 .checked_add(items)
59 .ok_or(Error::StackOverflow(self.sp, items))?;
60
61 if self.sp > MAX_STACK_SIZE {
62 return Err(Error::StackOverflow(self.sp, items));
63 }
64
65 Ok(())
66 }
67
68 pub fn decrement_sp(&mut self, items: u16) -> Result<()> {
70 if items == 0 {
71 return Ok(());
72 }
73
74 tracing::trace!(
75 "decrement stack pointer {}.sub({items}) -> {}",
76 self.sp,
77 self.sp - items
78 );
79 self.sp = if self.sp == items {
80 0
81 } else {
82 self.sp
83 .checked_sub(items)
84 .ok_or(Error::StackUnderflow(self.sp, items))?
85 };
86
87 Ok(())
88 }
89
90 pub fn increment_mp(&mut self, offset: usize) -> Result<()> {
92 self.mp = self
93 .mp
94 .checked_add(offset)
95 .ok_or(Error::MemoryOutOfBounds)?;
96
97 Ok(())
98 }
99
100 pub fn decrement_mp(&mut self, offset: usize) -> Result<()> {
102 self.mp = self
103 .mp
104 .checked_sub(offset)
105 .ok_or(Error::MemoryOutOfBounds)?;
106 Ok(())
107 }
108
109 pub fn emit(&mut self, byte: u8) {
111 self.buffer.push(byte);
112 }
113
114 pub fn emitn(&mut self, bytes: &[u8]) {
116 self.buffer.extend_from_slice(bytes);
117 }
118
119 pub fn emit_op(&mut self, opcode: OpCode) -> Result<()> {
124 tracing::trace!("emit opcode: {:?}", opcode);
125 self.decrement_sp(opcode.stack_in())?;
126 self.emit(opcode.into());
127 self.increment_gas(opcode.gas().into());
128 self.increment_sp(opcode.stack_out())?;
129
130 Ok(())
131 }
132}
133
134macro_rules! impl_opcodes {
135 ($($name:ident => $opcode:ident),+) => {
136 $(
137 #[doc = concat!(" Emit ", stringify!($opcode))]
138 pub fn $name(&mut self) -> Result<()> {
139 self.emit_op(OpCode::$opcode)?;
140 Ok(())
141 }
142 )*
143 };
144}
145
146impl Assembler {
148 for_each_cancun_operator!(impl_opcodes);
149}