diff --git a/crates/integration/contracts/MSize.sol b/crates/integration/contracts/MSize.sol new file mode 100644 index 0000000..b7a22ad --- /dev/null +++ b/crates/integration/contracts/MSize.sol @@ -0,0 +1,9 @@ +contract MSize { + uint[] public data; + + function mSize() public pure returns (uint size) { + assembly { + size := msize() + } + } +} diff --git a/crates/integration/src/lib.rs b/crates/integration/src/lib.rs index 31b70af..7d62110 100644 --- a/crates/integration/src/lib.rs +++ b/crates/integration/src/lib.rs @@ -1,14 +1,26 @@ pub mod mock_runtime; +/// Compile the blob of `contract_name` found in given `source_code`. +/// The `solc` optimizer will be enabled pub fn compile_blob(contract_name: &str, source_code: &str) -> Vec { + compile_blob_with_options(contract_name, source_code, true) +} + +/// Compile the blob of `contract_name` found in given `source_code`. +pub fn compile_blob_with_options( + contract_name: &str, + source_code: &str, + solc_optimizer_enabled: bool, +) -> Vec { let file_name = "contract.sol"; - let contracts = revive_solidity::test_utils::build_solidity( + let contracts = revive_solidity::test_utils::build_solidity_with_options( [(file_name.into(), source_code.into())].into(), Default::default(), None, revive_solidity::SolcPipeline::Yul, era_compiler_llvm_context::OptimizerSettings::cycles(), + solc_optimizer_enabled, ) .expect("source should compile") .contracts @@ -149,4 +161,30 @@ mod tests { let received = I256::from_be_bytes::<32>(state.output.data.try_into().unwrap()); assert_eq!(received, expected); } + + #[test] + fn msize() { + sol!( + #[derive(Debug, PartialEq, Eq)] + contract MSize { + function mSize() public pure returns (uint); + } + ); + let code = crate::compile_blob_with_options( + "MSize", + include_str!("../contracts/MSize.sol"), + false, + ); + + let input = MSize::mSizeCall::new(()).abi_encode(); + let (instance, export) = mock_runtime::prepare(&code, None); + let state = crate::mock_runtime::call(State::new(input), &instance, export); + + assert_eq!(state.output.flags, 0); + + // Solidity always stores the "free memory pointer" (32 byte int) at offset 64. + let expected = U256::try_from(64 + 32).unwrap(); + let received = U256::from_be_bytes::<32>(state.output.data.try_into().unwrap()); + assert_eq!(received, expected); + } } diff --git a/crates/llvm-context/src/eravm/evm/context.rs b/crates/llvm-context/src/eravm/evm/context.rs index 374bee2..682ac76 100644 --- a/crates/llvm-context/src/eravm/evm/context.rs +++ b/crates/llvm-context/src/eravm/evm/context.rs @@ -2,6 +2,8 @@ //! Translates the context getter instructions. //! +use inkwell::values::BasicValue; + use crate::eravm::context::Context; use crate::eravm::Dependency; @@ -180,10 +182,24 @@ where /// Translates the `msize` instruction. /// pub fn msize<'ctx, D>( - _context: &mut Context<'ctx, D>, + context: &mut Context<'ctx, D>, ) -> anyhow::Result> where D: Dependency + Clone, { - todo!() + let heap_end = context.build_sbrk(context.xlen_type().const_zero())?; + let heap_start = context + .get_global(crate::eravm::GLOBAL_HEAP_MEMORY_POINTER)? + .value + .as_pointer_value(); + let heap_size = context.builder().build_int_nuw_sub( + context + .builder() + .build_ptr_to_int(heap_end, context.xlen_type(), "heap_end")?, + context + .builder() + .build_ptr_to_int(heap_start, context.xlen_type(), "heap_start")?, + "heap_size", + )?; + Ok(heap_size.as_basic_value_enum()) } diff --git a/crates/solidity/src/test_utils.rs b/crates/solidity/src/test_utils.rs index bf2bd24..da82478 100644 --- a/crates/solidity/src/test_utils.rs +++ b/crates/solidity/src/test_utils.rs @@ -30,15 +30,34 @@ fn check_dependencies() { } } -/// /// Builds the Solidity project and returns the standard JSON output. -/// pub fn build_solidity( sources: BTreeMap, libraries: BTreeMap>, remappings: Option>, pipeline: SolcPipeline, optimizer_settings: era_compiler_llvm_context::OptimizerSettings, +) -> anyhow::Result { + build_solidity_with_options( + sources, + libraries, + remappings, + pipeline, + optimizer_settings, + true, + ) +} + +/// Builds the Solidity project and returns the standard JSON output. +/// Gives control over additional options: +/// - `solc_optimizer_enabled`: Whether to use the `solc` optimizer +pub fn build_solidity_with_options( + sources: BTreeMap, + libraries: BTreeMap>, + remappings: Option>, + pipeline: SolcPipeline, + optimizer_settings: era_compiler_llvm_context::OptimizerSettings, + solc_optimizer_enabled: bool, ) -> anyhow::Result { check_dependencies(); @@ -56,7 +75,7 @@ pub fn build_solidity( remappings, SolcStandardJsonInputSettingsSelection::new_required(pipeline), SolcStandardJsonInputSettingsOptimizer::new( - true, + solc_optimizer_enabled, None, &solc_version.default, false,