revmc_context/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), warn(unused_extern_crates))]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![cfg_attr(not(feature = "std"), no_std)]
5
6extern crate alloc;
7
8use alloc::vec::Vec;
9use core::{fmt, mem::MaybeUninit, ptr};
10use revm_interpreter::{
11    interpreter_types::{Jumps, ReturnData},
12    Gas, Host, InputsImpl, InstructionResult, Interpreter, InterpreterAction, InterpreterResult,
13    SharedMemory,
14};
15use revm_primitives::{ruint, Address, Bytes, U256};
16
17#[cfg(feature = "host-ext-any")]
18use core::any::Any;
19
20/// The EVM bytecode compiler runtime context.
21///
22/// This is a simple wrapper around the interpreter's resources, allowing the compiled function to
23/// access the memory, input, gas, host, and other resources.
24///
25/// # Safety
26/// This struct uses `#[repr(C)]` to ensure a stable field layout since the JIT compiler
27/// generates code that accesses fields by offset using `offset_of!`.
28#[repr(C)]
29pub struct EvmContext<'a> {
30    /// The memory.
31    pub memory: &'a mut SharedMemory,
32    /// Input information (target address, caller, input data, call value).
33    pub input: &'a mut InputsImpl,
34    /// The gas.
35    pub gas: &'a mut Gas,
36    /// The host.
37    pub host: &'a mut dyn HostExt,
38    /// The return action.
39    pub next_action: &'a mut Option<InterpreterAction>,
40    /// The return data.
41    pub return_data: &'a [u8],
42    /// Whether the context is static.
43    pub is_static: bool,
44    /// An index that is used internally to keep track of where execution should resume.
45    /// `0` is the initial state.
46    #[doc(hidden)]
47    pub resume_at: usize,
48}
49
50// Static assertions to ensure the struct layout matches expectations.
51// These offsets are used by the JIT compiler to access fields.
52const _: () = {
53    use core::mem::offset_of;
54    // EvmContext should be 80 bytes with #[repr(C)] (removed bytecode_ptr and bytecode_len)
55    assert!(core::mem::size_of::<EvmContext<'_>>() == 80);
56    // Key fields accessed by JIT code
57    assert!(offset_of!(EvmContext<'_>, memory) == 0);
58    assert!(offset_of!(EvmContext<'_>, resume_at) == 72);
59};
60
61impl fmt::Debug for EvmContext<'_> {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        f.debug_struct("EvmContext").field("memory", &self.memory).finish_non_exhaustive()
64    }
65}
66
67impl<'a> EvmContext<'a> {
68    /// Creates a new context from an interpreter.
69    #[inline]
70    pub fn from_interpreter(interpreter: &'a mut Interpreter, host: &'a mut dyn HostExt) -> Self {
71        Self::from_interpreter_with_stack(interpreter, host).0
72    }
73
74    /// Creates a new context from an interpreter.
75    #[inline]
76    pub fn from_interpreter_with_stack<'b: 'a>(
77        interpreter: &'a mut Interpreter,
78        host: &'b mut dyn HostExt,
79    ) -> (Self, &'a mut EvmStack, &'a mut usize) {
80        use revm_interpreter::interpreter_types::LegacyBytecode;
81
82        let (stack, stack_len) = EvmStack::from_interpreter_stack(&mut interpreter.stack);
83        let bytecode_slice = interpreter.bytecode.bytecode_slice();
84        let resume_at = ResumeAt::load(interpreter.bytecode.pc(), bytecode_slice);
85        let this = Self {
86            memory: &mut interpreter.memory,
87            input: &mut interpreter.input,
88            gas: &mut interpreter.gas,
89            host,
90            next_action: &mut interpreter.bytecode.action,
91            return_data: interpreter.return_data.buffer(),
92            is_static: interpreter.runtime_flag.is_static,
93            resume_at,
94        };
95        (this, stack, stack_len)
96    }
97}
98
99/// Extension trait for [`Host`].
100#[cfg(not(feature = "host-ext-any"))]
101pub trait HostExt: Host {}
102
103#[cfg(not(feature = "host-ext-any"))]
104impl<T: Host> HostExt for T {}
105
106/// Extension trait for [`Host`].
107#[cfg(feature = "host-ext-any")]
108pub trait HostExt: Host + Any {
109    #[doc(hidden)]
110    fn as_any(&self) -> &dyn Any;
111    #[doc(hidden)]
112    fn as_any_mut(&mut self) -> &mut dyn Any;
113}
114
115#[cfg(feature = "host-ext-any")]
116impl<T: Host + Any> HostExt for T {
117    fn as_any(&self) -> &dyn Any {
118        self
119    }
120
121    fn as_any_mut(&mut self) -> &mut dyn Any {
122        self
123    }
124}
125
126#[cfg(feature = "host-ext-any")]
127#[doc(hidden)]
128impl dyn HostExt {
129    /// Attempts to downcast the host to a concrete type.
130    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
131        self.as_any().downcast_ref()
132    }
133
134    /// Attempts to downcast the host to a concrete type.
135    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
136        self.as_any_mut().downcast_mut()
137    }
138}
139
140/// Declare [`RawEvmCompilerFn`] functions in an `extern "C"` block.
141///
142/// # Examples
143///
144/// ```no_run
145/// use revmc_context::{extern_revmc, EvmCompilerFn};
146///
147/// extern_revmc! {
148///    /// A simple function that returns `Continue`.
149///    pub fn test_fn;
150/// }
151///
152/// let test_fn = EvmCompilerFn::new(test_fn);
153/// ```
154#[macro_export]
155macro_rules! extern_revmc {
156    ($( $(#[$attr:meta])* $vis:vis fn $name:ident; )+) => {
157        #[allow(improper_ctypes)]
158        extern "C" {
159            $(
160                $(#[$attr])*
161                $vis fn $name(
162                    gas: *mut $crate::private::revm_interpreter::Gas,
163                    stack: *mut $crate::EvmStack,
164                    stack_len: *mut usize,
165                    input: *const $crate::private::revm_interpreter::InputsImpl,
166                    ecx: *mut $crate::EvmContext<'_>,
167                ) -> $crate::private::revm_interpreter::InstructionResult;
168            )+
169        }
170    };
171}
172
173/// The raw function signature of a bytecode function.
174///
175/// Prefer using [`EvmCompilerFn`] instead of this type. See [`EvmCompilerFn::call`] for more
176/// information.
177// When changing the signature, also update the corresponding declarations in `fn translate`.
178pub type RawEvmCompilerFn = unsafe extern "C" fn(
179    gas: *mut Gas,
180    stack: *mut EvmStack,
181    stack_len: *mut usize,
182    input: *const InputsImpl,
183    ecx: *mut EvmContext<'_>,
184) -> InstructionResult;
185
186/// An EVM bytecode function.
187#[derive(Clone, Copy, Debug, Hash)]
188pub struct EvmCompilerFn(RawEvmCompilerFn);
189
190impl From<RawEvmCompilerFn> for EvmCompilerFn {
191    #[inline]
192    fn from(f: RawEvmCompilerFn) -> Self {
193        Self::new(f)
194    }
195}
196
197impl From<EvmCompilerFn> for RawEvmCompilerFn {
198    #[inline]
199    fn from(f: EvmCompilerFn) -> Self {
200        f.into_inner()
201    }
202}
203
204impl EvmCompilerFn {
205    /// Wraps the function.
206    #[inline]
207    pub const fn new(f: RawEvmCompilerFn) -> Self {
208        Self(f)
209    }
210
211    /// Unwraps the function.
212    #[inline]
213    pub const fn into_inner(self) -> RawEvmCompilerFn {
214        self.0
215    }
216
217    /// Calls the function by re-using the interpreter's resources and memory.
218    ///
219    /// See [`call_with_interpreter_and_memory`](Self::call_with_interpreter_and_memory) for more
220    /// information.
221    ///
222    /// # Safety
223    ///
224    /// The caller must ensure that the function is safe to call.
225    #[inline]
226    pub unsafe fn call_with_interpreter_and_memory(
227        self,
228        interpreter: &mut Interpreter,
229        memory: &mut SharedMemory,
230        host: &mut dyn HostExt,
231    ) -> InterpreterAction {
232        interpreter.memory = core::mem::replace(memory, SharedMemory::invalid());
233        let result = self.call_with_interpreter(interpreter, host);
234        *memory = core::mem::replace(&mut interpreter.memory, SharedMemory::invalid());
235        result
236    }
237
238    /// Calls the function by re-using the interpreter's resources.
239    ///
240    /// This behaves similarly to `Interpreter::run_plain`, returning an [`InstructionResult`]
241    /// and the next action in an [`InterpreterAction`].
242    ///
243    /// # Safety
244    ///
245    /// The caller must ensure that the function is safe to call.
246    #[inline]
247    pub unsafe fn call_with_interpreter(
248        self,
249        interpreter: &mut Interpreter,
250        host: &mut dyn HostExt,
251    ) -> InterpreterAction {
252        interpreter.bytecode.action = None;
253
254        let (mut ecx, stack, stack_len) =
255            EvmContext::from_interpreter_with_stack(interpreter, host);
256        let result = self.call(Some(stack), Some(stack_len), &mut ecx);
257
258        // Set the remaining gas to 0 if the result is `OutOfGas`,
259        // as it might have overflown inside of the function.
260        if result == InstructionResult::OutOfGas {
261            ecx.gas.spend_all();
262        }
263
264        let return_data_is_empty = ecx.return_data.is_empty();
265
266        if return_data_is_empty {
267            interpreter.return_data.0.clear();
268        }
269
270        if let Some(action) = interpreter.bytecode.action.take() {
271            action
272        } else {
273            InterpreterAction::Return(InterpreterResult {
274                result,
275                output: Bytes::new(),
276                gas: interpreter.gas,
277            })
278        }
279    }
280
281    /// Calls the function.
282    ///
283    /// Arguments:
284    /// - `stack`: Pointer to the stack. Must be `Some` if `local_stack` is set to `false`.
285    /// - `stack_len`: Pointer to the stack length. Must be `Some` if `inspect_stack_length` is set
286    ///   to `true`.
287    /// - `ecx`: The context object.
288    ///
289    /// These conditions are enforced at runtime if `debug_assertions` is set to `true`.
290    ///
291    /// Use of this method is discouraged, as setup and cleanup need to be done manually.
292    ///
293    /// # Safety
294    ///
295    /// The caller must ensure that the arguments are valid and that the function is safe to call.
296    #[inline]
297    pub unsafe fn call(
298        self,
299        stack: Option<&mut EvmStack>,
300        stack_len: Option<&mut usize>,
301        ecx: &mut EvmContext<'_>,
302    ) -> InstructionResult {
303        (self.0)(ecx.gas, option_as_mut_ptr(stack), option_as_mut_ptr(stack_len), ecx.input, ecx)
304    }
305
306    /// Same as [`call`](Self::call) but with `#[inline(never)]`.
307    ///
308    /// Use of this method is discouraged, as setup and cleanup need to be done manually.
309    ///
310    /// # Safety
311    ///
312    /// See [`call`](Self::call).
313    #[inline(never)]
314    pub unsafe fn call_noinline(
315        self,
316        stack: Option<&mut EvmStack>,
317        stack_len: Option<&mut usize>,
318        ecx: &mut EvmContext<'_>,
319    ) -> InstructionResult {
320        self.call(stack, stack_len, ecx)
321    }
322}
323
324/// EVM context stack.
325#[repr(C)]
326#[allow(missing_debug_implementations)]
327pub struct EvmStack([MaybeUninit<EvmWord>; 1024]);
328
329#[allow(clippy::new_without_default)]
330impl EvmStack {
331    /// The size of the stack in bytes.
332    pub const SIZE: usize = 32 * Self::CAPACITY;
333
334    /// The size of the stack in U256 elements.
335    pub const CAPACITY: usize = 1024;
336
337    /// Creates a new EVM stack, allocated on the stack.
338    ///
339    /// Use [`EvmStack::new_heap`] to create a stack on the heap.
340    #[inline]
341    pub fn new() -> Self {
342        Self(unsafe { MaybeUninit::uninit().assume_init() })
343    }
344
345    /// Creates a vector that can be used as a stack.
346    #[inline]
347    pub fn new_heap() -> Vec<EvmWord> {
348        Vec::with_capacity(1024)
349    }
350
351    /// Creates a stack from the interpreter's stack. Assumes that the stack is large enough.
352    #[inline]
353    pub fn from_interpreter_stack(stack: &mut revm_interpreter::Stack) -> (&mut Self, &mut usize) {
354        debug_assert!(stack.data().capacity() >= Self::CAPACITY);
355        unsafe {
356            let data = Self::from_mut_ptr(stack.data_mut().as_mut_ptr().cast());
357            // Vec { data: ptr, cap: usize, len: usize }
358            let len = &mut *(stack.data_mut() as *mut Vec<_>).cast::<usize>().add(2);
359            debug_assert_eq!(stack.len(), *len);
360            (data, len)
361        }
362    }
363
364    /// Creates a stack from a vector's buffer.
365    ///
366    /// # Panics
367    ///
368    /// Panics if the vector's capacity is less than the required stack capacity.
369    #[inline]
370    pub fn from_vec(vec: &Vec<EvmWord>) -> &Self {
371        assert!(vec.capacity() >= Self::CAPACITY);
372        unsafe { Self::from_ptr(vec.as_ptr()) }
373    }
374
375    /// Creates a stack from a mutable vector's buffer.
376    ///
377    /// # Panics
378    ///
379    /// Panics if the vector's capacity is less than the required stack capacity.
380    #[inline]
381    pub fn from_mut_vec(vec: &mut Vec<EvmWord>) -> &mut Self {
382        assert!(vec.capacity() >= Self::CAPACITY);
383        unsafe { Self::from_mut_ptr(vec.as_mut_ptr()) }
384    }
385
386    /// Creates a stack from a pointer to a buffer.
387    ///
388    /// # Safety
389    ///
390    /// See [`from_vec`](Self::from_vec).
391    #[inline]
392    pub const unsafe fn from_ptr(ptr: *const EvmWord) -> &'static Self {
393        &*ptr.cast::<Self>()
394    }
395
396    /// Creates a stack from a mutable pointer to a buffer.
397    ///
398    /// # Safety
399    ///
400    /// See [`from_mut_vec`](Self::from_mut_vec).
401    #[inline]
402    pub unsafe fn from_mut_ptr(ptr: *mut EvmWord) -> &'static mut Self {
403        &mut *ptr.cast::<Self>()
404    }
405
406    /// Returns a pointer to the stack.
407    #[inline]
408    pub const fn as_ptr(&self) -> *const EvmWord {
409        self.0.as_ptr().cast()
410    }
411
412    /// Returns a mutable pointer to the stack.
413    #[inline]
414    pub fn as_mut_ptr(&mut self) -> *mut EvmWord {
415        self.0.as_mut_ptr().cast()
416    }
417
418    /// Returns a slice of the stack.
419    #[inline]
420    pub fn as_slice(&self) -> &[EvmWord] {
421        // SAFETY: EvmWord is repr(C) and same layout as [u8; 32]
422        unsafe { core::slice::from_raw_parts(self.as_ptr(), Self::CAPACITY) }
423    }
424
425    /// Returns a mutable slice of the stack.
426    #[inline]
427    pub fn as_mut_slice(&mut self) -> &mut [EvmWord] {
428        // SAFETY: EvmWord is repr(C) and same layout as [u8; 32]
429        unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr(), Self::CAPACITY) }
430    }
431
432    /// Returns the word at the given index as a reference.
433    #[inline]
434    pub fn get(&self, index: usize) -> Option<&EvmWord> {
435        self.0.get(index).map(|slot| unsafe { slot.assume_init_ref() })
436    }
437
438    /// Returns the word at the given index as a mutable reference.
439    #[inline]
440    pub fn get_mut(&mut self, index: usize) -> Option<&mut EvmWord> {
441        self.0.get_mut(index).map(|slot| unsafe { slot.assume_init_mut() })
442    }
443
444    /// Returns the word at the given index as a reference.
445    ///
446    /// # Safety
447    ///
448    /// The caller must ensure that the index is within bounds.
449    #[inline]
450    pub unsafe fn get_unchecked(&self, index: usize) -> &EvmWord {
451        self.0.get_unchecked(index).assume_init_ref()
452    }
453
454    /// Returns the word at the given index as a mutable reference.
455    ///
456    /// # Safety
457    ///
458    /// The caller must ensure that the index is within bounds.
459    #[inline]
460    pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut EvmWord {
461        self.0.get_unchecked_mut(index).assume_init_mut()
462    }
463
464    /// Sets the value at the top of the stack to `value`, and grows the stack by 1.
465    ///
466    /// # Safety
467    ///
468    /// The caller must ensure that the stack is not full.
469    #[inline]
470    pub unsafe fn push(&mut self, value: EvmWord, len: &mut usize) {
471        self.set_unchecked(*len, value);
472        *len += 1;
473    }
474
475    /// Returns the value at the top of the stack.
476    ///
477    /// # Safety
478    ///
479    /// The caller must ensure that the stack is not empty.
480    #[inline]
481    pub unsafe fn top_unchecked(&self, len: usize) -> &EvmWord {
482        self.get_unchecked(len - 1)
483    }
484
485    /// Returns the value at the top of the stack as a mutable reference.
486    ///
487    /// # Safety
488    ///
489    /// The caller must ensure that the stack is not empty.
490    #[inline]
491    pub unsafe fn top_unchecked_mut(&mut self, len: usize) -> &mut EvmWord {
492        self.get_unchecked_mut(len - 1)
493    }
494
495    /// Returns the value at the given index from the top of the stack.
496    ///
497    /// # Safety
498    ///
499    /// The caller must ensure that `len >= n + 1`.
500    #[inline]
501    pub unsafe fn from_top_unchecked(&self, len: usize, n: usize) -> &EvmWord {
502        self.get_unchecked(len - n - 1)
503    }
504
505    /// Returns the value at the given index from the top of the stack as a mutable reference.
506    ///
507    /// # Safety
508    ///
509    /// The caller must ensure that `len >= n + 1`.
510    #[inline]
511    pub unsafe fn from_top_unchecked_mut(&mut self, len: usize, n: usize) -> &mut EvmWord {
512        self.get_unchecked_mut(len - n - 1)
513    }
514
515    /// Sets the value at the given index.
516    ///
517    /// # Safety
518    ///
519    /// The caller must ensure that the index is within bounds.
520    #[inline]
521    pub unsafe fn set_unchecked(&mut self, index: usize, value: EvmWord) {
522        *self.0.get_unchecked_mut(index) = MaybeUninit::new(value);
523    }
524}
525
526/// An EVM stack word, which is stored in native-endian order.
527#[repr(C, align(8))]
528#[derive(Clone, Copy, PartialEq, Eq)]
529#[allow(missing_debug_implementations)]
530pub struct EvmWord([u8; 32]);
531
532impl Default for EvmWord {
533    #[inline]
534    fn default() -> Self {
535        Self::ZERO
536    }
537}
538
539impl fmt::Debug for EvmWord {
540    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541        write!(f, "0x")?;
542        for byte in &self.to_be_bytes() {
543            write!(f, "{byte:02x}")?;
544        }
545        Ok(())
546    }
547}
548
549impl TryFrom<EvmWord> for usize {
550    type Error = ruint::FromUintError<Self>;
551
552    #[inline]
553    fn try_from(w: EvmWord) -> Result<Self, Self::Error> {
554        Self::try_from(&w)
555    }
556}
557
558impl TryFrom<&EvmWord> for usize {
559    type Error = ruint::FromUintError<Self>;
560
561    #[inline]
562    fn try_from(w: &EvmWord) -> Result<Self, Self::Error> {
563        w.to_u256().try_into()
564    }
565}
566
567impl TryFrom<&mut EvmWord> for usize {
568    type Error = ruint::FromUintError<Self>;
569
570    #[inline]
571    fn try_from(w: &mut EvmWord) -> Result<Self, Self::Error> {
572        Self::try_from(&*w)
573    }
574}
575
576impl From<U256> for EvmWord {
577    #[inline]
578    fn from(u: U256) -> Self {
579        Self::from_u256(u)
580    }
581}
582
583impl EvmWord {
584    /// Zero.
585    pub const ZERO: Self = Self([0; 32]);
586
587    /// Create a new word from big-endian bytes.
588    #[inline]
589    pub fn from_be_bytes(bytes: [u8; 32]) -> Self {
590        Self::from_be(Self(bytes))
591    }
592
593    /// Create a new word from little-endian bytes.
594    #[inline]
595    pub fn from_le_bytes(bytes: [u8; 32]) -> Self {
596        Self::from_le(Self(bytes))
597    }
598
599    /// Create a new word from native-endian bytes.
600    #[inline]
601    pub const fn from_ne_bytes(bytes: [u8; 32]) -> Self {
602        Self(bytes)
603    }
604
605    /// Create a new word from a [`U256`]. This is a no-op on little-endian systems.
606    #[inline]
607    pub const fn from_u256(u: U256) -> Self {
608        #[cfg(target_endian = "little")]
609        return unsafe { core::mem::transmute::<U256, Self>(u) };
610        #[cfg(target_endian = "big")]
611        return Self(u.to_be_bytes());
612    }
613
614    /// Converts a big-endian representation into a native one.
615    #[inline]
616    pub fn from_be(x: Self) -> Self {
617        #[cfg(target_endian = "little")]
618        return x.swap_bytes();
619        #[cfg(target_endian = "big")]
620        return x;
621    }
622
623    /// Converts a little-endian representation into a native one.
624    #[inline]
625    pub fn from_le(x: Self) -> Self {
626        #[cfg(target_endian = "little")]
627        return x;
628        #[cfg(target_endian = "big")]
629        return x.swap_bytes();
630    }
631
632    /// Return the memory representation of this integer as a byte array in big-endian byte order.
633    #[inline]
634    pub fn to_be_bytes(self) -> [u8; 32] {
635        self.to_be().to_ne_bytes()
636    }
637
638    /// Return the memory representation of this integer as a byte array in little-endian byte
639    /// order.
640    #[inline]
641    pub fn to_le_bytes(self) -> [u8; 32] {
642        self.to_le().to_ne_bytes()
643    }
644
645    /// Return the memory representation of this integer as a byte array in native byte order.
646    #[inline]
647    pub const fn to_ne_bytes(self) -> [u8; 32] {
648        self.0
649    }
650
651    /// Converts `self` to big endian from the target's endianness.
652    #[inline]
653    pub fn to_be(self) -> Self {
654        #[cfg(target_endian = "little")]
655        return self.swap_bytes();
656        #[cfg(target_endian = "big")]
657        return self;
658    }
659
660    /// Converts `self` to little endian from the target's endianness.
661    #[inline]
662    pub fn to_le(self) -> Self {
663        #[cfg(target_endian = "little")]
664        return self;
665        #[cfg(target_endian = "big")]
666        return self.swap_bytes();
667    }
668
669    /// Reverses the byte order of the integer.
670    #[inline]
671    pub fn swap_bytes(mut self) -> Self {
672        self.0.reverse();
673        self
674    }
675
676    /// Casts this value to a [`U256`]. This is a no-op on little-endian systems.
677    #[cfg(target_endian = "little")]
678    #[inline]
679    pub const fn as_u256(&self) -> &U256 {
680        unsafe { &*(self as *const Self as *const U256) }
681    }
682
683    /// Casts this value to a [`U256`]. This is a no-op on little-endian systems.
684    #[cfg(target_endian = "little")]
685    #[inline]
686    pub fn as_u256_mut(&mut self) -> &mut U256 {
687        unsafe { &mut *(self as *mut Self as *mut U256) }
688    }
689
690    /// Converts this value to a [`U256`]. This is a simple copy on little-endian systems.
691    #[inline]
692    pub const fn to_u256(&self) -> U256 {
693        #[cfg(target_endian = "little")]
694        return *self.as_u256();
695        #[cfg(target_endian = "big")]
696        return U256::from_be_bytes(self.0);
697    }
698
699    /// Converts this value to a [`U256`]. This is a no-op on little-endian systems.
700    #[inline]
701    pub const fn into_u256(self) -> U256 {
702        #[cfg(target_endian = "little")]
703        return unsafe { core::mem::transmute::<Self, U256>(self) };
704        #[cfg(target_endian = "big")]
705        return U256::from_be_bytes(self.0);
706    }
707
708    /// Converts this value to an [`Address`].
709    #[inline]
710    pub fn to_address(self) -> Address {
711        Address::from_word(self.to_be_bytes().into())
712    }
713}
714
715/// Logic for handling the `resume_at` field.
716///
717/// This is stored in the bytecode's PC.
718struct ResumeAt;
719
720impl ResumeAt {
721    fn load(pc: usize, code: &[u8]) -> usize {
722        if pc < code.len() {
723            0
724        } else {
725            pc
726        }
727    }
728}
729
730#[inline(always)]
731fn option_as_mut_ptr<T>(opt: Option<&mut T>) -> *mut T {
732    match opt {
733        Some(ref_) => ref_,
734        None => ptr::null_mut(),
735    }
736}
737
738// Macro re-exports.
739// Not public API.
740#[doc(hidden)]
741pub mod private {
742    pub use revm_interpreter;
743    pub use revm_primitives;
744}
745
746#[cfg(test)]
747mod tests {
748    use super::*;
749
750    #[test]
751    fn conversions() {
752        let mut word = EvmWord::ZERO;
753        assert_eq!(usize::try_from(word), Ok(0));
754        assert_eq!(usize::try_from(&word), Ok(0));
755        assert_eq!(usize::try_from(&mut word), Ok(0));
756    }
757
758    extern_revmc! {
759        #[link_name = "__test_fn"]
760        fn test_fn;
761    }
762
763    #[no_mangle]
764    extern "C" fn __test_fn(
765        _gas: *mut Gas,
766        _stack: *mut EvmStack,
767        _stack_len: *mut usize,
768        _input: *const InputsImpl,
769        _ecx: *mut EvmContext<'_>,
770    ) -> InstructionResult {
771        InstructionResult::Stop
772    }
773
774    #[test]
775    fn extern_macro() {
776        let _f1 = EvmCompilerFn::new(test_fn);
777        let _f2 = EvmCompilerFn::new(__test_fn);
778        assert_eq!(test_fn as *const () as usize, __test_fn as *const () as usize);
779    }
780}