Struct EvmCompiler

Source
pub struct EvmCompiler<B: Backend> {
    name: Option<String>,
    backend: B,
    out_dir: Option<PathBuf>,
    config: FcxConfig,
    builtins: Builtins<B>,
    dump_assembly: bool,
    dump_unopt_assembly: bool,
    finalized: bool,
}
Expand description

EVM bytecode compiler.

This currently represents one single-threaded IR context and module, which can be used to compile multiple functions as JIT or AOT.

Functions can be incrementally added with translate, and then either written to an object file with write_object when in AOT mode, or JIT-compiled with jit_function.

Performing either of these operations finalizes the module, and no more functions can be added afterwards until clear is called, which will reset the module to its initial state.

Fields§

§name: Option<String>§backend: B§out_dir: Option<PathBuf>§config: FcxConfig§builtins: Builtins<B>§dump_assembly: bool§dump_unopt_assembly: bool§finalized: bool

Implementations§

Source§

impl<B: Backend> EvmCompiler<B>

Source

pub fn new(backend: B) -> Self

Creates a new instance of the compiler with the given backend.

Source

pub fn set_module_name(&mut self, name: impl Into<String>)

Sets the name of the module.

Source

fn is_aot(&self) -> bool

Source

fn is_jit(&self) -> bool

Source

pub fn out_dir(&self) -> Option<&Path>

Returns the output directory.

Source

pub fn set_dump_to(&mut self, output_dir: Option<PathBuf>)

Dumps intermediate outputs and other debug info to the given directory after compilation.

Disables dumping if output_dir is None.

Source

pub fn dump_assembly(&mut self, yes: bool)

Dumps assembly to the output directory.

This can be quite slow.

Defaults to true.

Source

pub fn dump_unopt_assembly(&mut self, yes: bool)

Dumps the unoptimized assembly to the output directory.

This can be quite slow.

Defaults to false.

Source

pub fn opt_level(&self) -> OptimizationLevel

Returns the optimization level.

Source

pub fn set_opt_level(&mut self, level: OptimizationLevel)

Sets the optimization level.

Note that some backends may not support setting the optimization level after initialization.

Defaults to the backend’s initial optimization level.

Source

pub fn debug_assertions(&mut self, yes: bool)

Sets whether to enable debug assertions.

These are useful for debugging, but they do a moderate performance penalty due to the insertion of extra checks and removal of certain assumptions.

Defaults to cfg!(debug_assertions).

Source

pub fn frame_pointers(&mut self, yes: bool)

Sets whether to enable frame pointers.

This is useful for profiling and debugging, but it incurs a very slight performance penalty.

Defaults to cfg!(debug_assertions).

Source

pub fn validate_eof(&mut self, yes: bool)

Sets whether to validate input EOF containers.

An invalid EOF container will likely results in a panic.

Defaults to true.

Source

pub fn local_stack(&mut self, yes: bool)

Sets whether to allocate the stack locally.

If this is set to true, the stack pointer argument will be ignored and the stack will be allocated in the function.

This setting will fail at runtime if the bytecode suspends execution, as it cannot be restored afterwards.

Defaults to false.

Source

pub fn inspect_stack_length(&mut self, yes: bool)

Sets whether to treat the stack length as observable outside the function.

This also implies that the length is loaded in the beginning of the function, meaning that a function can be executed with an initial stack.

If this is set to true, the stack length must be passed in the arguments.

This is useful to inspect the stack length after the function has been executed, but it does incur a performance penalty as the length will be stored at all return sites.

Defaults to false.

Source

pub unsafe fn stack_bound_checks(&mut self, yes: bool)

Sets whether to enable stack bound checks.

Ignored for EOF bytecodes, as they are assumed to be correct.

Defaults to true.

§Safety

Removing stack length checks may improve compilation speed and performance, but will result in undefined behavior if the stack length overflows at runtime, rather than a StackUnderflow/StackOverflow result.

Source

pub fn gas_metering(&mut self, yes: bool)

Sets whether to track gas costs.

Disabling this will greatly improves compilation speed and performance, at the cost of not being able to check for gas exhaustion.

Note that this does not disable gas usage in certain instructions, mainly the ones that are implemented as builtins.

Use with care, as executing a function with gas disabled may result in an infinite loop.

Defaults to true.

Source

pub fn translate<'a>( &mut self, name: &str, input: impl Into<EvmCompilerInput<'a>>, spec_id: SpecId, ) -> Result<B::FuncId>

Translates the given EVM bytecode into an internal function.

NOTE: name must be unique for each function, as it is used as the name of the final symbol.

Source

pub unsafe fn jit<'a>( &mut self, name: &str, bytecode: impl Into<EvmCompilerInput<'a>>, spec_id: SpecId, ) -> Result<EvmCompilerFn>

(JIT) Compiles the given EVM bytecode into a JIT function.

See translate for more information.

§Safety

The returned function pointer is owned by the module, and must not be called after the module is cleared or the function is freed.

Source

pub unsafe fn jit_function(&mut self, id: B::FuncId) -> Result<EvmCompilerFn>

(JIT) Finalizes the module and JITs the given function.

§Safety

The returned function pointer is owned by the module, and must not be called after the module is cleared or the function is freed.

Source

pub fn write_object_to_file(&mut self, path: &Path) -> Result<()>

(AOT) Writes the compiled object to the given file.

Source

pub fn write_object<W: Write>(&mut self, w: W) -> Result<()>

(AOT) Finalizes the module and writes the compiled object to the given writer.

Source

pub unsafe fn free_function(&mut self, id: B::FuncId) -> Result<()>

(JIT) Frees the memory associated with a single function.

Note that this will not reset the state of the internal module even if all functions are freed with this function. Use clear to reset the module.

§Safety

Because this function invalidates any pointers retrieved from the corresponding module, it should only be used when none of the functions from that module are currently executing and none of the fn pointers are called afterwards.

Source

pub unsafe fn clear(&mut self) -> Result<()>

Frees all functions and resets the state of the internal module, allowing for new functions to be compiled.

§Safety

Because this function invalidates any pointers retrieved from the corresponding module, it should only be used when none of the functions from that module are currently executing and none of the fn pointers are called afterwards.

Source

fn do_validate_eof(&self, eof: &Eof) -> Result<()>

Source

fn translate_inner( &mut self, name: &str, bytecode: &Bytecode<'_>, ) -> Result<B::FuncId>

Source

fn finalize(&mut self) -> Result<()>

Source

fn make_builder<'a>( backend: &'a mut B, config: &FcxConfig, name: &str, linkage: Linkage, ) -> Result<(B::Builder<'a>, B::FuncId)>

Source

fn dump_ir(&mut self, path: &Path) -> Result<()>

Source

fn dump_disasm(&mut self, path: &Path) -> Result<()>

Source

fn verify_module(&mut self) -> Result<()>

Source

fn optimize_module(&mut self) -> Result<()>

Source

fn dump_bytecode(dump_dir: &Path, bytecode: &Bytecode<'_>) -> Result<()>

Source

fn dump_dir(&self) -> Option<PathBuf>

Auto Trait Implementations§

§

impl<B> Freeze for EvmCompiler<B>
where B: Freeze, <B as BackendTypes>::Function: Freeze,

§

impl<B> RefUnwindSafe for EvmCompiler<B>

§

impl<B> Send for EvmCompiler<B>
where B: Send, <B as BackendTypes>::Function: Send,

§

impl<B> Sync for EvmCompiler<B>
where B: Sync, <B as BackendTypes>::Function: Sync,

§

impl<B> Unpin for EvmCompiler<B>
where B: Unpin, <B as BackendTypes>::Function: Unpin,

§

impl<B> UnwindSafe for EvmCompiler<B>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> Conv for T

§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
§

impl<T> FmtForward for T

§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pipe for T
where T: ?Sized,

§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
§

impl<T> Tap for T

§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
§

impl<T> TryConv for T

§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more

Layout§

Note: Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.