Skip to main content

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