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, doc_auto_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    Contract, FunctionStack, Gas, Host, InstructionResult, Interpreter, InterpreterAction,
12    InterpreterResult, SharedMemory, EMPTY_SHARED_MEMORY,
13};
14use revm_primitives::{Address, Bytes, Env, U256};
15
16#[cfg(feature = "host-ext-any")]
17use core::any::Any;
18
19/// The EVM bytecode compiler runtime context.
20///
21/// This is a simple wrapper around the interpreter's resources, allowing the compiled function to
22/// access the memory, contract, gas, host, and other resources.
23pub struct EvmContext<'a> {
24    /// The memory.
25    pub memory: &'a mut SharedMemory,
26    /// Contract information and call data.
27    pub contract: &'a mut Contract,
28    /// The gas.
29    pub gas: &'a mut Gas,
30    /// The host.
31    pub host: &'a mut dyn HostExt,
32    /// The return action.
33    pub next_action: &'a mut InterpreterAction,
34    /// The return data.
35    pub return_data: &'a [u8],
36    /// Whether the context is static.
37    pub is_static: bool,
38    /// An index that is used internally to keep track of where execution should resume.
39    /// `0` is the initial state.
40    #[doc(hidden)]
41    pub resume_at: u32,
42}
43
44impl fmt::Debug for EvmContext<'_> {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        f.debug_struct("EvmContext").field("memory", &self.memory).finish_non_exhaustive()
47    }
48}
49
50impl<'a> EvmContext<'a> {
51    /// Creates a new context from an interpreter.
52    #[inline]
53    pub fn from_interpreter(interpreter: &'a mut Interpreter, host: &'a mut dyn HostExt) -> Self {
54        Self::from_interpreter_with_stack(interpreter, host).0
55    }
56
57    /// Creates a new context from an interpreter.
58    #[inline]
59    pub fn from_interpreter_with_stack<'b: 'a>(
60        interpreter: &'a mut Interpreter,
61        host: &'b mut dyn HostExt,
62    ) -> (Self, &'a mut EvmStack, &'a mut usize) {
63        let (stack, stack_len) = EvmStack::from_interpreter_stack(&mut interpreter.stack);
64        let this = Self {
65            memory: &mut interpreter.shared_memory,
66            contract: &mut interpreter.contract,
67            gas: &mut interpreter.gas,
68            host,
69            next_action: &mut interpreter.next_action,
70            return_data: &interpreter.return_data_buffer,
71            is_static: interpreter.is_static,
72            resume_at: ResumeAt::load(interpreter.instruction_pointer),
73        };
74        (this, stack, stack_len)
75    }
76
77    /// Creates a new interpreter by cloning the context.
78    pub fn to_interpreter(&self, stack: revm_interpreter::Stack) -> Interpreter {
79        let bytecode = self.contract.bytecode.bytecode().clone();
80        Interpreter {
81            is_eof: self.contract.bytecode.is_eof(),
82            instruction_pointer: bytecode.as_ptr(),
83            bytecode,
84            function_stack: FunctionStack::new(),
85            is_eof_init: false,
86            contract: self.contract.clone(),
87            instruction_result: InstructionResult::Continue,
88            gas: *self.gas,
89            shared_memory: self.memory.clone(),
90            stack,
91            return_data_buffer: self.return_data.to_vec().into(),
92            is_static: self.is_static,
93            next_action: self.next_action.clone(),
94        }
95    }
96}
97
98/// Extension trait for [`Host`].
99#[cfg(not(feature = "host-ext-any"))]
100pub trait HostExt: Host {}
101
102#[cfg(not(feature = "host-ext-any"))]
103impl<T: Host> HostExt for T {}
104
105/// Extension trait for [`Host`].
106#[cfg(feature = "host-ext-any")]
107pub trait HostExt: Host + Any {
108    #[doc(hidden)]
109    fn as_any(&self) -> &dyn Any;
110    #[doc(hidden)]
111    fn as_any_mut(&mut self) -> &mut dyn Any;
112}
113
114#[cfg(feature = "host-ext-any")]
115impl<T: Host + Any> HostExt for T {
116    fn as_any(&self) -> &dyn Any {
117        self
118    }
119
120    fn as_any_mut(&mut self) -> &mut dyn Any {
121        self
122    }
123}
124
125#[cfg(feature = "host-ext-any")]
126#[doc(hidden)]
127impl dyn HostExt {
128    /// Attempts to downcast the host to a concrete type.
129    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
130        self.as_any().downcast_ref()
131    }
132
133    /// Attempts to downcast the host to a concrete type.
134    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
135        self.as_any_mut().downcast_mut()
136    }
137}
138
139/// Declare [`RawEvmCompilerFn`] functions in an `extern "C"` block.
140///
141/// # Examples
142///
143/// ```no_run
144/// use revmc_context::{extern_revmc, EvmCompilerFn};
145///
146/// extern_revmc! {
147///    /// A simple function that returns `Continue`.
148///    pub fn test_fn;
149/// }
150///
151/// let test_fn = EvmCompilerFn::new(test_fn);
152/// ```
153#[macro_export]
154macro_rules! extern_revmc {
155    ($( $(#[$attr:meta])* $vis:vis fn $name:ident; )+) => {
156        #[allow(improper_ctypes)]
157        extern "C" {
158            $(
159                $(#[$attr])*
160                $vis fn $name(
161                    gas: *mut $crate::private::revm_interpreter::Gas,
162                    stack: *mut $crate::EvmStack,
163                    stack_len: *mut usize,
164                    env: *const $crate::private::revm_primitives::Env,
165                    contract: *const $crate::private::revm_interpreter::Contract,
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    env: *const Env,
183    contract: *const Contract,
184    ecx: *mut EvmContext<'_>,
185) -> InstructionResult;
186
187/// An EVM bytecode function.
188#[derive(Clone, Copy, Debug, PartialEq, Eq)]
189pub struct EvmCompilerFn(RawEvmCompilerFn);
190
191impl From<RawEvmCompilerFn> for EvmCompilerFn {
192    #[inline]
193    fn from(f: RawEvmCompilerFn) -> Self {
194        Self::new(f)
195    }
196}
197
198impl From<EvmCompilerFn> for RawEvmCompilerFn {
199    #[inline]
200    fn from(f: EvmCompilerFn) -> Self {
201        f.into_inner()
202    }
203}
204
205impl EvmCompilerFn {
206    /// Wraps the function.
207    #[inline]
208    pub const fn new(f: RawEvmCompilerFn) -> Self {
209        Self(f)
210    }
211
212    /// Unwraps the function.
213    #[inline]
214    pub const fn into_inner(self) -> RawEvmCompilerFn {
215        self.0
216    }
217
218    /// Calls the function by re-using the interpreter's resources and memory.
219    ///
220    /// See [`call_with_interpreter_and_memory`](Self::call_with_interpreter_and_memory) for more
221    /// information.
222    ///
223    /// # Safety
224    ///
225    /// The caller must ensure that the function is safe to call.
226    #[inline]
227    pub unsafe fn call_with_interpreter_and_memory(
228        self,
229        interpreter: &mut Interpreter,
230        memory: &mut SharedMemory,
231        host: &mut dyn HostExt,
232    ) -> InterpreterAction {
233        interpreter.shared_memory = core::mem::replace(memory, EMPTY_SHARED_MEMORY);
234        let result = self.call_with_interpreter(interpreter, host);
235        *memory = interpreter.take_memory();
236        result
237    }
238
239    /// Calls the function by re-using the interpreter's resources.
240    ///
241    /// This behaves the same as [`Interpreter::run`], returning an [`InstructionResult`] in the
242    /// interpreter's [`instruction_result`](Interpreter::instruction_result) field and the next
243    /// action in the [`next_action`](Interpreter::next_action) field.
244    ///
245    /// # Safety
246    ///
247    /// The caller must ensure that the function is safe to call.
248    #[inline]
249    pub unsafe fn call_with_interpreter(
250        self,
251        interpreter: &mut Interpreter,
252        host: &mut dyn HostExt,
253    ) -> InterpreterAction {
254        interpreter.next_action = InterpreterAction::None;
255
256        let (mut ecx, stack, stack_len) =
257            EvmContext::from_interpreter_with_stack(interpreter, host);
258        let result = self.call(Some(stack), Some(stack_len), &mut ecx);
259
260        // Set the remaining gas to 0 if the result is `OutOfGas`,
261        // as it might have overflown inside of the function.
262        if result == InstructionResult::OutOfGas {
263            ecx.gas.spend_all();
264        }
265
266        let resume_at = ecx.resume_at;
267        ResumeAt::store(&mut interpreter.instruction_pointer, resume_at);
268
269        interpreter.instruction_result = result;
270        if interpreter.next_action.is_some() {
271            core::mem::take(&mut interpreter.next_action)
272        } else {
273            InterpreterAction::Return {
274                result: InterpreterResult { result, output: Bytes::new(), gas: interpreter.gas },
275            }
276        }
277    }
278
279    /// Calls the function.
280    ///
281    /// Arguments:
282    /// - `stack`: Pointer to the stack. Must be `Some` if `local_stack` is set to `false`.
283    /// - `stack_len`: Pointer to the stack length. Must be `Some` if `inspect_stack_length` is set
284    ///   to `true`.
285    /// - `ecx`: The context object.
286    ///
287    /// These conditions are enforced at runtime if `debug_assertions` is set to `true`.
288    ///
289    /// # Safety
290    ///
291    /// The caller must ensure that the arguments are valid and that the function is safe to call.
292    #[inline]
293    pub unsafe fn call(
294        self,
295        stack: Option<&mut EvmStack>,
296        stack_len: Option<&mut usize>,
297        ecx: &mut EvmContext<'_>,
298    ) -> InstructionResult {
299        assert!(!ecx.contract.bytecode.is_eof(), "EOF is not yet implemented");
300        (self.0)(
301            ecx.gas,
302            option_as_mut_ptr(stack),
303            option_as_mut_ptr(stack_len),
304            ecx.host.env(),
305            ecx.contract,
306            ecx,
307        )
308    }
309
310    /// Same as [`call`](Self::call) but with `#[inline(never)]`.
311    ///
312    /// # Safety
313    ///
314    /// See [`call`](Self::call).
315    #[inline(never)]
316    pub unsafe fn call_noinline(
317        self,
318        stack: Option<&mut EvmStack>,
319        stack_len: Option<&mut usize>,
320        ecx: &mut EvmContext<'_>,
321    ) -> InstructionResult {
322        self.call(stack, stack_len, ecx)
323    }
324}
325
326/// EVM context stack.
327#[repr(C)]
328#[allow(missing_debug_implementations)]
329pub struct EvmStack([MaybeUninit<EvmWord>; 1024]);
330
331#[allow(clippy::new_without_default)]
332impl EvmStack {
333    /// The size of the stack in bytes.
334    pub const SIZE: usize = 32 * Self::CAPACITY;
335
336    /// The size of the stack in U256 elements.
337    pub const CAPACITY: usize = 1024;
338
339    /// Creates a new EVM stack, allocated on the stack.
340    ///
341    /// Use [`EvmStack::new_heap`] to create a stack on the heap.
342    #[inline]
343    pub fn new() -> Self {
344        Self(unsafe { MaybeUninit::uninit().assume_init() })
345    }
346
347    /// Creates a vector that can be used as a stack.
348    #[inline]
349    pub fn new_heap() -> Vec<EvmWord> {
350        Vec::with_capacity(1024)
351    }
352
353    /// Creates a stack from the interpreter's stack. Assumes that the stack is large enough.
354    #[inline]
355    pub fn from_interpreter_stack(stack: &mut revm_interpreter::Stack) -> (&mut Self, &mut usize) {
356        debug_assert!(stack.data().capacity() >= Self::CAPACITY);
357        unsafe {
358            let data = Self::from_mut_ptr(stack.data_mut().as_mut_ptr().cast());
359            // Vec { data: ptr, cap: usize, len: usize }
360            let len = &mut *(stack.data_mut() as *mut Vec<_>).cast::<usize>().add(2);
361            debug_assert_eq!(stack.len(), *len);
362            (data, len)
363        }
364    }
365
366    /// Creates a stack from a vector's buffer.
367    ///
368    /// # Panics
369    ///
370    /// Panics if the vector's capacity is less than the required stack capacity.
371    #[inline]
372    pub fn from_vec(vec: &Vec<EvmWord>) -> &Self {
373        assert!(vec.capacity() >= Self::CAPACITY);
374        unsafe { Self::from_ptr(vec.as_ptr()) }
375    }
376
377    /// Creates a stack from a mutable vector's buffer.
378    ///
379    /// The bytecode function will overwrite the internal contents of the vector, and will not
380    /// set the length. This is simply to have the stack allocated on the heap.
381    ///
382    /// # Panics
383    ///
384    /// Panics if the vector's capacity is less than the required stack capacity.
385    ///
386    /// # Examples
387    ///
388    /// ```rust
389    /// use revmc_context::EvmStack;
390    /// let mut stack_buf = EvmStack::new_heap();
391    /// let stack = EvmStack::from_mut_vec(&mut stack_buf);
392    /// assert_eq!(stack.as_slice().len(), EvmStack::CAPACITY);
393    /// ```
394    #[inline]
395    pub fn from_mut_vec(vec: &mut Vec<EvmWord>) -> &mut Self {
396        assert!(vec.capacity() >= Self::CAPACITY);
397        unsafe { Self::from_mut_ptr(vec.as_mut_ptr()) }
398    }
399
400    /// Creates a stack from a slice.
401    ///
402    /// # Panics
403    ///
404    /// Panics if the slice's length is less than the required stack capacity.
405    #[inline]
406    pub const fn from_slice(slice: &[EvmWord]) -> &Self {
407        assert!(slice.len() >= Self::CAPACITY);
408        unsafe { Self::from_ptr(slice.as_ptr()) }
409    }
410
411    /// Creates a stack from a mutable slice.
412    ///
413    /// # Panics
414    ///
415    /// Panics if the slice's length is less than the required stack capacity.
416    #[inline]
417    pub fn from_mut_slice(slice: &mut [EvmWord]) -> &mut Self {
418        assert!(slice.len() >= Self::CAPACITY);
419        unsafe { Self::from_mut_ptr(slice.as_mut_ptr()) }
420    }
421
422    /// Creates a stack from a pointer.
423    ///
424    /// # Safety
425    ///
426    /// The caller must ensure that the pointer is valid and points to at least [`EvmStack::SIZE`]
427    /// bytes.
428    #[inline]
429    pub const unsafe fn from_ptr<'a>(ptr: *const EvmWord) -> &'a Self {
430        &*ptr.cast()
431    }
432
433    /// Creates a stack from a mutable pointer.
434    ///
435    /// # Safety
436    ///
437    /// The caller must ensure that the pointer is valid and points to at least [`EvmStack::SIZE`]
438    /// bytes.
439    #[inline]
440    pub unsafe fn from_mut_ptr<'a>(ptr: *mut EvmWord) -> &'a mut Self {
441        &mut *ptr.cast()
442    }
443
444    /// Returns the stack as a byte array.
445    #[inline]
446    pub const fn as_bytes(&self) -> &[u8; Self::SIZE] {
447        unsafe { &*self.0.as_ptr().cast() }
448    }
449
450    /// Returns the stack as a byte array.
451    #[inline]
452    pub fn as_bytes_mut(&mut self) -> &mut [u8; Self::SIZE] {
453        unsafe { &mut *self.0.as_mut_ptr().cast() }
454    }
455
456    /// Returns the stack as a slice.
457    #[inline]
458    pub const fn as_slice(&self) -> &[EvmWord; Self::CAPACITY] {
459        unsafe { &*self.0.as_ptr().cast() }
460    }
461
462    /// Returns the stack as a mutable slice.
463    #[inline]
464    pub fn as_mut_slice(&mut self) -> &mut [EvmWord; Self::CAPACITY] {
465        unsafe { &mut *self.0.as_mut_ptr().cast() }
466    }
467}
468
469/// A native-endian 256-bit unsigned integer, aligned to 8 bytes.
470///
471/// This is a transparent wrapper around [`U256`] on little-endian targets.
472#[repr(C, align(8))]
473#[derive(Clone, Copy, PartialEq, Eq)]
474pub struct EvmWord([u8; 32]);
475
476macro_rules! impl_fmt {
477    ($($trait:ident),* $(,)?) => {
478        $(
479            impl fmt::$trait for EvmWord {
480                #[inline]
481                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
482                    self.to_u256().fmt(f)
483                }
484            }
485        )*
486    };
487}
488
489impl_fmt!(Debug, Display, Binary, Octal, LowerHex, UpperHex);
490
491macro_rules! impl_conversions_through_u256 {
492    ($($ty:ty),*) => {
493        $(
494            impl From<$ty> for EvmWord {
495                #[inline]
496                fn from(value: $ty) -> Self {
497                    Self::from_u256(U256::from(value))
498                }
499            }
500
501            impl From<&$ty> for EvmWord {
502                #[inline]
503                fn from(value: &$ty) -> Self {
504                    Self::from(*value)
505                }
506            }
507
508            impl From<&mut $ty> for EvmWord {
509                #[inline]
510                fn from(value: &mut $ty) -> Self {
511                    Self::from(*value)
512                }
513            }
514
515            impl TryFrom<EvmWord> for $ty {
516                type Error = ();
517
518                #[inline]
519                fn try_from(value: EvmWord) -> Result<Self, Self::Error> {
520                    value.to_u256().try_into().map_err(drop)
521                }
522            }
523
524            impl TryFrom<&EvmWord> for $ty {
525                type Error = ();
526
527                #[inline]
528                fn try_from(value: &EvmWord) -> Result<Self, Self::Error> {
529                    (*value).try_into()
530                }
531            }
532
533            impl TryFrom<&mut EvmWord> for $ty {
534                type Error = ();
535
536                #[inline]
537                fn try_from(value: &mut EvmWord) -> Result<Self, Self::Error> {
538                    (*value).try_into()
539                }
540            }
541        )*
542    };
543}
544
545impl_conversions_through_u256!(bool, u8, u16, u32, u64, usize, u128);
546
547impl From<U256> for EvmWord {
548    #[inline]
549    fn from(value: U256) -> Self {
550        Self::from_u256(value)
551    }
552}
553
554impl From<&U256> for EvmWord {
555    #[inline]
556    fn from(value: &U256) -> Self {
557        Self::from(*value)
558    }
559}
560
561impl From<&mut U256> for EvmWord {
562    #[inline]
563    fn from(value: &mut U256) -> Self {
564        Self::from(*value)
565    }
566}
567
568impl EvmWord {
569    /// The zero value.
570    pub const ZERO: Self = Self([0; 32]);
571
572    /// Creates a new value from native-endian bytes.
573    #[inline]
574    pub const fn from_ne_bytes(x: [u8; 32]) -> Self {
575        Self(x)
576    }
577
578    /// Creates a new value from big-endian bytes.
579    #[inline]
580    pub fn from_be_bytes(x: [u8; 32]) -> Self {
581        Self::from_be(Self(x))
582    }
583
584    /// Creates a new value from little-endian bytes.
585    #[inline]
586    pub fn from_le_bytes(x: [u8; 32]) -> Self {
587        Self::from_le(Self(x))
588    }
589
590    /// Converts an integer from big endian to the target's endianness.
591    #[inline]
592    pub fn from_be(x: Self) -> Self {
593        #[cfg(target_endian = "little")]
594        return x.swap_bytes();
595        #[cfg(target_endian = "big")]
596        return x;
597    }
598
599    /// Converts an integer from little endian to the target's endianness.
600    #[inline]
601    pub fn from_le(x: Self) -> Self {
602        #[cfg(target_endian = "little")]
603        return x;
604        #[cfg(target_endian = "big")]
605        return x.swap_bytes();
606    }
607
608    /// Converts a [`U256`].
609    #[inline]
610    pub const fn from_u256(value: U256) -> Self {
611        #[cfg(target_endian = "little")]
612        return unsafe { core::mem::transmute::<U256, Self>(value) };
613        #[cfg(target_endian = "big")]
614        return Self(value.to_be_bytes());
615    }
616
617    /// Converts a [`U256`] reference to a [`U256`].
618    #[inline]
619    #[cfg(target_endian = "little")]
620    pub const fn from_u256_ref(value: &U256) -> &Self {
621        unsafe { &*(value as *const U256 as *const Self) }
622    }
623
624    /// Converts a [`U256`] mutable reference to a [`U256`].
625    #[inline]
626    #[cfg(target_endian = "little")]
627    pub fn from_u256_mut(value: &mut U256) -> &mut Self {
628        unsafe { &mut *(value as *mut U256 as *mut Self) }
629    }
630
631    /// Return the memory representation of this integer as a byte array in big-endian (network)
632    /// 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 [`Interpreter::instruction_pointer`] field.
718struct ResumeAt;
719
720impl ResumeAt {
721    fn load(ip: *const u8) -> u32 {
722        // Arbitrary limit.
723        // TODO: Use upper bits?
724        if (ip as usize) <= u16::MAX as usize {
725            ip as u32
726        } else {
727            0
728        }
729    }
730
731    fn store(ip: &mut *const u8, value: u32) {
732        *ip = value as _;
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    #[no_mangle]
770    extern "C" fn __test_fn(
771        _gas: *mut Gas,
772        _stack: *mut EvmStack,
773        _stack_len: *mut usize,
774        _env: *const Env,
775        _contract: *const Contract,
776        _ecx: *mut EvmContext<'_>,
777    ) -> InstructionResult {
778        InstructionResult::Continue
779    }
780
781    #[test]
782    fn extern_macro() {
783        let _f1 = EvmCompilerFn::new(test_fn);
784        let _f2 = EvmCompilerFn::new(__test_fn);
785        assert_eq!(test_fn as usize, __test_fn as usize);
786    }
787
788    #[test]
789    fn borrowing_host() {
790        #[allow(unused)]
791        struct BHost<'a>(&'a mut Env);
792        #[allow(unused)]
793        impl Host for BHost<'_> {
794            fn env(&self) -> &Env {
795                self.0
796            }
797            fn env_mut(&mut self) -> &mut Env {
798                self.0
799            }
800            fn load_account(
801                &mut self,
802                address: Address,
803            ) -> Option<revm_interpreter::LoadAccountResult> {
804                unimplemented!()
805            }
806            fn block_hash(&mut self, number: U256) -> Option<revm_primitives::B256> {
807                unimplemented!()
808            }
809            fn balance(&mut self, address: Address) -> Option<(U256, bool)> {
810                unimplemented!()
811            }
812            fn code(&mut self, address: Address) -> Option<(revm_primitives::Bytes, bool)> {
813                unimplemented!()
814            }
815            fn code_hash(&mut self, address: Address) -> Option<(revm_primitives::B256, bool)> {
816                unimplemented!()
817            }
818            fn sload(&mut self, address: Address, index: U256) -> Option<(U256, bool)> {
819                unimplemented!()
820            }
821            fn sstore(
822                &mut self,
823                address: Address,
824                index: U256,
825                value: U256,
826            ) -> Option<revm_interpreter::SStoreResult> {
827                unimplemented!()
828            }
829            fn tload(&mut self, address: Address, index: U256) -> U256 {
830                unimplemented!()
831            }
832            fn tstore(&mut self, address: Address, index: U256, value: U256) {
833                unimplemented!()
834            }
835            fn log(&mut self, log: revm_primitives::Log) {
836                unimplemented!()
837            }
838            fn selfdestruct(
839                &mut self,
840                address: Address,
841                target: Address,
842            ) -> Option<revm_interpreter::SelfDestructResult> {
843                unimplemented!()
844            }
845        }
846
847        #[allow(unused_mut)]
848        let mut env = Env::default();
849        #[cfg(not(feature = "host-ext-any"))]
850        let env = &mut env;
851        #[cfg(feature = "host-ext-any")]
852        let env = Box::leak(Box::new(env));
853
854        let mut host = BHost(env);
855        let f = EvmCompilerFn::new(test_fn);
856        let mut interpreter = Interpreter::new(Contract::default(), u64::MAX, false);
857
858        let (mut ecx, stack, stack_len) =
859            EvmContext::from_interpreter_with_stack(&mut interpreter, &mut host);
860        let r = unsafe { f.call(Some(stack), Some(stack_len), &mut ecx) };
861        assert_eq!(r, InstructionResult::Continue);
862
863        let r = unsafe { f.call_with_interpreter(&mut interpreter, &mut host) };
864        assert_eq!(
865            r,
866            InterpreterAction::Return {
867                result: InterpreterResult {
868                    result: InstructionResult::Continue,
869                    output: Bytes::new(),
870                    gas: Gas::new(u64::MAX),
871                }
872            }
873        );
874    }
875}