1use super::utility::{read_i16, read_u16};
2use crate::{
3 gas,
4 primitives::{Bytes, Spec, U256},
5 Host, InstructionResult, Interpreter, InterpreterResult,
6};
7
8pub fn rjump<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
9 require_eof!(interpreter);
10 gas!(interpreter, gas::BASE);
11 let offset = unsafe { read_i16(interpreter.instruction_pointer) } as isize;
12 interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(offset + 2) };
15}
16
17pub fn rjumpi<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
18 require_eof!(interpreter);
19 gas!(interpreter, gas::CONDITION_JUMP_GAS);
20 pop!(interpreter, condition);
21 let mut offset = 2;
24 if !condition.is_zero() {
25 offset += unsafe { read_i16(interpreter.instruction_pointer) } as isize;
26 }
27
28 interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(offset) };
29}
30
31pub fn rjumpv<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
32 require_eof!(interpreter);
33 gas!(interpreter, gas::CONDITION_JUMP_GAS);
34 pop!(interpreter, case);
35 let case = as_isize_saturated!(case);
36
37 let max_index = unsafe { *interpreter.instruction_pointer } as isize;
38 let mut offset = (max_index + 1) * 2 + 1;
41
42 if case <= max_index {
43 offset += unsafe {
44 read_i16(
45 interpreter
46 .instruction_pointer
47 .offset(1 + case * 2),
49 )
50 } as isize;
51 }
52
53 interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(offset) };
54}
55
56pub fn jump<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
57 gas!(interpreter, gas::MID);
58 pop!(interpreter, target);
59 jump_inner(interpreter, target);
60}
61
62pub fn jumpi<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
63 gas!(interpreter, gas::HIGH);
64 pop!(interpreter, target, cond);
65 if !cond.is_zero() {
66 jump_inner(interpreter, target);
67 }
68}
69
70#[inline]
71fn jump_inner(interpreter: &mut Interpreter, target: U256) {
72 let target = as_usize_or_fail!(interpreter, target, InstructionResult::InvalidJump);
73 if !interpreter.contract.is_valid_jump(target) {
74 interpreter.instruction_result = InstructionResult::InvalidJump;
75 return;
76 }
77 interpreter.instruction_pointer = unsafe { interpreter.bytecode.as_ptr().add(target) };
79}
80
81pub fn jumpdest_or_nop<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
82 gas!(interpreter, gas::JUMPDEST);
83}
84
85pub fn callf<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
86 require_eof!(interpreter);
87 gas!(interpreter, gas::LOW);
88
89 let idx = unsafe { read_u16(interpreter.instruction_pointer) } as usize;
90
91 if interpreter.function_stack.return_stack_len() >= 1024 {
92 interpreter.instruction_result = InstructionResult::EOFFunctionStackOverflow;
93 return;
94 }
95
96 let Some(types) = interpreter.eof().unwrap().body.types_section.get(idx) else {
98 panic!("Invalid EOF in execution, expecting correct intermediate in callf")
99 };
100
101 if interpreter.stack.len() + (types.max_stack_size - types.inputs as u16) as usize > 1024 {
104 interpreter.instruction_result = InstructionResult::StackOverflow;
105 return;
106 }
107
108 interpreter
111 .function_stack
112 .push(interpreter.program_counter() + 2, idx);
113
114 interpreter.load_eof_code(idx, 0)
115}
116
117pub fn retf<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
118 require_eof!(interpreter);
119 gas!(interpreter, gas::RETF_GAS);
120
121 let Some(fframe) = interpreter.function_stack.pop() else {
122 panic!("Expected function frame")
123 };
124
125 interpreter.load_eof_code(fframe.idx, fframe.pc);
126}
127
128pub fn jumpf<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
129 require_eof!(interpreter);
130 gas!(interpreter, gas::LOW);
131
132 let idx = unsafe { read_u16(interpreter.instruction_pointer) } as usize;
133
134 let Some(types) = interpreter.eof().unwrap().body.types_section.get(idx) else {
136 panic!("Invalid EOF in execution, expecting correct intermediate in jumpf")
137 };
138
139 if interpreter.stack.len() + (types.max_stack_size - types.inputs as u16) as usize > 1024 {
142 interpreter.instruction_result = InstructionResult::StackOverflow;
143 return;
144 }
145
146 interpreter.function_stack.set_current_code_idx(idx);
147 interpreter.load_eof_code(idx, 0)
148}
149
150pub fn pc<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
151 gas!(interpreter, gas::BASE);
152 push!(interpreter, U256::from(interpreter.program_counter() - 1));
154}
155
156#[inline]
157fn return_inner(interpreter: &mut Interpreter, instruction_result: InstructionResult) {
158 pop!(interpreter, offset, len);
161 let len = as_usize_or_fail!(interpreter, len);
162 let mut output = Bytes::default();
164 if len != 0 {
165 let offset = as_usize_or_fail!(interpreter, offset);
166 resize_memory!(interpreter, offset, len);
167
168 output = interpreter.shared_memory.slice(offset, len).to_vec().into()
169 }
170 interpreter.instruction_result = instruction_result;
171 interpreter.next_action = crate::InterpreterAction::Return {
172 result: InterpreterResult {
173 output,
174 gas: interpreter.gas,
175 result: instruction_result,
176 },
177 };
178}
179
180pub fn ret<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
181 return_inner(interpreter, InstructionResult::Return);
182}
183
184pub fn revert<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
186 check!(interpreter, BYZANTIUM);
187 return_inner(interpreter, InstructionResult::Revert);
188}
189
190pub fn stop<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
192 interpreter.instruction_result = InstructionResult::Stop;
193}
194
195pub fn invalid<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
197 interpreter.instruction_result = InstructionResult::InvalidFEOpcode;
198}
199
200pub fn unknown<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
202 interpreter.instruction_result = InstructionResult::OpcodeNotFound;
203}
204
205#[cfg(test)]
206mod test {
207 use std::sync::Arc;
208
209 use revm_primitives::{bytes, eof::TypesSection, Bytecode, Eof, PragueSpec};
210
211 use super::*;
212 use crate::{
213 opcode::{make_instruction_table, CALLF, JUMPF, NOP, RETF, RJUMP, RJUMPI, RJUMPV, STOP},
214 DummyHost, FunctionReturnFrame, Gas, Interpreter,
215 };
216
217 #[test]
218 fn rjump() {
219 let table = make_instruction_table::<_, PragueSpec>();
220 let mut host = DummyHost::default();
221 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(Bytes::from([
222 RJUMP, 0x00, 0x02, STOP, STOP,
223 ])));
224 interp.is_eof = true;
225 interp.gas = Gas::new(10000);
226
227 interp.step(&table, &mut host);
228 assert_eq!(interp.program_counter(), 5);
229 }
230
231 #[test]
232 fn rjumpi() {
233 let table = make_instruction_table::<_, PragueSpec>();
234 let mut host = DummyHost::default();
235 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(Bytes::from([
236 RJUMPI, 0x00, 0x03, RJUMPI, 0x00, 0x01, STOP, STOP,
237 ])));
238 interp.is_eof = true;
239 interp.stack.push(U256::from(1)).unwrap();
240 interp.stack.push(U256::from(0)).unwrap();
241 interp.gas = Gas::new(10000);
242
243 interp.step(&table, &mut host);
245 assert_eq!(interp.program_counter(), 3);
246 interp.step(&table, &mut host);
248 assert_eq!(interp.program_counter(), 7);
249 }
250
251 #[test]
252 fn rjumpv() {
253 let table = make_instruction_table::<_, PragueSpec>();
254 let mut host = DummyHost::default();
255 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(Bytes::from([
256 RJUMPV,
257 0x01, 0x00, 0x01,
260 0x00, 0x02,
262 NOP,
263 NOP,
264 NOP,
265 RJUMP,
266 0xFF,
267 (-12i8) as u8,
268 STOP,
269 ])));
270 interp.is_eof = true;
271 interp.gas = Gas::new(1000);
272
273 interp.stack.push(U256::from(10)).unwrap();
275 interp.step(&table, &mut host);
276 assert_eq!(interp.program_counter(), 6);
277
278 interp.step(&table, &mut host);
280 interp.step(&table, &mut host);
281 interp.step(&table, &mut host);
282 interp.step(&table, &mut host);
283 assert_eq!(interp.program_counter(), 0);
284
285 interp.stack.push(U256::from(0)).unwrap();
287 interp.step(&table, &mut host);
288 assert_eq!(interp.program_counter(), 7);
289
290 interp.step(&table, &mut host);
292 interp.step(&table, &mut host);
293 interp.step(&table, &mut host);
294 assert_eq!(interp.program_counter(), 0);
295
296 interp.stack.push(U256::from(1)).unwrap();
298 interp.step(&table, &mut host);
299 assert_eq!(interp.program_counter(), 8);
300 }
301
302 fn dummy_eof() -> Eof {
303 let bytes = bytes!("ef000101000402000100010400000000800000fe");
304 Eof::decode(bytes).unwrap()
305 }
306
307 fn eof_setup(bytes1: Bytes, bytes2: Bytes) -> Interpreter {
308 eof_setup_with_types(bytes1, bytes2, TypesSection::default())
309 }
310
311 fn eof_setup_with_types(bytes1: Bytes, bytes2: Bytes, types: TypesSection) -> Interpreter {
313 let mut eof = dummy_eof();
314
315 eof.body.code_section.clear();
316 eof.body.types_section.clear();
317 eof.header.code_sizes.clear();
318
319 eof.header.code_sizes.push(bytes1.len() as u16);
320 eof.body.code_section.push(bytes1.clone());
321 eof.body.types_section.push(TypesSection::new(0, 0, 11));
322
323 eof.header.code_sizes.push(bytes2.len() as u16);
324 eof.body.code_section.push(bytes2.clone());
325 eof.body.types_section.push(types);
326
327 let mut interp = Interpreter::new_bytecode(Bytecode::Eof(Arc::new(eof)));
328 interp.gas = Gas::new(10000);
329 interp
330 }
331
332 #[test]
333 fn callf_retf_stop() {
334 let table = make_instruction_table::<_, PragueSpec>();
335 let mut host = DummyHost::default();
336
337 let bytes1 = Bytes::from([CALLF, 0x00, 0x01, STOP]);
338 let bytes2 = Bytes::from([RETF]);
339 let mut interp = eof_setup(bytes1, bytes2.clone());
340
341 interp.step(&table, &mut host);
343
344 assert_eq!(interp.function_stack.current_code_idx, 1);
345 assert_eq!(
346 interp.function_stack.return_stack[0],
347 FunctionReturnFrame::new(0, 3)
348 );
349 assert_eq!(interp.instruction_pointer, bytes2.as_ptr());
350
351 interp.step(&table, &mut host);
353
354 assert_eq!(interp.function_stack.current_code_idx, 0);
355 assert_eq!(interp.function_stack.return_stack, Vec::new());
356 assert_eq!(interp.program_counter(), 3);
357
358 interp.step(&table, &mut host);
360 assert_eq!(interp.instruction_result, InstructionResult::Stop);
361 }
362
363 #[test]
364 fn callf_stop() {
365 let table = make_instruction_table::<_, PragueSpec>();
366 let mut host = DummyHost::default();
367
368 let bytes1 = Bytes::from([CALLF, 0x00, 0x01]);
369 let bytes2 = Bytes::from([STOP]);
370 let mut interp = eof_setup(bytes1, bytes2.clone());
371
372 interp.step(&table, &mut host);
374
375 assert_eq!(interp.function_stack.current_code_idx, 1);
376 assert_eq!(
377 interp.function_stack.return_stack[0],
378 FunctionReturnFrame::new(0, 3)
379 );
380 assert_eq!(interp.instruction_pointer, bytes2.as_ptr());
381
382 interp.step(&table, &mut host);
384 assert_eq!(interp.instruction_result, InstructionResult::Stop);
385 }
386
387 #[test]
388 fn callf_stack_overflow() {
389 let table = make_instruction_table::<_, PragueSpec>();
390 let mut host = DummyHost::default();
391
392 let bytes1 = Bytes::from([CALLF, 0x00, 0x01]);
393 let bytes2 = Bytes::from([STOP]);
394 let mut interp =
395 eof_setup_with_types(bytes1, bytes2.clone(), TypesSection::new(0, 0, 1025));
396
397 interp.step(&table, &mut host);
399
400 assert_eq!(interp.instruction_result, InstructionResult::StackOverflow);
402 }
403
404 #[test]
405 fn jumpf_stop() {
406 let table = make_instruction_table::<_, PragueSpec>();
407 let mut host = DummyHost::default();
408
409 let bytes1 = Bytes::from([JUMPF, 0x00, 0x01]);
410 let bytes2 = Bytes::from([STOP]);
411 let mut interp = eof_setup(bytes1, bytes2.clone());
412
413 interp.step(&table, &mut host);
415
416 assert_eq!(interp.function_stack.current_code_idx, 1);
417 assert!(interp.function_stack.return_stack.is_empty());
418 assert_eq!(interp.instruction_pointer, bytes2.as_ptr());
419
420 interp.step(&table, &mut host);
422 assert_eq!(interp.instruction_result, InstructionResult::Stop);
423 }
424
425 #[test]
426 fn jumpf_stack_overflow() {
427 let table = make_instruction_table::<_, PragueSpec>();
428 let mut host = DummyHost::default();
429
430 let bytes1 = Bytes::from([JUMPF, 0x00, 0x01]);
431 let bytes2 = Bytes::from([STOP]);
432 let mut interp =
433 eof_setup_with_types(bytes1, bytes2.clone(), TypesSection::new(0, 0, 1025));
434
435 interp.step(&table, &mut host);
437
438 assert_eq!(interp.instruction_result, InstructionResult::StackOverflow);
440 }
441}