Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stylus: prepare support for cross-compilation #2417

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions arbitrator/jit/src/stylus_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use std::{
thread::JoinHandle,
};
use stylus::{native::NativeInstance, run::RunProgram};
use wasmer::Target;

struct MessageToCothread {
result: Vec<u8>,
Expand Down Expand Up @@ -143,8 +144,15 @@ pub fn exec_wasm(

let evm_api = EvmApiRequestor::new(cothread);

let mut instance =
unsafe { NativeInstance::deserialize(&module, compile.clone(), evm_api, evm_data) }?;
let mut instance = unsafe {
NativeInstance::deserialize(
&module,
compile.clone(),
evm_api,
evm_data,
Target::default(),
)
}?;

let thread = thread::spawn(move || {
let outcome = instance.run_main(&calldata, config, ink);
Expand Down
38 changes: 21 additions & 17 deletions arbitrator/prover/src/programs/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use {
meter::Meter, start::StartMover, MiddlewareWrapper,
},
std::sync::Arc,
wasmer::{Cranelift, CraneliftOptLevel, Engine, Store},
wasmer::{Cranelift, CraneliftOptLevel, Engine, Store, Target},
wasmer_compiler_singlepass::Singlepass,
};

Expand Down Expand Up @@ -180,17 +180,19 @@ impl CompileConfig {
}

#[cfg(feature = "native")]
pub fn store(&self) -> Store {
let mut compiler: Box<dyn wasmer::CompilerConfig> = match self.debug.cranelift {
pub fn engine(&self, target: Target) -> Engine {
use wasmer::sys::EngineBuilder;

let mut wasmer_config: Box<dyn wasmer::CompilerConfig> = match self.debug.cranelift {
true => {
let mut compiler = Cranelift::new();
compiler.opt_level(CraneliftOptLevel::Speed);
Box::new(compiler)
let mut wasmer_config = Cranelift::new();
wasmer_config.opt_level(CraneliftOptLevel::Speed);
Box::new(wasmer_config)
}
false => Box::new(Singlepass::new()),
};
compiler.canonicalize_nans(true);
compiler.enable_verifier();
wasmer_config.canonicalize_nans(true);
wasmer_config.enable_verifier();

let start = MiddlewareWrapper::new(StartMover::new(self.debug.debug_info));
let meter = MiddlewareWrapper::new(Meter::new(&self.pricing));
Expand All @@ -200,22 +202,24 @@ impl CompileConfig {

// add the instrumentation in the order of application
// note: this must be consistent with the prover
compiler.push_middleware(Arc::new(start));
compiler.push_middleware(Arc::new(meter));
compiler.push_middleware(Arc::new(dygas));
compiler.push_middleware(Arc::new(depth));
compiler.push_middleware(Arc::new(bound));
wasmer_config.push_middleware(Arc::new(start));
wasmer_config.push_middleware(Arc::new(meter));
wasmer_config.push_middleware(Arc::new(dygas));
wasmer_config.push_middleware(Arc::new(depth));
wasmer_config.push_middleware(Arc::new(bound));

if self.debug.count_ops {
let counter = Counter::new();
compiler.push_middleware(Arc::new(MiddlewareWrapper::new(counter)));
wasmer_config.push_middleware(Arc::new(MiddlewareWrapper::new(counter)));
}

Store::new(compiler)
EngineBuilder::new(wasmer_config)
.set_target(Some(target))
.into()
}

#[cfg(feature = "native")]
pub fn engine(&self) -> Engine {
self.store().engine().clone()
pub fn store(&self, target: Target) -> Store {
Store::new(self.engine(target))
}
}
15 changes: 13 additions & 2 deletions arbitrator/stylus/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use lru::LruCache;
use parking_lot::Mutex;
use prover::programs::config::CompileConfig;
use std::{collections::HashMap, num::NonZeroUsize};
use wasmer::{Engine, Module, Store};
use wasmer::{Engine, Module, Store, Target};

lazy_static! {
static ref INIT_CACHE: Mutex<InitCache> = Mutex::new(InitCache::new(256));
Expand All @@ -23,6 +23,7 @@ macro_rules! cache {
pub struct InitCache {
long_term: HashMap<CacheKey, CacheItem>,
lru: LruCache<CacheKey, CacheItem>,
target: Target,
}

#[derive(Clone, Copy, Hash, PartialEq, Eq)]
Expand Down Expand Up @@ -68,6 +69,7 @@ impl InitCache {
Self {
long_term: HashMap::new(),
lru: LruCache::new(NonZeroUsize::new(size).unwrap()),
target: Target::default(),
}
}

Expand All @@ -77,6 +79,14 @@ impl InitCache {
.resize(NonZeroUsize::new(size.try_into().unwrap()).unwrap())
}

pub fn set_target(target: Target) {
cache!().target = target;
}

pub fn target() -> Target {
cache!().target.clone()
}

/// Retrieves a cached value, updating items as necessary.
pub fn get(module_hash: Bytes32, version: u16, debug: bool) -> Option<(Module, Store)> {
let mut cache = cache!();
Expand Down Expand Up @@ -118,9 +128,10 @@ impl InitCache {
}
return Ok(item.data());
}
let target = cache.target.clone();
drop(cache);

let engine = CompileConfig::version(version, debug).engine();
let engine = CompileConfig::version(version, debug).engine(target);
let module = unsafe { Module::deserialize_unchecked(&engine, module)? };

let item = CacheItem::new(module, engine);
Expand Down
87 changes: 75 additions & 12 deletions arbitrator/stylus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use native::NativeInstance;
use prover::programs::{prelude::*, StylusData};
use run::RunProgram;
use std::{marker::PhantomData, mem, ptr};
use target_cache::{target_cache_get, target_cache_set};

pub use brotli;
pub use prover;
Expand All @@ -29,6 +30,7 @@ pub mod run;

mod cache;
mod evm_api;
mod target_cache;
mod util;

#[cfg(test)]
Expand Down Expand Up @@ -122,9 +124,9 @@ impl RustBytes {
}
}

/// Instruments and "activates" a user wasm.
/// "activates" a user wasm.
///
/// The `output` is either the serialized asm & module pair or an error string.
/// The `output` is either the module or an error string.
/// Returns consensus info such as the module hash and footprint on success.
///
/// Note that this operation costs gas and is limited by the amount supplied via the `gas` pointer.
Expand All @@ -140,7 +142,6 @@ pub unsafe extern "C" fn stylus_activate(
version: u16,
debug: bool,
output: *mut RustBytes,
asm_len: *mut usize,
codehash: *const Bytes32,
module_hash: *mut Bytes32,
stylus_data: *mut StylusData,
Expand All @@ -152,18 +153,80 @@ pub unsafe extern "C" fn stylus_activate(
let codehash = &*codehash;
let gas = &mut *gas;

let (asm, module, info) =
match native::activate(wasm, codehash, version, page_limit, debug, gas) {
Ok(val) => val,
Err(err) => return output.write_err(err),
};
*asm_len = asm.len();
let (module, info) = match native::activate(wasm, codehash, version, page_limit, debug, gas) {
Ok(val) => val,
Err(err) => return output.write_err(err),
};

*module_hash = module.hash();
*stylus_data = info;

let mut data = asm;
data.extend(&*module.into_bytes());
output.write(data);
output.write(module.into_bytes());
UserOutcomeKind::Success
}

/// "compiles" a user wasm.
///
/// The `output` is either the asm or an error string.
/// Returns consensus info such as the module hash and footprint on success.
///
/// # Safety
///
/// `output` must not be null.
#[no_mangle]
pub unsafe extern "C" fn stylus_compile(
wasm: GoSliceData,
version: u16,
debug: bool,
name: GoSliceData,
output: *mut RustBytes,
) -> UserOutcomeKind {
let wasm = wasm.slice();
let output = &mut *output;
let name = String::from_utf8_unchecked(name.slice().to_vec());
let target = match target_cache_get(&name) {
Ok(val) => val,
Err(err) => return output.write_err(err),
};

let asm = match native::compile(wasm, version, debug, target) {
Ok(val) => val,
Err(err) => return output.write_err(err),
};

output.write(asm);
UserOutcomeKind::Success
}

/// sets target index to a string
///
/// String format is: Triple+CpuFeature+CpuFeature..
///
/// # Safety
///
/// `output` must not be null.
#[no_mangle]
pub unsafe extern "C" fn stylus_target_set(
name: GoSliceData,
description: GoSliceData,
output: *mut RustBytes,
native: bool,
) -> UserOutcomeKind {
let output = &mut *output;
let name = match String::from_utf8(name.slice().to_vec()) {
Ok(val) => val,
Err(err) => return output.write_err(err.into()),
};

let desc_str = match String::from_utf8(description.slice().to_vec()) {
Ok(val) => val,
Err(err) => return output.write_err(err.into()),
};

if let Err(err) = target_cache_set(name, desc_str, native) {
return output.write_err(err);
};

UserOutcomeKind::Success
}

Expand Down
29 changes: 15 additions & 14 deletions arbitrator/stylus/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use crate::{
cache::InitCache,
env::{MeterData, WasmEnv},
host, util,
host,
};
use arbutil::{
evm::{
Expand Down Expand Up @@ -33,7 +33,7 @@ use std::{
ops::{Deref, DerefMut},
};
use wasmer::{
imports, AsStoreMut, Function, FunctionEnv, Instance, Memory, Module, Pages, Store,
imports, AsStoreMut, Function, FunctionEnv, Instance, Memory, Module, Pages, Store, Target,
TypedFunction, Value, WasmTypeList,
};
use wasmer_vm::VMExtern;
Expand Down Expand Up @@ -96,9 +96,10 @@ impl<D: DataReader, E: EvmApi<D>> NativeInstance<D, E> {
compile: CompileConfig,
evm: E,
evm_data: EvmData,
target: Target,
) -> Result<Self> {
let env = WasmEnv::new(compile, None, evm, evm_data);
let store = env.compile.store();
let store = env.compile.store(target);
let module = unsafe { Module::deserialize_unchecked(&store, module)? };
Self::from_module(module, store, env)
}
Expand Down Expand Up @@ -137,9 +138,10 @@ impl<D: DataReader, E: EvmApi<D>> NativeInstance<D, E> {
evm_data: EvmData,
compile: &CompileConfig,
config: StylusConfig,
target: Target,
) -> Result<Self> {
let env = WasmEnv::new(compile.clone(), Some(config), evm_api, evm_data);
let store = env.compile.store();
let store = env.compile.store(target);
let wat_or_wasm = std::fs::read(path)?;
let module = Module::new(&store, wat_or_wasm)?;
Self::from_module(module, store, env)
Expand Down Expand Up @@ -347,8 +349,8 @@ impl<D: DataReader, E: EvmApi<D>> StartlessMachine for NativeInstance<D, E> {
}
}

pub fn module(wasm: &[u8], compile: CompileConfig) -> Result<Vec<u8>> {
let mut store = compile.store();
pub fn module(wasm: &[u8], compile: CompileConfig, target: Target) -> Result<Vec<u8>> {
let mut store = compile.store(target);
let module = Module::new(&store, wasm)?;
macro_rules! stub {
(u8 <- $($types:tt)+) => {
Expand Down Expand Up @@ -428,7 +430,6 @@ pub fn module(wasm: &[u8], compile: CompileConfig) -> Result<Vec<u8>> {
imports.define("console", "tee_f64", stub!(f64 <- |_: f64|));
imports.define("debug", "null_host", stub!(||));
}
Instance::new(&mut store, &module, &imports)?;

let module = module.serialize()?;
Ok(module.to_vec())
Expand All @@ -441,14 +442,14 @@ pub fn activate(
page_limit: u16,
debug: bool,
gas: &mut u64,
) -> Result<(Vec<u8>, ProverModule, StylusData)> {
let compile = CompileConfig::version(version, debug);
) -> Result<(ProverModule, StylusData)> {
let (module, stylus_data) =
ProverModule::activate(wasm, codehash, version, page_limit, debug, gas)?;

let asm = match self::module(wasm, compile) {
Ok(asm) => asm,
Err(err) => util::panic_with_wasm(wasm, err),
};
Ok((asm, module, stylus_data))
Ok((module, stylus_data))
}

pub fn compile(wasm: &[u8], version: u16, debug: bool, target: Target) -> Result<Vec<u8>> {
let compile = CompileConfig::version(version, debug);
self::module(wasm, compile, target)
}
Loading
Loading