diff --git a/Cargo.toml b/Cargo.toml index 66b1c71b..e31a6ddc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ which = "8.0" path-slash = "0.2" rayon = "1.11" clap = { version = "4", default-features = false, features = ["derive"] } +# TODO: Bump polkavm-* when a new release containing commit `ffddfe4` exists. polkavm-common = "0.35.0" polkavm-linker = "0.35.0" polkavm-disassembler = "0.35.0" diff --git a/crates/resolc/src/test_utils.rs b/crates/resolc/src/test_utils.rs index 44c7f67f..4167a1f1 100644 --- a/crates/resolc/src/test_utils.rs +++ b/crates/resolc/src/test_utils.rs @@ -56,6 +56,8 @@ struct CachedBlob { } /// Builds the Solidity project and returns the standard JSON output. +/// [`OptimizerSettings::cycles`] will be used. Debug info is emitted +/// at every optimization level except `-Oz`. pub fn build_solidity( sources: BTreeMap, ) -> anyhow::Result { @@ -70,6 +72,7 @@ pub fn build_solidity( } /// Builds the Solidity project and returns the standard JSON output. +/// Debug info is emitted at every optimization level except `-Oz`. pub fn build_solidity_with_options( sources: BTreeMap, libraries: SolcStandardJsonInputSettingsLibraries, diff --git a/crates/resolc/src/tests/unit/debug_info.rs b/crates/resolc/src/tests/unit/debug_info.rs new file mode 100644 index 00000000..bdf69f4a --- /dev/null +++ b/crates/resolc/src/tests/unit/debug_info.rs @@ -0,0 +1,61 @@ +//! The Solidity compiler tests for debug info. + +use revive_llvm_context::OptimizerSettings; + +use crate::test_utils::{build_solidity_with_options, sources}; + +/// Test for a PolkaVM debug line-program with too many instructions. +/// +/// At `-O1` through `-O3` and `-Os`, LLVM merges the identical code of many repeated +/// calls. With debug info enabled the merged instruction is attributed to every +/// original call site at once, so the PolkaVM linker reconstructs a very deep +/// inline-frame stack for a single instruction. A debug `resolc` build invoked with `-g` +/// panicked when there were more line-program ops than the runtime parser read per region. +#[test] +fn many_repeated_calls_do_not_overflow_the_line_program() { + let code = r#" +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; +interface I { + function f(uint256) external; +} +contract Test { + function run(I t, uint256 acc) external { + t.f(acc); t.f(acc); t.f(acc); t.f(acc); t.f(acc); t.f(acc); + t.f(acc); t.f(acc); t.f(acc); t.f(acc); t.f(acc); t.f(acc); + t.f(acc); t.f(acc); t.f(acc); t.f(acc); t.f(acc); t.f(acc); + t.f(acc); t.f(acc); t.f(acc); t.f(acc); t.f(acc); t.f(acc); + } +} +"#; + + for opt_level in ['1', '2', '3', 's'] { + let output = build_solidity_with_options( + sources(&[("test.sol", code)]), + Default::default(), + Default::default(), + OptimizerSettings::try_from_cli(opt_level).unwrap(), + true, + Default::default(), + ) + .unwrap_or_else(|error| panic!("-O{opt_level} should compile: {error}")); + + assert!( + !output + .contracts + .get("test.sol") + .expect("`test.sol` should exist") + .get("Test") + .expect("contract `Test` should exist") + .evm + .as_ref() + .expect("`evm` field should exist") + .bytecode + .as_ref() + .expect("`bytecode` field should exist") + .object + .is_empty(), + "-O{opt_level} should generate bytecode" + ); + } +} diff --git a/crates/resolc/src/tests/unit/mod.rs b/crates/resolc/src/tests/unit/mod.rs index 097d3c83..58d42e90 100644 --- a/crates/resolc/src/tests/unit/mod.rs +++ b/crates/resolc/src/tests/unit/mod.rs @@ -1,5 +1,6 @@ //! The Solidity compiler unit tests. +mod debug_info; mod factory_dependency; mod ir_artifacts; mod libraries;