diff --git a/lib/api/src/backend/js/entities/engine.rs b/lib/api/src/backend/js/entities/engine.rs index 96df07412ea3..cdb2316c3075 100644 --- a/lib/api/src/backend/js/entities/engine.rs +++ b/lib/api/src/backend/js/entities/engine.rs @@ -5,9 +5,9 @@ use wasmer_types::{target::Target, Features}; pub struct Engine; impl Engine { - pub(crate) fn deterministic_id(&self) -> &str { + pub(crate) fn deterministic_id(&self) -> String { // All js engines have the same id - "js-generic" + String::from("js-generic") } /// Returns the WebAssembly features supported by the JS engine. diff --git a/lib/api/src/backend/jsc/entities/engine.rs b/lib/api/src/backend/jsc/entities/engine.rs index 05b4fc924dd4..c026f4b18fc7 100644 --- a/lib/api/src/backend/jsc/entities/engine.rs +++ b/lib/api/src/backend/jsc/entities/engine.rs @@ -166,9 +166,9 @@ impl JSCEngine { } impl Engine { - pub(crate) fn deterministic_id(&self) -> &str { + pub(crate) fn deterministic_id(&self) -> String { // All js engines have the same id - "javascriptcore" + String::from("javascriptcore") } /// Returns the WebAssembly features supported by the JSC engine for the given target. diff --git a/lib/api/src/backend/v8/entities/engine.rs b/lib/api/src/backend/v8/entities/engine.rs index 75cc5f682f28..5e5e44de7c07 100644 --- a/lib/api/src/backend/v8/entities/engine.rs +++ b/lib/api/src/backend/v8/entities/engine.rs @@ -50,8 +50,8 @@ impl Engine { Self::default() } - pub(crate) fn deterministic_id(&self) -> &str { - "v8" + pub(crate) fn deterministic_id(&self) -> String { + String::from("v8") } /// Returns the WebAssembly features supported by the V8 engine. diff --git a/lib/api/src/backend/wamr/entities/engine.rs b/lib/api/src/backend/wamr/entities/engine.rs index 6f8e5eee56d9..6e30b96cf354 100644 --- a/lib/api/src/backend/wamr/entities/engine.rs +++ b/lib/api/src/backend/wamr/entities/engine.rs @@ -36,8 +36,8 @@ impl Engine { Self::default() } - pub(crate) fn deterministic_id(&self) -> &str { - "wamr" + pub(crate) fn deterministic_id(&self) -> String { + String::from("wamr") } /// Returns the WebAssembly features supported by the WAMR engine. diff --git a/lib/api/src/backend/wasmi/entities/engine.rs b/lib/api/src/backend/wasmi/entities/engine.rs index 89d8244efd30..896d40fce375 100644 --- a/lib/api/src/backend/wasmi/entities/engine.rs +++ b/lib/api/src/backend/wasmi/entities/engine.rs @@ -36,8 +36,8 @@ impl Engine { Self::default() } - pub(crate) fn deterministic_id(&self) -> &str { - "wasmi" + pub(crate) fn deterministic_id(&self) -> String { + String::from("wasmi") } /// Returns the WebAssembly features supported by the WASMI engine. diff --git a/lib/api/src/entities/engine/inner.rs b/lib/api/src/entities/engine/inner.rs index 78c6cacaa99e..8c0326e1d6c3 100644 --- a/lib/api/src/entities/engine/inner.rs +++ b/lib/api/src/entities/engine/inner.rs @@ -17,7 +17,7 @@ gen_rt_ty!(Engine @derives Debug, Clone); impl BackendEngine { /// Returns the deterministic id of this engine. #[inline] - pub fn deterministic_id(&self) -> &str { + pub fn deterministic_id(&self) -> String { match_rt!(on self => s { s.deterministic_id() }) diff --git a/lib/api/src/entities/engine/mod.rs b/lib/api/src/entities/engine/mod.rs index 881813a872a4..96cec93b4df8 100644 --- a/lib/api/src/entities/engine/mod.rs +++ b/lib/api/src/entities/engine/mod.rs @@ -2,7 +2,10 @@ use bytes::Bytes; use std::{path::Path, sync::Arc}; -use wasmer_types::{target::Target, DeserializeError, Features}; +use wasmer_types::{ + target::{Target, UserCompilerOptimizations}, + CompileError, DeserializeError, Features, +}; #[cfg(feature = "sys")] use wasmer_compiler::Artifact; @@ -51,7 +54,7 @@ impl Engine { } /// Returns the deterministic id of this engine. - pub fn deterministic_id(&self) -> &str { + pub fn deterministic_id(&self) -> String { self.be.deterministic_id() } @@ -223,4 +226,22 @@ impl Engine { ) -> Result, DeserializeError> { self.be.deserialize_from_file_unchecked(file_ref) } + + /// Add suggested optimizations to this engine. + /// + /// # Note + /// + /// Not every backend supports every optimization. This function may fail (i.e. not set the + /// suggested optimizations) silently if the underlying engine backend does not support one or + /// more optimizations. + pub fn with_opts( + &mut self, + suggested_opts: &UserCompilerOptimizations, + ) -> Result<(), CompileError> { + match self.be { + #[cfg(feature = "sys")] + BackendEngine::Sys(ref mut e) => e.with_opts(suggested_opts), + _ => Ok(()), + } + } } diff --git a/lib/cli/src/commands/init.rs b/lib/cli/src/commands/init.rs index d32866638b09..26b416bb3acf 100644 --- a/lib/cli/src/commands/init.rs +++ b/lib/cli/src/commands/init.rs @@ -491,6 +491,7 @@ async fn construct_manifest( map.insert("wasi".to_string(), "0.1.0-unstable".to_string()); map }), + annotations: None, }]; let mut pkg = wasmer_config::package::Package::builder( diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index ae682f67a42b..78156ef832ef 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -49,6 +49,7 @@ use wasmer_types::{ /// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR, /// optimizing it and then translating to assembly. +#[derive(Debug)] pub struct CraneliftCompiler { config: Cranelift, } @@ -70,6 +71,10 @@ impl Compiler for CraneliftCompiler { "cranelift" } + fn deterministic_id(&self) -> String { + String::from("cranelift") + } + /// Get the middlewares for this compiler fn get_middlewares(&self) -> &[Arc] { &self.config.middlewares diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index c41e80e70916..1d8a9a0dac73 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -29,6 +29,7 @@ use wasmer_vm::LibCall; /// A compiler that compiles a WebAssembly module with LLVM, translating the Wasm to LLVM IR, /// optimizing it and then translating to assembly. +#[derive(Debug)] pub struct LLVMCompiler { config: LLVM, } @@ -261,6 +262,24 @@ impl Compiler for LLVMCompiler { "llvm" } + fn deterministic_id(&self) -> String { + let mut ret = format!( + "llvm-{}", + match self.config.opt_level { + inkwell::OptimizationLevel::None => "opt0", + inkwell::OptimizationLevel::Less => "optl", + inkwell::OptimizationLevel::Default => "optd", + inkwell::OptimizationLevel::Aggressive => "opta", + } + ); + + if self.config.enable_g0m0_opt { + ret.push_str("-g0m0"); + } + + ret + } + /// Get the middlewares for this compiler fn get_middlewares(&self) -> &[Arc] { &self.config.middlewares @@ -538,4 +557,14 @@ impl Compiler for LLVMCompiler { got, }) } + + fn with_opts( + &mut self, + suggested_compiler_opts: &wasmer_types::target::UserCompilerOptimizations, + ) -> Result<(), CompileError> { + if suggested_compiler_opts.pass_params.is_some_and(|v| v) { + self.config.enable_g0m0_opt = true; + } + Ok(()) + } } diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index e5733774ec58..a48140a466b9 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -38,6 +38,7 @@ use wasmer_types::{ /// A compiler that compiles a WebAssembly module with Singlepass. /// It does the compilation in one pass +#[derive(Debug)] pub struct SinglepassCompiler { config: Singlepass, } @@ -59,6 +60,10 @@ impl Compiler for SinglepassCompiler { "singlepass" } + fn deterministic_id(&self) -> String { + String::from("singlepass") + } + /// Get the middlewares for this compiler fn get_middlewares(&self) -> &[Arc] { &self.config.middlewares diff --git a/lib/compiler/src/compiler.rs b/lib/compiler/src/compiler.rs index 8167c78a0207..c11134080340 100644 --- a/lib/compiler/src/compiler.rs +++ b/lib/compiler/src/compiler.rs @@ -12,7 +12,7 @@ use enumset::EnumSet; use wasmer_types::{ entity::PrimaryMap, error::CompileError, - target::{CpuFeature, Target}, + target::{CpuFeature, Target, UserCompilerOptimizations}, Features, LocalFunctionIndex, }; #[cfg(feature = "translator")] @@ -75,12 +75,31 @@ where } /// An implementation of a Compiler from parsed WebAssembly module to Compiled native code. -pub trait Compiler: Send { +pub trait Compiler: Send + std::fmt::Debug { /// Returns a descriptive name for this compiler. /// /// Note that this is an API breaking change since 3.0 fn name(&self) -> &str; + /// Returns the deterministic id of this compiler. Same compilers with different + /// optimizations map to different deterministic IDs. + fn deterministic_id(&self) -> String; + + /// Add suggested optimizations to this compiler. + /// + /// # Note + /// + /// Not every compiler supports every optimization. This function may fail (i.e. not set the + /// suggested optimizations) silently if the underlying compiler does not support one or + /// more optimizations. + fn with_opts( + &mut self, + suggested_compiler_opts: &UserCompilerOptimizations, + ) -> Result<(), CompileError> { + _ = suggested_compiler_opts; + Ok(()) + } + /// Validates a module. /// /// It returns the a succesful Result in case is valid, `CompileError` in case is not. diff --git a/lib/compiler/src/engine/inner.rs b/lib/compiler/src/engine/inner.rs index 01f555ce1c0f..7785aa7fb7f8 100644 --- a/lib/compiler/src/engine/inner.rs +++ b/lib/compiler/src/engine/inner.rs @@ -94,12 +94,21 @@ impl Engine { } /// Returns the deterministic id of this engine - pub fn deterministic_id(&self) -> &str { - // TODO: add a `deterministic_id` to the Compiler, so two - // compilers can actually serialize into a different deterministic_id - // if their configuration is different (eg. LLVM with optimizations vs LLVM - // without optimizations) - self.name.as_str() + pub fn deterministic_id(&self) -> String { + let i = self.inner(); + #[cfg(feature = "compiler")] + { + if let Some(ref c) = i.compiler { + return c.deterministic_id(); + } else { + return self.name.clone(); + } + } + + #[allow(unreachable_code)] + { + self.name.to_string() + } } /// Create a headless `Engine` @@ -283,11 +292,34 @@ impl Engine { pub fn tunables(&self) -> &dyn Tunables { self.tunables.as_ref() } + + /// Add suggested optimizations to this engine. + /// + /// # Note + /// + /// Not every backend supports every optimization. This function may fail (i.e. not set the + /// suggested optimizations) silently if the underlying engine backend does not support one or + /// more optimizations. + pub fn with_opts( + &mut self, + suggested_opts: &wasmer_types::target::UserCompilerOptimizations, + ) -> Result<(), CompileError> { + #[cfg(feature = "compiler")] + { + let mut i = self.inner_mut(); + if let Some(ref mut c) = i.compiler { + c.with_opts(suggested_opts)?; + } + } + + Ok(()) + } } impl std::fmt::Debug for Engine { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Engine") + .field("inner", &self.inner) .field("target", &self.target) .field("engine_id", &self.engine_id) .field("name", &self.name) @@ -313,6 +345,24 @@ pub struct EngineInner { signatures: SignatureRegistry, } +impl std::fmt::Debug for EngineInner { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut formatter = f.debug_struct("EngineInner"); + #[cfg(feature = "compiler")] + { + formatter.field("compiler", &self.compiler); + formatter.field("features", &self.features); + } + + #[cfg(not(target_arch = "wasm32"))] + { + formatter.field("signatures", &self.signatures); + } + + formatter.finish() + } +} + impl EngineInner { /// Gets the compiler associated to this engine. #[cfg(feature = "compiler")] diff --git a/lib/config/src/package/mod.rs b/lib/config/src/package/mod.rs index e21e7e1d2caf..2fb81ed7d056 100644 --- a/lib/config/src/package/mod.rs +++ b/lib/config/src/package/mod.rs @@ -503,6 +503,26 @@ pub struct Module { /// Interface definitions that can be used to generate bindings to this /// module. pub bindings: Option, + /// Miscellaneous annotations from the user. + #[serde(skip_serializing_if = "Option::is_none")] + pub annotations: Option, +} + +/// Miscellaneous annotations specified by the user. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] +pub struct UserAnnotations { + pub suggested_compiler_optimizations: SuggestedCompilerOptimizations, +} + +/// Suggested optimization that might be operated on the module when (and if) compiled. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] +pub struct SuggestedCompilerOptimizations { + pub pass_params: Option, +} + +impl SuggestedCompilerOptimizations { + pub const KEY: &'static str = "suggested_compiler_optimizations"; + pub const PASS_PARAMS_KEY: &'static str = "pass_params"; } /// The interface exposed by a [`Module`]. @@ -1007,6 +1027,7 @@ mod tests { interfaces: None, kind: Some("https://webc.org/kind/wasi".to_string()), source: Path::new("test.wasm").to_path_buf(), + annotations: None, }], commands: Vec::new(), fs: vec![ @@ -1062,6 +1083,7 @@ module = "mod" wit_exports: PathBuf::from("exports.wit"), wit_bindgen: "0.0.0".parse().unwrap() })), + annotations: None }, ); } diff --git a/lib/package/src/convert/webc_to_package.rs b/lib/package/src/convert/webc_to_package.rs index c15cbc17f232..81dea85b9093 100644 --- a/lib/package/src/convert/webc_to_package.rs +++ b/lib/package/src/convert/webc_to_package.rs @@ -1,6 +1,6 @@ use std::path::Path; -use wasmer_config::package::ModuleReference; +use wasmer_config::package::{ModuleReference, SuggestedCompilerOptimizations, UserAnnotations}; use webc::Container; @@ -150,6 +150,29 @@ pub fn webc_to_package_dir(webc: &Container, target_dir: &Path) -> Result<(), Co let relative_path = format!("./{module_dir_name}/{atom_name}"); + let mut annotations = None; + + if let Some(manifest_atom) = manifest.atoms.get(&atom_name) { + if let Some(sco) = manifest_atom + .annotations + .get(SuggestedCompilerOptimizations::KEY) + { + if let Some((_, v)) = sco.as_map().and_then(|v| { + v.iter().find(|(k, _)| { + k.as_text().is_some_and(|v| { + v == SuggestedCompilerOptimizations::PASS_PARAMS_KEY + }) + }) + }) { + annotations = Some(UserAnnotations { + suggested_compiler_optimizations: SuggestedCompilerOptimizations { + pass_params: Some(v.as_bool().unwrap_or_default()), + }, + }); + } + } + } + pkg_manifest.modules.push(wasmer_config::package::Module { name: atom_name, source: relative_path.into(), @@ -157,6 +180,7 @@ pub fn webc_to_package_dir(webc: &Container, target_dir: &Path) -> Result<(), Co kind: None, interfaces: None, bindings: None, + annotations, }); } } diff --git a/lib/package/src/package/manifest.rs b/lib/package/src/package/manifest.rs index c9d9519ea544..e716e46332d9 100644 --- a/lib/package/src/package/manifest.rs +++ b/lib/package/src/package/manifest.rs @@ -3,13 +3,14 @@ use std::{ path::{Path, PathBuf}, }; -use ciborium::Value; +use ciborium::{cbor, Value}; use semver::VersionReq; use sha2::Digest; use shared_buffer::{MmapError, OwnedBuffer}; use url::Url; #[allow(deprecated)] use wasmer_config::package::{CommandV1, CommandV2, Manifest as WasmerManifest, Package}; +use wasmer_config::package::{SuggestedCompilerOptimizations, UserAnnotations}; use webc::{ indexmap::{self, IndexMap}, metadata::AtomSignature, @@ -160,7 +161,7 @@ pub(crate) fn wasmer_manifest_to_webc( /// take a `wasmer.toml` manifest and convert it to the `*.webc` equivalent. pub(crate) fn in_memory_wasmer_manifest_to_webc( manifest: &WasmerManifest, - atoms: &BTreeMap, OwnedBuffer)>, + atoms: &BTreeMap, OwnedBuffer, Option<&UserAnnotations>)>, ) -> Result<(WebcManifest, BTreeMap), ManifestError> { let use_map = transform_dependencies(&manifest.dependencies)?; @@ -279,27 +280,41 @@ fn transform_atoms( error, })?; - atom_entries.insert(name.clone(), (module.kind.clone(), file)); + atom_entries.insert( + name.clone(), + (module.kind.clone(), file, module.annotations.as_ref()), + ); } transform_atoms_shared(&atom_entries) } fn transform_in_memory_atoms( - atoms: &BTreeMap, OwnedBuffer)>, + atoms: &BTreeMap, OwnedBuffer, Option<&UserAnnotations>)>, ) -> Result<(IndexMap, Atoms), ManifestError> { transform_atoms_shared(atoms) } fn transform_atoms_shared( - atoms: &BTreeMap, OwnedBuffer)>, + atoms: &BTreeMap, OwnedBuffer, Option<&UserAnnotations>)>, ) -> Result<(IndexMap, Atoms), ManifestError> { let mut atom_files = BTreeMap::new(); let mut metadata = IndexMap::new(); - for (name, (kind, content)) in atoms.iter() { + for (name, (kind, content, misc_annotations)) in atoms.iter() { // Create atom with annotations including Wasm features if available let mut annotations = IndexMap::new(); + if let Some(misc_annotations) = misc_annotations { + if let Some(pass_params) = misc_annotations + .suggested_compiler_optimizations + .pass_params + { + annotations.insert( + SuggestedCompilerOptimizations::KEY.to_string(), + cbor!({"pass_params" => pass_params}).unwrap(), + ); + } + } // Detect required WebAssembly features by analyzing the module binary let features_result = wasmer_types::Features::detect_from_wasm(content); diff --git a/lib/package/src/package/package.rs b/lib/package/src/package/package.rs index 4ca0f6955b19..74f8dc664dc9 100644 --- a/lib/package/src/package/package.rs +++ b/lib/package/src/package/package.rs @@ -355,8 +355,21 @@ impl Package { let volumes = new_volumes; + let mut annotated_atoms = BTreeMap::new(); + + for (atom_name, (a, b)) in atoms { + let annotations = + if let Some(module) = manifest.modules.iter().find(|v| v.name == atom_name) { + module.annotations.as_ref() + } else { + None + }; + + annotated_atoms.insert(atom_name, (a, b, annotations)); + } + let (mut manifest, atoms) = - super::manifest::in_memory_wasmer_manifest_to_webc(&manifest, &atoms)?; + super::manifest::in_memory_wasmer_manifest_to_webc(&manifest, &annotated_atoms)?; if let Some(entry) = manifest.package.get_mut(Wapm::KEY) { let mut wapm: Wapm = entry.deserialized()?; diff --git a/lib/types/src/target.rs b/lib/types/src/target.rs index 5aec0d0e63b8..739d16a3be1d 100644 --- a/lib/types/src/target.rs +++ b/lib/types/src/target.rs @@ -229,3 +229,13 @@ impl Default for Target { } } } + +/// User-suggested optimization that might be operated on the module when (and if) compiled. +/// +// Note: This type is a copy of `wasmer_config::package::SuggestedCompilerOptimizations`, so to +// avoid dependencies on `wasmer_config` for crates that already depend on `wasmer_types`. +#[derive(Clone, Debug, PartialEq, Eq, Default)] +pub struct UserCompilerOptimizations { + /// Suggest the `pass_params` (also known as g0m0) optimization pass. + pub pass_params: Option, +} diff --git a/lib/wasix/src/bin_factory/binary_package.rs b/lib/wasix/src/bin_factory/binary_package.rs index 78649b148293..6688c712b9c7 100644 --- a/lib/wasix/src/bin_factory/binary_package.rs +++ b/lib/wasix/src/bin_factory/binary_package.rs @@ -4,7 +4,9 @@ use anyhow::Context; use once_cell::sync::OnceCell; use sha2::Digest; use virtual_fs::FileSystem; -use wasmer_config::package::{PackageHash, PackageId, PackageSource}; +use wasmer_config::package::{ + PackageHash, PackageId, PackageSource, SuggestedCompilerOptimizations, +}; use wasmer_package::package::Package; use webc::compat::SharedBytes; use webc::Container; @@ -24,6 +26,7 @@ pub struct BinaryPackageCommand { pub(crate) atom: SharedBytes, hash: ModuleHash, features: Option, + pub suggested_compiler_optimizations: SuggestedCompilerOptimizations, } impl BinaryPackageCommand { @@ -33,6 +36,7 @@ impl BinaryPackageCommand { atom: SharedBytes, hash: ModuleHash, features: Option, + suggested_compiler_optimizations: SuggestedCompilerOptimizations, ) -> Self { Self { name, @@ -40,6 +44,7 @@ impl BinaryPackageCommand { atom, hash, features, + suggested_compiler_optimizations, } } diff --git a/lib/wasix/src/runtime/mod.rs b/lib/wasix/src/runtime/mod.rs index cfe2b974ce64..917f97bde431 100644 --- a/lib/wasix/src/runtime/mod.rs +++ b/lib/wasix/src/runtime/mod.rs @@ -5,7 +5,10 @@ pub mod task_manager; pub use self::task_manager::{SpawnMemoryType, VirtualTaskManager}; use self::{module_cache::CacheError, task_manager::InlineWaker}; -use wasmer_types::ModuleHash; +use wasmer_config::package::SuggestedCompilerOptimizations; +use wasmer_types::{ + target::UserCompilerOptimizations as WasmerSuggestedCompilerOptimizations, ModuleHash, +}; use std::{ fmt, @@ -15,7 +18,7 @@ use std::{ use futures::future::BoxFuture; use virtual_net::{DynVirtualNetworking, VirtualNetworking}; -use wasmer::{Module, RuntimeError}; +use wasmer::{CompileError, Module, RuntimeError}; use wasmer_wasix_types::wasi::ExitCode; #[cfg(feature = "journal")] @@ -77,6 +80,17 @@ where wasmer::Engine::default() } + fn engine_with_suggested_opts( + &self, + suggested_opts: &SuggestedCompilerOptimizations, + ) -> Result { + let mut engine = self.engine(); + engine.with_opts(&WasmerSuggestedCompilerOptimizations { + pass_params: suggested_opts.pass_params, + })?; + Ok(engine) + } + /// Create a new [`wasmer::Store`]. fn new_store(&self) -> wasmer::Store { cfg_if::cfg_if! { @@ -106,11 +120,22 @@ where &self, cmd: &BinaryPackageCommand, ) -> BoxFuture<'_, Result> { - let engine = self.engine(); let hash = *cmd.hash(); let wasm = cmd.atom(); let module_cache = self.module_cache(); + let engine = match self.engine_with_suggested_opts(&cmd.suggested_compiler_optimizations) { + Ok(engine) => engine, + Err(error) => { + return Box::pin(async move { + Err(SpawnError::CompileError { + module_hash: hash, + error, + }) + }) + } + }; + let task = async move { load_module(&engine, &module_cache, &wasm, hash).await }; Box::pin(task) diff --git a/lib/wasix/src/runtime/module_cache/filesystem.rs b/lib/wasix/src/runtime/module_cache/filesystem.rs index 5528ff2261fc..3571a2e759d9 100644 --- a/lib/wasix/src/runtime/module_cache/filesystem.rs +++ b/lib/wasix/src/runtime/module_cache/filesystem.rs @@ -42,7 +42,7 @@ impl FileSystemCache { impl ModuleCache for FileSystemCache { #[tracing::instrument(level = "debug", skip_all, fields(% key))] async fn load(&self, key: ModuleHash, engine: &Engine) -> Result { - let path = self.path(key, engine.deterministic_id()); + let path = self.path(key, &engine.deterministic_id()); self.task_manager .runtime_handle() @@ -97,7 +97,7 @@ impl ModuleCache for FileSystemCache { engine: &Engine, module: &Module, ) -> Result<(), CacheError> { - let path = self.path(key, engine.deterministic_id()); + let path = self.path(key, &engine.deterministic_id()); self.task_manager .runtime_handle() @@ -221,7 +221,7 @@ mod tests { let module = Module::new(&engine, ADD_WAT).unwrap(); let cache = FileSystemCache::new(temp.path(), create_tokio_task_manager()); let key = ModuleHash::xxhash_from_bytes([0; 8]); - let expected_path = cache.path(key, engine.deterministic_id()); + let expected_path = cache.path(key, &engine.deterministic_id()); cache.save(key, &engine, &module).await.unwrap(); @@ -262,7 +262,7 @@ mod tests { let module = Module::new(&engine, ADD_WAT).unwrap(); let key = ModuleHash::xxhash_from_bytes([0; 8]); let cache = FileSystemCache::new(temp.path(), create_tokio_task_manager()); - let expected_path = cache.path(key, engine.deterministic_id()); + let expected_path = cache.path(key, &engine.deterministic_id()); std::fs::create_dir_all(expected_path.parent().unwrap()).unwrap(); let serialized = module.serialize().unwrap(); std::fs::write(&expected_path, &serialized).unwrap(); @@ -285,7 +285,7 @@ mod tests { let module = Module::new(&engine, ADD_WAT).unwrap(); let key = ModuleHash::xxhash_from_bytes([0; 8]); let cache = FileSystemCache::new(temp.path(), create_tokio_task_manager()); - let expected_path = cache.path(key, engine.deterministic_id()); + let expected_path = cache.path(key, &engine.deterministic_id()); std::fs::create_dir_all(expected_path.parent().unwrap()).unwrap(); let serialized = module.serialize().unwrap(); let mut encoder = weezl::encode::Encoder::new(weezl::BitOrder::Msb, 8); diff --git a/lib/wasix/src/runtime/module_cache/shared.rs b/lib/wasix/src/runtime/module_cache/shared.rs index 305e80ff654a..101c401d778f 100644 --- a/lib/wasix/src/runtime/module_cache/shared.rs +++ b/lib/wasix/src/runtime/module_cache/shared.rs @@ -20,7 +20,7 @@ impl SharedCache { impl ModuleCache for SharedCache { #[tracing::instrument(level = "debug", skip_all, fields(%key))] async fn load(&self, key: ModuleHash, engine: &Engine) -> Result { - let key = (key, engine.deterministic_id().to_string()); + let key = (key, engine.deterministic_id()); match self.modules.get(&key) { Some(m) => { diff --git a/lib/wasix/src/runtime/module_cache/thread_local.rs b/lib/wasix/src/runtime/module_cache/thread_local.rs index c23744ae19cc..c873967af244 100644 --- a/lib/wasix/src/runtime/module_cache/thread_local.rs +++ b/lib/wasix/src/runtime/module_cache/thread_local.rs @@ -31,7 +31,7 @@ impl ThreadLocalCache { impl ModuleCache for ThreadLocalCache { #[tracing::instrument(level = "debug", skip_all, fields(%key))] async fn load(&self, key: ModuleHash, engine: &Engine) -> Result { - match self.lookup(key, engine.deterministic_id()) { + match self.lookup(key, &engine.deterministic_id()) { Some(m) => { tracing::debug!("Cache hit!"); Ok(m) @@ -47,7 +47,7 @@ impl ModuleCache for ThreadLocalCache { engine: &Engine, module: &Module, ) -> Result<(), CacheError> { - self.insert(key, module, engine.deterministic_id()); + self.insert(key, module, &engine.deterministic_id()); Ok(()) } } diff --git a/lib/wasix/src/runtime/package_loader/load_package_tree.rs b/lib/wasix/src/runtime/package_loader/load_package_tree.rs index e81c0197be87..743fb8ac3920 100644 --- a/lib/wasix/src/runtime/package_loader/load_package_tree.rs +++ b/lib/wasix/src/runtime/package_loader/load_package_tree.rs @@ -10,7 +10,7 @@ use futures::{future::BoxFuture, StreamExt, TryStreamExt}; use once_cell::sync::OnceCell; use petgraph::visit::EdgeRef; use virtual_fs::{FileSystem, OverlayFileSystem, UnionFileSystem, WebcVolumeFileSystem}; -use wasmer_config::package::PackageId; +use wasmer_config::package::{PackageId, SuggestedCompilerOptimizations}; use wasmer_package::utils::wasm_annotations_to_features; use webc::metadata::annotations::Atom as AtomAnnotation; use webc::{Container, Volume}; @@ -208,12 +208,47 @@ fn load_binary_command( None }; - let cmd = - BinaryPackageCommand::new(command_name.to_string(), cmd.clone(), atom, hash, features); + let suggested_compiler_optimizations = + if let Some(atom_metadata) = webc.manifest().atoms.get(&atom_name) { + extract_suggested_compiler_opts_from_atom_metadata(atom_metadata) + } else { + wasmer_config::package::SuggestedCompilerOptimizations::default() + }; + + let cmd = BinaryPackageCommand::new( + command_name.to_string(), + cmd.clone(), + atom, + hash, + features, + suggested_compiler_optimizations, + ); Ok(Some(cmd)) } +fn extract_suggested_compiler_opts_from_atom_metadata( + atom_metadata: &webc::metadata::Atom, +) -> wasmer_config::package::SuggestedCompilerOptimizations { + let mut ret = SuggestedCompilerOptimizations::default(); + + if let Some(sco) = atom_metadata + .annotations + .get(SuggestedCompilerOptimizations::KEY) + { + if let Some((_, v)) = sco.as_map().and_then(|v| { + v.iter().find(|(k, _)| { + k.as_text() + .is_some_and(|v| v == SuggestedCompilerOptimizations::PASS_PARAMS_KEY) + }) + }) { + ret.pass_params = v.as_bool() + } + } + + ret +} + fn atom_name_for_command( command_name: &str, cmd: &webc::metadata::Command, @@ -281,12 +316,21 @@ fn legacy_atom_hack( None }; + // Get WebAssembly features from manifest atom annotations + let suggested_opts_from_manifest = if let Some(atom_metadata) = webc.manifest().atoms.get(&name) + { + extract_suggested_compiler_opts_from_atom_metadata(atom_metadata) + } else { + SuggestedCompilerOptimizations::default() + }; + Ok(Some(BinaryPackageCommand::new( command_name.to_string(), metadata.clone(), atom, hash, features, + suggested_opts_from_manifest, ))) }