Skip to content

Commit

Permalink
Experimental aarch64 support (#6200)
Browse files Browse the repository at this point in the history
 feat: aarch64 (m1) support

Wasmer singlepass does not support aarch64, so disable it there and use
wasmtime instead

---

 feat: make everything compile on m1 (aarch64)

Condition all wasmer compilation on not being on aarch64. This could
also be done by using features, but then the reverse-dependencies would
have to know about this limitation.

Currently the code is a bit of a mess due to the amount of #![cfg()]
elements, but hopefully this can be improved on later on by having one
module with its own submodules per backend.

---

The support is still very experimental, but at least near-vm-runner's test will work now.

Related to #3803 

The first commit is pretty much required, the second commit is this way in order for reverse-dependencies of near-vm-runner to not have to care about which features get enabled. An alternative could have been to make wasmer build on aarch64 (even if panicking on the first call), and the other alternative would have been to have all reverse-dependencies expose the wasm* features and ask that people on aarch64 manually toggle the proper features for things to work.
  • Loading branch information
Ekleog authored Feb 1, 2022
1 parent a25386c commit d1d4559
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 42 deletions.
30 changes: 16 additions & 14 deletions runtime/near-vm-runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,9 @@ This crate implements the specification of the interface that Near blockchain ex
[dependencies]
borsh = "0.9"
serde = { version = "1", features = ["derive"] }
wasmer-runtime = { version = "0.18.0", features = ["default-backend-singlepass"], default-features = false, package = "wasmer-runtime-near", optional = true }
wasmer-runtime-core = { version = "0.18.2", package = "wasmer-runtime-core-near", optional = true}
wasmparser = "0.78"
memoffset = "0.6"

# Use the following for development versions of Wasmer.
# wasmer-types = { package = "wasmer-types-near", git = "https://github.com/near/wasmer", branch = "near-main", optional = true }
# wasmer-compiler-singlepass = { package = "wasmer-compiler-singlepass-near", git = "https://github.com/near/wasmer", branch = "near-main", optional = true }
# wasmer-engine-universal = { package = "wasmer-engine-universal-near", git = "https://github.com/near/wasmer", branch = "near-main", optional = true }
# wasmer-vm = { package = "wasmer-vm-near", git = "https://github.com/near/wasmer", branch = "near-main" }
wasmer-compiler = { package = "wasmer-compiler-near", version = "=2.2.0", optional = true }
wasmer-compiler-singlepass = { package = "wasmer-compiler-singlepass-near", version = "=2.2.0", optional = true }
wasmer-engine = { package = "wasmer-engine-near", version = "=2.2.0", optional = true }
wasmer-engine-universal = { package = "wasmer-engine-universal-near", version = "=2.2.0", optional = true, features = ["compiler"] }
wasmer-types = { package = "wasmer-types-near", version = "=2.2.0", optional = true }
wasmer-vm = { package = "wasmer-vm-near", version = "=2.2.0", optional = true }

loupe = "0.1"
once_cell = "1.5.2"
pwasm-utils = "0.18"
Expand All @@ -52,6 +38,22 @@ threadpool = "1.8.1"
pwasm-utils_12 = { package = "pwasm-utils", version = "0.12" }
parity-wasm_41 = { package = "parity-wasm", version = "0.41" }

[target.'cfg(target_arch = "x86_64")'.dependencies]
wasmer-runtime = { version = "0.18.0", features = ["default-backend-singlepass"], default-features = false, package = "wasmer-runtime-near", optional = true }
wasmer-runtime-core = { version = "0.18.2", package = "wasmer-runtime-core-near", optional = true}

# Use the following for development versions of Wasmer.
# wasmer-types = { package = "wasmer-types-near", git = "https://github.com/near/wasmer", branch = "near-main", optional = true }
# wasmer-compiler-singlepass = { package = "wasmer-compiler-singlepass-near", git = "https://github.com/near/wasmer", branch = "near-main", optional = true }
# wasmer-engine-universal = { package = "wasmer-engine-universal-near", git = "https://github.com/near/wasmer", branch = "near-main", optional = true }
# wasmer-vm = { package = "wasmer-vm-near", git = "https://github.com/near/wasmer", branch = "near-main" }
wasmer-compiler = { package = "wasmer-compiler-near", version = "=2.2.0", optional = true }
wasmer-compiler-singlepass = { package = "wasmer-compiler-singlepass-near", version = "=2.2.0", optional = true }
wasmer-engine = { package = "wasmer-engine-near", version = "=2.2.0", optional = true }
wasmer-engine-universal = { package = "wasmer-engine-universal-near", version = "=2.2.0", optional = true, features = ["compiler"] }
wasmer-types = { package = "wasmer-types-near", version = "=2.2.0", optional = true }
wasmer-vm = { package = "wasmer-vm-near", version = "=2.2.0", optional = true }


[dev-dependencies]
near-test-contracts = { path = "../near-test-contracts" }
Expand Down
36 changes: 21 additions & 15 deletions runtime/near-vm-runner/src/cache.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
use crate::errors::ContractPrecompilatonResult;
use crate::prepare;
use crate::vm_kind::VMKind;
use borsh::{BorshDeserialize, BorshSerialize};
use near_primitives::contract::ContractCode;
use near_primitives::hash::CryptoHash;
use near_primitives::types::CompiledContractCache;
use near_vm_errors::{CacheError, CompilationError, FunctionCallError, VMError};
use near_vm_errors::{CacheError, CompilationError};
use near_vm_logic::{ProtocolVersion, VMConfig};
use std::collections::HashMap;
use std::fmt;
use std::sync::{Arc, Mutex};

#[cfg(target_arch = "x86_64")]
use crate::prepare;
#[cfg(target_arch = "x86_64")]
use near_vm_errors::{FunctionCallError, VMError};

#[derive(Debug, Clone, BorshSerialize)]
enum ContractCacheKey {
_Version1,
Expand All @@ -32,13 +36,13 @@ enum CacheRecord {

fn vm_hash(vm_kind: VMKind) -> u64 {
match vm_kind {
#[cfg(feature = "wasmer0_vm")]
#[cfg(all(feature = "wasmer0_vm", target_arch = "x86_64"))]
VMKind::Wasmer0 => crate::wasmer_runner::wasmer0_vm_hash(),
#[cfg(not(feature = "wasmer0_vm"))]
#[cfg(not(all(feature = "wasmer0_vm", target_arch = "x86_64")))]
VMKind::Wasmer0 => panic!("Wasmer0 is not enabled"),
#[cfg(feature = "wasmer2_vm")]
#[cfg(all(feature = "wasmer2_vm", target_arch = "x86_64"))]
VMKind::Wasmer2 => crate::wasmer2_runner::wasmer2_vm_hash(),
#[cfg(not(feature = "wasmer2_vm"))]
#[cfg(not(all(feature = "wasmer2_vm", target_arch = "x86_64")))]
VMKind::Wasmer2 => panic!("Wasmer2 is not enabled"),
#[cfg(feature = "wasmtime_vm")]
VMKind::Wasmtime => crate::wasmtime_runner::wasmtime_vm_hash(),
Expand All @@ -62,6 +66,7 @@ pub fn get_contract_cache_key(
near_primitives::hash::hash(&key.try_to_vec().unwrap())
}

#[cfg(target_arch = "x86_64")]
fn cache_error(
error: &CompilationError,
key: &CryptoHash,
Expand All @@ -73,6 +78,7 @@ fn cache_error(
Ok(())
}

#[cfg(target_arch = "x86_64")]
pub fn into_vm_result<T>(
res: Result<Result<T, CompilationError>, CacheError>,
) -> Result<T, VMError> {
Expand Down Expand Up @@ -114,23 +120,23 @@ impl fmt::Debug for MockCompiledContractCache {
}
}

#[cfg(not(feature = "no_cache"))]
#[cfg(all(not(feature = "no_cache"), target_arch = "x86_64"))]
const CACHE_SIZE: usize = 128;

#[cfg(all(feature = "wasmer0_vm", not(feature = "no_cache")))]
#[cfg(all(feature = "wasmer0_vm", not(feature = "no_cache"), target_arch = "x86_64"))]
static WASMER_CACHE: once_cell::sync::Lazy<
near_cache::SyncLruCache<CryptoHash, Result<wasmer_runtime::Module, CompilationError>>,
> = once_cell::sync::Lazy::new(|| near_cache::SyncLruCache::new(CACHE_SIZE));

#[cfg(all(feature = "wasmer2_vm", not(feature = "no_cache")))]
#[cfg(all(feature = "wasmer2_vm", not(feature = "no_cache"), target_arch = "x86_64"))]
static WASMER2_CACHE: once_cell::sync::Lazy<
near_cache::SyncLruCache<
CryptoHash,
Result<crate::wasmer2_runner::VMArtifact, CompilationError>,
>,
> = once_cell::sync::Lazy::new(|| near_cache::SyncLruCache::new(CACHE_SIZE));

#[cfg(feature = "wasmer0_vm")]
#[cfg(all(feature = "wasmer0_vm", target_arch = "x86_64"))]
pub mod wasmer0_cache {
use super::*;
use near_vm_errors::CompilationError;
Expand Down Expand Up @@ -243,7 +249,7 @@ pub mod wasmer0_cache {
}
}

#[cfg(feature = "wasmer2_vm")]
#[cfg(all(feature = "wasmer2_vm", target_arch = "x86_64"))]
pub mod wasmer2_cache {
use crate::wasmer2_runner::{VMArtifact, Wasmer2VM};
use near_primitives::contract::ContractCode;
Expand Down Expand Up @@ -367,19 +373,19 @@ pub fn precompile_contract_vm(
None => {}
};
match vm_kind {
#[cfg(feature = "wasmer0_vm")]
#[cfg(all(feature = "wasmer0_vm", target_arch = "x86_64"))]
VMKind::Wasmer0 => {
Ok(wasmer0_cache::compile_and_serialize_wasmer(wasm_code.code(), config, &key, cache)?
.map(|_| ContractPrecompilatonResult::ContractCompiled))
}
#[cfg(not(feature = "wasmer0_vm"))]
#[cfg(not(all(feature = "wasmer0_vm", target_arch = "x86_64")))]
VMKind::Wasmer0 => panic!("Wasmer0 is not enabled!"),
#[cfg(feature = "wasmer2_vm")]
#[cfg(all(feature = "wasmer2_vm", target_arch = "x86_64"))]
VMKind::Wasmer2 => {
Ok(wasmer2_cache::compile_and_serialize_wasmer2(wasm_code.code(), &key, config, cache)?
.map(|_| ContractPrecompilatonResult::ContractCompiled))
}
#[cfg(not(feature = "wasmer2_vm"))]
#[cfg(not(all(feature = "wasmer2_vm", target_arch = "x86_64")))]
VMKind::Wasmer2 => panic!("Wasmer2 is not enabled!"),
VMKind::Wasmtime => panic!("Not yet supported"),
}
Expand Down
4 changes: 2 additions & 2 deletions runtime/near-vm-runner/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ imports! {
#["protocol_feature_alt_bn128", AltBn128] alt_bn128_pairing_check<[value_len: u64, value_ptr: u64] -> [u64]>,
}

#[cfg(feature = "wasmer0_vm")]
#[cfg(all(feature = "wasmer0_vm", target_arch = "x86_64"))]
pub(crate) mod wasmer {
use super::str_eq;
use near_vm_logic::{ProtocolVersion, VMLogic, VMLogicError};
Expand Down Expand Up @@ -272,7 +272,7 @@ pub(crate) mod wasmer {
}
}

#[cfg(feature = "wasmer2_vm")]
#[cfg(all(feature = "wasmer2_vm", target_arch = "x86_64"))]
pub(crate) mod wasmer2 {
use std::sync::Arc;

Expand Down
8 changes: 5 additions & 3 deletions runtime/near-vm-runner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
mod cache;
mod errors;
mod imports;
#[cfg(feature = "wasmer0_vm")]
#[cfg(all(feature = "wasmer0_vm", target_arch = "x86_64"))]
mod memory;
#[cfg(target_arch = "x86_64")]
mod preload;
pub mod prepare;
mod runner;
#[cfg(test)]
mod tests;
mod vm_kind;
#[cfg(feature = "wasmer2_vm")]
#[cfg(all(feature = "wasmer2_vm", target_arch = "x86_64"))]
mod wasmer2_runner;
#[cfg(feature = "wasmer0_vm")]
#[cfg(all(feature = "wasmer0_vm", target_arch = "x86_64"))]
mod wasmer_runner;
#[cfg(feature = "wasmtime_vm")]
mod wasmtime_runner;
Expand All @@ -24,6 +25,7 @@ pub use near_vm_logic::with_ext_cost_counter;
pub use cache::{
get_contract_cache_key, precompile_contract, precompile_contract_vm, MockCompiledContractCache,
};
#[cfg(target_arch = "x86_64")]
pub use preload::{ContractCallPrepareRequest, ContractCallPrepareResult, ContractCaller};
pub use runner::{run, VM};

Expand Down
4 changes: 2 additions & 2 deletions runtime/near-vm-runner/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ impl VMKind {
/// This is not intended to be used by code other than standalone-vm-runner.
pub fn runtime(&self, config: VMConfig) -> Option<Box<dyn VM>> {
match self {
#[cfg(feature = "wasmer0_vm")]
#[cfg(all(feature = "wasmer0_vm", target_arch = "x86_64"))]
Self::Wasmer0 => Some(Box::new(crate::wasmer_runner::Wasmer0VM::new(config))),
#[cfg(feature = "wasmtime_vm")]
Self::Wasmtime => Some(Box::new(crate::wasmtime_runner::WasmtimeVM::new(config))),
#[cfg(feature = "wasmer2_vm")]
#[cfg(all(feature = "wasmer2_vm", target_arch = "x86_64"))]
Self::Wasmer2 => Some(Box::new(crate::wasmer2_runner::Wasmer2VM::new(config))),
#[allow(unreachable_patterns)] // reachable when some of the VMs are disabled.
_ => None,
Expand Down
4 changes: 2 additions & 2 deletions runtime/near-vm-runner/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ const PREDECESSOR_ACCOUNT_ID: &str = "carol";
const LATEST_PROTOCOL_VERSION: ProtocolVersion = ProtocolVersion::MAX;

fn with_vm_variants(runner: fn(VMKind) -> ()) {
#[cfg(feature = "wasmer0_vm")]
#[cfg(all(feature = "wasmer0_vm", target_arch = "x86_64"))]
runner(VMKind::Wasmer0);

#[cfg(feature = "wasmtime_vm")]
runner(VMKind::Wasmtime);

#[cfg(feature = "wasmer2_vm")]
#[cfg(all(feature = "wasmer2_vm", target_arch = "x86_64"))]
runner(VMKind::Wasmer2);
}

Expand Down
4 changes: 3 additions & 1 deletion runtime/near-vm-runner/src/tests/cache.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//! Tests that `CompiledContractCache` is working correctly.
//! Tests that `CompiledContractCache` is working correctly. Currently testing only wasmer code, so disabled outside of x86_64
#![cfg(target_arch = "x86_64")]

use super::{create_context, with_vm_variants, LATEST_PROTOCOL_VERSION};
use crate::internal::VMKind;
use crate::wasmer2_runner::Wasmer2VM;
Expand Down
3 changes: 3 additions & 0 deletions runtime/near-vm-runner/src/tests/contract_preload.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Currently only testing wasmer code, so disabled outside of x86_64
#![cfg(target_arch = "x86_64")]

use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread::sleep;
Expand Down
19 changes: 16 additions & 3 deletions runtime/near-vm-runner/src/vm_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ pub enum VMKind {

impl VMKind {
pub fn for_protocol_version(protocol_version: ProtocolVersion) -> VMKind {
// Only wasmtime supports non-x86_64 systems
#[cfg(all(
not(target_arch = "x86_64"),
any(feature = "force_wasmer0", feature = "force_wasmer2")
))]
compile_error!(
"Wasmer only supports x86_64, but a force_wasmer* feature was passed to near-vm-runner"
);

if cfg!(feature = "force_wasmer0") {
return VMKind::Wasmer0;
}
Expand All @@ -30,10 +39,14 @@ impl VMKind {
return VMKind::Wasmer2;
}

if checked_feature!("stable", Wasmer2, protocol_version) {
VMKind::Wasmer2
if cfg!(target_arch = "x86_64") {
if checked_feature!("stable", Wasmer2, protocol_version) {
VMKind::Wasmer2
} else {
VMKind::Wasmer0
}
} else {
VMKind::Wasmer0
VMKind::Wasmtime
}
}
}

0 comments on commit d1d4559

Please sign in to comment.