1use super::with_evm_context;
2use crate::{Backend, EvmCompiler};
3use revm_bytecode::opcode as op;
4use revm_interpreter::InstructionResult;
5use revm_primitives::{U256, hardfork::SpecId};
6
7matrix_tests!(
9 translate_then_compile = |compiler| {
10 let bytecode: &[u8] = &[];
11 let spec_id = SpecId::CANCUN;
12 compiler.gas_metering(false);
13 let gas_id = compiler.translate("test1", bytecode, spec_id).unwrap();
14 compiler.gas_metering(true);
15 let no_gas_id = compiler.translate("test2", bytecode, spec_id).unwrap();
16 let gas_fn = unsafe { compiler.jit_function(gas_id) }.unwrap();
17 let no_gas_fn = unsafe { compiler.jit_function(no_gas_id) }.unwrap();
18 with_evm_context(bytecode, spec_id, |ecx, stack, stack_len| {
19 let r = unsafe { gas_fn.call(stack, stack_len, ecx) };
20 assert_eq!(r, InstructionResult::Stop);
21 let r = unsafe { no_gas_fn.call(stack, stack_len, ecx) };
22 assert_eq!(r, InstructionResult::Stop);
23 });
24 }
25);
26
27matrix_tests!(
30 clear_ir_between_compiles = |compiler| {
31 use revm_bytecode::opcode as op;
32
33 let spec_id = SpecId::CANCUN;
34 compiler.inspect_stack(true);
35
36 let bytecode1: &[u8] = &[op::PUSH1, 42];
38 let f1 = unsafe { compiler.jit("clear_ir_1", bytecode1, spec_id) }.unwrap();
39
40 compiler.clear_ir().unwrap();
41
42 let bytecode2: &[u8] =
45 &[op::PUSH1, 42, op::PUSH1, 0, op::MSTORE, op::PUSH1, 1, op::PUSH1, 2, op::ADD];
46 let f2 = unsafe { compiler.jit("clear_ir_2", bytecode2, spec_id) }.unwrap();
47
48 with_evm_context(bytecode1, spec_id, |ecx, stack, stack_len| {
50 let r = unsafe { f1.call(stack, stack_len, ecx) };
51 assert_eq!(r, InstructionResult::Stop);
52 assert_eq!(*stack_len, 1);
53 assert_eq!(unsafe { stack.as_slice(*stack_len) }[0].to_u256(), U256::from(42));
54 });
55
56 with_evm_context(bytecode2, spec_id, |ecx, stack, stack_len| {
58 let r = unsafe { f2.call(stack, stack_len, ecx) };
59 assert_eq!(r, InstructionResult::Stop);
60 assert_eq!(*stack_len, 1);
61 assert_eq!(unsafe { stack.as_slice(*stack_len) }[0].to_u256(), U256::from(3));
62 });
63 }
64);
65
66fn push_stop(value: u8) -> [u8; 3] {
68 [op::PUSH1, value, op::STOP]
69}
70
71fn jit_and_verify<B: Backend>(
73 compiler: &mut EvmCompiler<B>,
74 name: &str,
75 code: &[u8],
76 expected: U256,
77) -> B::FuncId {
78 compiler.inspect_stack(true);
79 let id = compiler.translate(name, code, super::DEF_SPEC).unwrap();
80 let f = unsafe { compiler.jit_function(id) }.unwrap();
81
82 with_evm_context(code, super::DEF_SPEC, |ecx, stack, stack_len| {
83 let r = unsafe { f.call(stack, stack_len, ecx) };
84 assert_eq!(r, InstructionResult::Stop, "{name}: unexpected return");
85 assert_eq!(*stack_len, 1, "{name}: expected 1 stack element");
86 assert_eq!(
87 unsafe { stack.as_slice(*stack_len) }[0].to_u256(),
88 expected,
89 "{name}: wrong value"
90 );
91 });
92 id
93}
94
95matrix_tests!(
97 free_single = |compiler| {
98 let code = push_stop(0x42);
99 let id = jit_and_verify(compiler, "f1", &code, U256::from(0x42));
100
101 unsafe { compiler.free_function(id) }.unwrap();
102
103 compiler.clear_ir().unwrap();
105 let code2 = push_stop(0x69);
106 jit_and_verify(compiler, "f2", &code2, U256::from(0x69));
107 }
108);
109
110matrix_tests!(
112 free_all = |compiler| {
113 let code = push_stop(0x10);
114 jit_and_verify(compiler, "g1", &code, U256::from(0x10));
115
116 unsafe { compiler.clear() }.unwrap();
117
118 let code2 = push_stop(0x20);
119 jit_and_verify(compiler, "g2", &code2, U256::from(0x20));
120 }
121);
122
123matrix_tests!(
126 repeated_clear_recompile = |compiler| {
127 for i in 0..1000u32 {
128 let code = push_stop((i & 0xFF) as u8);
129 jit_and_verify(compiler, "f", &code, U256::from(i & 0xFF));
130 unsafe { compiler.clear() }.unwrap();
131 }
132 }
133);
134
135matrix_tests!(
137 free_single_then_clear = |compiler| {
138 let code_a = push_stop(0xAA);
139 let id_a = jit_and_verify(compiler, "h1", &code_a, U256::from(0xAA));
140
141 compiler.clear_ir().unwrap();
142 let code_b = push_stop(0xBB);
143 jit_and_verify(compiler, "h2", &code_b, U256::from(0xBB));
144
145 unsafe { compiler.free_function(id_a) }.unwrap();
147
148 unsafe { compiler.clear() }.unwrap();
150
151 let code_c = push_stop(0xCC);
153 jit_and_verify(compiler, "h3", &code_c, U256::from(0xCC));
154 }
155);
156
157matrix_tests!(
159 free_multiple_individually = |compiler| {
160 let code_a = push_stop(0x11);
161 let id_a = jit_and_verify(compiler, "m1", &code_a, U256::from(0x11));
162
163 compiler.clear_ir().unwrap();
164 let code_b = push_stop(0x22);
165 let id_b = jit_and_verify(compiler, "m2", &code_b, U256::from(0x22));
166
167 unsafe { compiler.free_function(id_a) }.unwrap();
169 unsafe { compiler.free_function(id_b) }.unwrap();
170
171 compiler.clear_ir().unwrap();
173 let code_c = push_stop(0x33);
174 jit_and_verify(compiler, "m3", &code_c, U256::from(0x33));
175 }
176);
177
178#[cfg(feature = "llvm")]
181#[test]
182fn jit_memory_usage_tracking() {
183 use super::with_jit_compiler;
184 use revmc_llvm::jit_memory_usage;
185
186 with_jit_compiler(revmc_backend::OptimizationLevel::default(), |compiler| {
187 let baseline = jit_memory_usage().map(|u| u.total_bytes()).unwrap_or(0);
188
189 let code_a = push_stop(0x42);
190 let id_a = jit_and_verify(compiler, "mem_a", &code_a, U256::from(0x42));
191 let after_a = jit_memory_usage().unwrap().total_bytes();
192 assert!(after_a > baseline, "expected memory increase after first compile");
193
194 compiler.clear_ir().unwrap();
195 let code_b = push_stop(0x69);
196 let id_b = jit_and_verify(compiler, "mem_b", &code_b, U256::from(0x69));
197 let after_b = jit_memory_usage().unwrap().total_bytes();
198 assert!(after_b > after_a, "expected memory increase after second compile");
199
200 unsafe { compiler.free_function(id_a) }.unwrap();
201 let after_free_a = jit_memory_usage().unwrap().total_bytes();
202 assert!(after_free_a < after_b, "expected memory decrease after freeing first function");
203
204 unsafe { compiler.free_function(id_b) }.unwrap();
205 let after_free_b = jit_memory_usage().unwrap().total_bytes();
206 assert!(
207 after_free_b <= after_free_a,
208 "expected memory decrease after freeing second function"
209 );
210 });
211}
212
213matrix_tests!(
216 free_reuse_name = |compiler| {
217 let code_a = push_stop(0x42);
218 let id = jit_and_verify(compiler, "reuse", &code_a, U256::from(0x42));
219
220 unsafe { compiler.free_function(id) }.unwrap();
221 compiler.clear_ir().unwrap();
222
223 let code_b = push_stop(0x69);
225 jit_and_verify(compiler, "reuse", &code_b, U256::from(0x69));
226 }
227);