From 7c99f0e1c6e1f30edb3cbce26178ebdba8625fcf Mon Sep 17 00:00:00 2001 From: Victor Adossi Date: Fri, 11 Jul 2025 18:00:29 +0900 Subject: [PATCH 1/2] refactor: splicer WIT and generated bindings This commit refactors the WIT for the splicer, and moves the generated bindings to their own module file which is likely a bit easier to grok for most, and a good place to put extra functionality (e.g. custom impls for the generated types). --- .../src/bin/splicer.rs | 10 +- .../src/bindgen.rs | 131 ++++++++---------- .../spidermonkey-embedding-splicer/src/lib.rs | 26 ++-- .../src/splice.rs | 52 +++---- .../src/stub_wasi.rs | 18 +-- .../spidermonkey-embedding-splicer/src/wit.rs | 23 +++ .../wit/spidermonkey-embedding-splicer.wit | 31 ++++- crates/splicer-component/src/lib.rs | 6 +- src/componentize.js | 40 +++--- 9 files changed, 177 insertions(+), 160 deletions(-) create mode 100644 crates/spidermonkey-embedding-splicer/src/wit.rs diff --git a/crates/spidermonkey-embedding-splicer/src/bin/splicer.rs b/crates/spidermonkey-embedding-splicer/src/bin/splicer.rs index 6ccf4b50..5d9724ff 100644 --- a/crates/spidermonkey-embedding-splicer/src/bin/splicer.rs +++ b/crates/spidermonkey-embedding-splicer/src/bin/splicer.rs @@ -3,7 +3,7 @@ use clap::{Parser, Subcommand}; use std::fs; use std::path::PathBuf; -use spidermonkey_embedding_splicer::wit::Features; +use spidermonkey_embedding_splicer::wit::exports::local::spidermonkey_embedding_splicer::splicer::Features; use spidermonkey_embedding_splicer::{splice, stub_wasi}; #[derive(Parser, Debug)] @@ -70,7 +70,7 @@ enum Commands { /// random, /// http, ///} -fn map_features(features: &Vec) -> Vec { +fn map_features(features: &[String]) -> Vec { features .iter() .map(|f| match f.as_str() { @@ -78,7 +78,7 @@ fn map_features(features: &Vec) -> Vec { "clocks" => Features::Clocks, "random" => Features::Random, "http" => Features::Http, - _ => panic!("Unknown feature: {}", f), + _ => panic!("Unknown feature: {f}"), }) .collect() } @@ -131,13 +131,13 @@ fn main() -> Result<()> { let result = splice::splice_bindings(engine, world_name, wit_path_str, None, debug) .map_err(|e| anyhow::anyhow!(e))?; - fs::write(&out_dir.join("component.wasm"), result.wasm).with_context(|| { + fs::write(out_dir.join("component.wasm"), result.wasm).with_context(|| { format!( "Failed to write output file: {}", out_dir.join("component.wasm").display() ) })?; - fs::write(&out_dir.join("initializer.js"), result.js_bindings).with_context(|| { + fs::write(out_dir.join("initializer.js"), result.js_bindings).with_context(|| { format!( "Failed to write output file: {}", out_dir.join("initializer.js").display() diff --git a/crates/spidermonkey-embedding-splicer/src/bindgen.rs b/crates/spidermonkey-embedding-splicer/src/bindgen.rs index b682dfd7..1ddc99e3 100644 --- a/crates/spidermonkey-embedding-splicer/src/bindgen.rs +++ b/crates/spidermonkey-embedding-splicer/src/bindgen.rs @@ -191,7 +191,7 @@ pub fn componentize_bindgen(resolve: &Resolve, wid: WorldId) -> Result Result Result {} WorldItem::Type(id) => { let ty = &resolve.types[*id]; - match ty.kind { - TypeDefKind::Resource => { - imported_resource_modules.insert(*id, key_name.clone()); - } - _ => {} + if ty.kind == TypeDefKind::Resource { + imported_resource_modules.insert(*id, key_name.clone()); } } } @@ -390,7 +387,7 @@ pub fn componentize_bindgen(resolve: &Resolve, wid: WorldId) -> Result { fn intrinsic(&mut self, intrinsic: Intrinsic) -> String { self.all_intrinsics.insert(intrinsic); - return intrinsic.name().to_string(); + intrinsic.name().to_string() } fn exports_bindgen( @@ -448,14 +445,7 @@ impl JsBindgen<'_> { match export { WorldItem::Function(func) => { let local_name = self.local_names.create_once(&func.name).to_string(); - self.export_bindgen( - name.into(), - false, - None, - &local_name, - StringEncoding::UTF8, - func, - ); + self.export_bindgen(name, false, None, &local_name, StringEncoding::UTF8, func); self.esm_bindgen.add_export_func( None, local_name.to_string(), @@ -484,7 +474,7 @@ impl JsBindgen<'_> { interface_name(self.resolve, *id), &local_name, StringEncoding::UTF8, - &func, + func, ); self.esm_bindgen.add_export_func( Some(name), @@ -501,7 +491,7 @@ impl JsBindgen<'_> { let local_name = self .local_names .get_or_create( - &format!("resource:{resource_name}"), + format!("resource:{resource_name}"), &resource_name, ) .0 @@ -512,10 +502,10 @@ impl JsBindgen<'_> { interface_name(self.resolve, *id), &local_name, StringEncoding::UTF8, - &func, + func, ); self.esm_bindgen.ensure_exported_resource( - Some(&name), + Some(name), local_name, resource_name, ); @@ -547,7 +537,7 @@ impl JsBindgen<'_> { .as_ref() .unwrap() .to_upper_camel_case(), - &iface_name, + iface_name, ); uwriteln!(self.src, "\nclass import_{name} {{"); @@ -568,7 +558,7 @@ impl JsBindgen<'_> { let prefix = iface_name .as_deref() .map(|s| format!("{s}$")) - .unwrap_or(String::new()); + .unwrap_or_default(); let resource_symbol = self.intrinsic(Intrinsic::SymbolResourceHandle); let dispose_symbol = self.intrinsic(Intrinsic::SymbolDispose); @@ -646,44 +636,38 @@ impl JsBindgen<'_> { } WorldItem::Type(id) => { let ty = &self.resolve.types[*id]; - match ty.kind { - TypeDefKind::Resource => { - self.resource_directions - .insert(*id, AbiVariant::GuestImport); - - let resource_name = ty.name.as_ref().unwrap(); - - let mut resource_fns = Vec::new(); - for (_, impt) in &self.resolve.worlds[self.world].imports { - match impt { - WorldItem::Function(function) => { - let stripped = if let Some(stripped) = - function.name.strip_prefix("[constructor]") - { - stripped - } else if let Some(stripped) = - function.name.strip_prefix("[method]") - { - stripped - } else if let Some(stripped) = - function.name.strip_prefix("[static]") - { - stripped - } else { - continue; - }; - - if stripped.starts_with(resource_name) { - resource_fns.push((function.name.as_str(), function)); - } - } - _ => {} + if ty.kind == TypeDefKind::Resource { + self.resource_directions + .insert(*id, AbiVariant::GuestImport); + + let resource_name = ty.name.as_ref().unwrap(); + + let mut resource_fns = Vec::new(); + for (_, impt) in &self.resolve.worlds[self.world].imports { + if let WorldItem::Function(function) = impt { + let stripped = if let Some(stripped) = + function.name.strip_prefix("[constructor]") + { + stripped + } else if let Some(stripped) = + function.name.strip_prefix("[method]") + { + stripped + } else if let Some(stripped) = + function.name.strip_prefix("[static]") + { + stripped + } else { + continue; + }; + + if stripped.starts_with(resource_name) { + resource_fns.push((function.name.as_str(), function)); } } - - self.resource_bindgen(*id, "$root", &None, resource_fns); } - _ => {} + + self.resource_bindgen(*id, "$root", &None, resource_fns); } } }; @@ -1112,8 +1096,7 @@ impl EsmBindgen { iface = match iface.get_mut(&iface_id_or_kebab).unwrap() { Binding::Interface(iface) => iface, Binding::Resource(_) | Binding::Local(_) => panic!( - "Exported interface {} cannot be both a function and an interface or resource", - iface_id_or_kebab + "Exported interface {iface_id_or_kebab} cannot be both a function and an interface or resource" ), }; } @@ -1143,8 +1126,7 @@ impl EsmBindgen { iface = match iface.get_mut(&iface_id_or_kebab).unwrap() { Binding::Interface(iface) => iface, Binding::Resource(_) | Binding::Local(_) => panic!( - "Exported interface {} cannot be both a function and an interface or resource", - iface_id_or_kebab + "Exported interface {iface_id_or_kebab} cannot be both a function and an interface or resource" ), }; } @@ -1158,7 +1140,7 @@ impl EsmBindgen { let expt_name_sans_version = if let Some(version_idx) = expt_name.find('@') { &expt_name[0..version_idx] } else { - &expt_name + expt_name }; if let Some(alias) = interface_name_from_string(expt_name_sans_version) { if !self.exports.contains_key(&alias) @@ -1178,7 +1160,7 @@ impl EsmBindgen { ) { // TODO: bring back these validations of imports // including using the flattened bindings - if self.exports.len() > 0 { + if !self.exports.is_empty() { // error handling uwriteln!(output, " class BindingsError extends Error {{ @@ -1328,12 +1310,9 @@ fn interface_name_from_string(name: &str) -> Option { let path_idx = name.rfind('/')?; let name = &name[path_idx + 1..]; let at_idx = name.rfind('@'); - let alias = name[..at_idx.unwrap_or_else(|| name.len())].to_lower_camel_case(); + let alias = name[..at_idx.unwrap_or(name.len())].to_lower_camel_case(); let iface_name = Some(if let Some(at_idx) = at_idx { - format!( - "{alias}_{}", - name[at_idx + 1..].replace('.', "_").replace('-', "_") - ) + format!("{alias}_{}", name[at_idx + 1..].replace(['.', '-'], "_")) } else { alias }); @@ -1343,23 +1322,21 @@ fn interface_name_from_string(name: &str) -> Option { fn binding_name(func_name: &str, iface_name: &Option) -> String { match iface_name { Some(iface_name) => format!("{iface_name}${func_name}"), - None => format!("{func_name}"), + None => func_name.to_string(), } } /// Extract success and error types from a given optional type, if it is a Result -pub fn get_result_types<'a>( - resolve: &'a Resolve, +pub fn get_result_types( + resolve: &Resolve, return_type: Option, -) -> Option<(Option<&'a Type>, Option<&'a Type>)> { +) -> Option<(Option<&Type>, Option<&Type>)> { match return_type { None => None, - Some(ty) => match ty { - Type::Id(id) => match &resolve.types[id].kind { - TypeDefKind::Result(r) => Some((r.ok.as_ref(), r.err.as_ref())), - _ => None, - }, + Some(Type::Id(id)) => match &resolve.types[id].kind { + TypeDefKind::Result(r) => Some((r.ok.as_ref(), r.err.as_ref())), _ => None, }, + _ => None, } } diff --git a/crates/spidermonkey-embedding-splicer/src/lib.rs b/crates/spidermonkey-embedding-splicer/src/lib.rs index 3a7f2c0f..222f0e89 100644 --- a/crates/spidermonkey-embedding-splicer/src/lib.rs +++ b/crates/spidermonkey-embedding-splicer/src/lib.rs @@ -1,19 +1,14 @@ -use anyhow::{bail, Context, Result}; use std::path::Path; +use anyhow::{bail, Context, Result}; +use wit_parser::{PackageId, Resolve}; + pub mod bindgen; pub mod splice; pub mod stub_wasi; +pub mod wit; -use crate::wit::{CoreFn, CoreTy}; -use wit_parser::{PackageId, Resolve}; - -pub mod wit { - wit_bindgen::generate!({ - world: "spidermonkey-embedding-splicer", - pub_export_macro: true - }); -} +use wit::exports::local::spidermonkey_embedding_splicer::splicer::{CoreFn, CoreTy}; /// Calls [`write!`] with the passed arguments and unwraps the result. /// @@ -60,10 +55,7 @@ fn map_core_fn(cfn: &bindgen::CoreFn) -> CoreFn { } = cfn; CoreFn { params: params.iter().map(&map_core_ty).collect(), - ret: match ret { - Some(ref core_ty) => Some(map_core_ty(core_ty)), - None => None, - }, + ret: ret.as_ref().map(map_core_ty), retptr: *retptr, retsize: *retsize, paramptr: *paramptr, @@ -75,17 +67,17 @@ fn parse_wit(path: impl AsRef) -> Result<(Resolve, PackageId)> { let path = path.as_ref(); let id = if path.is_dir() { resolve - .push_dir(&path) + .push_dir(path) .with_context(|| format!("resolving WIT in {}", path.display()))? .0 } else { let contents = - std::fs::read(&path).with_context(|| format!("reading file {}", path.display()))?; + std::fs::read(path).with_context(|| format!("reading file {}", path.display()))?; let text = match std::str::from_utf8(&contents) { Ok(s) => s, Err(_) => bail!("input file is not valid utf-8"), }; - resolve.push_str(&path, text)? + resolve.push_str(path, text)? }; Ok((resolve, id)) } diff --git a/crates/spidermonkey-embedding-splicer/src/splice.rs b/crates/spidermonkey-embedding-splicer/src/splice.rs index 07083811..60f35e66 100644 --- a/crates/spidermonkey-embedding-splicer/src/splice.rs +++ b/crates/spidermonkey-embedding-splicer/src/splice.rs @@ -1,6 +1,5 @@ -use crate::bindgen::BindingItem; -use crate::wit::{CoreFn, CoreTy, SpliceResult}; -use crate::{bindgen, map_core_fn, parse_wit, splice}; +use std::path::PathBuf; + use anyhow::Result; use orca_wasm::ir::function::{FunctionBuilder, FunctionModifier}; use orca_wasm::ir::id::{ExportsID, FunctionID, LocalID}; @@ -9,7 +8,6 @@ use orca_wasm::ir::types::{BlockType, ElementItems, InstrumentationMode}; use orca_wasm::module_builder::AddLocal; use orca_wasm::opcode::{Inject, InjectAt}; use orca_wasm::{DataType, Opcode}; -use std::path::PathBuf; use wasm_encoder::{Encode, Section}; use wasmparser::ExternalKind; use wasmparser::MemArg; @@ -18,6 +16,12 @@ use wit_component::metadata::{decode, Bindgen}; use wit_component::StringEncoding; use wit_parser::Resolve; +use crate::bindgen::BindingItem; +use crate::wit::exports::local::spidermonkey_embedding_splicer::splicer::{ + CoreFn, CoreTy, SpliceResult, +}; +use crate::{bindgen, map_core_fn, parse_wit, splice}; + // Returns // pub struct SpliceResult { // pub wasm: _rt::Vec::, @@ -42,7 +46,7 @@ pub fn splice_bindings( .map_err(|e| e.to_string())?; (resolve, id) } - (_, Some(wit_path)) => parse_wit(&wit_path).map_err(|e| format!("{:?}", e))?, + (_, Some(wit_path)) => parse_wit(&wit_path).map_err(|e| format!("{e:?}"))?, (None, None) => { return Err("neither wit source nor path have been specified".into()); } @@ -187,7 +191,7 @@ pub fn splice_bindings( ) in &componentized.exports { let expt = if *iface { - let name = resource.canon_string(&name); + let name = resource.canon_string(name); format!("{export_name}#{name}") } else { export_name.clone() @@ -210,7 +214,7 @@ pub fn splice_bindings( if *iface { imports.push(( specifier.to_string(), - resource.canon_string(&name), + resource.canon_string(name), map_core_fn(func), if func.retsize > 0 { Some(func.retsize as i32) @@ -251,8 +255,7 @@ pub fn splice_bindings( )); } - let mut wasm = - splice::splice(engine, imports, exports, debug).map_err(|e| format!("{:?}", e))?; + let mut wasm = splice::splice(engine, imports, exports, debug).map_err(|e| format!("{e:?}"))?; // add the world section to the spliced wasm wasm.push(section.id()); @@ -269,7 +272,7 @@ pub fn splice_bindings( BindingItem { binding_name, func, .. }, - )| { (binding_name.to_string(), map_core_fn(&func)) }, + )| { (binding_name.to_string(), map_core_fn(func)) }, ) .collect(), imports: componentized @@ -293,7 +296,7 @@ pub fn splice_bindings( "$root".into() }, if *iface { - resource.canon_string(&name) + resource.canon_string(name) } else { specifier.to_string() }, @@ -336,7 +339,7 @@ pub fn splice( exports: Vec<(String, CoreFn)>, debug: bool, ) -> Result> { - let mut module = Module::parse(&*engine, false).unwrap(); + let mut module = Module::parse(&engine, false).unwrap(); // since StarlingMonkey implements CLI Run and incoming handler, // we override them only if the guest content exports those functions @@ -370,7 +373,7 @@ pub fn splice( fn remove_if_exported_by_js( module: &mut Module, - content_exports: &Vec<(String, CoreFn)>, + content_exports: &[(String, CoreFn)], name_start: &str, name_end: &str, ) { @@ -407,7 +410,7 @@ fn get_export_fid(module: &Module, expt_id: &ExportsID) -> FunctionID { fn synthesize_import_functions( module: &mut Module, - imports: &Vec<(String, String, CoreFn, Option)>, + imports: &[(String, String, CoreFn, Option)], debug: bool, ) -> Result<()> { let mut coreabi_get_import: Option = None; @@ -580,7 +583,7 @@ fn synthesize_import_functions( func.i32_wrap_i64(); } CoreTy::I64 => { - func.call(get_export_fid(&module, &coreabi_from_bigint64)); + func.call(get_export_fid(module, &coreabi_from_bigint64)); } CoreTy::F32 => { // isInt: (r.asRawBits() >> 32) == 0xFFFFFF81 @@ -633,7 +636,7 @@ fn synthesize_import_functions( // if a retptr, // allocate and put the retptr on the call stack as the last passed argument if impt_sig.retptr { - assert!(!impt_sig.ret.is_some()); + assert!(impt_sig.ret.is_none()); // prepare the context arg for the return set shortly func.local_get(vp_arg); @@ -669,7 +672,7 @@ fn synthesize_import_functions( func.inject(instr.clone()); }), Some(CoreTy::I64) => { - func.call(get_export_fid(&module, &coreabi_to_bigint64)); + func.call(get_export_fid(module, &coreabi_to_bigint64)); func.i64_extend_i32u(); func.i64_const(-511101108224); func.i64_or(); @@ -713,13 +716,10 @@ fn synthesize_import_functions( // create imported function table let els = module.elements.iter_mut().next().unwrap(); - match &mut els.1 { - ElementItems::Functions(ref mut funcs) => { - for fid in import_fnids { - funcs.push(fid); - } + if let ElementItems::Functions(ref mut funcs) = &mut els.1 { + for fid in import_fnids { + funcs.push(fid); } - _ => {} } } @@ -787,7 +787,7 @@ fn synthesize_import_functions( Ok(()) } -fn synthesize_export_functions(module: &mut Module, exports: &Vec<(String, CoreFn)>) -> Result<()> { +fn synthesize_export_functions(module: &mut Module, exports: &[(String, CoreFn)]) -> Result<()> { let cabi_realloc = get_export_fid( module, &module @@ -990,7 +990,7 @@ fn synthesize_export_functions(module: &mut Module, exports: &Vec<(String, CoreF vec![] }; let mut func = FunctionBuilder::new(¶ms, &[]); - func.set_name(format!("post_{}", expt_name)); + func.set_name(format!("post_{expt_name}")); // calls post_call with just the function number argument // internally post_call is already tracking the frees needed @@ -1000,7 +1000,7 @@ fn synthesize_export_functions(module: &mut Module, exports: &Vec<(String, CoreF let fid = func.finish_module(module); module .exports - .add_export_func(format!("cabi_post_{}", expt_name), *fid); + .add_export_func(format!("cabi_post_{expt_name}"), *fid); } // remove unnecessary exports diff --git a/crates/spidermonkey-embedding-splicer/src/stub_wasi.rs b/crates/spidermonkey-embedding-splicer/src/stub_wasi.rs index e7b03efc..104c7f29 100644 --- a/crates/spidermonkey-embedding-splicer/src/stub_wasi.rs +++ b/crates/spidermonkey-embedding-splicer/src/stub_wasi.rs @@ -1,5 +1,7 @@ -use crate::parse_wit; -use crate::wit::Features; +use std::collections::HashSet; +use std::path::PathBuf; +use std::time::{SystemTime, UNIX_EPOCH}; + use anyhow::{bail, Result}; use orca_wasm::ir::function::FunctionBuilder; use orca_wasm::ir::id::{FunctionID, LocalID}; @@ -7,14 +9,12 @@ use orca_wasm::ir::module::module_functions::FuncKind; use orca_wasm::ir::types::{BlockType, InitExpr, Value}; use orca_wasm::module_builder::AddLocal; use orca_wasm::{DataType, Instructions, Module, Opcode}; -use std::{ - collections::HashSet, - path::PathBuf, - time::{SystemTime, UNIX_EPOCH}, -}; use wasmparser::{MemArg, TypeRef}; use wit_parser::Resolve; +use crate::parse_wit; +use crate::wit::exports::local::spidermonkey_embedding_splicer::splicer::Features; + const WASI_VERSIONS: [&str; 4] = ["0.2.0", "0.2.1", "0.2.2", "0.2.3"]; fn stub_wasi_imports( @@ -52,7 +52,7 @@ where return Ok(Some(fid)); } - return Ok(None); + Ok(None) } fn stub_import( @@ -108,7 +108,7 @@ pub fn stub_wasi( (resolve, ids) } else { - parse_wit(&PathBuf::from(wit_path.unwrap()))? + parse_wit(PathBuf::from(wit_path.unwrap()))? }; let world = resolve.select_world(ids, world_name.as_deref())?; diff --git a/crates/spidermonkey-embedding-splicer/src/wit.rs b/crates/spidermonkey-embedding-splicer/src/wit.rs new file mode 100644 index 00000000..47fc19f6 --- /dev/null +++ b/crates/spidermonkey-embedding-splicer/src/wit.rs @@ -0,0 +1,23 @@ +use anyhow::{bail, Result}; + +wit_bindgen::generate!({ + world: "spidermonkey-embedding-splicer", + pub_export_macro: true +}); + +use crate::wit::exports::local::spidermonkey_embedding_splicer::splicer::Features; + +impl std::str::FromStr for Features { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + match s { + "stdio" => Ok(Features::Stdio), + "clocks" => Ok(Features::Clocks), + "random" => Ok(Features::Random), + "http" => Ok(Features::Http), + "fetch-event" => Ok(Features::FetchEvent), + _ => bail!("unrecognized feature string [{s}]"), + } + } +} diff --git a/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit b/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit index 96f4d87f..fdc25f79 100644 --- a/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit +++ b/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit @@ -1,6 +1,6 @@ package local:spidermonkey-embedding-splicer; -world spidermonkey-embedding-splicer { +interface splicer { enum core-ty { i32, i64, @@ -13,6 +13,7 @@ world spidermonkey-embedding-splicer { clocks, random, http, + fetch-event, } record core-fn { @@ -30,7 +31,31 @@ world spidermonkey-embedding-splicer { imports: list>, } - export stub-wasi: func(engine: list, features: list, wit-world: option, wit-path: option, world-name: option) -> result, string>; + /// Stub the WASI imports/exports of a given JS engine WebAssembly module + /// + /// Depending on which features have been enabled, different default-provided WASI + /// imports may be stubbed (for example to be made unreachable). + stub-wasi: func( + engine: list, + features: list, + wit-world: option, + wit-path: option, + world-name: option + ) -> result, string>; + + /// Splice blindings for a given WIT world into the spider monkey engine binary (spidermonkey.wasm) + /// this function produces a new WebAssembly component + splice-bindings: func( + spidermonkey-engine: list, + features: list, + wit-world: option, + wit-path: option, + world-name: option, + debug: bool, + ) -> result; - export splice-bindings: func(spidermonkey-engine: list, wit-world: option, wit-path: option, world-name: option, debug: bool) -> result; +} + +world spidermonkey-embedding-splicer { + export splicer; } diff --git a/crates/splicer-component/src/lib.rs b/crates/splicer-component/src/lib.rs index 77133af3..1cecc3bf 100644 --- a/crates/splicer-component/src/lib.rs +++ b/crates/splicer-component/src/lib.rs @@ -1,6 +1,7 @@ use spidermonkey_embedding_splicer::stub_wasi::stub_wasi; -use spidermonkey_embedding_splicer::wit::{export, Features, Guest, SpliceResult}; -use spidermonkey_embedding_splicer::{splice, wit}; +use spidermonkey_embedding_splicer::wit::{self, export}; +use spidermonkey_embedding_splicer::splice; +use spidermonkey_embedding_splicer::wit::exports::local::spidermonkey_embedding_splicer::splicer::{Features, Guest, SpliceResult}; struct SpidermonkeyEmbeddingSplicerComponent; @@ -17,6 +18,7 @@ impl Guest for SpidermonkeyEmbeddingSplicerComponent { fn splice_bindings( engine: Vec, + _features: Vec, world_name: Option, wit_path: Option, wit_source: Option, diff --git a/src/componentize.js b/src/componentize.js index 2de5f3f5..164173f0 100644 --- a/src/componentize.js +++ b/src/componentize.js @@ -18,10 +18,7 @@ import { preview1AdapterReactorPath, } from '@bytecodealliance/jco'; -import { - spliceBindings, - stubWasi, -} from '../lib/spidermonkey-embedding-splicer.js'; +import { splicer } from '../lib/spidermonkey-embedding-splicer.js'; import { maybeWindowsPath } from './platform.js'; @@ -119,8 +116,24 @@ export async function componentize( // Determine the path to the StarlingMonkey binary const engine = getEnginePath(opts); - let { wasm, jsBindings, exports, imports } = spliceBindings( + // We never disable a feature that is already in the target world usage + const features = []; + if (!disableFeatures.includes('stdio')) { + features.push('stdio'); + } + if (!disableFeatures.includes('random')) { + features.push('random'); + } + if (!disableFeatures.includes('clocks')) { + features.push('clocks'); + } + if (!disableFeatures.includes('http')) { + features.push('http'); + } + + let { wasm, jsBindings, exports, imports } = splicer.spliceBindings( await readFile(engine), + features, witWorld, maybeWindowsPath(witPath), worldName, @@ -180,21 +193,6 @@ export async function componentize( await writeFile(sourcePath, jsSource); } - // We never disable a feature that is already in the target world usage - const features = []; - if (!disableFeatures.includes('stdio')) { - features.push('stdio'); - } - if (!disableFeatures.includes('random')) { - features.push('random'); - } - if (!disableFeatures.includes('clocks')) { - features.push('clocks'); - } - if (!disableFeatures.includes('http')) { - features.push('http'); - } - let hostenv = {}; if (opts.env) { @@ -360,7 +358,7 @@ export async function componentize( ); // After wizening, stub out the wasi imports depending on what features are enabled - const finalBin = stubWasi( + const finalBin = splicer.stubWasi( bin, features, witWorld, From fcaebf0c0432b55fd51d29b5411aff46e6858599 Mon Sep 17 00:00:00 2001 From: Victor Adossi Date: Mon, 14 Jul 2025 22:11:41 +0900 Subject: [PATCH 2/2] fix: address code review comments --- .../src/bin/splicer.rs | 32 +++++-------------- .../spidermonkey-embedding-splicer/src/wit.rs | 1 - .../wit/spidermonkey-embedding-splicer.wit | 1 - 3 files changed, 8 insertions(+), 26 deletions(-) diff --git a/crates/spidermonkey-embedding-splicer/src/bin/splicer.rs b/crates/spidermonkey-embedding-splicer/src/bin/splicer.rs index 5d9724ff..0c3226ab 100644 --- a/crates/spidermonkey-embedding-splicer/src/bin/splicer.rs +++ b/crates/spidermonkey-embedding-splicer/src/bin/splicer.rs @@ -1,7 +1,9 @@ -use anyhow::{Context, Result}; -use clap::{Parser, Subcommand}; use std::fs; use std::path::PathBuf; +use std::str::FromStr; + +use anyhow::{Context, Result}; +use clap::{Parser, Subcommand}; use spidermonkey_embedding_splicer::wit::exports::local::spidermonkey_embedding_splicer::splicer::Features; use spidermonkey_embedding_splicer::{splice, stub_wasi}; @@ -62,27 +64,6 @@ enum Commands { }, } -/// Maps the list of features passed as strings into the list of features as given by the enum -/// -/// enum features { -/// stdio, -/// clocks, -/// random, -/// http, -///} -fn map_features(features: &[String]) -> Vec { - features - .iter() - .map(|f| match f.as_str() { - "stdio" => Features::Stdio, - "clocks" => Features::Clocks, - "random" => Features::Random, - "http" => Features::Http, - _ => panic!("Unknown feature: {f}"), - }) - .collect() -} - fn main() -> Result<()> { let cli = Cli::parse(); @@ -98,7 +79,10 @@ fn main() -> Result<()> { .with_context(|| format!("Failed to read input file: {}", input.display()))?; let wit_path_str = wit_path.as_ref().map(|p| p.to_string_lossy().to_string()); - let features = map_features(&features); + let features = features + .iter() + .map(|v| Features::from_str(v)) + .collect::>>()?; let result = stub_wasi::stub_wasi(wasm, features, None, wit_path_str, world_name) .map_err(|e| anyhow::anyhow!(e))?; diff --git a/crates/spidermonkey-embedding-splicer/src/wit.rs b/crates/spidermonkey-embedding-splicer/src/wit.rs index 47fc19f6..01dd2f70 100644 --- a/crates/spidermonkey-embedding-splicer/src/wit.rs +++ b/crates/spidermonkey-embedding-splicer/src/wit.rs @@ -16,7 +16,6 @@ impl std::str::FromStr for Features { "clocks" => Ok(Features::Clocks), "random" => Ok(Features::Random), "http" => Ok(Features::Http), - "fetch-event" => Ok(Features::FetchEvent), _ => bail!("unrecognized feature string [{s}]"), } } diff --git a/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit b/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit index fdc25f79..cdb56841 100644 --- a/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit +++ b/crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit @@ -13,7 +13,6 @@ interface splicer { clocks, random, http, - fetch-event, } record core-fn {