use normal style for comments

Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
xermicus
2024-05-01 16:12:32 +02:00
parent 72515254fe
commit 426f673b0a
184 changed files with 3 additions and 1789 deletions
-2
View File
@@ -1,6 +1,4 @@
//!
//! The number base constants.
//!
/// The binary number base.
pub const BASE_BINARY: u32 = 2;
-2
View File
@@ -1,6 +1,4 @@
//!
//! The common sizes in bits.
//!
/// The `bool` type bit-length.
pub const BIT_LENGTH_BOOLEAN: usize = 1;
-2
View File
@@ -1,6 +1,4 @@
//!
//! The common sizes in bytes.
//!
/// The byte-length.
pub const BYTE_LENGTH_BYTE: usize = 1;
-2
View File
@@ -1,6 +1,4 @@
//!
//! The EraVM address constants.
//!
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_TO_L1: u16 = 0xFFFF;
-4
View File
@@ -1,13 +1,9 @@
//!
//! The EVM version.
//!
use serde::Deserialize;
use serde::Serialize;
///
/// The EVM version.
///
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "camelCase")]
pub enum EVMVersion {
-2
View File
@@ -1,6 +1,4 @@
//!
//! The file extensions.
//!
/// The manifest file extension.
pub static EXTENSION_MANIFEST: &str = "toml";
-2
View File
@@ -1,6 +1,4 @@
//!
//! The compiler common library.
//!
pub(crate) mod base;
pub(crate) mod bit_length;
-8
View File
@@ -1,12 +1,7 @@
//!
//! The compiler common utils.
//!
///
/// Deserializes a `serde_json` object from slice with the recursion limit disabled.
///
/// Must be used for all JSON I/O to avoid crashes due to the aforementioned limit.
///
pub fn deserialize_from_slice<O>(input: &[u8]) -> anyhow::Result<O>
where
O: serde::de::DeserializeOwned,
@@ -18,11 +13,8 @@ where
Ok(result)
}
///
/// Deserializes a `serde_json` object from string with the recursion limit disabled.
///
/// Must be used for all JSON I/O to avoid crashes due to the aforementioned limit.
///
pub fn deserialize_from_str<O>(input: &str) -> anyhow::Result<O>
where
O: serde::de::DeserializeOwned,
-1
View File
@@ -9,7 +9,6 @@ include!(concat!(env!("OUT_DIR"), "/bswap.rs"));
/// - Takes a `i256` value argument
/// - Byte swaps it using `rev8` from the `zbb` extension
/// - Returns the `i256` value
///
/// Returns `Error` if the module fails to validate, which should never happen.
pub fn module<'context>(
context: &'context Context,
+3 -3
View File
@@ -1,7 +1,7 @@
{
"ERC20": 53186,
"Computation": 7380,
"Baseline": 3912,
"Flipper": 4354,
"Computation": 7380,
"Fibonacci": 5971
"Fibonacci": 5971,
"ERC20": 53186
}
@@ -1,10 +1,6 @@
//!
//! The debug IR type.
//!
///
/// The debug IR type.
///
#[allow(non_camel_case_types)]
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -24,9 +20,7 @@ pub enum IRType {
}
impl IRType {
///
/// Returns the file extension for the specified IR.
///
pub fn file_extension(&self) -> &'static str {
match self {
Self::Yul => revive_common::EXTENSION_YUL,
@@ -1,6 +1,4 @@
//!
//! The debug configuration.
//!
pub mod ir_type;
@@ -11,9 +9,7 @@ use serde::Serialize;
use self::ir_type::IRType;
///
/// The debug configuration.
///
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct DebugConfig {
/// The directory to dump the IRs to.
@@ -21,16 +17,12 @@ pub struct DebugConfig {
}
impl DebugConfig {
///
/// A shortcut constructor.
///
pub fn new(output_directory: PathBuf) -> Self {
Self { output_directory }
}
///
/// Dumps the Yul IR.
///
pub fn dump_yul(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::Yul);
@@ -40,9 +32,7 @@ impl DebugConfig {
Ok(())
}
///
/// Dumps the EVM legacy assembly IR.
///
pub fn dump_evmla(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::EVMLA);
@@ -52,9 +42,7 @@ impl DebugConfig {
Ok(())
}
///
/// Dumps the Ethereal IR.
///
pub fn dump_ethir(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::EthIR);
@@ -64,9 +52,7 @@ impl DebugConfig {
Ok(())
}
///
/// Dumps the LLL IR.
///
pub fn dump_lll(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::LLL);
@@ -76,9 +62,7 @@ impl DebugConfig {
Ok(())
}
///
/// Dumps the unoptimized LLVM IR.
///
pub fn dump_llvm_ir_unoptimized(
&self,
contract_path: &str,
@@ -94,9 +78,7 @@ impl DebugConfig {
Ok(())
}
///
/// Dumps the optimized LLVM IR.
///
pub fn dump_llvm_ir_optimized(
&self,
contract_path: &str,
@@ -112,9 +94,7 @@ impl DebugConfig {
Ok(())
}
///
/// Dumps the assembly.
///
pub fn dump_assembly(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::Assembly);
@@ -124,9 +104,7 @@ impl DebugConfig {
Ok(())
}
///
/// Creates a full file name, given the contract full path, suffix, and extension.
///
fn full_file_name(contract_path: &str, suffix: Option<&str>, ir_type: IRType) -> String {
let mut full_file_name = contract_path.replace('/', "_").replace(':', ".");
if let Some(suffix) = suffix {
-4
View File
@@ -1,6 +1,4 @@
//!
//! The LLVM context constants.
//!
/// The LLVM framework version.
pub const LLVM_VERSION: semver::Version = semver::Version::new(18, 1, 4);
@@ -63,13 +61,11 @@ pub const NO_SYSTEM_CALL_BIT: bool = false;
/// The system call bit.
pub const SYSTEM_CALL_BIT: bool = true;
///
/// The deployer call header size that consists of:
/// - selector (4 bytes)
/// - salt (32 bytes)
/// - bytecode hash (32 bytes)
/// - constructor arguments offset (32 bytes)
/// - constructor arguments length (32 bytes)
///
pub const DEPLOYER_CALL_HEADER_SIZE: usize =
revive_common::BYTE_LENGTH_X32 + (revive_common::BYTE_LENGTH_FIELD * 4);
@@ -1,10 +1,6 @@
//!
//! The address space aliases.
//!
///
/// The address space aliases.
///
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AddressSpace {
/// The stack memory.
@@ -1,10 +1,6 @@
//!
//! The LLVM argument with metadata.
//!
///
/// The LLVM argument with metadata.
///
#[derive(Debug, Clone)]
pub struct Argument<'ctx> {
/// The actual LLVM operand.
@@ -22,9 +18,7 @@ impl<'ctx> Argument<'ctx> {
/// The calldata length argument index.
pub const ARGUMENT_INDEX_CALLDATA_LENGTH: usize = 1;
///
/// A shortcut constructor.
///
pub fn new(value: inkwell::values::BasicValueEnum<'ctx>) -> Self {
Self {
value,
@@ -33,9 +27,7 @@ impl<'ctx> Argument<'ctx> {
}
}
///
/// A shortcut constructor.
///
pub fn new_with_original(
value: inkwell::values::BasicValueEnum<'ctx>,
original: String,
@@ -47,9 +39,7 @@ impl<'ctx> Argument<'ctx> {
}
}
///
/// A shortcut constructor.
///
pub fn new_with_constant(
value: inkwell::values::BasicValueEnum<'ctx>,
constant: num::BigUint,
@@ -61,9 +51,7 @@ impl<'ctx> Argument<'ctx> {
}
}
///
/// Returns the inner LLVM value.
///
pub fn to_llvm(&self) -> inkwell::values::BasicValueEnum<'ctx> {
self.value
}
@@ -4,10 +4,8 @@ use serde::Deserialize;
use serde::Serialize;
/// The LLVM attribute.
///
/// In order to check the real order in a new major version of LLVM, find the `Attributes.inc` file
/// inside of the LLVM build directory. This order is actually generated during the building.
///
/// FIXME: Generate this in build.rs?
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Attribute {
@@ -1,15 +1,11 @@
//!
//! The LLVM module build.
//!
use std::collections::BTreeMap;
use serde::Deserialize;
use serde::Serialize;
///
/// The LLVM module build.
///
#[derive(Debug, Serialize, Deserialize)]
pub struct Build {
/// The EraVM text assembly.
@@ -25,9 +21,7 @@ pub struct Build {
}
impl Build {
///
/// A shortcut constructor.
///
pub fn new(
assembly_text: String,
metadata_hash: Option<[u8; revive_common::BYTE_LENGTH_FIELD]>,
@@ -1,13 +1,8 @@
//!
//! The contract code types.
//!
///
/// The contract code types (deploy and runtime).
///
/// They do not represent any entities in the final bytecode, but this separation is always present
/// in the IRs used for translation to the EVM bytecode.
///
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CodeType {
/// The deploy code.
@@ -1,13 +1,9 @@
//!
//! The LLVM debug information.
//!
use inkwell::debug_info::AsDIScope;
use num::Zero;
///
/// The LLVM debug information.
///
pub struct DebugInfo<'ctx> {
/// The compile unit.
compile_unit: inkwell::debug_info::DICompileUnit<'ctx>,
@@ -16,9 +12,7 @@ pub struct DebugInfo<'ctx> {
}
impl<'ctx> DebugInfo<'ctx> {
///
/// A shortcut constructor.
///
pub fn new(module: &inkwell::module::Module<'ctx>) -> Self {
let (builder, compile_unit) = module.create_debug_info_builder(
true,
@@ -44,9 +38,7 @@ impl<'ctx> DebugInfo<'ctx> {
}
}
///
/// Creates a function info.
///
pub fn create_function(
&self,
name: &str,
@@ -82,9 +74,7 @@ impl<'ctx> DebugInfo<'ctx> {
Ok(function)
}
///
/// Creates a primitive type info.
///
pub fn create_type(
&self,
bit_length: usize,
@@ -100,9 +90,7 @@ impl<'ctx> DebugInfo<'ctx> {
.map_err(|error| anyhow::anyhow!("Debug info error: {}", error))
}
///
/// Finalizes the builder.
///
pub fn finalize(&self) {
self.builder.finalize();
}
@@ -1,14 +1,9 @@
//!
//! The LLVM IR generator EVM legacy assembly data.
//!
use crate::eravm::context::argument::Argument;
///
/// The LLVM IR generator EVM legacy assembly data.
///
/// Describes some data that is only relevant to the EVM legacy assembly.
///
#[derive(Debug, Clone)]
pub struct EVMLAData<'ctx> {
/// The Solidity compiler version.
@@ -22,9 +17,7 @@ impl<'ctx> EVMLAData<'ctx> {
/// The default stack size.
pub const DEFAULT_STACK_SIZE: usize = 64;
///
/// A shortcut constructor.
///
pub fn new(version: semver::Version) -> Self {
Self {
version,
@@ -1,14 +1,9 @@
//!
//! The LLVM IR generator function block key.
//!
use crate::eravm::context::code_type::CodeType;
///
/// The LLVM IR generator function block key.
///
/// Is only relevant to the EVM legacy assembly.
///
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Key {
/// The block code type.
@@ -18,9 +13,7 @@ pub struct Key {
}
impl Key {
///
/// A shortcut constructor.
///
pub fn new(code_type: CodeType, tag: num::BigUint) -> Self {
Self { code_type, tag }
}
@@ -1,14 +1,9 @@
//!
//! The LLVM function block EVM legacy assembly data.
//!
pub mod key;
///
/// The LLVM function block EVM legacy assembly data.
///
/// Describes some data that is only relevant to the EVM legacy assembly.
///
#[derive(Debug, Clone)]
pub struct EVMLAData {
/// The initial hashes of the allowed stack states.
@@ -16,9 +11,7 @@ pub struct EVMLAData {
}
impl EVMLAData {
///
/// A shortcut constructor.
///
pub fn new(stack_hashes: Vec<md5::Digest>) -> Self {
Self { stack_hashes }
}
@@ -1,14 +1,10 @@
//!
//! The LLVM IR generator function block.
//!
pub mod evmla_data;
use self::evmla_data::EVMLAData;
///
/// The LLVM IR generator function block.
///
#[derive(Debug, Clone)]
pub struct Block<'ctx> {
/// The inner block.
@@ -18,9 +14,7 @@ pub struct Block<'ctx> {
}
impl<'ctx> Block<'ctx> {
///
/// A shortcut constructor.
///
pub fn new(inner: inkwell::basic_block::BasicBlock<'ctx>) -> Self {
Self {
inner,
@@ -28,38 +22,28 @@ impl<'ctx> Block<'ctx> {
}
}
///
/// Sets the EVM legacy assembly data.
///
pub fn set_evmla_data(&mut self, data: EVMLAData) {
self.evmla_data = Some(data);
}
///
/// The LLVM object reference.
///
pub fn inner(&self) -> inkwell::basic_block::BasicBlock<'ctx> {
self.inner
}
///
/// Returns the EVM data reference.
///
/// # Panics
/// If the EVM data has not been initialized.
///
pub fn evm(&self) -> &EVMLAData {
self.evmla_data
.as_ref()
.expect("The EVM data must have been initialized")
}
///
/// Returns the EVM data mutable reference.
///
/// # Panics
/// If the EVM data has not been initialized.
///
pub fn evm_mut(&mut self) -> &mut EVMLAData {
self.evmla_data
.as_mut()
@@ -1,10 +1,6 @@
//!
//! The LLVM function declaration.
//!
///
/// The LLVM function declaration.
///
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Declaration<'ctx> {
/// The function type.
@@ -14,9 +10,7 @@ pub struct Declaration<'ctx> {
}
impl<'ctx> Declaration<'ctx> {
///
/// A shortcut constructor.
///
pub fn new(
r#type: inkwell::types::FunctionType<'ctx>,
value: inkwell::values::FunctionValue<'ctx>,
@@ -1,17 +1,12 @@
//!
//! The LLVM function EVM legacy assembly data.
//!
use std::collections::BTreeMap;
use crate::eravm::context::function::block::evmla_data::key::Key as BlockKey;
use crate::eravm::context::function::block::Block;
///
/// The LLVM function EVM legacy assembly data.
///
/// Describes some data that is only relevant to the EVM legacy assembly.
///
#[derive(Debug)]
pub struct EVMLAData<'ctx> {
/// The ordinary blocks with numeric tags.
@@ -22,9 +17,7 @@ pub struct EVMLAData<'ctx> {
}
impl<'ctx> EVMLAData<'ctx> {
///
/// A shortcut constructor.
///
pub fn new(stack_size: usize) -> Self {
Self {
blocks: BTreeMap::new(),
@@ -32,9 +25,7 @@ impl<'ctx> EVMLAData<'ctx> {
}
}
///
/// Inserts a function block.
///
pub fn insert_block(&mut self, key: BlockKey, block: Block<'ctx>) {
if let Some(blocks) = self.blocks.get_mut(&key) {
blocks.push(block);
@@ -43,11 +34,8 @@ impl<'ctx> EVMLAData<'ctx> {
}
}
///
/// Returns the block with the specified tag and initial stack pattern.
///
/// If there is only one block, it is returned unconditionally.
///
pub fn find_block(
&self,
key: &BlockKey,
@@ -1,17 +1,12 @@
//!
//! The LLVM intrinsic functions.
//!
use inkwell::types::BasicType;
use crate::eravm::context::address_space::AddressSpace;
use crate::eravm::context::function::declaration::Declaration as FunctionDeclaration;
///
/// The LLVM intrinsic functions, implemented in the LLVM back-end.
///
/// Most of them are translated directly into bytecode instructions.
///
#[derive(Debug)]
pub struct Intrinsics<'ctx> {
/// The trap.
@@ -37,9 +32,7 @@ impl<'ctx> Intrinsics<'ctx> {
/// The corresponding intrinsic function name.
pub const FUNCTION_BYTE_SWAP: &'static str = "llvm.bswap.i256";
///
/// A shortcut constructor.
///
pub fn new(
llvm: &'ctx inkwell::context::Context,
module: &inkwell::module::Module<'ctx>,
@@ -100,9 +93,7 @@ impl<'ctx> Intrinsics<'ctx> {
}
}
///
/// Finds the specified LLVM intrinsic function in the target and returns its declaration.
///
pub fn declare(
llvm: &'ctx inkwell::context::Context,
module: &inkwell::module::Module<'ctx>,
@@ -118,9 +109,7 @@ impl<'ctx> Intrinsics<'ctx> {
FunctionDeclaration::new(r#type, value)
}
///
/// Returns the LLVM types for selecting via the signature.
///
pub fn argument_types(
llvm: &'ctx inkwell::context::Context,
name: &str,
@@ -1,6 +1,4 @@
//!
//! The LLVM runtime functions.
//!
use inkwell::types::BasicType;
@@ -9,11 +7,8 @@ use crate::eravm::context::function::declaration::Declaration as FunctionDeclara
use crate::eravm::context::function::Function;
use crate::optimizer::Optimizer;
///
/// The runtime functions, implemented on the LLVM side.
///
/// The functions are automatically linked to the LLVM implementations if the signatures match.
///
#[derive(Debug)]
pub struct LLVMRuntime<'ctx> {
/// The LLVM personality function, used for exception handling.
@@ -159,9 +154,7 @@ impl<'ctx> LLVMRuntime<'ctx> {
/// The corresponding runtime function name.
pub const FUNCTION_REVERT: &'static str = "__revert";
///
/// A shortcut constructor.
///
pub fn new(
llvm: &'ctx inkwell::context::Context,
module: &inkwell::module::Module<'ctx>,
@@ -602,9 +595,7 @@ impl<'ctx> LLVMRuntime<'ctx> {
}
}
///
/// Declares an LLVM runtime function in the `module`,
///
pub fn declare(
module: &inkwell::module::Module<'ctx>,
name: &str,
@@ -625,9 +616,7 @@ impl<'ctx> LLVMRuntime<'ctx> {
FunctionDeclaration::new(value.get_type(), value).into()
}
///
/// Modifies the external call function with `is_byref` and `is_system` modifiers.
///
pub fn modify(
&self,
function: FunctionDeclaration<'ctx>,
@@ -1,6 +1,4 @@
//!
//! The LLVM IR generator function.
//!
pub mod block;
pub mod declaration;
@@ -26,9 +24,7 @@ use self::runtime::Runtime;
use self::vyper_data::VyperData;
use self::yul_data::YulData;
///
/// The LLVM IR generator function.
///
#[derive(Debug)]
pub struct Function<'ctx> {
/// The high-level source code name.
@@ -66,9 +62,7 @@ impl<'ctx> Function<'ctx> {
/// The stack hashmap default capacity.
const STACK_HASHMAP_INITIAL_CAPACITY: usize = 64;
///
/// A shortcut constructor.
///
pub fn new(
name: String,
declaration: Declaration<'ctx>,
@@ -92,16 +86,12 @@ impl<'ctx> Function<'ctx> {
}
}
///
/// Returns the function name reference.
///
pub fn name(&self) -> &str {
self.name.as_str()
}
///
/// Checks whether the function is defined outside of the front-end.
///
pub fn is_name_external(name: &str) -> bool {
name.starts_with("llvm.")
|| (name.starts_with("__")
@@ -110,24 +100,18 @@ impl<'ctx> Function<'ctx> {
&& name != Runtime::FUNCTION_RUNTIME_CODE)
}
///
/// Checks whether the function is related to the near call ABI.
///
pub fn is_near_call_abi(name: &str) -> bool {
name.starts_with(Self::ZKSYNC_NEAR_CALL_ABI_PREFIX)
|| name == Self::ZKSYNC_NEAR_CALL_ABI_EXCEPTION_HANDLER
}
///
/// Returns the LLVM function declaration.
///
pub fn declaration(&self) -> Declaration<'ctx> {
self.declaration
}
///
/// Returns the N-th parameter of the function.
///
pub fn get_nth_param(&self, index: usize) -> inkwell::values::BasicValueEnum<'ctx> {
self.declaration()
.value
@@ -135,9 +119,7 @@ impl<'ctx> Function<'ctx> {
.expect("Always exists")
}
///
/// Sets the memory writer function attributes.
///
pub fn set_attributes(
llvm: &'ctx inkwell::context::Context,
declaration: Declaration<'ctx>,
@@ -201,11 +183,8 @@ impl<'ctx> Function<'ctx> {
}
}
///
/// Sets the default attributes.
///
/// The attributes only affect the LLVM optimizations.
///
pub fn set_default_attributes(
llvm: &'ctx inkwell::context::Context,
declaration: Declaration<'ctx>,
@@ -234,9 +213,7 @@ impl<'ctx> Function<'ctx> {
Self::set_attributes(llvm, declaration, vec![Attribute::NoFree], false);
}
///
/// Sets the front-end runtime attributes.
///
pub fn set_frontend_runtime_attributes(
llvm: &'ctx inkwell::context::Context,
declaration: Declaration<'ctx>,
@@ -247,9 +224,7 @@ impl<'ctx> Function<'ctx> {
}
}
///
/// Sets the exception handler attributes.
///
pub fn set_exception_handler_attributes(
llvm: &'ctx inkwell::context::Context,
declaration: Declaration<'ctx>,
@@ -257,9 +232,7 @@ impl<'ctx> Function<'ctx> {
Self::set_attributes(llvm, declaration, vec![Attribute::NoInline], false);
}
///
/// Sets the CXA-throw attributes.
///
pub fn set_cxa_throw_attributes(
llvm: &'ctx inkwell::context::Context,
declaration: Declaration<'ctx>,
@@ -267,9 +240,7 @@ impl<'ctx> Function<'ctx> {
Self::set_attributes(llvm, declaration, vec![Attribute::NoProfile], false);
}
///
/// Sets the pure function attributes.
///
pub fn set_pure_function_attributes(
llvm: &'ctx inkwell::context::Context,
declaration: Declaration<'ctx>,
@@ -288,10 +259,8 @@ impl<'ctx> Function<'ctx> {
);
}
///
/// Saves the pointer to a stack variable, returning the pointer to the shadowed variable,
/// if it exists.
///
pub fn insert_stack_pointer(
&mut self,
name: String,
@@ -300,148 +269,108 @@ impl<'ctx> Function<'ctx> {
self.stack.insert(name, pointer)
}
///
/// Gets the pointer to a stack variable.
///
pub fn get_stack_pointer(&self, name: &str) -> Option<Pointer<'ctx>> {
self.stack.get(name).copied()
}
///
/// Removes the pointer to a stack variable.
///
pub fn remove_stack_pointer(&mut self, name: &str) {
self.stack.remove(name);
}
///
/// Returns the return entity representation.
///
pub fn r#return(&self) -> Return<'ctx> {
self.r#return
}
///
/// Returns the pointer to the function return value.
///
/// # Panics
/// If the pointer has not been set yet.
///
pub fn return_pointer(&self) -> Option<Pointer<'ctx>> {
self.r#return.return_pointer()
}
///
/// Returns the return data size in bytes, based on the default stack alignment.
///
/// # Panics
/// If the pointer has not been set yet.
///
pub fn return_data_size(&self) -> usize {
self.r#return.return_data_size()
}
///
/// Returns the function entry block.
///
pub fn entry_block(&self) -> inkwell::basic_block::BasicBlock<'ctx> {
self.entry_block
}
///
/// Returns the function return block.
///
pub fn return_block(&self) -> inkwell::basic_block::BasicBlock<'ctx> {
self.return_block
}
///
/// Sets the EVM legacy assembly data.
///
pub fn set_evmla_data(&mut self, data: EVMLAData<'ctx>) {
self.evmla_data = Some(data);
}
///
/// Returns the EVM legacy assembly data reference.
///
/// # Panics
/// If the EVM data has not been initialized.
///
pub fn evmla(&self) -> &EVMLAData<'ctx> {
self.evmla_data
.as_ref()
.expect("The EVM data must have been initialized")
}
///
/// Returns the EVM legacy assembly data mutable reference.
///
/// # Panics
/// If the EVM data has not been initialized.
///
pub fn evmla_mut(&mut self) -> &mut EVMLAData<'ctx> {
self.evmla_data
.as_mut()
.expect("The EVM data must have been initialized")
}
///
/// Sets the Vyper data.
///
pub fn set_vyper_data(&mut self, data: VyperData) {
self.vyper_data = Some(data);
}
///
/// Returns the Vyper data reference.
///
/// # Panics
/// If the Vyper data has not been initialized.
///
pub fn vyper(&self) -> &VyperData {
self.vyper_data
.as_ref()
.expect("The Vyper data must have been initialized")
}
///
/// Returns the Vyper data mutable reference.
///
/// # Panics
/// If the Vyper data has not been initialized.
///
pub fn vyper_mut(&mut self) -> &mut VyperData {
self.vyper_data
.as_mut()
.expect("The Vyper data must have been initialized")
}
///
/// Sets the Yul data.
///
pub fn set_yul_data(&mut self, data: YulData) {
self.yul_data = Some(data);
}
///
/// Returns the Yul data reference.
///
/// # Panics
/// If the Yul data has not been initialized.
///
pub fn yul(&self) -> &YulData {
self.yul_data
.as_ref()
.expect("The Yul data must have been initialized")
}
///
/// Returns the Yul data mutable reference.
///
/// # Panics
/// If the Yul data has not been initialized.
///
pub fn yul_mut(&mut self) -> &mut YulData {
self.yul_data
.as_mut()
@@ -1,12 +1,8 @@
//!
//! The LLVM IR generator function return entity.
//!
use crate::eravm::context::pointer::Pointer;
///
/// The LLVM IR generator function return entity.
///
#[derive(Debug, Clone, Copy)]
pub enum Return<'ctx> {
/// The function does not return a value.
@@ -27,30 +23,22 @@ pub enum Return<'ctx> {
}
impl<'ctx> Return<'ctx> {
///
/// A shortcut constructor.
///
pub fn none() -> Self {
Self::None
}
///
/// A shortcut constructor.
///
pub fn primitive(pointer: Pointer<'ctx>) -> Self {
Self::Primitive { pointer }
}
///
/// A shortcut constructor.
///
pub fn compound(pointer: Pointer<'ctx>, size: usize) -> Self {
Self::Compound { pointer, size }
}
///
/// Returns the pointer to the function return value.
///
pub fn return_pointer(&self) -> Option<Pointer<'ctx>> {
match self {
Return::None => None,
@@ -59,9 +47,7 @@ impl<'ctx> Return<'ctx> {
}
}
///
/// Returns the return data size in bytes, based on the default stack alignment.
///
pub fn return_data_size(&self) -> usize {
revive_common::BYTE_LENGTH_FIELD
* match self {
@@ -1,6 +1,4 @@
//!
//! The `default_call` function.
//!
use inkwell::types::BasicType;
@@ -11,11 +9,8 @@ use crate::eravm::context::Context;
use crate::eravm::Dependency;
use crate::eravm::WriteLLVM;
///
/// The `default_call` function.
///
/// Generates a default contract call, if the `msg.value` is zero.
///
#[derive(Debug)]
pub struct DefaultCall {
/// The name of the inner function used for the low-level call.
@@ -44,9 +39,7 @@ impl DefaultCall {
/// The output length argument index.
pub const ARGUMENT_INDEX_OUTPUT_LENGTH: usize = 5;
///
/// A shortcut constructor.
///
pub fn new(call_function: FunctionDeclaration) -> Self {
let inner_name = call_function.value.get_name().to_string_lossy().to_string();
let name = Self::name(call_function);
@@ -54,9 +47,7 @@ impl DefaultCall {
Self { inner_name, name }
}
///
/// Returns the function name.
///
pub fn name(call_function: FunctionDeclaration) -> String {
let suffix = match call_function.value.get_name().to_string_lossy() {
name if name == LLVMRuntime::FUNCTION_FARCALL => "far",
@@ -67,9 +58,7 @@ impl DefaultCall {
format!("__default_{suffix}_call")
}
///
/// Returns the low-level call function.
///
fn inner_function<'ctx, D>(&self, context: &Context<'ctx, D>) -> FunctionDeclaration<'ctx>
where
D: Dependency + Clone,
@@ -1,6 +1,4 @@
//!
//! The deploy code function.
//!
use std::marker::PhantomData;
@@ -12,11 +10,8 @@ use crate::eravm::context::Context;
use crate::eravm::Dependency;
use crate::eravm::WriteLLVM;
///
/// The deploy code function.
///
/// Is a special function that is only used by the front-end generated code.
///
#[derive(Debug)]
pub struct DeployCode<B, D>
where
@@ -34,9 +29,7 @@ where
B: WriteLLVM<D>,
D: Dependency + Clone,
{
///
/// A shortcut constructor.
///
pub fn new(inner: B) -> Self {
Self {
inner,
@@ -1,6 +1,4 @@
//!
//! The `deployer_call` function.
//!
use inkwell::types::BasicType;
@@ -11,14 +9,10 @@ use crate::eravm::context::Context;
use crate::eravm::Dependency;
use crate::eravm::WriteLLVM;
///
/// The `deployer_call` function.
///
/// Calls the deployer system contract, which returns the newly deployed contract address or 0.
///
/// The address is returned in the first 32-byte word of the return data. If it is 0, the 0 is
/// returned. If the entire call has failed, there is also a 0 returned.
///
#[derive(Debug)]
pub struct DeployerCall {
/// The address space where the calldata is allocated.
@@ -45,9 +39,7 @@ impl DeployerCall {
/// The salt argument index.
pub const ARGUMENT_INDEX_SALT: usize = 4;
///
/// A shortcut constructor.
///
pub fn new(address_space: AddressSpace) -> Self {
Self { address_space }
}
@@ -1,6 +1,4 @@
//!
//! The entry function.
//!
use inkwell::types::BasicType;
@@ -11,13 +9,9 @@ use crate::eravm::Dependency;
use crate::eravm::WriteLLVM;
use crate::EraVMPointer as Pointer;
///
/// The entry function.
///
/// The function is a wrapper managing the runtime and deploy code calling logic.
///
/// Is a special runtime function that is only used by the front-end generated code.
///
#[derive(Debug, Default)]
pub struct Entry {}
@@ -1,6 +1,4 @@
//!
//! The front-end runtime functions.
//!
pub mod default_call;
pub mod deploy_code;
@@ -17,9 +15,7 @@ use crate::eravm::WriteLLVM;
use self::default_call::DefaultCall;
use self::deployer_call::DeployerCall;
///
/// The front-end runtime functions.
///
#[derive(Debug, Clone)]
pub struct Runtime {
/// The address space where the calldata is allocated.
@@ -37,16 +33,12 @@ impl Runtime {
/// The runtime code function name.
pub const FUNCTION_RUNTIME_CODE: &'static str = "__runtime";
///
/// A shortcut constructor.
///
pub fn new(address_space: AddressSpace) -> Self {
Self { address_space }
}
///
/// Returns the corresponding runtime function.
///
pub fn default_call<'ctx, D>(
context: &Context<'ctx, D>,
call_function: FunctionDeclaration<'ctx>,
@@ -61,9 +53,7 @@ impl Runtime {
.declaration()
}
///
/// Returns the corresponding runtime function.
///
pub fn deployer_call<'ctx, D>(context: &Context<'ctx, D>) -> FunctionDeclaration<'ctx>
where
D: Dependency + Clone,
@@ -1,6 +1,4 @@
//!
//! The runtime code function.
//!
use std::marker::PhantomData;
@@ -10,11 +8,8 @@ use crate::eravm::context::Context;
use crate::eravm::Dependency;
use crate::eravm::WriteLLVM;
///
/// The runtime code function.
///
/// Is a special function that is only used by the front-end generated code.
///
#[derive(Debug)]
pub struct RuntimeCode<B, D>
where
@@ -32,9 +27,7 @@ where
B: WriteLLVM<D>,
D: Dependency + Clone,
{
///
/// A shortcut constructor.
///
pub fn new(inner: B) -> Self {
Self {
inner,
@@ -1,14 +1,9 @@
//!
//! The LLVM function Vyper data.
//!
use std::collections::HashMap;
///
/// The LLVM function Vyper data.
///
/// Describes some data that is only relevant to Vyper.
///
#[derive(Debug)]
pub struct VyperData {
/// The block-local variables. They are still allocated at the beginning of the function,
@@ -29,23 +24,17 @@ impl VyperData {
/// The label arguments hashmap default capacity.
const LABEL_ARGUMENTS_HASHMAP_INITIAL_CAPACITY: usize = 16;
///
/// A shortcut constructor.
///
pub fn new() -> Self {
Self::default()
}
///
/// Returns the list of a Vyper label arguments.
///
pub fn label_arguments(&self, label_name: &str) -> Option<Vec<String>> {
self.label_arguments.get(label_name).cloned()
}
///
/// Inserts arguments for the specified label.
///
pub fn insert_label_arguments(&mut self, label_name: String, arguments: Vec<String>) {
self.label_arguments.insert(label_name, arguments);
}
@@ -1,16 +1,11 @@
//!
//! The LLVM function Yul data.
//!
use std::collections::HashMap;
use num::BigUint;
///
/// The LLVM function Yul data.
///
/// Describes some data that is only relevant to Yul.
///
#[derive(Debug)]
pub struct YulData {
/// The constants saved to variables. Used for peculiar cases like call simulation.
@@ -30,23 +25,17 @@ impl YulData {
/// The constants hashmap default capacity.
const CONSTANTS_HASHMAP_INITIAL_CAPACITY: usize = 16;
///
/// A shortcut constructor.
///
pub fn new() -> Self {
Self::default()
}
///
/// Returns a constant if it has been saved.
///
pub fn get_constant(&self, name: &str) -> Option<BigUint> {
self.constants.get(name).cloned()
}
///
/// Saves a constant detected with the partial constant propagation.
///
pub fn insert_constant(&mut self, name: String, value: BigUint) {
self.constants.insert(name, value);
}
@@ -1,6 +1,4 @@
//!
//! The LLVM global value.
//!
use inkwell::types::BasicType;
use inkwell::values::BasicValue;
@@ -9,9 +7,7 @@ use crate::eravm::context::address_space::AddressSpace;
use crate::eravm::context::Context;
use crate::EraVMDependency;
///
/// The LLVM global value.
///
#[derive(Debug, Clone, Copy)]
pub struct Global<'ctx> {
/// The global type.
@@ -21,9 +17,7 @@ pub struct Global<'ctx> {
}
impl<'ctx> Global<'ctx> {
///
/// A shortcut constructor.
///
pub fn new<D, T, V>(
context: &mut Context<'ctx, D>,
r#type: T,
@@ -1,10 +1,6 @@
//!
//! The LLVM IR generator loop.
//!
///
/// The LLVM IR generator loop.
///
#[derive(Debug, Clone)]
pub struct Loop<'ctx> {
/// The loop current block.
@@ -16,9 +12,7 @@ pub struct Loop<'ctx> {
}
impl<'ctx> Loop<'ctx> {
///
/// A shortcut constructor.
///
pub fn new(
body_block: inkwell::basic_block::BasicBlock<'ctx>,
continue_block: inkwell::basic_block::BasicBlock<'ctx>,
@@ -1,6 +1,4 @@
//!
//! The LLVM IR generator context.
//!
pub mod address_space;
pub mod argument;
@@ -52,12 +50,9 @@ use self::solidity_data::SolidityData;
use self::vyper_data::VyperData;
use self::yul_data::YulData;
///
/// The LLVM IR generator context.
///
/// It is a not-so-big god-like object glueing all the compilers' complexity and act as an adapter
/// and a superstructure over the inner `inkwell` LLVM context.
///
pub struct Context<'ctx, D>
where
D: Dependency + Clone,
@@ -191,9 +186,7 @@ where
);
}
///
/// Initializes a new LLVM context.
///
pub fn new(
llvm: &'ctx inkwell::context::Context,
module: inkwell::module::Module<'ctx>,
@@ -235,9 +228,7 @@ where
}
}
///
/// Builds the LLVM IR module, returning the build artifacts.
///
pub fn build(
mut self,
contract_path: &str,
@@ -312,53 +303,39 @@ where
Ok(build)
}
///
/// Verifies the current LLVM IR module.
///
pub fn verify(&self) -> anyhow::Result<()> {
self.module()
.verify()
.map_err(|error| anyhow::anyhow!(error.to_string()))
}
///
/// Returns the inner LLVM context.
///
pub fn llvm(&self) -> &'ctx inkwell::context::Context {
self.llvm
}
///
/// Returns the LLVM IR builder.
///
pub fn builder(&self) -> &inkwell::builder::Builder<'ctx> {
&self.builder
}
///
/// Returns the current LLVM IR module reference.
///
pub fn module(&self) -> &inkwell::module::Module<'ctx> {
&self.module
}
///
/// Sets the current code type (deploy or runtime).
///
pub fn set_code_type(&mut self, code_type: CodeType) {
self.code_type = Some(code_type);
}
///
/// Returns the current code type (deploy or runtime).
///
pub fn code_type(&self) -> Option<CodeType> {
self.code_type.to_owned()
}
///
/// Returns the pointer to a global variable.
///
pub fn get_global(&self, name: &str) -> anyhow::Result<Global<'ctx>> {
match self.globals.get(name) {
Some(global) => Ok(*global),
@@ -366,9 +343,7 @@ where
}
}
///
/// Returns the value of a global variable.
///
pub fn get_global_value(
&self,
name: &str,
@@ -377,9 +352,7 @@ where
self.build_load(global.into(), name)
}
///
/// Sets the value to a global variable.
///
pub fn set_global<T, V>(&mut self, name: &str, r#type: T, address_space: AddressSpace, value: V)
where
T: BasicType<'ctx> + Clone + Copy,
@@ -397,16 +370,12 @@ where
}
}
///
/// Returns the LLVM intrinsics collection reference.
///
pub fn intrinsics(&self) -> &Intrinsics<'ctx> {
&self.intrinsics
}
///
/// Returns the LLVM runtime function collection reference.
///
pub fn llvm_runtime(&self) -> &LLVMRuntime<'ctx> {
&self.llvm_runtime
}
@@ -440,9 +409,7 @@ where
Ok(function)
}
///
/// Appends a function to the current module.
///
pub fn add_function(
&mut self,
name: &str,
@@ -504,25 +471,19 @@ where
Ok(function)
}
///
/// Returns a shared reference to the specified function.
///
pub fn get_function(&self, name: &str) -> Option<Rc<RefCell<Function<'ctx>>>> {
self.functions.get(name).cloned()
}
///
/// Returns a shared reference to the current active function.
///
pub fn current_function(&self) -> Rc<RefCell<Function<'ctx>>> {
self.current_function
.clone()
.expect("Must be declared before use")
}
///
/// Sets the current active function.
///
pub fn set_current_function(&mut self, name: &str) -> anyhow::Result<()> {
let function = self.functions.get(name).cloned().ok_or_else(|| {
anyhow::anyhow!("Failed to activate an undeclared function `{}`", name)
@@ -531,9 +492,7 @@ where
Ok(())
}
///
/// Pushes a new loop context to the stack.
///
pub fn push_loop(
&mut self,
body_block: inkwell::basic_block::BasicBlock<'ctx>,
@@ -544,25 +503,19 @@ where
.push(Loop::new(body_block, continue_block, join_block));
}
///
/// Pops the current loop context from the stack.
///
pub fn pop_loop(&mut self) {
self.loop_stack.pop();
}
///
/// Returns the current loop context.
///
pub fn r#loop(&self) -> &Loop<'ctx> {
self.loop_stack
.last()
.expect("The current context is not in a loop")
}
///
/// Compiles a contract dependency, if the dependency manager is set.
///
pub fn compile_dependency(&mut self, name: &str) -> anyhow::Result<String> {
if let Some(vyper_data) = self.vyper_data.as_mut() {
vyper_data.set_is_forwarder_used();
@@ -585,9 +538,7 @@ where
})
}
///
/// Gets a full contract_path from the dependency manager.
///
pub fn resolve_path(&self, identifier: &str) -> anyhow::Result<String> {
self.dependency_manager
.to_owned()
@@ -598,9 +549,7 @@ where
})
}
///
/// Gets a deployed library address from the dependency manager.
///
pub fn resolve_library(&self, path: &str) -> anyhow::Result<inkwell::values::IntValue<'ctx>> {
self.dependency_manager
.to_owned()
@@ -612,49 +561,36 @@ where
})
}
///
/// Extracts the dependency manager.
///
pub fn take_dependency_manager(&mut self) -> D {
self.dependency_manager
.take()
.expect("The dependency manager is unset")
}
///
/// Returns the debug config reference.
///
pub fn debug_config(&self) -> Option<&DebugConfig> {
self.debug_config.as_ref()
}
///
/// Appends a new basic block to the current function.
///
pub fn append_basic_block(&self, name: &str) -> inkwell::basic_block::BasicBlock<'ctx> {
self.llvm
.append_basic_block(self.current_function().borrow().declaration().value, name)
}
///
/// Sets the current basic block.
///
pub fn set_basic_block(&self, block: inkwell::basic_block::BasicBlock<'ctx>) {
self.builder.position_at_end(block);
}
///
/// Returns the current basic block.
///
pub fn basic_block(&self) -> inkwell::basic_block::BasicBlock<'ctx> {
self.builder.get_insert_block().expect("Always exists")
}
///
/// Builds a stack allocation instruction.
///
/// Sets the alignment to 128 bits.
///
pub fn build_alloca<T: BasicType<'ctx> + Clone + Copy>(
&self,
r#type: T,
@@ -669,11 +605,8 @@ where
Pointer::new(r#type, AddressSpace::Stack, pointer)
}
///
/// Builds a stack load instruction.
///
/// Sets the alignment to 256 bits for the stack and 1 bit for the heap, parent, and child.
///
pub fn build_load(
&self,
pointer: Pointer<'ctx>,
@@ -784,11 +717,8 @@ where
}
}
///
/// Builds a stack store instruction.
///
/// Sets the alignment to 256 bits for the stack and 1 bit for the heap, parent, and child.
///
pub fn build_store<V>(&self, pointer: Pointer<'ctx>, value: V) -> anyhow::Result<()>
where
V: BasicValue<'ctx>,
@@ -893,9 +823,7 @@ where
.expect("byte_swap should return a value")
}
///
/// Builds a GEP instruction.
///
pub fn build_gep<T>(
&self,
pointer: Pointer<'ctx>,
@@ -917,11 +845,8 @@ where
Pointer::new(element_type, pointer.address_space, value)
}
///
/// Builds a conditional branch.
///
/// Checks if there are no other terminators in the block.
///
pub fn build_conditional_branch(
&self,
comparison: inkwell::values::IntValue<'ctx>,
@@ -938,11 +863,8 @@ where
Ok(())
}
///
/// Builds an unconditional branch.
///
/// Checks if there are no other terminators in the block.
///
pub fn build_unconditional_branch(
&self,
destination_block: inkwell::basic_block::BasicBlock<'ctx>,
@@ -956,9 +878,7 @@ where
.unwrap();
}
///
/// Builds a call.
///
pub fn build_call(
&self,
function: FunctionDeclaration<'ctx>,
@@ -983,11 +903,8 @@ where
call_site_value.try_as_basic_value().left()
}
///
/// Builds an invoke.
///
/// Is defaulted to a call if there is no global exception handler.
///
pub fn build_invoke(
&self,
function: FunctionDeclaration<'ctx>,
@@ -1072,13 +989,10 @@ where
return_pointer.map(|pointer| self.build_load(pointer, "invoke_result").unwrap())
}
///
/// Builds an invoke of local call covered with an exception handler.
///
/// Yul does not the exception handling, so the user can declare a special handling function
/// called (see constant `ZKSYNC_NEAR_CALL_ABI_EXCEPTION_HANDLER`. If the enclosed function
/// panics, the control flow will be transferred to the exception handler.
///
pub fn build_invoke_near_call_abi(
&self,
_function: FunctionDeclaration<'ctx>,
@@ -1088,11 +1002,8 @@ where
unimplemented!()
}
///
/// Builds a memory copy call.
///
/// Sets the alignment to `1`, since all non-stack memory pages have such alignment.
///
pub fn build_memcpy(
&self,
_function: FunctionDeclaration<'ctx>,
@@ -1108,12 +1019,9 @@ where
Ok(())
}
///
/// Builds a memory copy call for the return data.
///
/// Sets the output length to `min(output_length, return_data_size` and calls the default
/// generic page memory copy builder.
///
pub fn build_memcpy_return_data(
&self,
function: FunctionDeclaration<'ctx>,
@@ -1159,11 +1067,8 @@ where
Ok(())
}
///
/// Builds a return.
///
/// Checks if there are no other terminators in the block.
///
pub fn build_return(&self, value: Option<&dyn BasicValue<'ctx>>) {
if self.basic_block().get_terminator().is_some() {
return;
@@ -1172,11 +1077,8 @@ where
self.builder.build_return(value).unwrap();
}
///
/// Builds an unreachable.
///
/// Checks if there are no other terminators in the block.
///
pub fn build_unreachable(&self) {
if self.basic_block().get_terminator().is_some() {
return;
@@ -1185,14 +1087,11 @@ where
self.builder.build_unreachable().unwrap();
}
///
/// Builds a long contract exit sequence.
///
/// The deploy code does not return the runtime code like in EVM. Instead, it returns some
/// additional contract metadata, e.g. the array of immutables.
/// The deploy code uses the auxiliary heap for the return, because otherwise it is not possible
/// to allocate memory together with the Yul allocator safely.
///
pub fn build_exit(
&self,
flags: inkwell::values::IntValue<'ctx>,
@@ -1230,7 +1129,6 @@ where
}
/// Truncate a memory offset into 32 bits, trapping if it doesn't fit.
///
/// Pointers are represented as opaque 256 bit integer values in EVM.
/// In practice, they should never exceed a 32 bit value. However, we
/// still protect against this possibility here.
@@ -1287,7 +1185,6 @@ where
/// Call PolkaVM `sbrk` for extending the heap by `size`,
/// trapping the contract if the call failed.
///
/// Returns the end of memory pointer.
pub fn build_heap_alloc(
&self,
@@ -1316,7 +1213,6 @@ where
/// Returns a pointer to `offset` into the heap, allocating
/// enough memory if `offset + length` would be out of bounds.
///
/// # Panics
/// Assumes `offset` and `length` to be an i32 value.
pub fn build_heap_gep(
@@ -1369,9 +1265,7 @@ where
))
}
///
/// Writes the ABI pointer to the global variable.
///
pub fn write_abi_pointer(&mut self, pointer: Pointer<'ctx>, global_name: &str) {
self.set_global(
global_name,
@@ -1381,9 +1275,7 @@ where
);
}
///
/// Writes the ABI data size to the global variable.
///
pub fn write_abi_data_size(&mut self, _pointer: Pointer<'ctx>, _global_name: &str) {
/*
let abi_pointer_value = self
@@ -1416,46 +1308,34 @@ where
*/
}
///
/// Returns a boolean type constant.
///
pub fn bool_const(&self, value: bool) -> inkwell::values::IntValue<'ctx> {
self.bool_type().const_int(u64::from(value), false)
}
///
/// Returns an integer type constant.
///
pub fn integer_const(&self, bit_length: usize, value: u64) -> inkwell::values::IntValue<'ctx> {
self.integer_type(bit_length).const_int(value, false)
}
///
/// Returns a 256-bit field type constant.
///
pub fn field_const(&self, value: u64) -> inkwell::values::IntValue<'ctx> {
self.field_type().const_int(value, false)
}
///
/// Returns a 256-bit field type undefined value.
///
pub fn field_undef(&self) -> inkwell::values::IntValue<'ctx> {
self.field_type().get_undef()
}
///
/// Returns a field type constant from a decimal string.
///
pub fn field_const_str_dec(&self, value: &str) -> inkwell::values::IntValue<'ctx> {
self.field_type()
.const_int_from_string(value, inkwell::types::StringRadix::Decimal)
.unwrap_or_else(|| panic!("Invalid string constant `{value}`"))
}
///
/// Returns a field type constant from a hexadecimal string.
///
pub fn field_const_str_hex(&self, value: &str) -> inkwell::values::IntValue<'ctx> {
self.field_type()
.const_int_from_string(
@@ -1465,31 +1345,23 @@ where
.unwrap_or_else(|| panic!("Invalid string constant `{value}`"))
}
///
/// Returns the void type.
///
pub fn void_type(&self) -> inkwell::types::VoidType<'ctx> {
self.llvm.void_type()
}
///
/// Returns the boolean type.
///
pub fn bool_type(&self) -> inkwell::types::IntType<'ctx> {
self.llvm.bool_type()
}
///
/// Returns the default byte type.
///
pub fn byte_type(&self) -> inkwell::types::IntType<'ctx> {
self.llvm
.custom_width_int_type(revive_common::BIT_LENGTH_BYTE as u32)
}
///
/// Returns the integer type of the specified bit-length.
///
pub fn integer_type(&self, bit_length: usize) -> inkwell::types::IntType<'ctx> {
self.llvm.custom_width_int_type(bit_length as u32)
}
@@ -1505,17 +1377,13 @@ where
.custom_width_int_type(revive_common::BIT_LENGTH_VALUE as u32)
}
///
/// Returns the default field type.
///
pub fn field_type(&self) -> inkwell::types::IntType<'ctx> {
self.llvm
.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32)
}
///
/// Returns the array type with the specified length.
///
pub fn array_type<T>(&self, element_type: T, length: usize) -> inkwell::types::ArrayType<'ctx>
where
T: BasicType<'ctx>,
@@ -1523,9 +1391,7 @@ where
element_type.array_type(length as u32)
}
///
/// Returns the structure type with specified fields.
///
pub fn structure_type<T>(&self, field_types: &[T]) -> inkwell::types::StructType<'ctx>
where
T: BasicType<'ctx>,
@@ -1535,9 +1401,7 @@ where
self.llvm.struct_type(field_types.as_slice(), false)
}
///
/// Returns a Yul function type with the specified arguments and number of return values.
///
pub fn function_type<T>(
&self,
argument_types: Vec<T>,
@@ -1570,11 +1434,8 @@ where
}
}
///
/// Modifies the call site value, setting the default attributes.
///
/// The attributes only affect the LLVM optimizations.
///
pub fn modify_call_site_value(
&self,
arguments: &[inkwell::values::BasicValueEnum<'ctx>],
@@ -1680,124 +1541,92 @@ where
}
}
///
/// Sets the Solidity data.
///
pub fn set_solidity_data(&mut self, data: SolidityData) {
self.solidity_data = Some(data);
}
///
/// Returns the Solidity data reference.
///
/// # Panics
/// If the Solidity data has not been initialized.
///
pub fn solidity(&self) -> &SolidityData {
self.solidity_data
.as_ref()
.expect("The Solidity data must have been initialized")
}
///
/// Returns the Solidity data mutable reference.
///
/// # Panics
/// If the Solidity data has not been initialized.
///
pub fn solidity_mut(&mut self) -> &mut SolidityData {
self.solidity_data
.as_mut()
.expect("The Solidity data must have been initialized")
}
///
/// Sets the Yul data.
///
pub fn set_yul_data(&mut self, data: YulData) {
self.yul_data = Some(data);
}
///
/// Returns the Yul data reference.
///
/// # Panics
/// If the Yul data has not been initialized.
///
pub fn yul(&self) -> &YulData {
self.yul_data
.as_ref()
.expect("The Yul data must have been initialized")
}
///
/// Returns the Yul data mutable reference.
///
/// # Panics
/// If the Yul data has not been initialized.
///
pub fn yul_mut(&mut self) -> &mut YulData {
self.yul_data
.as_mut()
.expect("The Yul data must have been initialized")
}
///
/// Sets the EVM legacy assembly data.
///
pub fn set_evmla_data(&mut self, data: EVMLAData<'ctx>) {
self.evmla_data = Some(data);
}
///
/// Returns the EVM legacy assembly data reference.
///
/// # Panics
/// If the EVM data has not been initialized.
///
pub fn evmla(&self) -> &EVMLAData<'ctx> {
self.evmla_data
.as_ref()
.expect("The EVMLA data must have been initialized")
}
///
/// Returns the EVM legacy assembly data mutable reference.
///
/// # Panics
/// If the EVM data has not been initialized.
///
pub fn evmla_mut(&mut self) -> &mut EVMLAData<'ctx> {
self.evmla_data
.as_mut()
.expect("The EVMLA data must have been initialized")
}
///
/// Sets the EVM legacy assembly data.
///
pub fn set_vyper_data(&mut self, data: VyperData) {
self.vyper_data = Some(data);
}
///
/// Returns the Vyper data reference.
///
/// # Panics
/// If the Vyper data has not been initialized.
///
pub fn vyper(&self) -> &VyperData {
self.vyper_data
.as_ref()
.expect("The Solidity data must have been initialized")
}
///
/// Returns the current number of immutables values in the contract.
///
/// If the size is set manually, then it is returned. Otherwise, the number of elements in
/// the identifier-to-offset mapping tree is returned.
///
pub fn immutables_size(&self) -> anyhow::Result<usize> {
if let Some(solidity) = self.solidity_data.as_ref() {
Ok(solidity.immutables_size())
@@ -1808,9 +1637,7 @@ where
}
}
///
/// Whether the system mode is enabled.
///
pub fn is_system_mode(&self) -> bool {
self.yul_data
.as_ref()
@@ -1,6 +1,4 @@
//!
//! The LLVM pointer.
//!
use inkwell::types::BasicType;
@@ -9,9 +7,7 @@ use crate::eravm::context::global::Global;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// The LLVM pointer.
///
#[derive(Debug, Clone, Copy)]
pub struct Pointer<'ctx> {
/// The pointee type.
@@ -23,9 +19,7 @@ pub struct Pointer<'ctx> {
}
impl<'ctx> Pointer<'ctx> {
///
/// A shortcut constructor.
///
pub fn new<T>(
r#type: T,
address_space: AddressSpace,
@@ -41,9 +35,7 @@ impl<'ctx> Pointer<'ctx> {
}
}
///
/// Wraps a 256-bit primitive type pointer.
///
pub fn new_stack_field<D>(
context: &Context<'ctx, D>,
value: inkwell::values::PointerValue<'ctx>,
@@ -58,9 +50,7 @@ impl<'ctx> Pointer<'ctx> {
}
}
///
/// Creates a new pointer with the specified `offset`.
///
pub fn new_with_offset<D, T>(
context: &Context<'ctx, D>,
address_space: AddressSpace,
@@ -86,9 +76,7 @@ impl<'ctx> Pointer<'ctx> {
Self::new(r#type, address_space, value)
}
///
/// Casts the pointer into another type.
///
pub fn cast<T>(self, r#type: T) -> Self
where
T: BasicType<'ctx>,
@@ -1,14 +1,9 @@
//!
//! The LLVM IR generator Solidity data.
//!
use std::collections::BTreeMap;
///
/// The LLVM IR generator Solidity data.
///
/// Describes some data that is only relevant to Solidity.
///
#[derive(Debug, Default)]
pub struct SolidityData {
/// The immutables identifier-to-offset mapping. Is only used by Solidity due to
@@ -17,25 +12,18 @@ pub struct SolidityData {
}
impl SolidityData {
///
/// A shortcut constructor.
///
pub fn new() -> Self {
Self::default()
}
///
/// Returns the current number of immutables values in the contract.
///
pub fn immutables_size(&self) -> usize {
self.immutables.len() * revive_common::BYTE_LENGTH_FIELD
}
///
/// Allocates memory for an immutable value in the auxiliary heap.
///
/// If the identifier is already known, just returns its offset.
///
pub fn allocate_immutable(&mut self, identifier: &str) -> usize {
let number_of_elements = self.immutables.len();
let new_offset = number_of_elements * revive_common::BYTE_LENGTH_FIELD;
@@ -45,11 +33,8 @@ impl SolidityData {
.or_insert(new_offset)
}
///
/// Gets the offset of the immutable value.
///
/// If the value is not yet allocated, then it is done forcibly.
///
pub fn get_or_allocate_immutable(&mut self, identifier: &str) -> usize {
match self.immutables.get(identifier).copied() {
Some(offset) => offset,
@@ -1,6 +1,4 @@
//!
//! The LLVM IR generator context tests.
//!
use crate::eravm::context::attribute::Attribute;
use crate::eravm::context::Context;
@@ -1,12 +1,7 @@
//!
//! The LLVM IR generator Vyper data.
//!
///
/// The LLVM IR generator Vyper data.
///
/// Describes some data that is only relevant to Vyper.
///
#[derive(Debug)]
pub struct VyperData {
/// The immutables size tracker. Stores the size in bytes.
@@ -17,9 +12,7 @@ pub struct VyperData {
}
impl VyperData {
///
/// A shortcut constructor.
///
pub fn new(immutables_size: usize, is_forwarder_used: bool) -> Self {
Self {
immutables_size,
@@ -27,23 +20,17 @@ impl VyperData {
}
}
///
/// Returns the size of the immutables data of the contract.
///
pub fn immutables_size(&self) -> usize {
self.immutables_size
}
///
/// Sets the forwarder usage flag.
///
pub fn set_is_forwarder_used(&mut self) {
self.is_forwarder_used = true;
}
///
/// Returns the forwarder usage flag.
///
pub fn is_forwarder_used(&self) -> bool {
self.is_forwarder_used
}
@@ -1,16 +1,11 @@
//!
//! The LLVM IR generator Yul data.
//!
use std::collections::BTreeMap;
use num::Zero;
///
/// The LLVM IR generator Yul data.
///
/// Describes some data that is only relevant to Yul.
///
#[derive(Debug, Default)]
pub struct YulData {
/// The system mode flag.
@@ -22,9 +17,7 @@ pub struct YulData {
}
impl YulData {
///
/// A shortcut constructor.
///
pub fn new(is_system_mode: bool) -> Self {
Self {
is_system_mode,
@@ -32,16 +25,12 @@ impl YulData {
}
}
///
/// Whether the system mode is enabled.
///
pub fn is_system_mode(&self) -> bool {
self.is_system_mode
}
///
/// Declares a temporary constant array representation.
///
pub fn const_array_declare(&mut self, index: u8, size: u16) -> anyhow::Result<()> {
if self.const_arrays.contains_key(&index) {
anyhow::bail!(
@@ -56,9 +45,7 @@ impl YulData {
Ok(())
}
///
/// Sets a value in the constant array representation.
///
pub fn const_array_set(
&mut self,
index: u8,
@@ -81,9 +68,7 @@ impl YulData {
Ok(())
}
///
/// Finalizes the constant array declaration.
///
pub fn const_array_take(&mut self, index: u8) -> anyhow::Result<Vec<num::BigUint>> {
self.const_arrays.remove(&index).ok_or_else(|| {
anyhow::anyhow!("The constant array with index {} is not declared", index)
@@ -1,15 +1,11 @@
//!
//! Translates the arithmetic operations.
//!
use inkwell::values::BasicValue;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the arithmetic addition.
///
pub fn addition<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -24,9 +20,7 @@ where
.as_basic_value_enum())
}
///
/// Translates the arithmetic subtraction.
///
pub fn subtraction<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -41,9 +35,7 @@ where
.as_basic_value_enum())
}
///
/// Translates the arithmetic multiplication.
///
pub fn multiplication<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -58,9 +50,7 @@ where
.as_basic_value_enum())
}
///
/// Translates the arithmetic division.
///
pub fn division<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -75,9 +65,7 @@ where
.into())
}
///
/// Translates the arithmetic remainder.
///
pub fn remainder<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -98,13 +86,10 @@ where
.expect("Always exists"))
}
///
/// Translates the signed arithmetic division.
///
/// Two differences between the EVM and LLVM IR:
/// 1. In case of division by zero, 0 is returned.
/// 2. In case of overflow, the first argument is returned.
///
pub fn division_signed<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -125,9 +110,7 @@ where
.expect("Always exists"))
}
///
/// Translates the signed arithmetic remainder.
///
pub fn remainder_signed<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -1,15 +1,11 @@
//!
//! Translates the bitwise operations.
//!
use inkwell::values::BasicValue;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the bitwise OR.
///
pub fn or<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -24,9 +20,7 @@ where
.as_basic_value_enum())
}
///
/// Translates the bitwise XOR.
///
pub fn xor<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -41,9 +35,7 @@ where
.as_basic_value_enum())
}
///
/// Translates the bitwise AND.
///
pub fn and<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -58,9 +50,7 @@ where
.as_basic_value_enum())
}
///
/// Translates the bitwise shift left.
///
pub fn shift_left<'ctx, D>(
context: &mut Context<'ctx, D>,
shift: inkwell::values::IntValue<'ctx>,
@@ -98,9 +88,7 @@ where
context.build_load(result_pointer, "shift_left_result")
}
///
/// Translates the bitwise shift right.
///
pub fn shift_right<'ctx, D>(
context: &mut Context<'ctx, D>,
shift: inkwell::values::IntValue<'ctx>,
@@ -140,9 +128,7 @@ where
context.build_load(result_pointer, "shift_right_result")
}
///
/// Translates the arithmetic bitwise shift right.
///
pub fn shift_right_arithmetic<'ctx, D>(
context: &mut Context<'ctx, D>,
shift: inkwell::values::IntValue<'ctx>,
@@ -211,9 +197,7 @@ where
context.build_load(result_pointer, "shift_right_arithmetic_result")
}
///
/// Translates the `byte` instruction.
///
pub fn byte<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -1,6 +1,4 @@
//!
//! Translates a contract call.
//!
use inkwell::values::BasicValue;
@@ -9,12 +7,9 @@ use crate::eravm::context::function::declaration::Declaration as FunctionDeclara
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates a contract call.
///
/// If the `simulation_address` is specified, the call is substituted with another instruction
/// according to the specification.
///
#[allow(clippy::too_many_arguments)]
pub fn default<'ctx, D>(
_context: &mut Context<'ctx, D>,
@@ -95,9 +90,7 @@ where
*/
}
///
/// Translates the Yul `linkersymbol` instruction.
///
pub fn linker_symbol<'ctx, D>(
context: &mut Context<'ctx, D>,
mut arguments: [Argument<'ctx>; 1],
@@ -1,6 +1,4 @@
//!
//! Translates the calldata instructions.
//!
use crate::eravm::context::address_space::AddressSpace;
use crate::eravm::context::pointer::Pointer;
@@ -8,9 +6,7 @@ use crate::eravm::context::Context;
use crate::eravm::Dependency;
use inkwell::types::BasicType;
///
/// Translates the calldata load.
///
pub fn load<'ctx, D>(
context: &mut Context<'ctx, D>,
offset: inkwell::values::IntValue<'ctx>,
@@ -33,9 +29,7 @@ where
.map(|value| context.build_byte_swap(value))
}
///
/// Translates the calldata size.
///
pub fn size<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -47,9 +41,7 @@ where
Ok(value)
}
///
/// Translates the calldata copy.
///
pub fn copy<'ctx, D>(
context: &mut Context<'ctx, D>,
destination_offset: inkwell::values::IntValue<'ctx>,
@@ -1,17 +1,12 @@
//!
//! Translates the comparison operations.
//!
use inkwell::values::BasicValue;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the comparison operations.
///
/// There is not difference between the EVM and LLVM IR behaviors.
///
pub fn compare<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -1,15 +1,11 @@
//!
//! Translates the context getter instructions.
//!
use inkwell::values::BasicValue;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the `gas_limit` instruction.
///
pub fn gas_limit<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -19,9 +15,7 @@ where
todo!()
}
///
/// Translates the `gas_price` instruction.
///
pub fn gas_price<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -31,9 +25,7 @@ where
todo!()
}
///
/// Translates the `tx.origin` instruction.
///
pub fn origin<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -43,9 +35,7 @@ where
todo!()
}
///
/// Translates the `chain_id` instruction.
///
pub fn chain_id<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -55,9 +45,7 @@ where
todo!()
}
///
/// Translates the `block_number` instruction.
///
pub fn block_number<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -67,9 +55,7 @@ where
todo!()
}
///
/// Translates the `block_timestamp` instruction.
///
pub fn block_timestamp<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -79,9 +65,7 @@ where
todo!()
}
///
/// Translates the `block_hash` instruction.
///
pub fn block_hash<'ctx, D>(
_context: &mut Context<'ctx, D>,
_index: inkwell::values::IntValue<'ctx>,
@@ -92,9 +76,7 @@ where
todo!()
}
///
/// Translates the `difficulty` instruction.
///
pub fn difficulty<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -104,9 +86,7 @@ where
todo!()
}
///
/// Translates the `coinbase` instruction.
///
pub fn coinbase<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -116,9 +96,7 @@ where
todo!()
}
///
/// Translates the `basefee` instruction.
///
pub fn basefee<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -128,9 +106,7 @@ where
todo!()
}
///
/// Translates the `msize` instruction.
///
pub fn msize<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -1,6 +1,4 @@
//!
//! Translates the contract creation instructions.
//!
use inkwell::values::BasicValue;
use num::Zero;
@@ -11,11 +9,8 @@ use crate::eravm::context::function::runtime::Runtime;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the contract `create` instruction.
///
/// The instruction is simulated by a call to a system contract.
///
pub fn create<'ctx, D>(
context: &mut Context<'ctx, D>,
value: inkwell::values::IntValue<'ctx>,
@@ -49,11 +44,8 @@ where
Ok(result)
}
///
/// Translates the contract `create2` instruction.
///
/// The instruction is simulated by a call to a system contract.
///
pub fn create2<'ctx, D>(
context: &mut Context<'ctx, D>,
value: inkwell::values::IntValue<'ctx>,
@@ -88,12 +80,9 @@ where
Ok(result)
}
///
/// Translates the contract hash instruction, which is actually used to set the hash of the contract
/// being created, or other related auxiliary data.
///
/// Represents `dataoffset` in Yul and `PUSH [$]` in the EVM legacy assembly.
///
pub fn contract_hash<'ctx, D>(
context: &mut Context<'ctx, D>,
identifier: String,
@@ -132,20 +121,16 @@ where
Ok(Argument::new_with_original(hash_value, hash_string))
}
///
/// Translates the deployer call header size instruction, Usually, the header consists of:
/// - the deployer contract method signature
/// - the salt if the call is `create2`, or zero if the call is `create1`
/// - the hash of the bytecode of the contract whose instance is being created
/// - the offset of the constructor arguments
/// - the length of the constructor arguments
///
/// If the call is `create1`, the space for the salt is still allocated, because the memory for the
/// header is allocated by the Yul or EVM legacy assembly before it is known which version of
/// `create` is going to be used.
///
/// Represents `datasize` in Yul and `PUSH #[$]` in the EVM legacy assembly.
///
pub fn header_size<'ctx, D>(
context: &mut Context<'ctx, D>,
identifier: String,
@@ -1,13 +1,9 @@
//!
//! Translates the cryptographic operations.
//!
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the `sha3` instruction.
///
pub fn sha3<'ctx, D>(
context: &mut Context<'ctx, D>,
offset: inkwell::values::IntValue<'ctx>,
@@ -1,15 +1,11 @@
//!
//! Translates the value and balance operations.
//!
use inkwell::values::BasicValue;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the `gas` instruction.
///
pub fn gas<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -19,9 +15,7 @@ where
Ok(context.integer_const(256, 0).as_basic_value_enum())
}
///
/// Translates the `value` instruction.
///
pub fn value<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -67,9 +61,7 @@ where
Ok(value_extended.as_basic_value_enum())
}
///
/// Translates the `balance` instructions.
///
pub fn balance<'ctx, D>(
_context: &mut Context<'ctx, D>,
_address: inkwell::values::IntValue<'ctx>,
@@ -1,19 +1,13 @@
//!
//! Translates a log or event call.
//!
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates a log or event call.
///
/// The decoding logic is implemented in a system contract, which is called from here.
///
/// There are several cases of the translation for the sake of efficiency, since the front-end
/// emits topics and values sequentially by one, but the LLVM intrinsic and bytecode instruction
/// accept two at once.
///
pub fn log<'ctx, D>(
_context: &mut Context<'ctx, D>,
_input_offset: inkwell::values::IntValue<'ctx>,
@@ -1,13 +1,9 @@
//!
//! Translates the external code operations.
//!
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the `extcodesize` instruction.
///
pub fn size<'ctx, D>(
_context: &mut Context<'ctx, D>,
_address: inkwell::values::IntValue<'ctx>,
@@ -18,9 +14,7 @@ where
todo!()
}
///
/// Translates the `extcodehash` instruction.
///
pub fn hash<'ctx, D>(
_context: &mut Context<'ctx, D>,
_address: inkwell::values::IntValue<'ctx>,
@@ -1,6 +1,4 @@
//!
//! Translates the contract immutable operations.
//!
use crate::eravm::context::address_space::AddressSpace;
use crate::eravm::context::code_type::CodeType;
@@ -8,12 +6,9 @@ use crate::eravm::context::pointer::Pointer;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the contract immutable load.
///
/// In the deploy code the values are read from the auxiliary heap.
/// In the runtime code they are requested from the system contract.
///
pub fn load<'ctx, D>(
context: &mut Context<'ctx, D>,
index: inkwell::values::IntValue<'ctx>,
@@ -54,14 +49,10 @@ where
}
}
///
/// Translates the contract immutable store.
///
/// In the deploy code the values are written to the auxiliary heap at the predefined offset,
/// being prepared for returning to the system contract for saving.
///
/// Ignored in the runtime code.
///
pub fn store<'ctx, D>(
context: &mut Context<'ctx, D>,
index: inkwell::values::IntValue<'ctx>,
-10
View File
@@ -1,15 +1,11 @@
//!
//! Translates the mathematical operations.
//!
use inkwell::values::BasicValue;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the `addmod` instruction.
///
pub fn add_mod<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -32,9 +28,7 @@ where
.expect("Always exists"))
}
///
/// Translates the `mulmod` instruction.
///
pub fn mul_mod<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
@@ -57,9 +51,7 @@ where
.expect("Always exists"))
}
///
/// Translates the `exp` instruction.
///
pub fn exponent<'ctx, D>(
context: &mut Context<'ctx, D>,
value: inkwell::values::IntValue<'ctx>,
@@ -77,9 +69,7 @@ where
.expect("Always exists"))
}
///
/// Translates the `signextend` instruction.
///
pub fn sign_extend<'ctx, D>(
context: &mut Context<'ctx, D>,
bytes: inkwell::values::IntValue<'ctx>,
@@ -1,17 +1,12 @@
//!
//! Translates the heap memory operations.
//!
use crate::eravm::context::address_space::AddressSpace;
use crate::eravm::context::pointer::Pointer;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the `mload` instruction.
///
/// Uses the main heap.
///
pub fn load<'ctx, D>(
context: &mut Context<'ctx, D>,
offset: inkwell::values::IntValue<'ctx>,
@@ -29,11 +24,8 @@ where
context.build_load(pointer, "memory_load_result")
}
///
/// Translates the `mstore` instruction.
///
/// Uses the main heap.
///
pub fn store<'ctx, D>(
context: &mut Context<'ctx, D>,
offset: inkwell::values::IntValue<'ctx>,
@@ -53,11 +45,8 @@ where
Ok(())
}
///
/// Translates the `mstore8` instruction.
///
/// Uses the main heap.
///
pub fn store_byte<'ctx, D>(
context: &mut Context<'ctx, D>,
offset: inkwell::values::IntValue<'ctx>,
-2
View File
@@ -1,6 +1,4 @@
//!
//! The EVM instructions translation utils.
//!
pub mod arithmetic;
pub mod bitwise;
@@ -1,6 +1,4 @@
//!
//! Translates the transaction return operations.
//!
use crate::eravm::context::address_space::AddressSpace;
use crate::eravm::context::code_type::CodeType;
@@ -8,11 +6,8 @@ use crate::eravm::context::pointer::Pointer;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the `return` instruction.
///
/// Unlike in EVM, zkSync constructors return the array of contract immutables.
///
pub fn r#return<'ctx, D>(
context: &mut Context<'ctx, D>,
offset: inkwell::values::IntValue<'ctx>,
@@ -79,9 +74,7 @@ where
Ok(())
}
///
/// Translates the `revert` instruction.
///
pub fn revert<'ctx, D>(
context: &mut Context<'ctx, D>,
offset: inkwell::values::IntValue<'ctx>,
@@ -93,11 +86,8 @@ where
context.build_exit(context.integer_const(32, 1), offset, length)
}
///
/// Translates the `stop` instruction.
///
/// Is the same as `return(0, 0)`.
///
pub fn stop<D>(context: &mut Context<D>) -> anyhow::Result<()>
where
D: Dependency + Clone,
@@ -109,11 +99,8 @@ where
)
}
///
/// Translates the `invalid` instruction.
///
/// Burns all gas using an out-of-bounds memory store, causing a panic.
///
pub fn invalid<D>(context: &mut Context<D>) -> anyhow::Result<()>
where
D: Dependency + Clone,
@@ -1,6 +1,4 @@
//!
//! Translates the return data instructions.
//!
use inkwell::types::BasicType;
use inkwell::values::BasicValue;
@@ -10,9 +8,7 @@ use crate::eravm::context::pointer::Pointer;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the return data size.
///
pub fn size<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
@@ -25,9 +21,7 @@ where
}
}
///
/// Translates the return data copy.
///
pub fn copy<'ctx, D>(
context: &mut Context<'ctx, D>,
destination_offset: inkwell::values::IntValue<'ctx>,
@@ -1,15 +1,11 @@
//!
//! Translates the storage operations.
//!
use crate::eravm::context::address_space::AddressSpace;
use crate::eravm::context::pointer::Pointer;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the storage load.
///
pub fn load<'ctx, D>(
context: &mut Context<'ctx, D>,
position: inkwell::values::IntValue<'ctx>,
@@ -27,9 +23,7 @@ where
context.build_load(position_pointer, "storage_load_value")
}
///
/// Translates the storage store.
///
pub fn store<'ctx, D>(
context: &mut Context<'ctx, D>,
position: inkwell::values::IntValue<'ctx>,
@@ -49,9 +43,7 @@ where
Ok(())
}
///
/// Translates the transient storage load.
///
pub fn transient_load<'ctx, D>(
context: &mut Context<'ctx, D>,
position: inkwell::values::IntValue<'ctx>,
@@ -69,9 +61,7 @@ where
context.build_load(position_pointer, "transient_storage_load_value")
}
///
/// Translates the transient storage store.
///
pub fn transient_store<'ctx, D>(
context: &mut Context<'ctx, D>,
position: inkwell::values::IntValue<'ctx>,
@@ -1,15 +1,11 @@
//!
//! The metadata hash mode.
//!
use std::str::FromStr;
use serde::Deserialize;
use serde::Serialize;
///
/// The metadata hash mode.
///
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MetadataHash {
/// Do not include bytecode hash.
-28
View File
@@ -1,6 +1,4 @@
//!
//! The LLVM context library.
//!
pub mod r#const;
pub mod context;
@@ -16,16 +14,12 @@ use crate::optimizer::settings::Settings as OptimizerSettings;
use self::context::build::Build;
use self::context::Context;
///
/// Initializes the EraVM target machine.
///
pub fn initialize_target() {
inkwell::targets::Target::initialize_riscv(&Default::default());
}
///
/// Builds EraVM assembly text.
///
pub fn build_assembly_text(
contract_path: &str,
assembly_text: &str,
@@ -90,31 +84,23 @@ pub fn build_assembly_text(
))
}
///
/// Implemented by items which are translated into LLVM IR.
///
#[allow(clippy::upper_case_acronyms)]
pub trait WriteLLVM<D>
where
D: Dependency + Clone,
{
///
/// Declares the entity in the LLVM IR.
/// Is usually performed in order to use the item before defining it.
///
fn declare(&mut self, _context: &mut Context<D>) -> anyhow::Result<()> {
Ok(())
}
///
/// Translates the entity into LLVM IR.
///
fn into_llvm(self, context: &mut Context<D>) -> anyhow::Result<()>;
}
///
/// The dummy LLVM writable entity.
///
#[derive(Debug, Default, Clone)]
pub struct DummyLLVMWritable {}
@@ -127,13 +113,9 @@ where
}
}
///
/// Implemented by items managing project dependencies.
///
pub trait Dependency {
///
/// Compiles a project dependency.
///
fn compile(
dependency: Self,
path: &str,
@@ -143,20 +125,14 @@ pub trait Dependency {
debug_config: Option<DebugConfig>,
) -> anyhow::Result<String>;
///
/// Resolves a full contract path.
///
fn resolve_path(&self, identifier: &str) -> anyhow::Result<String>;
///
/// Resolves a library address.
///
fn resolve_library(&self, path: &str) -> anyhow::Result<String>;
}
///
/// The dummy dependency entity.
///
#[derive(Debug, Default, Clone)]
pub struct DummyDependency {}
@@ -172,16 +148,12 @@ impl Dependency for DummyDependency {
Ok(String::new())
}
///
/// Resolves a full contract path.
///
fn resolve_path(&self, _identifier: &str) -> anyhow::Result<String> {
Ok(String::new())
}
///
/// Resolves a library address.
///
fn resolve_library(&self, _path: &str) -> anyhow::Result<String> {
Ok(String::new())
}
-16
View File
@@ -1,6 +1,4 @@
//!
//! Some LLVM IR generator utilies.
//!
use inkwell::values::BasicValue;
@@ -9,9 +7,7 @@ use crate::eravm::context::function::llvm_runtime::LLVMRuntime;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Clamps `value` to `max_value`, if `value` is bigger than `max_value`.
///
pub fn clamp<'ctx, D>(
context: &mut Context<'ctx, D>,
value: inkwell::values::IntValue<'ctx>,
@@ -44,9 +40,7 @@ where
Ok(result.into_int_value())
}
///
/// Generates an exception.
///
pub fn throw<D>(context: &Context<D>)
where
D: Dependency + Clone,
@@ -63,11 +57,8 @@ where
context.build_unreachable();
}
///
/// Returns the full list of arguments for an external call.
///
/// Performs the extra ABI data padding and adds the mimic call extra argument.
///
pub fn external_call_arguments<'ctx, D>(
_context: &Context<'ctx, D>,
abi_data: inkwell::values::BasicValueEnum<'ctx>,
@@ -96,11 +87,8 @@ where
result
}
///
/// Generates an ABI data for an external call.
///
/// If `gas` is `None`, it is fetched from the contract context.
///
pub fn abi_data<'ctx, D>(
context: &mut Context<'ctx, D>,
input_offset: inkwell::values::IntValue<'ctx>,
@@ -190,9 +178,7 @@ where
Ok(abi_data.as_basic_value_enum())
}
///
/// Pads the extra ABI data with `i256::undef`, so it always consists of 10 values.
///
pub fn pad_extra_abi_data<'ctx, D>(
context: &Context<'ctx, D>,
initial_data: Vec<inkwell::values::IntValue<'ctx>>,
@@ -208,9 +194,7 @@ where
padded_data.try_into().expect("Always valid")
}
///
/// Computes the `keccak256` hash for `preimage`.
///
pub fn keccak256(preimage: &[u8]) -> String {
use sha3::Digest;
-4
View File
@@ -1,6 +1,4 @@
//!
//! The LLVM context library.
//!
pub(crate) mod debug_config;
pub(crate) mod eravm;
@@ -68,9 +66,7 @@ pub use self::optimizer::Optimizer;
pub use self::target_machine::target::Target;
pub use self::target_machine::TargetMachine;
///
/// Initializes the target machine.
///
pub fn initialize_target(target: Target) {
match target {
Target::PVM => self::eravm::initialize_target(),
-10
View File
@@ -1,6 +1,4 @@
//!
//! The LLVM optimizing tools.
//!
pub mod settings;
@@ -11,9 +9,7 @@ use crate::target_machine::TargetMachine;
use self::settings::Settings;
///
/// The LLVM optimizing tools.
///
#[derive(Debug, Serialize, Deserialize)]
pub struct Optimizer {
/// The optimizer settings.
@@ -21,16 +17,12 @@ pub struct Optimizer {
}
impl Optimizer {
///
/// A shortcut constructor.
///
pub fn new(settings: Settings) -> Self {
Self { settings }
}
///
/// Runs the new pass manager.
///
pub fn run(
&self,
target_machine: &TargetMachine,
@@ -42,9 +34,7 @@ impl Optimizer {
)
}
///
/// Returns the optimizer settings reference.
///
pub fn settings(&self) -> &Settings {
&self.settings
}
@@ -1,6 +1,4 @@
//!
//! The LLVM optimizer settings.
//!
pub mod size_level;
@@ -11,9 +9,7 @@ use itertools::Itertools;
use self::size_level::SizeLevel;
///
/// The LLVM optimizer settings.
///
#[derive(Debug, Serialize, Deserialize, Clone, Eq)]
pub struct Settings {
/// The middle-end optimization level.
@@ -35,9 +31,7 @@ pub struct Settings {
}
impl Settings {
///
/// A shortcut constructor.
///
pub fn new(
level_middle_end: inkwell::OptimizationLevel,
level_middle_end_size: SizeLevel,
@@ -56,9 +50,7 @@ impl Settings {
}
}
///
/// A shortcut constructor with debugging tools.
///
pub fn new_debug(
level_middle_end: inkwell::OptimizationLevel,
level_middle_end_size: SizeLevel,
@@ -80,9 +72,7 @@ impl Settings {
}
}
///
/// Creates settings from a CLI optimization parameter.
///
pub fn try_from_cli(value: char) -> anyhow::Result<Self> {
Ok(match value {
'0' => Self::new(
@@ -126,9 +116,7 @@ impl Settings {
})
}
///
/// Returns the settings without optimizations.
///
pub fn none() -> Self {
Self::new(
inkwell::OptimizationLevel::None,
@@ -137,9 +125,7 @@ impl Settings {
)
}
///
/// Returns the settings for the optimal number of VM execution cycles.
///
pub fn cycles() -> Self {
Self::new(
inkwell::OptimizationLevel::Aggressive,
@@ -148,9 +134,7 @@ impl Settings {
)
}
///
/// Returns the settings for the optimal size.
///
pub fn size() -> Self {
Self::new(
inkwell::OptimizationLevel::Default,
@@ -159,9 +143,7 @@ impl Settings {
)
}
///
/// Returns the middle-end optimization parameter as string.
///
pub fn middle_end_as_string(&self) -> String {
match self.level_middle_end_size {
SizeLevel::Zero => (self.level_middle_end as u8).to_string(),
@@ -169,19 +151,14 @@ impl Settings {
}
}
///
/// Checks whether there are middle-end optimizations enabled.
///
pub fn is_middle_end_enabled(&self) -> bool {
self.level_middle_end != inkwell::OptimizationLevel::None
|| self.level_middle_end_size != SizeLevel::Zero
}
///
/// Returns all possible combinations of the optimizer settings.
///
/// Used only for testing purposes.
///
pub fn combinations() -> Vec<Self> {
let performance_combinations: Vec<Self> = vec![
inkwell::OptimizationLevel::None,
@@ -224,30 +201,22 @@ impl Settings {
combinations
}
///
/// Sets the fallback to optimizing for size if the bytecode is too large.
///
pub fn enable_fallback_to_size(&mut self) {
self.is_fallback_to_size_enabled = true;
}
///
/// Disables the system request memoization.
///
pub fn disable_system_request_memoization(&mut self) {
self.is_system_request_memoization_disabled = true;
}
///
/// Whether the fallback to optimizing for size is enabled.
///
pub fn is_fallback_to_size_enabled(&self) -> bool {
self.is_fallback_to_size_enabled
}
///
/// Whether the system request memoization is disabled.
///
pub fn is_system_request_memoization_disabled(&self) -> bool {
self.is_system_request_memoization_disabled
}
@@ -1,13 +1,9 @@
//!
//! The LLVM optimizer settings size level.
//!
use serde::Deserialize;
use serde::Serialize;
///
/// The LLVM optimizer settings size level.
///
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
pub enum SizeLevel {
/// No size optimizations.
@@ -1,6 +1,4 @@
//!
//! The LLVM target machine.
//!
pub mod target;
@@ -9,9 +7,7 @@ use crate::optimizer::settings::Settings as OptimizerSettings;
use self::target::Target;
///
/// The LLVM target machine.
///
#[derive(Debug)]
pub struct TargetMachine {
/// The LLVM target.
@@ -35,11 +31,8 @@ impl TargetMachine {
#[cfg(not(feature = "riscv-zbb"))]
pub const VM_FEATURES: &'static str = "+e,+m";
///
/// A shortcut constructor.
///
/// A separate instance for every optimization level is created.
///
pub fn new(target: Target, optimizer_settings: &OptimizerSettings) -> anyhow::Result<Self> {
let target_machine = inkwell::targets::Target::from_name(target.name())
.ok_or_else(|| anyhow::anyhow!("LLVM target machine `{}` not found", target.name()))?
@@ -65,17 +58,13 @@ impl TargetMachine {
})
}
///
/// Sets the target-specific data in the module.
///
pub fn set_target_data(&self, module: &inkwell::module::Module) {
module.set_triple(&self.target_machine.get_triple());
module.set_data_layout(&self.target_machine.get_target_data().get_data_layout());
}
///
/// Writes the LLVM module to a memory buffer.
///
pub fn write_to_memory_buffer(
&self,
module: &inkwell::module::Module,
@@ -87,9 +76,7 @@ impl TargetMachine {
}
}
///
/// Runs the optimization passes on `module`.
///
pub fn run_optimization_passes(
&self,
module: &inkwell::module::Module,
@@ -107,16 +94,12 @@ impl TargetMachine {
module.run_passes(passes, &self.target_machine, pass_builder_options)
}
///
/// Returns the target triple.
///
pub fn get_triple(&self) -> inkwell::targets::TargetTriple {
self.target_machine.get_triple()
}
///
/// Returns the target data.
///
pub fn get_target_data(&self) -> inkwell::targets::TargetData {
self.target_machine.get_target_data()
}
@@ -1,12 +1,8 @@
//!
//! The LLVM target.
//!
use std::str::FromStr;
///
/// The LLVM target.
///
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Target {
/// The EraVM target.
@@ -14,27 +10,21 @@ pub enum Target {
}
impl Target {
///
/// Returns the target name.
///
pub fn name(&self) -> &str {
match self {
Self::PVM => "riscv32",
}
}
///
/// Returns the target triple.
///
pub fn triple(&self) -> &str {
match self {
Self::PVM => "riscv32-unknown-unknown-elf",
}
}
///
/// Returns the target production name.
///
pub fn production_name(&self) -> &str {
match self {
Self::PVM => "PVM",
@@ -1,24 +1,19 @@
//! This crate vendors the [PolkaVM][0] C API and provides a LLVM module for interacting
//! with the `pallet-contracts` runtime API.
//!
//! At present, the contracts pallet requires blobs to export `call` and `deploy`,
//! and offers a bunch of [runtime API methods][1]. The provided [module] implements
//! those exports and imports.
//!
//! [0]: [https://crates.io/crates/polkavm]
//! [1]: [https://docs.rs/pallet-contracts/26.0.0/pallet_contracts/api_doc/index.html]
//!
use inkwell::{context::Context, memory_buffer::MemoryBuffer, module::Module, support::LLVMString};
include!(concat!(env!("OUT_DIR"), "/polkavm_guest.rs"));
/// Creates a LLVM module from the [BITCODE].
///
/// The module does:
/// - Export the `call` and `deploy` functions (which are named thereafter).
/// - Import (most) `pallet-contracts` runtime API functions.
///
/// Returns `Error` if the bitcode fails to parse, which should never happen.
pub fn module<'context>(
context: &'context Context,
-14
View File
@@ -1,6 +1,4 @@
//!
//! The Solidity contract build.
//!
use std::collections::HashSet;
use std::fs::File;
@@ -13,9 +11,7 @@ use serde::Serialize;
use crate::solc::combined_json::contract::Contract as CombinedJsonContract;
use crate::solc::standard_json::output::contract::Contract as StandardJsonOutputContract;
///
/// The Solidity contract build.
///
#[derive(Debug, Serialize, Deserialize)]
pub struct Contract {
/// The contract path.
@@ -31,9 +27,7 @@ pub struct Contract {
}
impl Contract {
///
/// A shortcut constructor.
///
pub fn new(
path: String,
identifier: String,
@@ -50,9 +44,7 @@ impl Contract {
}
}
///
/// Writes the contract text assembly and bytecode to files.
///
pub fn write_to_directory(
self,
path: &Path,
@@ -107,9 +99,7 @@ impl Contract {
Ok(())
}
///
/// Writes the contract text assembly and bytecode to the combined JSON.
///
pub fn write_to_combined_json(
self,
combined_json_contract: &mut CombinedJsonContract,
@@ -130,9 +120,7 @@ impl Contract {
Ok(())
}
///
/// Writes the contract text assembly and bytecode to the standard JSON.
///
pub fn write_to_standard_json(
self,
standard_json_contract: &mut StandardJsonOutputContract,
@@ -151,9 +139,7 @@ impl Contract {
Ok(())
}
///
/// Converts the full path to a short one.
///
pub fn short_path(path: &str) -> &str {
path.rfind('/')
.map(|last_slash| &path[last_slash + 1..])
-10
View File
@@ -1,6 +1,4 @@
//!
//! The Solidity project build.
//!
pub mod contract;
@@ -13,9 +11,7 @@ use crate::solc::version::Version as SolcVersion;
use self::contract::Contract;
///
/// The Solidity project build.
///
#[derive(Debug, Default)]
pub struct Build {
/// The contract data,
@@ -23,9 +19,7 @@ pub struct Build {
}
impl Build {
///
/// Writes all contracts to the specified directory.
///
pub fn write_to_directory(
self,
output_directory: &Path,
@@ -45,9 +39,7 @@ impl Build {
Ok(())
}
///
/// Writes all contracts assembly and bytecode to the combined JSON.
///
pub fn write_to_combined_json(
self,
combined_json: &mut CombinedJson,
@@ -74,9 +66,7 @@ impl Build {
Ok(())
}
///
/// Writes all contracts assembly and bytecode to the standard JSON.
///
pub fn write_to_standard_json(
mut self,
standard_json: &mut StandardJsonOutput,
-2
View File
@@ -1,6 +1,4 @@
//!
//! Solidity to EraVM compiler constants.
//!
#![allow(dead_code)]
@@ -1,6 +1,4 @@
//!
//! The inner JSON legacy assembly code element.
//!
use std::collections::HashSet;
@@ -9,9 +7,7 @@ use serde::Serialize;
use crate::evmla::assembly::Assembly;
///
/// The inner JSON legacy assembly code element.
///
#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(untagged)]
pub enum Data {
@@ -24,9 +20,7 @@ pub enum Data {
}
impl Data {
///
/// Returns the inner assembly reference if it is present.
///
pub fn get_assembly(&self) -> Option<&Assembly> {
match self {
Self::Assembly(ref assembly) => Some(assembly),
@@ -34,9 +28,7 @@ impl Data {
Self::Path(_) => None,
}
}
///
/// Returns the inner assembly mutable reference if it is present.
///
pub fn get_assembly_mut(&mut self) -> Option<&mut Assembly> {
match self {
Self::Assembly(ref mut assembly) => Some(assembly),
@@ -45,9 +37,7 @@ impl Data {
}
}
///
/// Get the list of missing deployable libraries.
///
pub fn get_missing_libraries(&self) -> HashSet<String> {
match self {
Self::Assembly(assembly) => assembly.get_missing_libraries(),
@@ -56,9 +46,7 @@ impl Data {
}
}
///
/// Gets the contract `keccak256` hash.
///
pub fn keccak256(&self) -> String {
match self {
Self::Assembly(assembly) => assembly.keccak256(),
@@ -1,10 +1,6 @@
//!
//! Translates the CODECOPY use cases.
//!
///
/// Translates the contract hash copying.
///
pub fn contract_hash<'ctx, D>(
context: &mut revive_llvm_context::EraVMContext<'ctx, D>,
offset: inkwell::values::IntValue<'ctx>,
@@ -26,9 +22,7 @@ where
Ok(())
}
///
/// Translates the library marker copying.
///
pub fn library_marker<D>(
context: &mut revive_llvm_context::EraVMContext<D>,
offset: u64,
@@ -46,9 +40,7 @@ where
Ok(())
}
///
/// Translates the static data copying.
///
pub fn static_data<'ctx, D>(
context: &mut revive_llvm_context::EraVMContext<'ctx, D>,
destination: inkwell::values::IntValue<'ctx>,
@@ -1,10 +1,6 @@
//!
//! Translates the jump operations.
//!
///
/// Translates the unconditional jump.
///
pub fn unconditional<D>(
context: &mut revive_llvm_context::EraVMContext<D>,
destination: num::BigUint,
@@ -28,9 +24,7 @@ where
Ok(())
}
///
/// Translates the conditional jump.
///
pub fn conditional<D>(
context: &mut revive_llvm_context::EraVMContext<D>,
destination: num::BigUint,
@@ -1,6 +1,4 @@
//!
//! The EVM instruction.
//!
pub mod codecopy;
pub mod jump;
@@ -14,9 +12,7 @@ use serde::Serialize;
use self::name::Name;
///
/// The EVM instruction.
///
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Instruction {
/// The opcode or tag identifier.
@@ -34,9 +30,7 @@ pub struct Instruction {
}
impl Instruction {
///
/// Returns the number of input stack arguments.
///
pub const fn input_size(&self, version: &semver::Version) -> usize {
match self.name {
Name::POP => 1,
@@ -135,9 +129,7 @@ impl Instruction {
}
}
///
/// Returns the number of output stack arguments.
///
pub const fn output_size(&self) -> usize {
match self.name {
Name::PUSH => 1,
@@ -285,9 +277,7 @@ impl Instruction {
}
}
///
/// Replaces the instruction data aliases with the actual data.
///
pub fn replace_data_aliases(
instructions: &mut [Self],
mapping: &BTreeMap<String, String>,
@@ -323,9 +313,7 @@ impl Instruction {
Ok(())
}
///
/// Initializes an `INVALID` instruction to terminate an invalid unreachable block part.
///
pub fn invalid(previous: &Self) -> Self {
Self {
name: Name::INVALID,
@@ -337,9 +325,7 @@ impl Instruction {
}
}
///
/// Initializes a recursive function `Call` instruction.
///
pub fn recursive_call(
name: String,
entry_key: revive_llvm_context::EraVMFunctionBlockKey,
@@ -366,9 +352,7 @@ impl Instruction {
}
}
///
/// Initializes a recursive function `Return` instruction.
///
pub fn recursive_return(input_size: usize, previous: &Self) -> Self {
Self {
name: Name::RecursiveReturn { input_size },
@@ -1,13 +1,9 @@
//!
//! The EVM instruction name.
//!
use serde::Deserialize;
use serde::Serialize;
///
/// The EVM instruction name.
///
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types)]
#[allow(clippy::upper_case_acronyms)]
@@ -1,12 +1,8 @@
//!
//! Translates the stack memory operations.
//!
use inkwell::values::BasicValue;
///
/// Translates the ordinar value push.
///
pub fn push<'ctx, D>(
context: &mut revive_llvm_context::EraVMContext<'ctx, D>,
value: String,
@@ -25,9 +21,7 @@ where
Ok(result)
}
///
/// Translates the block tag label push.
///
pub fn push_tag<'ctx, D>(
context: &mut revive_llvm_context::EraVMContext<'ctx, D>,
value: String,
@@ -42,9 +36,7 @@ where
Ok(result.as_basic_value_enum())
}
///
/// Translates the stack memory duplicate.
///
pub fn dup<'ctx, D>(
context: &mut revive_llvm_context::EraVMContext<'ctx, D>,
offset: usize,
@@ -68,9 +60,7 @@ where
Ok(value)
}
///
/// Translates the stack memory swap.
///
pub fn swap<D>(
context: &mut revive_llvm_context::EraVMContext<D>,
offset: usize,
@@ -103,9 +93,7 @@ where
Ok(())
}
///
/// Translates the stack memory pop.
///
pub fn pop<D>(_context: &mut revive_llvm_context::EraVMContext<D>) -> anyhow::Result<()>
where
D: revive_llvm_context::EraVMDependency + Clone,
-17
View File
@@ -1,6 +1,4 @@
//!
//! The `solc --asm-json` output.
//!
pub mod data;
pub mod instruction;
@@ -19,9 +17,7 @@ use self::data::Data;
use self::instruction::name::Name as InstructionName;
use self::instruction::Instruction;
///
/// The JSON assembly.
///
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Assembly {
/// The metadata string.
@@ -46,36 +42,27 @@ pub struct Assembly {
}
impl Assembly {
///
/// Gets the contract `keccak256` hash.
///
pub fn keccak256(&self) -> String {
let json = serde_json::to_vec(self).expect("Always valid");
revive_llvm_context::eravm_utils::keccak256(json.as_slice())
}
///
/// Sets the full contract path.
///
pub fn set_full_path(&mut self, full_path: String) {
self.full_path = Some(full_path);
}
///
/// Returns the full contract path if it is set, or `<undefined>` otherwise.
///
/// # Panics
/// If the `full_path` has not been set.
///
pub fn full_path(&self) -> &str {
self.full_path
.as_deref()
.unwrap_or_else(|| panic!("The full path of some contracts is unset"))
}
///
/// Get the list of missing deployable libraries.
///
pub fn get_missing_libraries(&self) -> HashSet<String> {
let mut missing_libraries = HashSet::new();
if let Some(code) = self.code.as_ref() {
@@ -94,9 +81,7 @@ impl Assembly {
missing_libraries
}
///
/// Replaces the deploy code dependencies with full contract path and returns the list.
///
pub fn deploy_dependencies_pass(
&mut self,
full_path: &str,
@@ -144,9 +129,7 @@ impl Assembly {
Ok(index_path_mapping)
}
///
/// Replaces the runtime code dependencies with full contract path and returns the list.
///
pub fn runtime_dependencies_pass(
&mut self,
full_path: &str,
@@ -1,16 +1,11 @@
//!
//! The Ethereal IR entry function link.
//!
use inkwell::values::BasicValue;
use crate::evmla::ethereal_ir::EtherealIR;
///
/// The Ethereal IR entry function link.
///
/// The link represents branching between the deploy and runtime code.
///
#[derive(Debug, Clone)]
pub struct EntryLink {
/// The code part type.
@@ -18,9 +13,7 @@ pub struct EntryLink {
}
impl EntryLink {
///
/// A shortcut constructor.
///
pub fn new(code_type: revive_llvm_context::EraVMCodeType) -> Self {
Self { code_type }
}
@@ -1,6 +1,4 @@
//!
//! The Ethereal IR block element.
//!
pub mod stack;
@@ -13,9 +11,7 @@ use crate::evmla::assembly::instruction::Instruction;
use self::stack::element::Element as StackElement;
use self::stack::Stack;
///
/// The Ethereal IR block element.
///
#[derive(Debug, Clone)]
pub struct Element {
/// The Solidity compiler version.
@@ -31,9 +27,7 @@ pub struct Element {
}
impl Element {
///
/// A shortcut constructor.
///
pub fn new(solc_version: semver::Version, instruction: Instruction) -> Self {
let input_size = instruction.input_size(&solc_version);
let output_size = instruction.output_size();
@@ -47,9 +41,7 @@ impl Element {
}
}
///
/// Pops the specified number of arguments, converted into their LLVM values.
///
fn pop_arguments_llvm<'ctx, D>(
&mut self,
context: &mut revive_llvm_context::EraVMContext<'ctx, D>,
@@ -1,10 +1,6 @@
//!
//! The Ethereal IR block element stack element.
//!
///
/// The Ethereal IR block element stack element.
///
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Element {
/// The runtime value.
@@ -1,14 +1,10 @@
//!
//! The Ethereal IR block element stack.
//!
pub mod element;
use self::element::Element;
///
/// The Ethereal IR block element stack.
///
#[derive(Debug, Default, Clone)]
pub struct Stack {
/// The stack elements.
@@ -19,36 +15,27 @@ impl Stack {
/// The default stack size.
pub const DEFAULT_STACK_SIZE: usize = 16;
///
/// A shortcut constructor.
///
pub fn new() -> Self {
Self {
elements: Vec::with_capacity(Self::DEFAULT_STACK_SIZE),
}
}
///
/// A shortcut constructor.
///
pub fn with_capacity(capacity: usize) -> Self {
Self {
elements: Vec::with_capacity(capacity),
}
}
///
/// A shortcut constructor.
///
pub fn new_with_elements(elements: Vec<Element>) -> Self {
Self { elements }
}
///
/// The stack state hash, which acts as a block identifier.
///
/// Each block clone has its own initial stack state, which uniquely identifies the block.
///
pub fn hash(&self) -> md5::Digest {
let mut hash_context = md5::Context::new();
for element in self.elements.iter() {
@@ -60,32 +47,24 @@ impl Stack {
hash_context.compute()
}
///
/// Pushes an element onto the stack.
///
pub fn push(&mut self, element: Element) {
self.elements.push(element);
}
///
/// Appends another stack on top of this one.
///
pub fn append(&mut self, other: &mut Self) {
self.elements.append(&mut other.elements);
}
///
/// Pops a stack element.
///
pub fn pop(&mut self) -> anyhow::Result<Element> {
self.elements
.pop()
.ok_or_else(|| anyhow::anyhow!("Stack underflow"))
}
///
/// Pops the tag from the top.
///
pub fn pop_tag(&mut self) -> anyhow::Result<num::BigUint> {
match self.elements.pop() {
Some(Element::Tag(tag)) => Ok(tag),
@@ -94,9 +73,7 @@ impl Stack {
}
}
///
/// Swaps two stack elements.
///
pub fn swap(&mut self, index: usize) -> anyhow::Result<()> {
if self.elements.len() < index + 1 {
anyhow::bail!("Stack underflow");
@@ -108,9 +85,7 @@ impl Stack {
Ok(())
}
///
/// Duplicates a stack element.
///
pub fn dup(&mut self, index: usize) -> anyhow::Result<Element> {
if self.elements.len() < index {
anyhow::bail!("Stack underflow");
@@ -119,16 +94,12 @@ impl Stack {
Ok(self.elements[self.elements.len() - index].to_owned())
}
///
/// Returns the stack length.
///
pub fn len(&self) -> usize {
self.elements.len()
}
///
/// Returns an emptiness flag.
///
pub fn is_empty(&self) -> bool {
self.elements.len() == 0
}
@@ -1,6 +1,4 @@
//!
//! The Ethereal IR block.
//!
pub mod element;
@@ -14,9 +12,7 @@ use crate::evmla::assembly::instruction::Instruction;
use self::element::stack::Stack as ElementStack;
use self::element::Element;
///
/// The Ethereal IR block.
///
#[derive(Debug, Clone)]
pub struct Block {
/// The Solidity compiler version.
@@ -43,9 +39,7 @@ impl Block {
/// The predecessors hashset initial capacity.
pub const PREDECESSORS_HASHSET_DEFAULT_CAPACITY: usize = 4;
///
/// Assembles a block from the sequence of instructions.
///
pub fn try_from_instructions(
solc_version: semver::Version,
code_type: revive_llvm_context::EraVMCodeType,
@@ -109,9 +103,7 @@ impl Block {
Ok((block, cursor))
}
///
/// Inserts a predecessor tag.
///
pub fn insert_predecessor(
&mut self,
key: revive_llvm_context::EraVMFunctionBlockKey,
@@ -1,6 +1,4 @@
//!
//! The Ethereal IR function.
//!
pub mod block;
pub mod queue_element;
@@ -37,9 +35,7 @@ use self::queue_element::QueueElement;
use self::r#type::Type;
use self::visited_element::VisitedElement;
///
/// The Ethereal IR function.
///
#[derive(Debug, Clone)]
pub struct Function {
/// The Solidity compiler version.
@@ -55,9 +51,7 @@ pub struct Function {
}
impl Function {
///
/// A shortcut constructor.
///
pub fn new(solc_version: semver::Version, r#type: Type) -> Self {
let name = match r#type {
Type::Initial => EtherealIR::DEFAULT_ENTRY_FUNCTION_NAME.to_string(),
@@ -77,9 +71,7 @@ impl Function {
}
}
///
/// Runs the function block traversal.
///
pub fn traverse(
&mut self,
blocks: &HashMap<revive_llvm_context::EraVMFunctionBlockKey, Block>,
@@ -143,9 +135,7 @@ impl Function {
Ok(())
}
///
/// Consumes the entry or a conditional block attached to another one.
///
fn consume_block(
&mut self,
blocks: &HashMap<revive_llvm_context::EraVMFunctionBlockKey, Block>,
@@ -219,12 +209,9 @@ impl Function {
Ok(())
}
///
/// Processes an instruction, returning an error, if there is an invalid stack state.
///
/// The blocks with an invalid stack state are considered being partially unreachable, and
/// the invalid part is truncated after terminating with an `INVALID` instruction.
///
#[allow(clippy::too_many_arguments)]
fn handle_instruction(
blocks: &HashMap<revive_llvm_context::EraVMFunctionBlockKey, Block>,
@@ -993,9 +980,7 @@ impl Function {
Ok(())
}
///
/// Updates the stack data with input and output data.
///
fn update_io_data(
block_stack: &mut Stack,
block_element: &mut BlockElement,
@@ -1017,9 +1002,7 @@ impl Function {
Ok(())
}
///
/// Handles the recursive function call.
///
#[allow(clippy::too_many_arguments)]
fn handle_recursive_function_call(
recursive_function: &RecursiveFunction,
@@ -1095,9 +1078,7 @@ impl Function {
Ok((return_address, stack_output))
}
///
/// Pushes a block into the function.
///
fn insert_block(&mut self, mut block: Block) -> &mut Block {
let key = block.key.clone();
@@ -1120,11 +1101,8 @@ impl Function {
.expect("Always exists")
}
///
/// Checks whether the tag value actually references an existing block.
///
/// Checks both deploy and runtime code.
///
fn is_tag_value_valid(
blocks: &HashMap<revive_llvm_context::EraVMFunctionBlockKey, Block>,
tag: &num::BigUint,
@@ -1138,9 +1116,7 @@ impl Function {
))
}
///
/// Finalizes the function data.
///
fn finalize(&mut self) {
for (_tag, blocks) in self.blocks.iter() {
for block in blocks.iter() {
@@ -1,12 +1,8 @@
//!
//! The Ethereal IR block queue element.
//!
use crate::evmla::ethereal_ir::function::block::element::stack::Stack;
///
/// The Ethereal IR block queue element.
///
#[derive(Debug, Clone)]
pub struct QueueElement {
/// The block key.
@@ -18,9 +14,7 @@ pub struct QueueElement {
}
impl QueueElement {
///
/// A shortcut constructor.
///
pub fn new(
block_key: revive_llvm_context::EraVMFunctionBlockKey,
predecessor: Option<(revive_llvm_context::EraVMFunctionBlockKey, usize)>,
@@ -1,10 +1,6 @@
//!
//! The Ethereal IR function type.
//!
///
/// The Ethereal IR function type.
///
#[derive(Debug, Clone)]
pub enum Type {
/// The initial function, combining deploy and runtime code.
@@ -23,16 +19,12 @@ pub enum Type {
}
impl Type {
///
/// A shortcut constructor.
///
pub fn new_initial() -> Self {
Self::Initial
}
///
/// A shortcut constructor.
///
pub fn new_recursive(
name: String,
block_key: revive_llvm_context::EraVMFunctionBlockKey,
@@ -1,12 +1,8 @@
//!
//! The Ethereal IR block visited element.
//!
use std::cmp::Ordering;
///
/// The Ethereal IR block visited element.
///
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VisitedElement {
/// The block key.
@@ -16,9 +12,7 @@ pub struct VisitedElement {
}
impl VisitedElement {
///
/// A shortcut constructor.
///
pub fn new(
block_key: revive_llvm_context::EraVMFunctionBlockKey,
stack_hash: md5::Digest,
@@ -1,6 +1,4 @@
//!
//! The Ethereal IR of the EVM bytecode.
//!
pub mod entry_link;
pub mod function;
@@ -16,18 +14,14 @@ use self::function::block::Block;
use self::function::r#type::Type as FunctionType;
use self::function::Function;
///
/// The Ethereal IR of the EVM bytecode.
///
/// The Ethereal IR (EthIR) is a special IR between the EVM legacy assembly and LLVM IR. It is
/// created to facilitate the translation and provide an additional environment for applying some
/// transformations, duplicating parts of the call and control flow graphs, tracking the
/// data flow, and a few more algorithms of static analysis.
///
/// The most important feature of EthIR is flattening the block tags and duplicating blocks for
/// each of initial states of the stack. The LLVM IR supports only static control flow, so the
/// stack state must be known all the way throughout the program.
///
#[derive(Debug)]
pub struct EtherealIR {
/// The Solidity compiler version.
@@ -47,9 +41,7 @@ impl EtherealIR {
/// The blocks hashmap initial capacity.
pub const BLOCKS_HASHMAP_DEFAULT_CAPACITY: usize = 64;
///
/// Assembles a sequence of functions from the sequence of instructions.
///
pub fn new(
solc_version: semver::Version,
extra_metadata: ExtraMetadata,
@@ -73,9 +65,7 @@ impl EtherealIR {
})
}
///
/// Gets blocks for the specified type of the contract code.
///
pub fn get_blocks(
solc_version: semver::Version,
code_type: revive_llvm_context::EraVMCodeType,
-2
View File
@@ -1,6 +1,4 @@
//!
//! The EVM legacy assembly compiling tools.
//!
pub mod assembly;
pub mod ethereal_ir;
-14
View File
@@ -1,6 +1,4 @@
//!
//! Solidity to EraVM compiler library.
//!
pub(crate) mod build;
pub(crate) mod r#const;
@@ -48,9 +46,7 @@ pub mod tests;
use std::collections::BTreeSet;
use std::path::PathBuf;
///
/// Runs the Yul mode.
///
pub fn yul(
input_files: &[PathBuf],
solc: &mut SolcCompiler,
@@ -94,9 +90,7 @@ pub fn yul(
Ok(build)
}
///
/// Runs the LLVM IR mode.
///
pub fn llvm_ir(
input_files: &[PathBuf],
optimizer_settings: revive_llvm_context::OptimizerSettings,
@@ -126,9 +120,7 @@ pub fn llvm_ir(
Ok(build)
}
///
/// Runs the EraVM assembly mode.
///
pub fn zkasm(
input_files: &[PathBuf],
include_metadata_hash: bool,
@@ -157,9 +149,7 @@ pub fn zkasm(
Ok(build)
}
///
/// Runs the standard output mode.
///
#[allow(clippy::too_many_arguments)]
pub fn standard_output(
input_files: &[PathBuf],
@@ -250,9 +240,7 @@ pub fn standard_output(
Ok(build)
}
///
/// Runs the standard JSON mode.
///
#[allow(clippy::too_many_arguments)]
pub fn standard_json(
solc: &mut SolcCompiler,
@@ -332,9 +320,7 @@ pub fn standard_json(
std::process::exit(0);
}
///
/// Runs the combined JSON mode.
///
#[allow(clippy::too_many_arguments)]
pub fn combined_json(
format: String,
-8
View File
@@ -1,6 +1,4 @@
//!
//! The missing Solidity libraries.
//!
use std::collections::BTreeMap;
use std::collections::HashSet;
@@ -8,25 +6,19 @@ use std::collections::HashSet;
use crate::solc::standard_json::output::Output as StandardJsonOutput;
use crate::solc::version::Version as SolcVersion;
///
/// The missing Solidity libraries.
///
pub struct MissingLibraries {
/// The missing libraries.
pub contract_libraries: BTreeMap<String, HashSet<String>>,
}
impl MissingLibraries {
///
/// A shortcut constructor.
///
pub fn new(contract_libraries: BTreeMap<String, HashSet<String>>) -> Self {
Self { contract_libraries }
}
///
/// Writes the missing libraries to the standard JSON.
///
pub fn write_to_standard_json(
mut self,
standard_json: &mut StandardJsonOutput,
-7
View File
@@ -1,8 +1,5 @@
//!
//! Process for compiling a single compilation unit.
//!
//! The input data.
//!
use serde::Deserialize;
use serde::Serialize;
@@ -10,9 +7,7 @@ use serde::Serialize;
use crate::project::contract::Contract;
use crate::project::Project;
///
/// The input data.
///
#[derive(Debug, Serialize, Deserialize)]
pub struct Input {
/// The contract representation.
@@ -32,9 +27,7 @@ pub struct Input {
}
impl Input {
///
/// A shortcut constructor.
///
pub fn new(
contract: Contract,
project: Project,
-6
View File
@@ -1,6 +1,4 @@
//!
//! Process for compiling a single compilation unit.
//!
pub mod input;
pub mod output;
@@ -18,9 +16,7 @@ use self::output::Output;
/// The overriden executable name used when the compiler is run as a library.
pub static EXECUTABLE: OnceCell<PathBuf> = OnceCell::new();
///
/// Read input from `stdin`, compile a contract, and write the output to `stdout`.
///
pub fn run() -> anyhow::Result<()> {
let mut stdin = std::io::stdin();
let mut stdout = std::io::stdout();
@@ -60,9 +56,7 @@ pub fn run() -> anyhow::Result<()> {
}
}
///
/// Runs this process recursively to compile a single contract.
///
pub fn call(input: Input) -> anyhow::Result<Output> {
let input_json = serde_json::to_vec(&input).expect("Always valid");
-7
View File
@@ -1,17 +1,12 @@
//!
//! Process for compiling a single compilation unit.
//!
//! The output data.
//!
use serde::Deserialize;
use serde::Serialize;
use crate::build::contract::Contract as ContractBuild;
///
/// The output data.
///
#[derive(Debug, Serialize, Deserialize)]
pub struct Output {
/// The contract build.
@@ -19,9 +14,7 @@ pub struct Output {
}
impl Output {
///
/// A shortcut constructor.
///
pub fn new(build: ContractBuild) -> Self {
Self { build }
}
@@ -1,6 +1,4 @@
//!
//! The contract EVM legacy assembly source code.
//!
use std::collections::HashSet;
@@ -10,9 +8,7 @@ use serde::Serialize;
use crate::evmla::assembly::Assembly;
use crate::solc::standard_json::output::contract::evm::extra_metadata::ExtraMetadata;
///
/// The contract EVM legacy assembly source code.
///
#[derive(Debug, Serialize, Deserialize, Clone)]
#[allow(non_camel_case_types)]
#[allow(clippy::upper_case_acronyms)]
@@ -22,17 +18,13 @@ pub struct EVMLA {
}
impl EVMLA {
///
/// A shortcut constructor.
///
pub fn new(mut assembly: Assembly, extra_metadata: ExtraMetadata) -> Self {
assembly.extra_metadata = Some(extra_metadata);
Self { assembly }
}
///
/// Get the list of missing deployable libraries.
///
pub fn get_missing_libraries(&self) -> HashSet<String> {
self.assembly.get_missing_libraries()
}

Some files were not shown because too many files have changed in this diff Show More