Compare commits

..

5 Commits

Author SHA1 Message Date
elle-j 6187f76d63 Control concurrency and cancel in-progress runs when re-triggered. 2025-12-02 16:38:06 +01:00
LJ e6ccaa0bab Merge branch 'main' into lj/ci-benchmarks 2025-12-02 08:13:11 +01:00
elle-j 7cc1921c01 Update naming. 2025-11-27 21:31:31 +01:00
elle-j 3446aaa238 Update checkouts and report generation. 2025-11-27 17:21:41 +01:00
elle-j 0847b99a7d Implement initial workflow to run benchmarks. 2025-11-26 11:35:30 +01:00
46 changed files with 182 additions and 257 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ runs:
shell: bash
run: |
mkdir -p solc
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.31/${SOLC_NAME}
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.30/${SOLC_NAME}
- name: Make Solc Executable
if: ${{ runner.os == 'Windows' }}
+123
View File
@@ -0,0 +1,123 @@
# This workflow will run on the default branch when triggered by a `workflow_run` event.
name: Benchmark
on:
workflow_run:
workflows: [Test]
types: [completed]
concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true
jobs:
benchmark:
runs-on: ubuntu-24.04
if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' }}
permissions:
pull-requests: write
steps:
- name: Checkout PR Branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}
- name: Set Up Rust Toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
# Without this it will override our rust flags.
rustflags: ""
- name: Install Solc
uses: ./.github/actions/get-solc
- name: Download LLVM
uses: ./.github/actions/get-llvm
with:
target: x86_64-unknown-linux-gnu
- name: Set LLVM Environment Variables
run: |
echo "LLVM_SYS_181_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV
- name: Install Benchmarking Tools
run: |
cargo install critcmp
- name: Checkout and Compile Main Branch
run: |
git fetch origin main
git checkout -f main
make install
- name: Run Benchmarks on Main Branch
run: |
cargo bench --package resolc --bench compile -- --save-baseline main_resolc
cargo bench --package revive-yul --bench parse -- --save-baseline main_yul_parse
cargo bench --package revive-yul --bench lower -- --save-baseline main_yul_lower
timeout-minutes: 20
- name: Checkout and Compile PR Branch
run: |
git checkout -f ${{ github.event.workflow_run.head_sha }}
make install
- name: Run Benchmarks on PR Branch
run: |
cargo bench --package resolc --bench compile -- --save-baseline pr_resolc
cargo bench --package revive-yul --bench parse -- --save-baseline pr_yul_parse
cargo bench --package revive-yul --bench lower -- --save-baseline pr_yul_lower
timeout-minutes: 20
- name: Compare Benchmarks
run: |
critcmp main_resolc pr_resolc > benchmarks_resolc
critcmp main_yul_parse pr_yul_parse > benchmarks_yul_parse
critcmp main_yul_lower pr_yul_lower > benchmarks_yul_lower
- name: Create Report
run: |
cat > BENCHMARK_REPORT.md << EOF
# Benchmarks
## Compile E2E
<details>
<summary>Results</summary>
\`\`\`
$(cat benchmarks_resolc)
\`\`\`
</details>
## Parse Yul
<details>
<summary>Results</summary>
\`\`\`
$(cat benchmarks_yul_parse)
\`\`\`
</details>
## Lower Yul
<details>
<summary>Results</summary>
\`\`\`
$(cat benchmarks_yul_lower)
\`\`\`
</details>
EOF
- name: Post PR Comment with Benchmark Report
uses: marocchino/sticky-pull-request-comment@v2
with:
header: benchmark
number: ${{ github.event.workflow_run.pull_requests[0].number }}
path: BENCHMARK_REPORT.md
+1 -4
View File
@@ -82,10 +82,7 @@ jobs:
- name: Install Dependencies
if: ${{ matrix.host == 'linux' }}
run: |
cat /etc/apt/sources.list
sudo sed -i 's/jammy/noble/g' /etc/apt/sources.list
cat /etc/apt/sources.list
sudo apt-get update && sudo apt-get install -y cmake ninja-build curl git libssl-dev pkg-config clang lld musl xz-utils libc6-dev gcc-multilib
sudo apt-get update && sudo apt-get install -y cmake ninja-build curl git libssl-dev pkg-config clang lld musl
- name: Install Dependencies
if: ${{ matrix.host == 'macos' }}
+1 -1
View File
@@ -177,7 +177,7 @@ jobs:
- name: Basic Sanity Check
run: |
mkdir -p solc
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.31/soljson.js
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.30/soljson.js
node -e "
const soljson = require('solc/soljson');
const createRevive = require('./target/wasm32-unknown-emscripten/release/resolc.js');
-3
View File
@@ -8,8 +8,6 @@ Supported `polkadot-sdk` rev: `2509.0.0`
### Added
- The comprehensive revive compiler book documentation page: https://paritytech.github.io/revive/
- Support for solc v0.8.31.
- Support for the `clz` Yul builtin.
### Changed
- Instruct the LLVM backend and linker to `--relax` (may lead to smaller contract code size).
@@ -17,7 +15,6 @@ Supported `polkadot-sdk` rev: `2509.0.0`
### Fixed:
- The missing `STOP` instruction at the end of `code` blocks.
- The missing bounds check in the internal sbrk implementation.
## v0.5.0
+1 -1
View File
@@ -45,7 +45,7 @@ Unlike with the EVM, where heap memory usage is gas metered, our heap size is st
LLVM is a special non Rust dependency. We interface its builder interface via the [inkwell](https://crates.io/crates/inkwell) wrapper crate.
We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM `rv64emacb` target and always leave assertions on. Furthermore, we need cross builds because `resolc` itself targets emscripten and musl. The [revive-llvm-builer](https://crates.io/crates/revive-llvm-builder) functions as a cross-platform build script and is used to build and release the LLVM dependency.
We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM rv64e target and always leave assertions on. Furthermore, we need cross builds because `resolc` itself targets emscripten and musl. The [revive-llvm-builer](https://crates.io/crates/revive-llvm-builder) functions as a cross-platform build script and is used to build and release the LLVM dependency.
We also maintain the [lld-sys crate](https://crates.io/crates/lld-sys) for interfacing with `LLD`. The LLVM linker is used during the compilation process, but we don't want to distribute another binary.
+4 -4
View File
@@ -21,7 +21,7 @@ Valid levels are the following:
- `s`: Optimize for code size.
- `z`: Aggressively optimize for code size.
By default, `-Oz` is applied.
By default, `-O3` is applied.
### Stack size
```bash
@@ -31,11 +31,11 @@ By default, `-Oz` is applied.
PVM is a register machine with a traditional stack memory space for local variables. This controls the total amount of stack space the contract can use.
You are incentivized to keep this value as small as possible:
1. Increasing the stack size will increase gas costs due to increased startup costs.
1. Increasing the stack size will increase startup costs.
2. The stack size contributes to the total memory size a contract can use, which includes the contract's code size.
Default value: 32768
> [!WARNING]
>
> If the contract uses more stack memory than configured, it will compile fine but eventually revert execution at runtime!
@@ -52,7 +52,7 @@ You are incentivized to keep this value as small as possible:
2.The heap size contributes to the total memory size a contract can use, which includes the contract's code size
Default value: 65536
> [!WARNING]
>
> If the contract uses more heap memory than configured, it will compile fine but eventually revert execution at runtime!
-10
View File
@@ -43,12 +43,6 @@ pub enum EVMVersion {
/// The corresponding EVM version.
#[serde(rename = "cancun")]
Cancun,
/// The corresponding EVM version.
#[serde(rename = "prague")]
Prague,
/// The corresponding EVM version.
#[serde(rename = "osaka")]
Osaka,
}
impl TryFrom<&str> for EVMVersion {
@@ -68,8 +62,6 @@ impl TryFrom<&str> for EVMVersion {
"paris" => Self::Paris,
"shanghai" => Self::Shanghai,
"cancun" => Self::Cancun,
"prague" => Self::Prague,
"osaka" => Self::Osaka,
_ => anyhow::bail!("Invalid EVM version: {}", value),
})
}
@@ -90,8 +82,6 @@ impl std::fmt::Display for EVMVersion {
Self::Paris => write!(f, "paris"),
Self::Shanghai => write!(f, "shanghai"),
Self::Cancun => write!(f, "cancun"),
Self::Prague => write!(f, "prague"),
Self::Osaka => write!(f, "osaka"),
}
}
}
+1 -13
View File
@@ -15,8 +15,6 @@
"grayGlacierBlock": 0,
"shanghaiTime": 0,
"cancunTime": 0,
"pragueTime": 0,
"osakaTime": 0,
"terminalTotalDifficulty": 0,
"terminalTotalDifficultyPassed": true,
"blobSchedule": {
@@ -24,16 +22,6 @@
"target": 3,
"max": 6,
"baseFeeUpdateFraction": 3338477
},
"prague": {
"target": 6,
"max": 9,
"baseFeeUpdateFraction": 5007716
},
"osaka": {
"target": 6,
"max": 9,
"baseFeeUpdateFraction": 5007716
}
}
},
@@ -56,4 +44,4 @@
"balance": "1000000000"
}
}
}
}
+8 -8
View File
@@ -1,10 +1,10 @@
{
"Baseline": 911,
"Computation": 2293,
"DivisionArithmetics": 14353,
"ERC20": 16936,
"Events": 1672,
"FibonacciIterative": 1454,
"Flipper": 2083,
"SHA1": 7727
"Baseline": 905,
"Computation": 2286,
"DivisionArithmetics": 14347,
"ERC20": 16929,
"Events": 1665,
"FibonacciIterative": 1447,
"Flipper": 2077,
"SHA1": 7721
}
@@ -1,57 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.31;
/* runner.json
{
"differential": true,
"actions": [
{
"Instantiate": {
"code": {
"Solidity": {
"contract": "CountLeadingZeros"
}
}
}
}
]
}
*/
/// The EIP-7939 test vectors:
/// https://eips.ethereum.org/EIPS/eip-7939#test-cases
contract CountLeadingZeros {
function clz(uint256 x) internal pure returns (uint256 r) {
assembly {
r := clz(x)
}
}
constructor() payable {
assert(
clz(0x000000000000000000000000000000000000000000000000000000000000000)
== 0x0000000000000000000000000000000000000000000000000000000000000100
);
assert(
clz(0x8000000000000000000000000000000000000000000000000000000000000000)
== 0x0000000000000000000000000000000000000000000000000000000000000000
);
assert(
clz(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
== 0x0000000000000000000000000000000000000000000000000000000000000000
);
assert(
clz(0x4000000000000000000000000000000000000000000000000000000000000000)
== 0x0000000000000000000000000000000000000000000000000000000000000001
);
assert(
clz(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
== 0x0000000000000000000000000000000000000000000000000000000000000001
);
assert(
clz(0x0000000000000000000000000000000000000000000000000000000000000001)
== 0x00000000000000000000000000000000000000000000000000000000000000ff
);
}
}
-50
View File
@@ -65,7 +65,6 @@ test_spec!(shift_arithmetic_right, "SAR", "SAR.sol");
test_spec!(add_mod_mul_mod, "AddModMulModTester", "AddModMulMod.sol");
test_spec!(memory_bounds, "MemoryBounds", "MemoryBounds.sol");
test_spec!(selfdestruct, "Selfdestruct", "Selfdestruct.sol");
test_spec!(clz, "CountLeadingZeros", "CountLeadingZeros.sol");
fn instantiate(path: &str, contract: &str) -> Vec<SpecsAction> {
vec![Instantiate {
@@ -620,52 +619,3 @@ fn code_block_with_nested_object_stops() {
}
.run();
}
#[test]
fn sbrk_bounds_checks() {
let code = &build_yul(&[(
"poc.yul",
r#"object "Test" {
code {
return(0x4, 0xffffffff)
stop()
}
object "Test_deployed" {
code {
stop()
}
}
}"#,
)])
.unwrap()["poc.yul:Test"];
let results = Specs {
actions: vec![
Instantiate {
origin: TestAddress::Alice,
value: 0,
gas_limit: Some(GAS_LIMIT),
storage_deposit_limit: None,
code: Code::Bytes(code.to_vec()),
data: Default::default(),
salt: OptionalHex::default(),
},
VerifyCall(VerifyCallExpectation {
success: false,
..Default::default()
}),
],
differential: false,
..Default::default()
}
.run();
let CallResult::Instantiate { result, .. } = results.last().unwrap() else {
unreachable!()
};
assert!(
format!("{result:?}").contains("ContractTrapped"),
"not seeing a trap means the contract did not catch the OOB"
);
}
@@ -14,8 +14,6 @@ pub struct Intrinsics<'ctx> {
pub byte_swap_word: FunctionDeclaration<'ctx>,
/// Performs endianness swaps on i160 values
pub byte_swap_eth_address: FunctionDeclaration<'ctx>,
/// Counts leading zeroes.
pub count_leading_zeros: FunctionDeclaration<'ctx>,
}
impl<'ctx> Intrinsics<'ctx> {
@@ -28,9 +26,6 @@ impl<'ctx> Intrinsics<'ctx> {
/// The corresponding intrinsic function name.
pub const FUNCTION_BYTE_SWAP_ETH_ADDRESS: &'static str = "llvm.bswap.i160";
/// The corresponding intrinsic function name.
pub const FUNCTION_COUNT_LEADING_ZEROS: &'static str = "llvm.ctlz.i256";
/// A shortcut constructor.
pub fn new(
llvm: &'ctx inkwell::context::Context,
@@ -58,18 +53,11 @@ impl<'ctx> Intrinsics<'ctx> {
Self::FUNCTION_BYTE_SWAP_ETH_ADDRESS,
address_type.fn_type(&[address_type.as_basic_type_enum().into()], false),
);
let count_leading_zeros = Self::declare(
llvm,
module,
Self::FUNCTION_COUNT_LEADING_ZEROS,
word_type.fn_type(&[word_type.into(), llvm.bool_type().into()], false),
);
Self {
trap,
byte_swap_word,
byte_swap_eth_address,
count_leading_zeros,
}
}
@@ -97,15 +85,12 @@ impl<'ctx> Intrinsics<'ctx> {
let word_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32);
match name {
_ if name == Self::FUNCTION_BYTE_SWAP_WORD => vec![word_type.as_basic_type_enum()],
_ if name == Self::FUNCTION_BYTE_SWAP_ETH_ADDRESS => {
name if name == Self::FUNCTION_BYTE_SWAP_WORD => vec![word_type.as_basic_type_enum()],
name if name == Self::FUNCTION_BYTE_SWAP_ETH_ADDRESS => {
vec![llvm
.custom_width_int_type(revive_common::BIT_LENGTH_ETH_ADDRESS as u32)
.as_basic_type_enum()]
}
_ if name == Self::FUNCTION_COUNT_LEADING_ZEROS => {
vec![word_type.as_basic_type_enum()]
}
_ => vec![],
}
}
@@ -77,20 +77,6 @@ impl RuntimeFunction for Sbrk {
context.build_unreachable();
context.set_basic_block(offset_in_bounds_block);
let size_in_bounds_block = context.append_basic_block("size_in_bounds");
let is_size_out_of_bounds = context.builder().build_int_compare(
inkwell::IntPredicate::UGT,
size,
context.heap_size(),
"size_in_bounds",
)?;
context.build_conditional_branch(
is_size_out_of_bounds,
trap_block,
size_in_bounds_block,
)?;
context.set_basic_block(size_in_bounds_block);
let mask = context
.xlen_type()
.const_int(BYTE_LENGTH_WORD as u64 - 1, false);
@@ -102,20 +88,20 @@ impl RuntimeFunction for Sbrk {
context.builder().build_not(mask, "mask_not")?,
"memory_size",
)?;
let total_size_in_bounds_block = context.append_basic_block("total_size_in_bounds");
let is_total_size_out_of_bounds = context.builder().build_int_compare(
let size_in_bounds_block = context.append_basic_block("size_in_bounds");
let is_size_out_of_bounds = context.builder().build_int_compare(
inkwell::IntPredicate::UGT,
memory_size,
context.heap_size(),
"size_out_of_bounds",
)?;
context.build_conditional_branch(
is_total_size_out_of_bounds,
is_size_out_of_bounds,
trap_block,
total_size_in_bounds_block,
size_in_bounds_block,
)?;
context.set_basic_block(total_size_in_bounds_block);
context.set_basic_block(size_in_bounds_block);
let new_size_block = context.append_basic_block("new_size");
let is_new_size = context.builder().build_int_compare(
inkwell::IntPredicate::UGT,
@@ -261,20 +261,3 @@ pub fn byte<'ctx>(
Ok(byte.as_basic_value_enum())
}
/// Translates the CLZ instruction.
pub fn count_leading_zeros<'ctx>(
context: &mut Context<'ctx>,
value: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>> {
Ok(context
.builder()
.build_call(
context.intrinsics().count_leading_zeros.function_value(),
&[value.into(), context.bool_const(false).into()],
"clz",
)?
.try_as_basic_value()
.left()
.expect("the llvm.ctlz should return a value"))
}
+1 -1
View File
@@ -23,7 +23,7 @@ pub mod version;
pub const FIRST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 0);
/// The last supported version of `solc`.
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 31);
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 30);
/// The Solidity compiler.
pub trait Compiler {
@@ -348,14 +348,6 @@ impl FunctionCall {
)
.map(Some)
}
Name::Clz => {
let arguments = self.pop_arguments_llvm::<1>(context)?;
revive_llvm_context::polkavm_evm_bitwise::count_leading_zeros(
context,
arguments[0].into_int_value(),
)
.map(Some)
}
Name::Byte => {
let arguments = self.pop_arguments_llvm::<2>(context)?;
revive_llvm_context::polkavm_evm_bitwise::byte(
@@ -54,8 +54,6 @@ pub enum Name {
Shr,
/// signed arithmetic shift right `y` by `x` bits
Sar,
/// number of leading zero bits of x, 256 if x == 0
Clz,
/// `n`th byte of `x`, where the most significant byte is the `0`th byte
Byte,
/// discard value x
@@ -272,7 +270,6 @@ impl From<&str> for Name {
"shl" => Self::Shl,
"shr" => Self::Shr,
"sar" => Self::Sar,
"clz" => Self::Clz,
"byte" => Self::Byte,
"pop" => Self::Pop,
@@ -396,7 +393,6 @@ impl fmt::Display for Name {
Self::Shl => "shl",
Self::Shr => "shr",
Self::Sar => "sar",
Self::Clz => "clz",
Self::Byte => "byte",
Self::Pop => "pop",
+1 -1
View File
@@ -36,7 +36,7 @@
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-82723808.js";
window.path_to_searchindex_js = "searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-82723808.js";
window.path_to_searchindex_js = "searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script>
+2 -2
View File
@@ -35,7 +35,7 @@
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-82723808.js";
window.path_to_searchindex_js = "../searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script>
@@ -205,7 +205,7 @@
<p>Unlike with the EVM, where heap memory usage is gas metered, our heap size is static (the size is user controllable via a setting flag). The compiler emits bound checks to prevent overflows.</p>
<h2 id="the-llvm-dependency"><a class="header" href="#the-llvm-dependency">The LLVM dependency</a></h2>
<p>LLVM is a special non Rust dependency. We interface its builder interface via the <a href="https://crates.io/crates/inkwell">inkwell</a> wrapper crate.</p>
<p>We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM <code>rv64emacb</code> target and always leave assertions on. Furthermore, we need cross builds because <code>resolc</code> itself targets emscripten and musl. The <a href="https://crates.io/crates/revive-llvm-builder">revive-llvm-builer</a> functions as a cross-platform build script and is used to build and release the LLVM dependency.</p>
<p>We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM rv64e target and always leave assertions on. Furthermore, we need cross builds because <code>resolc</code> itself targets emscripten and musl. The <a href="https://crates.io/crates/revive-llvm-builder">revive-llvm-builer</a> functions as a cross-platform build script and is used to build and release the LLVM dependency.</p>
<p>We also maintain the <a href="https://crates.io/crates/lld-sys">lld-sys crate</a> for interfacing with <code>LLD</code>. The LLVM linker is used during the compilation process, but we dont want to distribute another binary.</p>
<h2 id="custom-optimizations"><a class="header" href="#custom-optimizations">Custom optimizations</a></h2>
<p>At the moment, no significant custom optimizations are implemented. Thus, we are missing some optimization opportunities that neither <code>solc</code> nor LLVM can realize (due to their lack of domain specific knowledge about the semantics of our target environment). Furthermore, <code>solc</code> optimizes for EVM gas and a target machine orthogonal to our target (BE 256-bit stack machine EVM vs. 64-bit LE RISC architecture PVM). We have started working on an additional IR layer between Yul and LLVM to capture missed optimization opportunities, though.</p>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-82723808.js";
window.path_to_searchindex_js = "../searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-82723808.js";
window.path_to_searchindex_js = "../searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-82723808.js";
window.path_to_searchindex_js = "../searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-82723808.js";
window.path_to_searchindex_js = "../searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-82723808.js";
window.path_to_searchindex_js = "searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-82723808.js";
window.path_to_searchindex_js = "searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script>
+4 -4
View File
@@ -36,7 +36,7 @@
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-82723808.js";
window.path_to_searchindex_js = "searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script>
@@ -235,14 +235,14 @@ Please find our <a href="https://github.com/paritytech/revive/releases">binary r
<li><code>s</code>: Optimize for code size.</li>
<li><code>z</code>: Aggressively optimize for code size.</li>
</ul>
<p>By default, <code>-Oz</code> is applied.</p>
<p>By default, <code>-O3</code> is applied.</p>
<h3 id="stack-size"><a class="header" href="#stack-size">Stack size</a></h3>
<pre><code class="language-bash">--stack-size &lt;STACK_SIZE&gt;
</code></pre>
<p>PVM is a register machine with a traditional stack memory space for local variables. This controls the total amount of stack space the contract can use.</p>
<p>You are incentivized to keep this value as small as possible:</p>
<ol>
<li>Increasing the stack size will increase gas costs due to increased startup costs.</li>
<li>Increasing the stack size will increase startup costs.</li>
<li>The stack size contributes to the total memory size a contract can use, which includes the contracts code size.</li>
</ol>
<p>Default value: 32768</p>
@@ -539,7 +539,7 @@ Thus, <code>revive</code> is able to supply the expected code hash and construct
<p>Unlike with the EVM, where heap memory usage is gas metered, our heap size is static (the size is user controllable via a setting flag). The compiler emits bound checks to prevent overflows.</p>
<h2 id="the-llvm-dependency"><a class="header" href="#the-llvm-dependency">The LLVM dependency</a></h2>
<p>LLVM is a special non Rust dependency. We interface its builder interface via the <a href="https://crates.io/crates/inkwell">inkwell</a> wrapper crate.</p>
<p>We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM <code>rv64emacb</code> target and always leave assertions on. Furthermore, we need cross builds because <code>resolc</code> itself targets emscripten and musl. The <a href="https://crates.io/crates/revive-llvm-builder">revive-llvm-builer</a> functions as a cross-platform build script and is used to build and release the LLVM dependency.</p>
<p>We use upstream LLVM, but release and use our custom builds. We require the compiler builtins specifically built for the PVM rv64e target and always leave assertions on. Furthermore, we need cross builds because <code>resolc</code> itself targets emscripten and musl. The <a href="https://crates.io/crates/revive-llvm-builder">revive-llvm-builer</a> functions as a cross-platform build script and is used to build and release the LLVM dependency.</p>
<p>We also maintain the <a href="https://crates.io/crates/lld-sys">lld-sys crate</a> for interfacing with <code>LLD</code>. The LLVM linker is used during the compilation process, but we dont want to distribute another binary.</p>
<h2 id="custom-optimizations"><a class="header" href="#custom-optimizations">Custom optimizations</a></h2>
<p>At the moment, no significant custom optimizations are implemented. Thus, we are missing some optimization opportunities that neither <code>solc</code> nor LLVM can realize (due to their lack of domain specific knowledge about the semantics of our target environment). Furthermore, <code>solc</code> optimizes for EVM gas and a target machine orthogonal to our target (BE 256-bit stack machine EVM vs. 64-bit LE RISC architecture PVM). We have started working on an additional IR layer between Yul and LLVM to capture missed optimization opportunities, though.</p>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-82723808.js";
window.path_to_searchindex_js = "searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-82723808.js";
window.path_to_searchindex_js = "searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script>
+1 -1
View File
@@ -437,7 +437,7 @@ window.search = window.search || {};
if (yes) {
loadSearchScript(
window.path_to_searchindex_js ||
path_to_root + 'searchindex-82723808.js',
path_to_root + 'searchindex-756a6899.js',
'mdbook-search-index');
search_wrap.classList.remove('hidden');
searchicon.setAttribute('aria-expanded', 'true');
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-82723808.js";
window.path_to_searchindex_js = "searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script>
+3 -3
View File
@@ -35,7 +35,7 @@
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-82723808.js";
window.path_to_searchindex_js = "../searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script>
@@ -193,14 +193,14 @@
<li><code>s</code>: Optimize for code size.</li>
<li><code>z</code>: Aggressively optimize for code size.</li>
</ul>
<p>By default, <code>-Oz</code> is applied.</p>
<p>By default, <code>-O3</code> is applied.</p>
<h3 id="stack-size"><a class="header" href="#stack-size">Stack size</a></h3>
<pre><code class="language-bash">--stack-size &lt;STACK_SIZE&gt;
</code></pre>
<p>PVM is a register machine with a traditional stack memory space for local variables. This controls the total amount of stack space the contract can use.</p>
<p>You are incentivized to keep this value as small as possible:</p>
<ol>
<li>Increasing the stack size will increase gas costs due to increased startup costs.</li>
<li>Increasing the stack size will increase startup costs.</li>
<li>The stack size contributes to the total memory size a contract can use, which includes the contracts code size.</li>
</ol>
<p>Default value: 32768</p>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-82723808.js";
window.path_to_searchindex_js = "../searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-82723808.js";
window.path_to_searchindex_js = "../searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-82723808.js";
window.path_to_searchindex_js = "../searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-82723808.js";
window.path_to_searchindex_js = "../searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-82723808.js";
window.path_to_searchindex_js = "../searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-82723808.js";
window.path_to_searchindex_js = "../searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-6f3f265e.js"></script>
+1 -1
View File
@@ -35,7 +35,7 @@
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-82723808.js";
window.path_to_searchindex_js = "searchindex-756a6899.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-6f3f265e.js"></script>
+1 -1
View File
@@ -3,7 +3,7 @@ const path = require("path");
const { minify } = require("terser");
const SOLJSON_URI =
"https://binaries.soliditylang.org/wasm/soljson-v0.8.31+commit.fd3a2265.js";
"https://binaries.soliditylang.org/wasm/soljson-v0.8.30+commit.73712a01.js";
const RESOLC_WASM_URI =
process.env.RELEASE_RESOLC_WASM_URI || "http://127.0.0.1:8080/resolc.wasm";
const RESOLC_WASM_TARGET_DIR = path.join(
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "revive",
"private": true,
"dependencies": {
"solc": ">=0.8.0 <=0.8.31"
"solc": ">=0.8.0 <=0.8.30"
},
"scripts": {
"example:web": "http-server ./examples/web/",
+1 -1
View File
@@ -34,6 +34,6 @@
"commander": "^13.1.0",
"package-json": "^10.0.1",
"resolve-pkg": "^2.0.0",
"solc": ">=0.8.0 <=0.8.31"
"solc": ">=0.8.0 <=0.8.30"
}
}
+2 -7
View File
@@ -18,7 +18,7 @@
"js/emscripten": {
"name": "revive",
"dependencies": {
"solc": ">=0.8.0 <=0.8.31"
"solc": ">=0.8.0 <=0.8.30"
},
"devDependencies": {
"@playwright/test": "^1.49.1",
@@ -38,7 +38,7 @@
"commander": "^13.1.0",
"package-json": "^10.0.1",
"resolve-pkg": "^2.0.0",
"solc": ">=0.8.0 <=0.8.31"
"solc": ">=0.8.0 <=0.8.30"
},
"bin": {
"resolc": "dist/bin.js"
@@ -1585,7 +1585,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz",
"integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.32.1",
"@typescript-eslint/types": "8.32.1",
@@ -1753,7 +1752,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -2363,7 +2361,6 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz",
"integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -2522,7 +2519,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"@ethersproject/abi": "5.8.0",
"@ethersproject/abstract-provider": "5.8.0",
@@ -4397,7 +4393,6 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"