revm_bytecode/legacy/
analyzed.rs1use super::JumpTable;
2use crate::opcode;
3use primitives::Bytes;
4
5#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct LegacyAnalyzedBytecode {
32 bytecode: Bytes,
34 original_len: usize,
36 jump_table: JumpTable,
38}
39
40impl Default for LegacyAnalyzedBytecode {
41 #[inline]
42 fn default() -> Self {
43 Self {
44 bytecode: Bytes::from_static(&[0]),
45 original_len: 0,
46 jump_table: JumpTable::default(),
47 }
48 }
49}
50
51impl LegacyAnalyzedBytecode {
52 pub fn analyze(bytecode: Bytes) -> Self {
56 let original_len = bytecode.len();
57 let (jump_table, padded_bytecode) = super::analysis::analyze_legacy(bytecode);
58 Self::new(padded_bytecode, original_len, jump_table)
59 }
60
61 pub fn new(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self {
71 assert!(
72 original_len <= bytecode.len(),
73 "original_len is greater than bytecode length"
74 );
75 assert!(
76 original_len <= jump_table.len(),
77 "jump table length is less than original length"
78 );
79 assert!(!bytecode.is_empty(), "bytecode cannot be empty");
80
81 if let Some(&last_opcode) = bytecode.last() {
82 assert!(
83 opcode::OpCode::info_by_op(last_opcode)
84 .map(|o| o.is_terminating())
85 .unwrap_or(false),
86 "last bytecode byte should be terminating"
87 );
88 }
89
90 Self {
91 bytecode,
92 original_len,
93 jump_table,
94 }
95 }
96
97 pub fn bytecode(&self) -> &Bytes {
101 &self.bytecode
102 }
103
104 pub fn original_len(&self) -> usize {
106 self.original_len
107 }
108
109 pub fn original_bytes(&self) -> Bytes {
111 self.bytecode.slice(..self.original_len)
112 }
113
114 pub fn original_byte_slice(&self) -> &[u8] {
116 &self.bytecode[..self.original_len]
117 }
118
119 pub fn jump_table(&self) -> &JumpTable {
121 &self.jump_table
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128 use crate::{opcode, LegacyRawBytecode};
129 use bitvec::{bitvec, order::Lsb0};
130
131 #[test]
132 fn test_bytecode_new() {
133 let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]);
134 let bytecode = LegacyRawBytecode(bytecode).into_analyzed();
135 let _ = LegacyAnalyzedBytecode::new(
136 bytecode.bytecode,
137 bytecode.original_len,
138 bytecode.jump_table,
139 );
140 }
141
142 #[test]
143 #[should_panic(expected = "original_len is greater than bytecode length")]
144 fn test_panic_on_large_original_len() {
145 let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]);
146 let bytecode = LegacyRawBytecode(bytecode).into_analyzed();
147 let _ = LegacyAnalyzedBytecode::new(bytecode.bytecode, 100, bytecode.jump_table);
148 }
149
150 #[test]
151 #[should_panic(expected = "jump table length is less than original length")]
152 fn test_panic_on_short_jump_table() {
153 let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]);
154 let bytecode = LegacyRawBytecode(bytecode).into_analyzed();
155 let jump_table = JumpTable::new(bitvec![u8, Lsb0; 0; 1]);
156 let _ = LegacyAnalyzedBytecode::new(bytecode.bytecode, bytecode.original_len, jump_table);
157 }
158
159 #[test]
160 #[should_panic(expected = "bytecode cannot be empty")]
161 fn test_panic_on_empty_bytecode() {
162 let bytecode = Bytes::from_static(&[]);
163 let jump_table = JumpTable::new(bitvec![u8, Lsb0; 0; 0]);
164 let _ = LegacyAnalyzedBytecode::new(bytecode, 0, jump_table);
165 }
166
167 #[test]
168 #[should_panic(expected = "last bytecode byte should be terminating")]
169 fn test_panic_on_non_stop_bytecode() {
170 let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]);
171 let jump_table = JumpTable::new(bitvec![u8, Lsb0; 0; 2]);
172 let _ = LegacyAnalyzedBytecode::new(bytecode, 2, jump_table);
173 }
174}