mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-14 18:01:05 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ab11a09a9 | |||
| 9446132608 | |||
| c952471647 | |||
| 91bd1b0b4e | |||
| e568a924ae | |||
| 11f82c8488 | |||
| d0c10e6d5c | |||
| 45ceab7dc7 | |||
| a9ccb1f9b4 |
@@ -26,11 +26,14 @@ runs:
|
||||
# Extract version from branch name (e.g., "18.x" from "release/18.x")
|
||||
VERSION_PREFIX=$(echo "$BRANCH" | sed 's|release/||' | sed 's|\.x$||')
|
||||
echo "Detected LLVM version prefix from submodule branch: $VERSION_PREFIX"
|
||||
|
||||
|
||||
# Special case: pin LLVM 18 to specific version 18.1.8
|
||||
if [ "$VERSION_PREFIX" = "18" ]; then
|
||||
echo "Using pinned version for LLVM 18: llvm-18.1.8"
|
||||
echo "version_prefix=llvm-18.1.8" >> $GITHUB_OUTPUT
|
||||
elif [ "$VERSION_PREFIX" = "21" ]; then
|
||||
echo "Using pinned version for LLVM 21: llvm-21.1.6"
|
||||
echo "version_prefix=llvm-21.1.6" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "version_prefix=llvm-$VERSION_PREFIX" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
@@ -42,7 +45,7 @@ runs:
|
||||
echo "Using explicitly provided version: ${{ inputs.version }}"
|
||||
echo "version_prefix=${{ inputs.version }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
|
||||
- name: find asset
|
||||
id: find
|
||||
uses: actions/github-script@v7
|
||||
@@ -53,12 +56,15 @@ runs:
|
||||
result-encoding: string
|
||||
script: |
|
||||
let page = 1;
|
||||
let releases = [];
|
||||
let allReleases = [];
|
||||
|
||||
let target = process.env.target
|
||||
let versionPrefix = process.env.version_prefix
|
||||
|
||||
do {
|
||||
// Fetch all releases from all pages
|
||||
core.info('Fetching releases from revive repository...');
|
||||
let hasMorePages = true;
|
||||
while (hasMorePages) {
|
||||
const res = await github.rest.repos.listReleases({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
@@ -66,43 +72,57 @@ runs:
|
||||
page,
|
||||
});
|
||||
|
||||
releases = res.data
|
||||
releases.sort((a, b) => {
|
||||
return (a.published_at < b.published_at) ? 1 : ((a.published_at > b.published_at) ? -1 : 0);
|
||||
});
|
||||
|
||||
let llvmRelease;
|
||||
if (versionPrefix) {
|
||||
// Search for latest release matching the version prefix
|
||||
llvmRelease = releases.find(release => {
|
||||
return release.tag_name.startsWith(versionPrefix);
|
||||
});
|
||||
if (llvmRelease) {
|
||||
core.info(`Found LLVM release matching prefix '${versionPrefix}': ${llvmRelease.tag_name}`);
|
||||
}
|
||||
if (res.data.length > 0) {
|
||||
core.info(`Page ${page}: Fetched ${res.data.length} releases`);
|
||||
allReleases.push(...res.data);
|
||||
page++;
|
||||
} else {
|
||||
// Find latest LLVM release
|
||||
llvmRelease = releases.find(release => {
|
||||
return release.tag_name.startsWith('llvm-');
|
||||
});
|
||||
if (llvmRelease) {
|
||||
core.info(`Found latest LLVM version: ${llvmRelease.tag_name}`);
|
||||
}
|
||||
hasMorePages = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (llvmRelease){
|
||||
let asset = llvmRelease.assets.find(asset =>{
|
||||
return asset.name.includes(target);
|
||||
});
|
||||
if (!asset){
|
||||
core.setFailed(`Artifact for '${target}' not found in release ${llvmRelease.tag_name} (${llvmRelease.html_url})`);
|
||||
process.exit();
|
||||
}
|
||||
return asset.browser_download_url;
|
||||
core.info(`Total releases fetched: ${allReleases.length}`);
|
||||
|
||||
// Sort all releases by publication date (newest first)
|
||||
allReleases.sort((a, b) => {
|
||||
return (a.published_at < b.published_at) ? 1 : ((a.published_at > b.published_at) ? -1 : 0);
|
||||
});
|
||||
|
||||
// Debug: Print all LLVM releases
|
||||
const llvmReleases = allReleases.filter(r => r.tag_name.startsWith('llvm-'));
|
||||
core.info(`Found ${llvmReleases.length} LLVM releases in total:`);
|
||||
llvmReleases.forEach(r => {
|
||||
core.info(` - ${r.tag_name} (published: ${r.published_at})`);
|
||||
});
|
||||
|
||||
// Find the appropriate LLVM release
|
||||
let llvmRelease;
|
||||
if (versionPrefix) {
|
||||
// Search for latest release matching the version prefix
|
||||
llvmRelease = llvmReleases.find(release => {
|
||||
return release.tag_name.startsWith(versionPrefix);
|
||||
});
|
||||
if (llvmRelease) {
|
||||
core.info(`Selected LLVM release matching prefix '${versionPrefix}': ${llvmRelease.tag_name}`);
|
||||
}
|
||||
} else {
|
||||
// Find latest LLVM release (first in sorted list)
|
||||
llvmRelease = llvmReleases[0];
|
||||
if (llvmRelease) {
|
||||
core.info(`Selected latest LLVM version: ${llvmRelease.tag_name}`);
|
||||
}
|
||||
}
|
||||
|
||||
page++;
|
||||
} while(releases.length > 0);
|
||||
if (llvmRelease) {
|
||||
let asset = llvmRelease.assets.find(asset => {
|
||||
return asset.name.includes(target);
|
||||
});
|
||||
if (!asset) {
|
||||
core.setFailed(`Artifact for '${target}' not found in release ${llvmRelease.tag_name} (${llvmRelease.html_url})`);
|
||||
process.exit();
|
||||
}
|
||||
return asset.browser_download_url;
|
||||
}
|
||||
|
||||
if (versionPrefix) {
|
||||
core.setFailed(`No LLVM releases matching prefix '${versionPrefix}' found! Please check the version.`);
|
||||
|
||||
@@ -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.30/${SOLC_NAME}
|
||||
curl -sSL --output solc/solc https://github.com/ethereum/solidity/releases/download/v0.8.31/${SOLC_NAME}
|
||||
|
||||
- name: Make Solc Executable
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
# 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
|
||||
@@ -25,9 +25,12 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
with: { fetch-depth: 0 }
|
||||
|
||||
- name: Install mdBook
|
||||
- name: Install and test the mdBook
|
||||
run: make test-book
|
||||
|
||||
- name: Build book
|
||||
run: mdbook build book
|
||||
|
||||
- name: Build book to tmp
|
||||
run: mdbook build book -d docs-tmp
|
||||
|
||||
|
||||
@@ -82,7 +82,10 @@ jobs:
|
||||
- name: Install Dependencies
|
||||
if: ${{ matrix.host == 'linux' }}
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install -y cmake ninja-build curl git libssl-dev pkg-config clang lld musl
|
||||
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 g++ build-essential linux-libc-dev
|
||||
|
||||
- name: Install Dependencies
|
||||
if: ${{ matrix.host == 'macos' }}
|
||||
|
||||
@@ -92,7 +92,7 @@ jobs:
|
||||
if: ${{ matrix.type == 'native' }}
|
||||
shell: bash
|
||||
run: |
|
||||
export LLVM_SYS_181_PREFIX=$PWD/llvm-${{ matrix.target }}
|
||||
export LLVM_SYS_211_PREFIX=$PWD/llvm-${{ matrix.target }}
|
||||
make install-bin
|
||||
mv target/release/resolc resolc-${{ matrix.target }} || mv target/release/resolc.exe resolc-${{ matrix.target }}.exe
|
||||
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
cd /opt/revive
|
||||
chown -R root:root .
|
||||
apt update && apt upgrade -y && apt install -y pkg-config
|
||||
export LLVM_SYS_181_PREFIX=/opt/revive/llvm-${{ matrix.target }}
|
||||
export LLVM_SYS_211_PREFIX=/opt/revive/llvm-${{ matrix.target }}
|
||||
make install-bin
|
||||
mv target/${{ matrix.target }}/release/resolc resolc-${{ matrix.target }}
|
||||
"
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
export LLVM_SYS_181_PREFIX=$PWD/llvm-x86_64-unknown-linux-gnu
|
||||
export LLVM_SYS_211_PREFIX=$PWD/llvm-x86_64-unknown-linux-gnu
|
||||
export REVIVE_LLVM_TARGET_PREFIX=$PWD/llvm-wasm32-unknown-emscripten
|
||||
source emsdk/emsdk_env.sh
|
||||
make install-wasm
|
||||
@@ -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.30/soljson.js
|
||||
curl -sSLo solc/soljson.js https://github.com/ethereum/solidity/releases/download/v0.8.31/soljson.js
|
||||
node -e "
|
||||
const soljson = require('solc/soljson');
|
||||
const createRevive = require('./target/wasm32-unknown-emscripten/release/resolc.js');
|
||||
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
|
||||
- name: Set LLVM Environment Variables
|
||||
run: |
|
||||
echo "LLVM_SYS_181_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV
|
||||
echo "LLVM_SYS_211_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV
|
||||
echo "REVIVE_LLVM_TARGET_PREFIX=$(pwd)/llvm-wasm32-unknown-emscripten" >> $GITHUB_ENV
|
||||
|
||||
- name: Build Revive
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
|
||||
- name: Set LLVM Environment Variables
|
||||
run: |
|
||||
echo "LLVM_SYS_181_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV
|
||||
echo "LLVM_SYS_211_PREFIX=$(pwd)/llvm-x86_64-unknown-linux-gnu" >> $GITHUB_ENV
|
||||
|
||||
- name: Install Geth
|
||||
run: |
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
[submodule "llvm"]
|
||||
path = llvm
|
||||
url = https://github.com/llvm/llvm-project.git
|
||||
branch = release/18.x
|
||||
branch = release/21.x
|
||||
|
||||
+6
-1
@@ -4,17 +4,22 @@
|
||||
|
||||
This is a development pre-release.
|
||||
|
||||
Supported `polkadot-sdk` rev: `2509.0.0`
|
||||
Supported `polkadot-sdk` rev: `unstable2507`
|
||||
|
||||
### 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).
|
||||
- Standard JSON mode: Don't forward EVM bytecode related output selections to solc.
|
||||
- The supported `polkadot-sdk` release is `unstable2507`.
|
||||
- The `INVALID` opcode and OOB memory accesses now consume all remaining gas.
|
||||
|
||||
### Fixed:
|
||||
- The missing `STOP` instruction at the end of `code` blocks.
|
||||
- The missing bounds check in the internal sbrk implementation.
|
||||
|
||||
## v0.5.0
|
||||
|
||||
|
||||
Generated
+1030
-1036
File diff suppressed because it is too large
Load Diff
+4
-3
@@ -76,13 +76,14 @@ normpath = "1.5"
|
||||
# polkadot-sdk and friends
|
||||
codec = { version = "3.7.5", default-features = false, package = "parity-scale-codec" }
|
||||
scale-info = { version = "2.11.6", default-features = false }
|
||||
polkadot-sdk = { version = "2509.0.0" }
|
||||
polkadot-sdk = { version = "=2507.4.0" }
|
||||
|
||||
# llvm
|
||||
[workspace.dependencies.inkwell]
|
||||
version = "0.6.0"
|
||||
git = "https://github.com/TheDan64/inkwell.git"
|
||||
branch = "master"
|
||||
default-features = false
|
||||
features = ["serde", "llvm18-1", "no-libffi-linking", "target-riscv"]
|
||||
features = ["serde", "llvm21-1", "no-libffi-linking", "target-riscv"]
|
||||
|
||||
[profile.bench]
|
||||
inherits = "release"
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ RUN apt update && \
|
||||
COPY . .
|
||||
COPY --from=llvm-builder /opt/revive/target-llvm /opt/revive/target-llvm
|
||||
|
||||
ENV LLVM_SYS_181_PREFIX=/opt/revive/target-llvm/musl/target-final
|
||||
ENV LLVM_SYS_211_PREFIX=/opt/revive/target-llvm/musl/target-final
|
||||
RUN make install-bin
|
||||
|
||||
FROM alpine:latest
|
||||
|
||||
@@ -92,7 +92,6 @@ test-llvm-builder:
|
||||
test-book:
|
||||
cargo install mdbook --version 0.5.1 --locked
|
||||
mdbook test book
|
||||
mdbook build book
|
||||
|
||||
bench: install-bin
|
||||
cargo criterion --all --all-features --message-format=json \
|
||||
|
||||
@@ -69,9 +69,9 @@ Download the [latest LLVM build](https://github.com/paritytech/revive/releases?q
|
||||
> xattr -rc </path/to/the/extracted/archive>/target-llvm/gnu/target-final/bin/*
|
||||
> ```
|
||||
|
||||
After extracting the archive, point `$LLVM_SYS_181_PREFIX` to it:
|
||||
After extracting the archive, point `$LLVM_SYS_211_PREFIX` to it:
|
||||
```sh
|
||||
export LLVM_SYS_181_PREFIX=</path/to/the/extracted/archive>/target-llvm/gnu/target-final
|
||||
export LLVM_SYS_211_PREFIX=</path/to/the/extracted/archive>/target-llvm/gnu/target-final
|
||||
```
|
||||
|
||||
</details>
|
||||
@@ -79,18 +79,18 @@ export LLVM_SYS_181_PREFIX=</path/to/the/extracted/archive>/target-llvm/gnu/targ
|
||||
<details>
|
||||
<summary>Building from source</summary>
|
||||
|
||||
The `Makefile` provides a shortcut target to obtain a compatible LLVM build, using the provided [revive-llvm](crates/llvm-builder/README.md) utility. Once installed, point `$LLVM_SYS_181_PREFIX` to the installation afterwards:
|
||||
The `Makefile` provides a shortcut target to obtain a compatible LLVM build, using the provided [revive-llvm](crates/llvm-builder/README.md) utility. Once installed, point `$LLVM_SYS_211_PREFIX` to the installation afterwards:
|
||||
|
||||
```sh
|
||||
make install-llvm
|
||||
export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final
|
||||
export LLVM_SYS_211_PREFIX=${PWD}/target-llvm/gnu/target-final
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### The `resolc` Solidity frontend
|
||||
|
||||
To build the `resolc` Solidity frontend executable, make sure you have obtained a compatible LLVM build and did export the `LLVM_SYS_181_PREFIX` environment variable pointing to it (see [above](#LLVM)).
|
||||
To build the `resolc` Solidity frontend executable, make sure you have obtained a compatible LLVM build and did export the `LLVM_SYS_211_PREFIX` environment variable pointing to it (see [above](#LLVM)).
|
||||
|
||||
To install the `resolc` Solidity frontend executable:
|
||||
|
||||
|
||||
@@ -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 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 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 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.
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Valid levels are the following:
|
||||
- `s`: Optimize for code size.
|
||||
- `z`: Aggressively optimize for code size.
|
||||
|
||||
By default, `-O3` is applied.
|
||||
By default, `-Oz` is applied.
|
||||
|
||||
### Stack size
|
||||
```bash
|
||||
@@ -31,11 +31,11 @@ By default, `-O3` 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 startup costs.
|
||||
1. Increasing the stack size will increase gas costs due to increased 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!
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! The compiler build utilities library.
|
||||
|
||||
/// The revive LLVM host dependency directory prefix environment variable.
|
||||
pub const REVIVE_LLVM_HOST_PREFIX: &str = "LLVM_SYS_181_PREFIX";
|
||||
pub const REVIVE_LLVM_HOST_PREFIX: &str = "LLVM_SYS_211_PREFIX";
|
||||
|
||||
/// The revive LLVM target dependency directory prefix environment variable.
|
||||
pub const REVIVE_LLVM_TARGET_PREFIX: &str = "REVIVE_LLVM_TARGET_PREFIX";
|
||||
|
||||
@@ -43,6 +43,12 @@ 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 {
|
||||
@@ -62,6 +68,8 @@ 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),
|
||||
})
|
||||
}
|
||||
@@ -82,6 +90,8 @@ 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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
"grayGlacierBlock": 0,
|
||||
"shanghaiTime": 0,
|
||||
"cancunTime": 0,
|
||||
"pragueTime": 0,
|
||||
"osakaTime": 0,
|
||||
"terminalTotalDifficulty": 0,
|
||||
"terminalTotalDifficultyPassed": true,
|
||||
"blobSchedule": {
|
||||
@@ -22,6 +24,16 @@
|
||||
"target": 3,
|
||||
"max": 6,
|
||||
"baseFeeUpdateFraction": 3338477
|
||||
},
|
||||
"prague": {
|
||||
"target": 6,
|
||||
"max": 9,
|
||||
"baseFeeUpdateFraction": 5007716
|
||||
},
|
||||
"osaka": {
|
||||
"target": 6,
|
||||
"max": 9,
|
||||
"baseFeeUpdateFraction": 5007716
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -44,4 +56,4 @@
|
||||
"balance": "1000000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"Baseline": 905,
|
||||
"Computation": 2286,
|
||||
"DivisionArithmetics": 14347,
|
||||
"ERC20": 16929,
|
||||
"Events": 1665,
|
||||
"FibonacciIterative": 1447,
|
||||
"Flipper": 2077,
|
||||
"SHA1": 7721
|
||||
"Baseline": 911,
|
||||
"Computation": 2337,
|
||||
"DivisionArithmetics": 14488,
|
||||
"ERC20": 17041,
|
||||
"Events": 1672,
|
||||
"FibonacciIterative": 1454,
|
||||
"Flipper": 2106,
|
||||
"SHA1": 7814
|
||||
}
|
||||
@@ -26,6 +26,6 @@ pragma solidity ^0.8;
|
||||
|
||||
contract BaseFee {
|
||||
constructor() payable {
|
||||
assert(block.basefee == 0);
|
||||
assert(block.basefee > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// 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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@ pragma solidity ^0.8;
|
||||
|
||||
contract GasLeft {
|
||||
constructor() payable {
|
||||
assert(gasleft() > gasleft());
|
||||
assert(gasleft() > 0 && gasleft() < 0xffffffffffffffff);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,6 @@ pragma solidity ^0.8;
|
||||
|
||||
contract GasLimit {
|
||||
constructor() payable {
|
||||
assert(block.gaslimit == 2000000000000);
|
||||
assert(block.gaslimit > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,6 @@ pragma solidity ^0.8;
|
||||
|
||||
contract GasPrice {
|
||||
constructor() payable {
|
||||
assert(tx.gasprice == 1000);
|
||||
assert(tx.gasprice > 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ 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 {
|
||||
@@ -619,3 +620,97 @@ 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"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_opcode_works() {
|
||||
let code = &build_yul(&[(
|
||||
"invalid.yul",
|
||||
r#"object "Test" {
|
||||
code {
|
||||
invalid()
|
||||
}
|
||||
object "Test_deployed" {
|
||||
code {
|
||||
invalid()
|
||||
}
|
||||
}
|
||||
}"#,
|
||||
)])
|
||||
.unwrap()["invalid.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_eq!(result.weight_consumed, GAS_LIMIT);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ fn set_rustc_link_flags() {
|
||||
"lldELF",
|
||||
"lldCommon",
|
||||
"lldMachO",
|
||||
"lldWasm",
|
||||
"LLVMSupport",
|
||||
"LLVMLinker",
|
||||
"LLVMCore",
|
||||
@@ -68,6 +69,33 @@ fn set_rustc_link_flags() {
|
||||
"LLVMBitReader",
|
||||
"LLVMRemarks",
|
||||
"LLVMBitstreamReader",
|
||||
"LLVMTextAPI",
|
||||
"LLVMDebugInfoDWARFLowLevel",
|
||||
"LLVMDebugInfoGSYM",
|
||||
"LLVMDebugInfoMSF",
|
||||
"LLVMDebugInfoPDB",
|
||||
"LLVMDebugInfoBTF",
|
||||
"LLVMInterfaceStub",
|
||||
"LLVMCGData",
|
||||
"LLVMMIRParser",
|
||||
"LLVMDWARFLinker",
|
||||
"LLVMDWARFLinkerParallel",
|
||||
"LLVMDWARFLinkerClassic",
|
||||
"LLVMLibDriver",
|
||||
"LLVMDlltoolDriver",
|
||||
"LLVMTextAPIBinaryReader",
|
||||
"LLVMCoverage",
|
||||
"LLVMLineEditor",
|
||||
"LLVMRISCVTargetMCA",
|
||||
"LLVMRuntimeDyld",
|
||||
"LLVMDWP",
|
||||
"LLVMDWARFCFIChecker",
|
||||
"LLVMDebugInfoLogicalView",
|
||||
"LLVMMCA",
|
||||
"LLVMipo",
|
||||
"LLVMVectorize",
|
||||
"LLVMSandboxIR",
|
||||
"LLVMExtensions",
|
||||
] {
|
||||
println!("cargo:rustc-link-lib=static={lib}");
|
||||
}
|
||||
|
||||
@@ -82,10 +82,10 @@ Obtain a compatible build for your host platform from the release section of thi
|
||||
|
||||
Build artifacts end up in the `./target-llvm/gnu/target-final/` directory by default.
|
||||
The `gnu` directory depends on the supported archticture and will either be `gnu`, `musl` or `emscripten`.
|
||||
You now need to export the final target directory `$LLVM_SYS_181_PREFIX`:
|
||||
You now need to export the final target directory `$LLVM_SYS_211_PREFIX`:
|
||||
|
||||
```shell
|
||||
export LLVM_SYS_181_PREFIX=${PWD}/target-llvm/gnu/target-final
|
||||
export LLVM_SYS_211_PREFIX=${PWD}/target-llvm/gnu/target-final
|
||||
```
|
||||
|
||||
If built with the `--enable-tests` option, test tools will be in the `./target-llvm/gnu/build-final/` directory, along with copies of the build artifacts. For all supported build options, run `revive-llvm build --help`.
|
||||
|
||||
@@ -221,7 +221,6 @@ fn build_host(
|
||||
"-DCOMPILER_RT_BUILD_MEMPROF='Off'",
|
||||
"-DCOMPILER_RT_BUILD_ORC='Off'",
|
||||
"-DCOMPILER_RT_DEFAULT_TARGET_ARCH='aarch64'",
|
||||
"-DCOMPILER_RT_DEFAULT_TARGET_ONLY='On'",
|
||||
])
|
||||
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
|
||||
.args(crate::platforms::shared::shared_build_opts_ccache(
|
||||
|
||||
@@ -219,7 +219,6 @@ fn build_host(
|
||||
"-DCOMPILER_RT_BUILD_MEMPROF='Off'",
|
||||
"-DCOMPILER_RT_BUILD_ORC='Off'",
|
||||
"-DCOMPILER_RT_DEFAULT_TARGET_ARCH='x86_64'",
|
||||
"-DCOMPILER_RT_DEFAULT_TARGET_ONLY='On'",
|
||||
"-DLIBCLANG_BUILD_STATIC='On'",
|
||||
"-DBUILD_SHARED_LIBS='Off'",
|
||||
])
|
||||
|
||||
@@ -38,7 +38,7 @@ pub const MUSL_SNAPSHOTS_URL: &str = "https://git.musl-libc.org/cgit/musl/snapsh
|
||||
pub const EMSDK_SOURCE_URL: &str = "https://github.com/emscripten-core/emsdk.git";
|
||||
|
||||
/// The emscripten SDK version.
|
||||
pub const EMSDK_VERSION: &str = "4.0.9";
|
||||
pub const EMSDK_VERSION: &str = "4.0.20";
|
||||
|
||||
/// The subprocess runner.
|
||||
///
|
||||
|
||||
@@ -8,7 +8,7 @@ use serde::Serialize;
|
||||
/// inside of the LLVM build directory. This order is actually generated during the building.
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Attribute {
|
||||
Unused = 0,
|
||||
// FirstEnumAttr = 1,
|
||||
AllocAlign = 1,
|
||||
AllocatedPointer = 2,
|
||||
AlwaysInline = 3,
|
||||
@@ -16,92 +16,107 @@ pub enum Attribute {
|
||||
Cold = 5,
|
||||
Convergent = 6,
|
||||
CoroDestroyOnlyWhenComplete = 7,
|
||||
DeadOnUnwind = 8,
|
||||
DisableSanitizerInstrumentation = 9,
|
||||
FnRetThunkExtern = 10,
|
||||
Hot = 11,
|
||||
ImmArg = 12,
|
||||
InReg = 13,
|
||||
InlineHint = 14,
|
||||
JumpTable = 15,
|
||||
MinSize = 16,
|
||||
MustProgress = 17,
|
||||
Naked = 18,
|
||||
Nest = 19,
|
||||
NoAlias = 20,
|
||||
NoBuiltin = 21,
|
||||
NoCallback = 22,
|
||||
NoCapture = 23,
|
||||
NoCfCheck = 24,
|
||||
NoDuplicate = 25,
|
||||
NoFree = 26,
|
||||
NoImplicitFloat = 27,
|
||||
NoInline = 28,
|
||||
NoMerge = 29,
|
||||
NoProfile = 30,
|
||||
NoRecurse = 31,
|
||||
NoRedZone = 32,
|
||||
NoReturn = 33,
|
||||
NoSanitizeBounds = 34,
|
||||
NoSanitizeCoverage = 35,
|
||||
NoSync = 36,
|
||||
NoUndef = 37,
|
||||
NoUnwind = 38,
|
||||
NonLazyBind = 39,
|
||||
NonNull = 40,
|
||||
NullPointerIsValid = 41,
|
||||
OptForFuzzing = 42,
|
||||
OptimizeForDebugging = 43,
|
||||
OptimizeForSize = 44,
|
||||
OptimizeNone = 45,
|
||||
PresplitCoroutine = 46,
|
||||
ReadNone = 47,
|
||||
ReadOnly = 48,
|
||||
Returned = 49,
|
||||
ReturnsTwice = 50,
|
||||
SExt = 51,
|
||||
SafeStack = 52,
|
||||
SanitizeAddress = 53,
|
||||
SanitizeHWAddress = 54,
|
||||
SanitizeMemTag = 55,
|
||||
SanitizeMemory = 56,
|
||||
SanitizeThread = 57,
|
||||
ShadowCallStack = 58,
|
||||
SkipProfile = 59,
|
||||
Speculatable = 60,
|
||||
SpeculativeLoadHardening = 61,
|
||||
StackProtect = 62,
|
||||
StackProtectReq = 63,
|
||||
StackProtectStrong = 64,
|
||||
StrictFP = 65,
|
||||
SwiftAsync = 66,
|
||||
SwiftError = 67,
|
||||
SwiftSelf = 68,
|
||||
WillReturn = 69,
|
||||
Writable = 70,
|
||||
WriteOnly = 71,
|
||||
ZExt = 72,
|
||||
// LastEnumAttr = 72,
|
||||
// FirstTypeAttr = 73,
|
||||
ByRef = 73,
|
||||
ByVal = 74,
|
||||
ElementType = 75,
|
||||
InAlloca = 76,
|
||||
Preallocated = 77,
|
||||
StructRet = 78,
|
||||
// LastTypeAttr = 78,
|
||||
// FirstIntAttr = 79,
|
||||
Alignment = 79,
|
||||
AllocKind = 80,
|
||||
AllocSize = 81,
|
||||
Dereferenceable = 82,
|
||||
DereferenceableOrNull = 83,
|
||||
Memory = 84,
|
||||
NoFPClass = 85,
|
||||
StackAlignment = 86,
|
||||
UWTable = 87,
|
||||
VScaleRange = 88,
|
||||
// LastIntAttr = 88,
|
||||
CoroElideSafe = 8,
|
||||
DeadOnReturn = 9,
|
||||
DeadOnUnwind = 10,
|
||||
DisableSanitizerInstrumentation = 11,
|
||||
FnRetThunkExtern = 12,
|
||||
Hot = 13,
|
||||
HybridPatchable = 14,
|
||||
ImmArg = 15,
|
||||
InReg = 16,
|
||||
InlineHint = 17,
|
||||
JumpTable = 18,
|
||||
MinSize = 19,
|
||||
MustProgress = 20,
|
||||
Naked = 21,
|
||||
Nest = 22,
|
||||
NoAlias = 23,
|
||||
NoBuiltin = 24,
|
||||
NoCallback = 25,
|
||||
NoCfCheck = 26,
|
||||
NoDivergenceSource = 27,
|
||||
NoDuplicate = 28,
|
||||
NoExt = 29,
|
||||
NoFree = 30,
|
||||
NoImplicitFloat = 31,
|
||||
NoInline = 32,
|
||||
NoMerge = 33,
|
||||
NoProfile = 34,
|
||||
NoRecurse = 35,
|
||||
NoRedZone = 36,
|
||||
NoReturn = 37,
|
||||
NoSanitizeBounds = 38,
|
||||
NoSanitizeCoverage = 39,
|
||||
NoSync = 40,
|
||||
NoUndef = 41,
|
||||
NoUnwind = 42,
|
||||
NonLazyBind = 43,
|
||||
NonNull = 44,
|
||||
NullPointerIsValid = 45,
|
||||
OptForFuzzing = 46,
|
||||
OptimizeForDebugging = 47,
|
||||
OptimizeForSize = 48,
|
||||
OptimizeNone = 49,
|
||||
PresplitCoroutine = 50,
|
||||
ReadNone = 51,
|
||||
ReadOnly = 52,
|
||||
Returned = 53,
|
||||
ReturnsTwice = 54,
|
||||
SExt = 55,
|
||||
SafeStack = 56,
|
||||
SanitizeAddress = 57,
|
||||
SanitizeHWAddress = 58,
|
||||
SanitizeMemTag = 59,
|
||||
SanitizeMemory = 60,
|
||||
SanitizeNumericalStability = 61,
|
||||
SanitizeRealtime = 62,
|
||||
SanitizeRealtimeBlocking = 63,
|
||||
SanitizeThread = 64,
|
||||
SanitizeType = 65,
|
||||
ShadowCallStack = 66,
|
||||
SkipProfile = 67,
|
||||
Speculatable = 68,
|
||||
SpeculativeLoadHardening = 69,
|
||||
StackProtect = 70,
|
||||
StackProtectReq = 71,
|
||||
StackProtectStrong = 72,
|
||||
StrictFP = 73,
|
||||
SwiftAsync = 74,
|
||||
SwiftError = 75,
|
||||
SwiftSelf = 76,
|
||||
WillReturn = 77,
|
||||
Writable = 78,
|
||||
WriteOnly = 79,
|
||||
ZExt = 80,
|
||||
//LastEnumAttr = 80,
|
||||
//FirstTypeAttr = 81,
|
||||
ByRef = 81,
|
||||
ByVal = 82,
|
||||
ElementType = 83,
|
||||
InAlloca = 84,
|
||||
Preallocated = 85,
|
||||
StructRet = 86,
|
||||
//LastTypeAttr = 86,
|
||||
//FirstIntAttr = 87,
|
||||
Alignment = 87,
|
||||
AllocKind = 88,
|
||||
AllocSize = 89,
|
||||
Captures = 90,
|
||||
Dereferenceable = 91,
|
||||
DereferenceableOrNull = 92,
|
||||
Memory = 93,
|
||||
NoFPClass = 94,
|
||||
StackAlignment = 95,
|
||||
UWTable = 96,
|
||||
VScaleRange = 97,
|
||||
//LastIntAttr = 97,
|
||||
//FirstConstantRangeAttr = 98,
|
||||
Range = 98,
|
||||
//LastConstantRangeAttr = 98,
|
||||
//FirstConstantRangeListAttr = 99,
|
||||
Initializes = 99,
|
||||
//LastConstantRangeListAttr = 99,
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Attribute {
|
||||
|
||||
@@ -14,6 +14,8 @@ 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> {
|
||||
@@ -26,6 +28,9 @@ 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,
|
||||
@@ -53,11 +58,18 @@ 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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,12 +97,15 @@ impl<'ctx> Intrinsics<'ctx> {
|
||||
let word_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32);
|
||||
|
||||
match name {
|
||||
name if name == Self::FUNCTION_BYTE_SWAP_WORD => vec![word_type.as_basic_type_enum()],
|
||||
name if name == Self::FUNCTION_BYTE_SWAP_ETH_ADDRESS => {
|
||||
_ if name == Self::FUNCTION_BYTE_SWAP_WORD => vec![word_type.as_basic_type_enum()],
|
||||
_ 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![],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,11 +51,11 @@ impl RuntimeFunction for WordToPointer {
|
||||
)?;
|
||||
|
||||
let block_continue = context.append_basic_block("offset_pointer_ok");
|
||||
let block_trap = context.append_basic_block("offset_pointer_overflow");
|
||||
context.build_conditional_branch(is_overflow, block_trap, block_continue)?;
|
||||
let block_invalid = context.append_basic_block("offset_pointer_overflow");
|
||||
context.build_conditional_branch(is_overflow, block_invalid, block_continue)?;
|
||||
|
||||
context.set_basic_block(block_trap);
|
||||
context.build_call(context.intrinsics().trap, &[], "invalid_trap");
|
||||
context.set_basic_block(block_invalid);
|
||||
context.build_runtime_call(revive_runtime_api::polkavm_imports::INVALID, &[]);
|
||||
context.build_unreachable();
|
||||
|
||||
context.set_basic_block(block_continue);
|
||||
|
||||
@@ -77,6 +77,20 @@ 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);
|
||||
@@ -88,20 +102,20 @@ impl RuntimeFunction for Sbrk {
|
||||
context.builder().build_not(mask, "mask_not")?,
|
||||
"memory_size",
|
||||
)?;
|
||||
let size_in_bounds_block = context.append_basic_block("size_in_bounds");
|
||||
let is_size_out_of_bounds = context.builder().build_int_compare(
|
||||
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(
|
||||
inkwell::IntPredicate::UGT,
|
||||
memory_size,
|
||||
context.heap_size(),
|
||||
"size_out_of_bounds",
|
||||
)?;
|
||||
context.build_conditional_branch(
|
||||
is_size_out_of_bounds,
|
||||
is_total_size_out_of_bounds,
|
||||
trap_block,
|
||||
size_in_bounds_block,
|
||||
total_size_in_bounds_block,
|
||||
)?;
|
||||
|
||||
context.set_basic_block(size_in_bounds_block);
|
||||
context.set_basic_block(total_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,
|
||||
|
||||
@@ -838,8 +838,7 @@ impl<'ctx> Context<'ctx> {
|
||||
.builder()
|
||||
.build_call(intrinsic, &[value.into()], "call_byte_swap")?
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap())
|
||||
.unwrap_basic())
|
||||
}
|
||||
|
||||
/// Builds a GEP instruction.
|
||||
@@ -912,7 +911,7 @@ impl<'ctx> Context<'ctx> {
|
||||
)
|
||||
.unwrap()
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.basic()
|
||||
}
|
||||
|
||||
/// Builds a call to the runtime API `import`, where `import` is a "getter" API.
|
||||
@@ -950,7 +949,7 @@ impl<'ctx> Context<'ctx> {
|
||||
)
|
||||
.unwrap();
|
||||
self.modify_call_site_value(arguments, call_site_value, function);
|
||||
call_site_value.try_as_basic_value().left()
|
||||
call_site_value.try_as_basic_value().basic()
|
||||
}
|
||||
|
||||
/// Sets the alignment to `1`, since all non-stack memory pages have such alignment.
|
||||
@@ -1082,13 +1081,7 @@ impl<'ctx> Context<'ctx> {
|
||||
|
||||
Ok(call_site_value
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"revive runtime function {} should return a value",
|
||||
<PolkaVMSbrkFunction as RuntimeFunction>::NAME,
|
||||
)
|
||||
})
|
||||
.unwrap_basic()
|
||||
.into_pointer_value())
|
||||
}
|
||||
|
||||
@@ -1277,7 +1270,7 @@ impl<'ctx> Context<'ctx> {
|
||||
call_site_value.add_attribute(
|
||||
inkwell::attributes::AttributeLoc::Param(index as u32),
|
||||
self.llvm
|
||||
.create_enum_attribute(Attribute::NoCapture as u32, 0),
|
||||
.create_enum_attribute(Attribute::Captures as u32, 0), // captures(none)
|
||||
);
|
||||
call_site_value.add_attribute(
|
||||
inkwell::attributes::AttributeLoc::Param(index as u32),
|
||||
|
||||
@@ -261,3 +261,20 @@ 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()
|
||||
.basic()
|
||||
.expect("the llvm.ctlz should return a value"))
|
||||
}
|
||||
|
||||
@@ -52,12 +52,14 @@ pub fn stop(context: &mut Context) -> anyhow::Result<()> {
|
||||
/// Translates the `invalid` instruction.
|
||||
/// Burns all gas using an out-of-bounds memory store, causing a panic.
|
||||
pub fn invalid(context: &mut Context) -> anyhow::Result<()> {
|
||||
crate::polkavm::evm::memory::store(
|
||||
context,
|
||||
context.word_type().const_all_ones(),
|
||||
context.word_const(0),
|
||||
)?;
|
||||
context.build_call(context.intrinsics().trap, &[], "invalid_trap");
|
||||
let invalid_block = context.append_basic_block("explicit_invalid");
|
||||
context.build_unconditional_branch(invalid_block);
|
||||
context.set_basic_block(invalid_block);
|
||||
context.build_runtime_call(revive_runtime_api::polkavm_imports::INVALID, &[]);
|
||||
context.build_unreachable();
|
||||
|
||||
context.set_basic_block(context.append_basic_block("dead_code"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ mimalloc = { version = "0.1.46", default-features = false }
|
||||
|
||||
[target.'cfg(target_os = "emscripten")'.dependencies]
|
||||
libc = { workspace = true }
|
||||
inkwell = { workspace = true, features = ["target-riscv", "llvm18-1-no-llvm-linking"]}
|
||||
inkwell = { workspace = true, features = ["target-riscv", "llvm21-1-no-llvm-linking"]}
|
||||
|
||||
[build-dependencies]
|
||||
git2 = { workspace = true, default-features = false }
|
||||
|
||||
@@ -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, 30);
|
||||
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 31);
|
||||
|
||||
/// The Solidity compiler.
|
||||
pub trait Compiler {
|
||||
|
||||
@@ -59,7 +59,7 @@ pub const CHARLIE: H160 = H160([3u8; 20]);
|
||||
/// Default gas limit
|
||||
pub const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000_000, 3 * 1024 * 1024 * 1024);
|
||||
/// Default deposit limit
|
||||
pub const DEPOSIT_LIMIT: Balance = 10_000_000;
|
||||
pub const DEPOSIT_LIMIT: Balance = 100_000_000_000;
|
||||
/// The native to ETH balance factor.
|
||||
pub const ETH_RATIO: Balance = 1_000_000;
|
||||
|
||||
@@ -97,14 +97,19 @@ impl ExtBuilder {
|
||||
.unwrap();
|
||||
|
||||
let mut ext = sp_io::TestExternalities::new(t);
|
||||
let checking_account = Pallet::<Runtime>::account_id();
|
||||
ext.register_extension(KeystoreExt::new(MemoryKeystore::new()));
|
||||
ext.execute_with(|| {
|
||||
let _ = <Runtime as Config>::Currency::deposit_creating(
|
||||
&Pallet::<Runtime>::account_id(),
|
||||
<Runtime as Config>::Currency::minimum_balance(),
|
||||
&checking_account,
|
||||
1_000_000_000_000,
|
||||
);
|
||||
|
||||
System::set_block_number(1);
|
||||
|
||||
assert_ok!(Pallet::<Runtime>::map_account(RuntimeOrigin::signed(
|
||||
checking_account
|
||||
)));
|
||||
});
|
||||
|
||||
ext
|
||||
@@ -115,7 +120,7 @@ impl ExtBuilder {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VerifyCallExpectation {
|
||||
/// When provided, the expected gas consumed
|
||||
pub gas_consumed: Option<Weight>,
|
||||
pub gas_consumed: Option<u128>,
|
||||
/// When provided, the expected output
|
||||
#[serde(default, with = "hex")]
|
||||
pub output: OptionalHex<Vec<u8>>,
|
||||
@@ -238,7 +243,7 @@ impl CallResult {
|
||||
}
|
||||
|
||||
/// Get the gas consumed by the call
|
||||
fn gas_consumed(&self) -> Weight {
|
||||
fn gas_consumed(&self) -> u128 {
|
||||
match self {
|
||||
Self::Exec { result, .. } => result.gas_consumed,
|
||||
Self::Instantiate { result, .. } => result.gas_consumed,
|
||||
|
||||
@@ -2,7 +2,7 @@ use frame_support::{runtime, traits::FindAuthor, weights::constants::WEIGHT_REF_
|
||||
use pallet_revive::AccountId32Mapper;
|
||||
use polkadot_sdk::*;
|
||||
use polkadot_sdk::{
|
||||
polkadot_sdk_frame::{log, runtime::prelude::*},
|
||||
polkadot_sdk_frame::runtime::prelude::*,
|
||||
sp_runtime::{AccountId32, Perbill},
|
||||
};
|
||||
|
||||
@@ -72,6 +72,7 @@ parameter_types! {
|
||||
|
||||
#[derive_impl(pallet_revive::config_preludes::TestDefaultConfig)]
|
||||
impl pallet_revive::Config for Runtime {
|
||||
type Balance = Balance;
|
||||
type Time = Timestamp;
|
||||
type Currency = Balances;
|
||||
type DepositPerByte = DepositPerByte;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{str::FromStr, time::Instant};
|
||||
|
||||
use polkadot_sdk::pallet_revive::Pallet;
|
||||
use polkadot_sdk::pallet_revive::{ExecConfig, Pallet, TransactionLimits};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::*;
|
||||
@@ -210,9 +210,9 @@ impl Default for Specs {
|
||||
Self {
|
||||
differential: false,
|
||||
balances: vec![
|
||||
(ALICE, 1_000_000_000),
|
||||
(BOB, 1_000_000_000),
|
||||
(CHARLIE, 1_000_000_000),
|
||||
(ALICE, 1_000_000_000_000),
|
||||
(BOB, 1_000_000_000_000),
|
||||
(CHARLIE, 1_000_000_000_000),
|
||||
],
|
||||
actions: Default::default(),
|
||||
}
|
||||
@@ -447,12 +447,14 @@ impl Specs {
|
||||
let result = Contracts::bare_instantiate(
|
||||
origin,
|
||||
value.into(),
|
||||
gas_limit.unwrap_or(GAS_LIMIT),
|
||||
storage_deposit_limit.unwrap_or(DEPOSIT_LIMIT).into(),
|
||||
TransactionLimits::WeightAndDeposit {
|
||||
weight_limit: gas_limit.unwrap_or(GAS_LIMIT),
|
||||
deposit_limit: storage_deposit_limit.unwrap_or(DEPOSIT_LIMIT),
|
||||
},
|
||||
code,
|
||||
data,
|
||||
salt.0,
|
||||
pallet_revive::BumpNonce::No,
|
||||
ExecConfig::new_substrate_tx(),
|
||||
);
|
||||
results.push(CallResult::Instantiate {
|
||||
result,
|
||||
@@ -486,9 +488,12 @@ impl Specs {
|
||||
RuntimeOrigin::signed(origin.to_account_id(&results)),
|
||||
dest.to_eth_addr(&results),
|
||||
value.into(),
|
||||
gas_limit.unwrap_or(GAS_LIMIT),
|
||||
storage_deposit_limit.unwrap_or(DEPOSIT_LIMIT).into(),
|
||||
TransactionLimits::WeightAndDeposit {
|
||||
weight_limit: gas_limit.unwrap_or(GAS_LIMIT),
|
||||
deposit_limit: storage_deposit_limit.unwrap_or(DEPOSIT_LIMIT),
|
||||
},
|
||||
data,
|
||||
ExecConfig::new_substrate_tx(),
|
||||
);
|
||||
results.push(CallResult::Exec {
|
||||
result,
|
||||
|
||||
@@ -9,7 +9,7 @@ description = "Implements the low level runtime API bindings with pallet contrac
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
inkwell = { workspace = true, features = ["target-riscv", "no-libffi-linking", "llvm18-1"] }
|
||||
inkwell = { workspace = true, features = ["target-riscv", "no-libffi-linking", "llvm21-1"] }
|
||||
|
||||
revive-common = { workspace = true }
|
||||
|
||||
|
||||
@@ -69,6 +69,8 @@ POLKAVM_IMPORT(uint64_t, code_size, uint32_t)
|
||||
|
||||
POLKAVM_IMPORT(void, code_hash, uint32_t, uint32_t)
|
||||
|
||||
POLKAVM_IMPORT(void, consume_all_gas)
|
||||
|
||||
POLKAVM_IMPORT(uint32_t, delegate_call, uint64_t, uint64_t, uint64_t, uint32_t, uint64_t, uint64_t)
|
||||
|
||||
POLKAVM_IMPORT(void, deposit_event, uint32_t, uint32_t, uint32_t, uint32_t)
|
||||
|
||||
@@ -48,6 +48,8 @@ pub static HASH_KECCAK_256: &str = "hash_keccak_256";
|
||||
|
||||
pub static INSTANTIATE: &str = "instantiate";
|
||||
|
||||
pub static INVALID: &str = "consume_all_gas";
|
||||
|
||||
pub static NOW: &str = "now";
|
||||
|
||||
pub static ORIGIN: &str = "origin";
|
||||
@@ -70,7 +72,7 @@ pub static VALUE_TRANSFERRED: &str = "value_transferred";
|
||||
|
||||
/// All imported runtime API symbols.
|
||||
/// Useful for configuring common attributes and linkage.
|
||||
pub static IMPORTS: [&str; 33] = [
|
||||
pub static IMPORTS: [&str; 34] = [
|
||||
ADDRESS,
|
||||
BALANCE,
|
||||
BALANCE_OF,
|
||||
@@ -94,6 +96,7 @@ pub static IMPORTS: [&str; 33] = [
|
||||
GET_STORAGE,
|
||||
HASH_KECCAK_256,
|
||||
INSTANTIATE,
|
||||
INVALID,
|
||||
NOW,
|
||||
ORIGIN,
|
||||
REF_TIME_LEFT,
|
||||
|
||||
@@ -7,7 +7,7 @@ repository.workspace = true
|
||||
description = "revive compiler stdlib components"
|
||||
|
||||
[dependencies]
|
||||
inkwell = { workspace = true, features = ["target-riscv", "no-libffi-linking", "llvm18-1"] }
|
||||
inkwell = { workspace = true, features = ["target-riscv", "no-libffi-linking", "llvm21-1"] }
|
||||
|
||||
[build-dependencies]
|
||||
revive-build-utils = { workspace = true }
|
||||
|
||||
@@ -348,6 +348,14 @@ 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,6 +54,8 @@ 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
|
||||
@@ -270,6 +272,7 @@ impl From<&str> for Name {
|
||||
"shl" => Self::Shl,
|
||||
"shr" => Self::Shr,
|
||||
"sar" => Self::Sar,
|
||||
"clz" => Self::Clz,
|
||||
"byte" => Self::Byte,
|
||||
"pop" => Self::Pop,
|
||||
|
||||
@@ -393,6 +396,7 @@ 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
@@ -36,7 +36,7 @@
|
||||
const path_to_root = "";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "../";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "../searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "../searchindex-82723808.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 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 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 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 don’t 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>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "../";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "../searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "../searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "../";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "../searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "../searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "../";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "../searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "../searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "../";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "../searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "../searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc-6f3f265e.js"></script>
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="toc-6f3f265e.js"></script>
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="toc-6f3f265e.js"></script>
|
||||
|
||||
+4
-4
@@ -36,7 +36,7 @@
|
||||
const path_to_root = "";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "searchindex-82723808.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>-O3</code> is applied.</p>
|
||||
<p>By default, <code>-Oz</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 <STACK_SIZE>
|
||||
</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 startup costs.</li>
|
||||
<li>Increasing the stack size will increase gas costs due to increased startup costs.</li>
|
||||
<li>The stack size contributes to the total memory size a contract can use, which includes the contract’s 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 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 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 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 don’t 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>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="toc-6f3f265e.js"></script>
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -437,7 +437,7 @@ window.search = window.search || {};
|
||||
if (yes) {
|
||||
loadSearchScript(
|
||||
window.path_to_searchindex_js ||
|
||||
path_to_root + 'searchindex-756a6899.js',
|
||||
path_to_root + 'searchindex-82723808.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
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "../";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "../searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "../searchindex-82723808.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>-O3</code> is applied.</p>
|
||||
<p>By default, <code>-Oz</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 <STACK_SIZE>
|
||||
</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 startup costs.</li>
|
||||
<li>Increasing the stack size will increase gas costs due to increased startup costs.</li>
|
||||
<li>The stack size contributes to the total memory size a contract can use, which includes the contract’s code size.</li>
|
||||
</ol>
|
||||
<p>Default value: 32768</p>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "../";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "../searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "../searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "../";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "../searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "../searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "../";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "../searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "../searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "../";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "../searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "../searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "../";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "../searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "../searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "../";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "../searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "../searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc-6f3f265e.js"></script>
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
const path_to_root = "";
|
||||
const default_light_theme = "light";
|
||||
const default_dark_theme = "navy";
|
||||
window.path_to_searchindex_js = "searchindex-756a6899.js";
|
||||
window.path_to_searchindex_js = "searchindex-82723808.js";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="toc-6f3f265e.js"></script>
|
||||
|
||||
@@ -3,7 +3,7 @@ const path = require("path");
|
||||
const { minify } = require("terser");
|
||||
|
||||
const SOLJSON_URI =
|
||||
"https://binaries.soliditylang.org/wasm/soljson-v0.8.30+commit.73712a01.js";
|
||||
"https://binaries.soliditylang.org/wasm/soljson-v0.8.31+commit.fd3a2265.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(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "revive",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"solc": ">=0.8.0 <=0.8.30"
|
||||
"solc": ">=0.8.0 <=0.8.31"
|
||||
},
|
||||
"scripts": {
|
||||
"example:web": "http-server ./examples/web/",
|
||||
|
||||
@@ -34,6 +34,6 @@
|
||||
"commander": "^13.1.0",
|
||||
"package-json": "^10.0.1",
|
||||
"resolve-pkg": "^2.0.0",
|
||||
"solc": ">=0.8.0 <=0.8.30"
|
||||
"solc": ">=0.8.0 <=0.8.31"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
Submodule llvm updated: 3b5b5c1ec4...f68f64eb81
Generated
+7
-2
@@ -18,7 +18,7 @@
|
||||
"js/emscripten": {
|
||||
"name": "revive",
|
||||
"dependencies": {
|
||||
"solc": ">=0.8.0 <=0.8.30"
|
||||
"solc": ">=0.8.0 <=0.8.31"
|
||||
},
|
||||
"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.30"
|
||||
"solc": ">=0.8.0 <=0.8.31"
|
||||
},
|
||||
"bin": {
|
||||
"resolc": "dist/bin.js"
|
||||
@@ -1585,6 +1585,7 @@
|
||||
"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",
|
||||
@@ -1752,6 +1753,7 @@
|
||||
"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"
|
||||
},
|
||||
@@ -2361,6 +2363,7 @@
|
||||
"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",
|
||||
@@ -2519,6 +2522,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ethersproject/abi": "5.8.0",
|
||||
"@ethersproject/abstract-provider": "5.8.0",
|
||||
@@ -4393,6 +4397,7 @@
|
||||
"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"
|
||||
|
||||
Reference in New Issue
Block a user