Skip to content

Commit

Permalink
Added Singlepass backend
Browse files Browse the repository at this point in the history
  • Loading branch information
syrusakbary committed Apr 22, 2020
1 parent 5020116 commit 5eef30c
Show file tree
Hide file tree
Showing 14 changed files with 225 additions and 8 deletions.
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ autoexamples = false
wasmer = { path = "lib/api" }
wasmer-compiler = { path = "lib/compiler" }
wasmer-compiler-cranelift = { path = "lib/compiler-cranelift", optional = true }
wasmer-compiler-singlepass = { path = "lib/compiler-singlepass", optional = true }
wasmer-jit = { path = "lib/jit" }
atty = "0.2"
anyhow = "1.0.28"
Expand All @@ -43,6 +44,7 @@ anyhow = "1.0.28"
test-utils = { path = "tests/lib/test-utils" }
wasmer = { path = "lib/api" }
wasmer-compiler = { path = "lib/compiler" }
wasmer-compiler-singlepass = { path = "lib/compiler-singlepass" }
wasmer-compiler-cranelift = { path = "lib/compiler-cranelift" }
wasmer-jit = { path = "lib/jit" }
wasmer-wast = { path = "tests/lib/wast" }
Expand All @@ -52,6 +54,9 @@ wasmer-wast = { path = "tests/lib/wast" }
# since we might want to autoconfigure them depending on the availability on the host.
# default = ["wasi"]
default = ["compiler-cranelift"]
compiler-singlepass = [
"wasmer-compiler-singlepass",
]
compiler-cranelift = [
"wasmer-compiler-cranelift",
]
Expand Down
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn main() -> anyhow::Result<()> {
ignores: ignores.clone(),
};

let backends = vec!["cranelift"];
let backends = vec!["singlepass", "cranelift"];
with_backends(&mut spectests, &backends, |mut spectests| {
with_test_module(&mut spectests, "spec", |spectests| {
let _spec_tests = test_directory(spectests, "tests/wast/spec", wast_processor)?;
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler-cranelift/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license = "MIT OR (Apache-2.0 WITH LLVM-exception)"
repository = "https://github.com/wasmerio/wasmer"
documentation = "https://docs.rs/wasmer-compiler-cranelift/"
categories = ["wasm"]
keywords = ["webassembly", "wasm"]
keywords = ["webassembly", "wasm", "compiler", "cranelift"]
readme = "README.md"
edition = "2018"

Expand Down
2 changes: 1 addition & 1 deletion lib/compiler-llvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.16.2"
license = "MIT"
authors = ["The Wasmer Engineering Team <[email protected]>"]
repository = "https://github.com/wasmerio/wasmer"
keywords = ["wasm", "webassembly", "compiler", "JIT", "llvm"]
keywords = ["webassembly", "wasm", "compiler", "llvm"]
categories = ["wasm"]
edition = "2018"
readme = "README.md"
Expand Down
32 changes: 32 additions & 0 deletions lib/compiler-singlepass/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "wasmer-compiler-singlepass"
version = "0.16.2"
authors = ["Wasmer Engineering Team <[email protected]>"]
description = "Standalone environment support for WebAsssembly code in Singlepass"
license = "MIT OR (Apache-2.0 WITH LLVM-exception)"
repository = "https://github.com/wasmerio/wasmer"
documentation = "https://docs.rs/wasmer-compiler-singlepass/"
categories = ["wasm"]
keywords = ["webassembly", "wasm", "compiler", "singlepass"]
readme = "README.md"
edition = "2018"

[dependencies]
hashbrown = { version = "0.7.1", optional = true }
log = { version = "0.4.8", default-features = false }
wasmer-compiler = { path = "../compiler", version = "0.16.2", default-features = false }
wasmer-runtime = { path = "../runtime", version = "0.16.2" }
wasm-common = { path = "../wasm-common", version = "0.16.2", default-features = false }
wasmparser = "0.51.4"
rayon = "1.3.0"
serde = { version = "1.0.106", features = ["derive"] }
more-asserts = "0.2.1"

[badges]
maintenance = { status = "actively-developed" }

[features]
default = ["std", "enable-serde"]
enable-serde = ["wasmer-compiler/enable-serde", "wasm-common/enable-serde"]
std = ["wasmer-compiler/std", "wasm-common/std"]
core = ["hashbrown"]
77 changes: 77 additions & 0 deletions lib/compiler-singlepass/src/compiler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//! Support for compiling with Singlepass.
// Allow unused imports while developing.
#![allow(unused_imports, dead_code)]

use crate::config::SinglepassConfig;
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
use wasm_common::entity::{EntityRef, PrimaryMap};
use wasm_common::Features;
use wasm_common::{FuncIndex, FuncType, LocalFuncIndex, MemoryIndex, TableIndex};
use wasmer_compiler::FunctionBodyData;
use wasmer_compiler::TrapInformation;
use wasmer_compiler::{Compilation, CompileError, CompiledFunction, Compiler};
use wasmer_compiler::{CompilerConfig, ModuleTranslationState, Target};
use wasmer_runtime::Module;
use wasmer_runtime::TrapCode;
use wasmer_runtime::{MemoryPlan, TablePlan};

/// A compiler that compiles a WebAssembly module with Singlepass.
/// It does the compilation in one pass
pub struct SinglepassCompiler {
config: SinglepassConfig,
}

impl SinglepassCompiler {
/// Creates a new Singlepass compiler
pub fn new(config: &SinglepassConfig) -> Self {
Self {
config: config.clone(),
}
}

/// Gets the WebAssembly features for this Compiler
fn config(&self) -> &SinglepassConfig {
&self.config
}
}

impl Compiler for SinglepassCompiler {
/// Gets the WebAssembly features for this Compiler
fn features(&self) -> &Features {
self.config.features()
}

/// Gets the target associated to this Compiler.
fn target(&self) -> &Target {
self.config.target()
}

/// Compile the module using LLVM, producing a compilation result with
/// associated relocations.
fn compile_module(
&self,
_module: &Module,
_module_translation: &ModuleTranslationState,
_function_body_inputs: PrimaryMap<LocalFuncIndex, FunctionBodyData<'_>>,
_memory_plans: PrimaryMap<MemoryIndex, MemoryPlan>,
_table_plans: PrimaryMap<TableIndex, TablePlan>,
) -> Result<Compilation, CompileError> {
// Note to implementors: please use rayon paralell iterator to generate
// the machine code in parallel.
// Here's an example on how Cranelift is doing it:
// https://github.com/wasmerio/wasmer-reborn/blob/master/lib/compiler-cranelift/src/compiler.rs#L202-L267
Err(CompileError::Codegen(
"Singlepass compilation not supported yet".to_owned(),
))
}

fn compile_wasm_trampolines(
&self,
_signatures: &[FuncType],
) -> Result<Vec<CompiledFunction>, CompileError> {
// Note: do not implement this yet
Err(CompileError::Codegen(
"Singlepass trampoline compilation not supported yet".to_owned(),
))
}
}
64 changes: 64 additions & 0 deletions lib/compiler-singlepass/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Allow unused imports while developing
#![allow(unused_imports, dead_code)]

use crate::compiler::SinglepassCompiler;
use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, Features, Target};

#[derive(Clone)]
pub struct SinglepassConfig {
/// Enable NaN canonicalization.
///
/// NaN canonicalization is useful when trying to run WebAssembly
/// deterministically across different architectures.
pub enable_nan_canonicalization: bool,

features: Features,
target: Target,
}

impl SinglepassConfig {
/// Creates a new configuration object with the default configuration
/// specified.
pub fn new() -> Self {
Self {
enable_nan_canonicalization: true,
features: Default::default(),
target: Default::default(),
}
}
}

impl CompilerConfig for SinglepassConfig {
/// Gets the WebAssembly features
fn features(&self) -> &Features {
&self.features
}

/// Gets the WebAssembly features, mutable
fn features_mut(&mut self) -> &mut Features {
&mut self.features
}

/// Gets the target that we will use for compiling
/// the WebAssembly module
fn target(&self) -> &Target {
&self.target
}

/// Gets the target that we will use for compiling
/// the WebAssembly module, mutable
fn target_mut(&mut self) -> &mut Target {
&mut self.target
}

/// Transform it into the compiler
fn compiler(&self) -> Box<dyn Compiler> {
Box::new(SinglepassCompiler::new(&self))
}
}

impl Default for SinglepassConfig {
fn default() -> SinglepassConfig {
SinglepassConfig::new()
}
}
15 changes: 15 additions & 0 deletions lib/compiler-singlepass/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! A WebAssembly `Compiler` implementation using Singlepass.
//!
//! Singlepass is a super-fast assembly generator that generates
//! assembly code in just one pass. This is useful for different applications
//! including Blockchains and Edge computing where quick compilation
//! times are a must, and JIT bombs should never happen.
//!
//! Compared to Cranelift and LLVM, Singlepass is much faster to compile.
//! > Note: Singlepass currently depends on Rust nightly features.
mod compiler;
mod config;

pub use crate::compiler::SinglepassCompiler;
pub use crate::config::SinglepassConfig;
2 changes: 1 addition & 1 deletion lib/compiler/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl Default for Target {
///
/// This options must have WebAssembly `Features` and a specific
/// `Target` to compile to.
pub trait CompilerConfig: Clone {
pub trait CompilerConfig {
/// Gets the WebAssembly features
fn features(&self) -> &Features;

Expand Down
1 change: 1 addition & 0 deletions tests/lib/test-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ private = true

[dependencies]
wasmer-compiler = { path = "../../../lib/compiler", version = "0.16.2" }
wasmer-compiler-singlepass = { path = "../../../lib/compiler-singlepass", version = "0.16.2" }
wasmer-compiler-cranelift = { path = "../../../lib/compiler-cranelift", version = "0.16.2" }
10 changes: 8 additions & 2 deletions tests/lib/test-utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
use wasmer_compiler::CompilerConfig;
use wasmer_compiler_cranelift::CraneliftConfig;
use wasmer_compiler_singlepass::SinglepassConfig;

pub fn get_compiler_config_from_str(
compiler_name: &str,
try_nan_canonicalization: bool,
) -> impl CompilerConfig {
) -> Box<dyn CompilerConfig> {
match compiler_name {
"singlepass" => {
let mut singlepass_config = SinglepassConfig::default();
singlepass_config.enable_nan_canonicalization = try_nan_canonicalization;
Box::new(singlepass_config)
}
"cranelift" => {
let mut cranelift_config = CraneliftConfig::default();
cranelift_config.enable_nan_canonicalization = try_nan_canonicalization;
cranelift_config
Box::new(cranelift_config)
}
_ => panic!("Compiler {} not supported", compiler_name),
}
Expand Down
2 changes: 1 addition & 1 deletion tests/lib/wast/src/wast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl Wast {
store,
import_object,
instances: HashMap::new(),
fail_fast: false,
fail_fast: true,
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/wast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> {
let try_nan_canonicalization = wast_path.contains("nan-canonicalization");
let mut compiler_config = get_compiler_config_from_str(compiler, try_nan_canonicalization);
compiler_config.features_mut().multi_value(true);
let store = Store::new(&Engine::new(&compiler_config));
let store = Store::new(&Engine::new(&*compiler_config));
let mut wast = Wast::new_with_spectest(store);
let path = Path::new(wast_path);
wast.run_file(path)
Expand Down

0 comments on commit 5eef30c

Please sign in to comment.