mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 19:51:05 +00:00
Initial support for building RISC-V runtimes targeting PolkaVM (#3179)
This PR adds initial support for building RISC-V runtimes targeting PolkaVM. - Setting the `SUBSTRATE_RUNTIME_TARGET=riscv` environment variable will now build a RISC-V runtime instead of a WASM runtime. - This only adds support for *building* runtimes; running them will need a PolkaVM-based executor, which I will add in a future PR. - Only building the minimal runtime is supported (building the Polkadot runtime doesn't work *yet* due to one of the dependencies). - The builder now sets a `substrate_runtime` cfg flag when building the runtimes, with the idea being that instead of doing `#[cfg(not(feature = "std"))]` or `#[cfg(target_arch = "wasm32")]` to detect that we're building a runtime you'll do `#[cfg(substrate_runtime)]`. (Switching the whole codebase to use this will be done in a future PR; I deliberately didn't do this here to keep this PR minimal and reviewable.) - Further renaming of things (e.g. types, environment variables and proc macro attributes having "wasm" in their name) to be target-agnostic will also be done in a future refactoring PR (while keeping backwards compatibility where it makes sense; I don't intend to break anyone's workflow or create unnecessary churn). - This PR also fixes two bugs in the `wasm-builder` crate: * The `RUSTC` environment variable is now removed when invoking the compiler. This prevents the toolchain version from being overridden when called from a `build.rs` script. * When parsing the `rustup toolchain list` output the `(default)` is now properly stripped and not treated as part of the version. - I've also added a minimal CI job that makes sure this doesn't break in the future. (cc @paritytech/ci) cc @athei ------ Also, just a fun little tidbit: quickly comparing the size of the built runtimes it seems that the PolkaVM runtime is slightly smaller than the WASM one. (`production` build, with the `names` section substracted from the WASM's size to keep things fair, since for the PolkaVM runtime we're currently stripping out everything) - `.wasm`: 625505 bytes - `.wasm` (after wasm-opt -O3): 563205 bytes - `.wasm` (after wasm-opt -Os): 562987 bytes - `.wasm` (after wasm-opt -Oz): 536852 bytes - `.polkavm`: ~~580338 bytes~~ 550476 bytes (after enabling extra target features; I'll add those in another PR once we have an executor working) --------- Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
@@ -21,13 +21,16 @@ sp-api-proc-macro = { path = "proc-macro", default-features = false }
|
||||
sp-core = { path = "../core", default-features = false }
|
||||
sp-std = { path = "../std", default-features = false }
|
||||
sp-runtime = { path = "../runtime", default-features = false }
|
||||
sp-runtime-interface = { path = "../runtime-interface", default-features = false }
|
||||
sp-externalities = { path = "../externalities", default-features = false, optional = true }
|
||||
sp-version = { path = "../version", default-features = false }
|
||||
sp-state-machine = { path = "../state-machine", default-features = false, optional = true }
|
||||
sp-trie = { path = "../trie", default-features = false, optional = true }
|
||||
hash-db = { version = "0.16.0", optional = true }
|
||||
thiserror = { version = "1.0.48", optional = true }
|
||||
scale-info = { version = "2.10.0", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "2.10.0", default-features = false, features = [
|
||||
"derive",
|
||||
] }
|
||||
sp-metadata-ir = { path = "../metadata-ir", default-features = false, optional = true }
|
||||
log = { version = "0.4.17", default-features = false }
|
||||
|
||||
@@ -46,6 +49,7 @@ std = [
|
||||
"sp-externalities",
|
||||
"sp-externalities?/std",
|
||||
"sp-metadata-ir?/std",
|
||||
"sp-runtime-interface/std",
|
||||
"sp-runtime/std",
|
||||
"sp-state-machine/std",
|
||||
"sp-std/std",
|
||||
|
||||
@@ -237,7 +237,8 @@ fn generate_wasm_interface(impls: &[ItemImpl]) -> Result<TokenStream> {
|
||||
#c::std_disabled! {
|
||||
#( #attrs )*
|
||||
#[no_mangle]
|
||||
pub unsafe fn #fn_name(input_data: *mut u8, input_len: usize) -> u64 {
|
||||
#[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), #c::__private::polkavm_export(abi = #c::__private::polkavm_abi))]
|
||||
pub unsafe extern fn #fn_name(input_data: *mut u8, input_len: usize) -> u64 {
|
||||
let mut #input = if input_len == 0 {
|
||||
&[0u8; 0]
|
||||
} else {
|
||||
|
||||
@@ -105,6 +105,9 @@ pub mod __private {
|
||||
};
|
||||
pub use sp_std::{mem, slice, vec};
|
||||
pub use sp_version::{create_apis_vec, ApiId, ApisVec, RuntimeVersion};
|
||||
|
||||
#[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), substrate_runtime))]
|
||||
pub use sp_runtime_interface::polkavm::{polkavm_abi, polkavm_export};
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
|
||||
@@ -1737,20 +1737,20 @@ mod tracing_setup {
|
||||
|
||||
pub use tracing_setup::init_tracing;
|
||||
|
||||
/// Allocator used by Substrate when executing the Wasm runtime.
|
||||
#[cfg(all(target_arch = "wasm32", not(feature = "std")))]
|
||||
struct WasmAllocator;
|
||||
/// Allocator used by Substrate from within the runtime.
|
||||
#[cfg(substrate_runtime)]
|
||||
struct RuntimeAllocator;
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", not(feature = "disable_allocator"), not(feature = "std")))]
|
||||
#[cfg(all(not(feature = "disable_allocator"), substrate_runtime))]
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: WasmAllocator = WasmAllocator;
|
||||
static ALLOCATOR: RuntimeAllocator = RuntimeAllocator;
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", not(feature = "std")))]
|
||||
#[cfg(substrate_runtime)]
|
||||
mod allocator_impl {
|
||||
use super::*;
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
|
||||
unsafe impl GlobalAlloc for WasmAllocator {
|
||||
unsafe impl GlobalAlloc for RuntimeAllocator {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
allocator::malloc(layout.size() as u32)
|
||||
}
|
||||
@@ -1761,8 +1761,27 @@ mod allocator_impl {
|
||||
}
|
||||
}
|
||||
|
||||
/// A default panic handler for WASM environment.
|
||||
#[cfg(all(not(feature = "disable_panic_handler"), not(feature = "std")))]
|
||||
/// Crashes the execution of the program.
|
||||
///
|
||||
/// Equivalent to the WASM `unreachable` instruction, RISC-V `unimp` instruction,
|
||||
/// or just the `unreachable!()` macro everywhere else.
|
||||
pub fn unreachable() -> ! {
|
||||
#[cfg(target_family = "wasm")]
|
||||
{
|
||||
core::arch::wasm32::unreachable();
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
unsafe {
|
||||
core::arch::asm!("unimp", options(noreturn));
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64", target_family = "wasm")))]
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
/// A default panic handler for the runtime environment.
|
||||
#[cfg(all(not(feature = "disable_panic_handler"), substrate_runtime))]
|
||||
#[panic_handler]
|
||||
#[no_mangle]
|
||||
pub fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
@@ -1774,11 +1793,11 @@ pub fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
#[cfg(not(feature = "improved_panic_error_reporting"))]
|
||||
{
|
||||
logging::log(LogLevel::Error, "runtime", message.as_bytes());
|
||||
core::arch::wasm32::unreachable();
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
/// A default OOM handler for WASM environment.
|
||||
/// A default OOM handler for the runtime environment.
|
||||
#[cfg(all(not(feature = "disable_oom"), enable_alloc_error_handler))]
|
||||
#[alloc_error_handler]
|
||||
pub fn oom(_: core::alloc::Layout) -> ! {
|
||||
@@ -1789,7 +1808,7 @@ pub fn oom(_: core::alloc::Layout) -> ! {
|
||||
#[cfg(not(feature = "improved_panic_error_reporting"))]
|
||||
{
|
||||
logging::log(LogLevel::Error, "runtime", b"Runtime memory exhausted. Aborting");
|
||||
core::arch::wasm32::unreachable();
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ primitive-types = { version = "0.12.0", default-features = false }
|
||||
sp-storage = { path = "../storage", default-features = false }
|
||||
impl-trait-for-tuples = "0.2.2"
|
||||
|
||||
[target.'cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), substrate_runtime))'.dependencies]
|
||||
polkavm-derive = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
sp-runtime-interface-test-wasm = { path = "test-wasm" }
|
||||
sp-state-machine = { path = "../state-machine" }
|
||||
|
||||
+7
-2
@@ -109,7 +109,12 @@ fn function_no_std_impl(
|
||||
};
|
||||
let maybe_unreachable = if method.should_trap_on_return() {
|
||||
quote! {
|
||||
; core::arch::wasm32::unreachable();
|
||||
;
|
||||
#[cfg(target_family = "wasm")]
|
||||
{ core::arch::wasm32::unreachable(); }
|
||||
|
||||
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
unsafe { core::arch::asm!("unimp", options(noreturn)); }
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
@@ -118,7 +123,7 @@ fn function_no_std_impl(
|
||||
let attrs = method.attrs.iter().filter(|a| !a.path().is_ident("version"));
|
||||
|
||||
let cfg_wasm_only = if is_wasm_only {
|
||||
quote! { #[cfg(target_arch = "wasm32")] }
|
||||
quote! { #[cfg(substrate_runtime)] }
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
+1
-1
@@ -116,8 +116,8 @@ fn generate_extern_host_function(
|
||||
#(#cfg_attrs)*
|
||||
#[doc = #doc_string]
|
||||
pub fn #function ( #( #args ),* ) #return_value {
|
||||
#[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), #crate_::polkavm::polkavm_import(abi = #crate_::polkavm::polkavm_abi))]
|
||||
extern "C" {
|
||||
/// The extern function.
|
||||
pub fn #ext_function (
|
||||
#( #arg_names: <#arg_types as #crate_::RIType>::FFIType ),*
|
||||
) #ffi_return_value;
|
||||
|
||||
@@ -376,6 +376,9 @@ pub use sp_externalities::{
|
||||
#[doc(hidden)]
|
||||
pub use codec;
|
||||
|
||||
#[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), substrate_runtime))]
|
||||
pub mod polkavm;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub mod host;
|
||||
pub(crate) mod impls;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
pub use polkavm_derive::{polkavm_export, polkavm_import};
|
||||
|
||||
#[polkavm_derive::polkavm_define_abi(allow_extra_input_registers)]
|
||||
pub mod polkavm_abi {}
|
||||
|
||||
impl self::polkavm_abi::FromHost for *mut u8 {
|
||||
type Regs = (u32,);
|
||||
|
||||
#[inline]
|
||||
fn from_host((value,): Self::Regs) -> Self {
|
||||
value as *mut u8
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user