Module name (#775)
This commit is contained in:
@@ -29,6 +29,7 @@ impl Resolver for SimpleResolver {
|
||||
pub fn instantiate_in_context(
|
||||
data: &[u8],
|
||||
imports: Vec<(String, String, Extern)>,
|
||||
module_name: Option<String>,
|
||||
context: Context,
|
||||
exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
|
||||
) -> Result<(InstanceHandle, HashSet<Context>), Error> {
|
||||
@@ -38,6 +39,7 @@ pub fn instantiate_in_context(
|
||||
let instance = instantiate(
|
||||
&mut context.compiler(),
|
||||
data,
|
||||
module_name,
|
||||
&mut resolver,
|
||||
exports,
|
||||
debug_info,
|
||||
@@ -77,8 +79,13 @@ impl Instance {
|
||||
.zip(externs.iter())
|
||||
.map(|(i, e)| (i.module().to_string(), i.name().to_string(), e.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
let (mut instance_handle, contexts) =
|
||||
instantiate_in_context(module.binary().expect("binary"), imports, context, exports)?;
|
||||
let (mut instance_handle, contexts) = instantiate_in_context(
|
||||
module.binary().expect("binary"),
|
||||
imports,
|
||||
module.name().cloned(),
|
||||
context,
|
||||
exports,
|
||||
)?;
|
||||
|
||||
let exports = {
|
||||
let mut exports = Vec::with_capacity(module.exports().len());
|
||||
|
||||
@@ -6,8 +6,8 @@ use crate::types::{
|
||||
use anyhow::{Error, Result};
|
||||
use std::rc::Rc;
|
||||
use wasmparser::{
|
||||
validate, ExternalKind, ImportSectionEntryType, ModuleReader, OperatorValidatorConfig,
|
||||
SectionCode, ValidatingParserConfig,
|
||||
validate, CustomSectionKind, ExternalKind, ImportSectionEntryType, ModuleReader, Name,
|
||||
OperatorValidatorConfig, SectionCode, ValidatingParserConfig,
|
||||
};
|
||||
|
||||
fn into_memory_type(mt: wasmparser::MemoryType) -> MemoryType {
|
||||
@@ -56,7 +56,9 @@ fn into_table_type(tt: wasmparser::TableType) -> TableType {
|
||||
TableType::new(ty, limits)
|
||||
}
|
||||
|
||||
fn read_imports_and_exports(binary: &[u8]) -> Result<(Box<[ImportType]>, Box<[ExportType]>)> {
|
||||
fn read_imports_and_exports(
|
||||
binary: &[u8],
|
||||
) -> Result<(Box<[ImportType]>, Box<[ExportType]>, Option<String>)> {
|
||||
let mut reader = ModuleReader::new(binary)?;
|
||||
let mut imports = Vec::new();
|
||||
let mut exports = Vec::new();
|
||||
@@ -65,6 +67,7 @@ fn read_imports_and_exports(binary: &[u8]) -> Result<(Box<[ImportType]>, Box<[Ex
|
||||
let mut func_sig = Vec::new();
|
||||
let mut sigs = Vec::new();
|
||||
let mut globals = Vec::new();
|
||||
let mut module_name = None;
|
||||
while !reader.eof() {
|
||||
let section = reader.read()?;
|
||||
match section.code {
|
||||
@@ -157,12 +160,32 @@ fn read_imports_and_exports(binary: &[u8]) -> Result<(Box<[ImportType]>, Box<[Ex
|
||||
exports.push(ExportType::new(entry.field, r#type));
|
||||
}
|
||||
}
|
||||
SectionCode::Custom {
|
||||
kind: CustomSectionKind::Name,
|
||||
..
|
||||
} => {
|
||||
// Read name section. Per spec, ignore invalid custom section.
|
||||
if let Ok(mut reader) = section.get_name_section_reader() {
|
||||
while let Ok(entry) = reader.read() {
|
||||
if let Name::Module(name) = entry {
|
||||
if let Ok(name) = name.get_name() {
|
||||
module_name = Some(name.to_string());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// skip other sections
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((imports.into_boxed_slice(), exports.into_boxed_slice()))
|
||||
Ok((
|
||||
imports.into_boxed_slice(),
|
||||
exports.into_boxed_slice(),
|
||||
module_name,
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -196,6 +219,7 @@ struct ModuleInner {
|
||||
source: ModuleCodeSource,
|
||||
imports: Box<[ImportType]>,
|
||||
exports: Box<[ExportType]>,
|
||||
name: Option<String>,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
@@ -239,7 +263,16 @@ impl Module {
|
||||
// Note that the call to `unsafe` here should be ok because we
|
||||
// previously validated the binary, meaning we're guaranteed to pass a
|
||||
// valid binary for `store`.
|
||||
unsafe { Self::new_unchecked(store, binary) }
|
||||
unsafe { Self::create(store, binary, None) }
|
||||
}
|
||||
|
||||
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
||||
/// data. The provided `name` will be used in traps/backtrace details.
|
||||
///
|
||||
/// See [`Module::new`] for other details.
|
||||
pub fn new_with_name(store: &Store, binary: &[u8], name: String) -> Result<Module> {
|
||||
Self::validate(store, binary)?;
|
||||
unsafe { Self::create(store, binary, Some(name)) }
|
||||
}
|
||||
|
||||
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
||||
@@ -269,13 +302,22 @@ impl Module {
|
||||
/// be somewhat valid for decoding purposes, and the basics of decoding can
|
||||
/// still fail.
|
||||
pub unsafe fn new_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
|
||||
let (imports, exports) = read_imports_and_exports(binary)?;
|
||||
Self::create(store, binary, None)
|
||||
}
|
||||
|
||||
unsafe fn create(
|
||||
store: &Store,
|
||||
binary: &[u8],
|
||||
name_override: Option<String>,
|
||||
) -> Result<Module> {
|
||||
let (imports, exports, name) = read_imports_and_exports(binary)?;
|
||||
Ok(Module {
|
||||
inner: Rc::new(ModuleInner {
|
||||
store: store.clone(),
|
||||
source: ModuleCodeSource::Binary(binary.into()),
|
||||
imports,
|
||||
exports,
|
||||
name: name_override.or(name),
|
||||
}),
|
||||
})
|
||||
}
|
||||
@@ -320,6 +362,7 @@ impl Module {
|
||||
source: ModuleCodeSource::Unknown,
|
||||
imports: Box::new([]),
|
||||
exports,
|
||||
name: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -331,6 +374,12 @@ impl Module {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns identifier/name that this [`Module`] has. This name
|
||||
/// is used in traps/backtrace details.
|
||||
pub fn name(&self) -> Option<&String> {
|
||||
self.inner.name.as_ref()
|
||||
}
|
||||
|
||||
/// Returns the list of imports that this [`Module`] has and must be
|
||||
/// satisfied.
|
||||
pub fn imports(&self) -> &[ImportType] {
|
||||
|
||||
54
crates/api/tests/name.rs
Normal file
54
crates/api/tests/name.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
use wasmtime::*;
|
||||
use wat::parse_str;
|
||||
|
||||
#[test]
|
||||
fn test_module_no_name() -> Result<(), String> {
|
||||
let store = Store::default();
|
||||
let binary = parse_str(
|
||||
r#"
|
||||
(module
|
||||
(func (export "run") (nop))
|
||||
)
|
||||
"#,
|
||||
)
|
||||
.map_err(|e| format!("failed to parse WebAssembly text source: {}", e))?;
|
||||
|
||||
let module = HostRef::new(
|
||||
Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?,
|
||||
);
|
||||
assert_eq!(module.borrow().name().cloned(), None);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_module_name() -> Result<(), String> {
|
||||
let store = Store::default();
|
||||
let binary = parse_str(
|
||||
r#"
|
||||
(module $from_name_section
|
||||
(func (export "run") (nop))
|
||||
)
|
||||
"#,
|
||||
)
|
||||
.map_err(|e| format!("failed to parse WebAssembly text source: {}", e))?;
|
||||
|
||||
let module = HostRef::new(
|
||||
Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?,
|
||||
);
|
||||
assert_eq!(
|
||||
module.borrow().name().cloned(),
|
||||
Some("from_name_section".to_string())
|
||||
);
|
||||
|
||||
let module = HostRef::new(
|
||||
Module::new_with_name(&store, &binary, "override".to_string())
|
||||
.map_err(|e| format!("failed to compile module: {}", e))?,
|
||||
);
|
||||
assert_eq!(
|
||||
module.borrow().name().cloned(),
|
||||
Some("override".to_string())
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -168,6 +168,9 @@ pub struct Module {
|
||||
|
||||
/// WebAssembly table initializers.
|
||||
pub table_elements: Vec<TableElements>,
|
||||
|
||||
/// Module name.
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
@@ -186,6 +189,7 @@ impl Module {
|
||||
exports: IndexMap::new(),
|
||||
start_func: None,
|
||||
table_elements: Vec::new(),
|
||||
name: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,14 @@ pub fn compile(wasm: &[u8], compilation_strategy: CompilationStrategy) {
|
||||
let mut compiler = Compiler::new(isa, compilation_strategy);
|
||||
let mut resolver = NullResolver {};
|
||||
let global_exports = Rc::new(RefCell::new(HashMap::new()));
|
||||
let _ = CompiledModule::new(&mut compiler, wasm, &mut resolver, global_exports, false);
|
||||
let _ = CompiledModule::new(
|
||||
&mut compiler,
|
||||
wasm,
|
||||
None,
|
||||
&mut resolver,
|
||||
global_exports,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
/// Invoke the given API calls.
|
||||
|
||||
@@ -117,6 +117,7 @@ impl Context {
|
||||
instantiate(
|
||||
&mut *self.compiler,
|
||||
&data,
|
||||
None,
|
||||
&mut self.namespace,
|
||||
Rc::clone(&self.global_exports),
|
||||
debug_info,
|
||||
@@ -154,6 +155,7 @@ impl Context {
|
||||
CompiledModule::new(
|
||||
&mut *self.compiler,
|
||||
data,
|
||||
None,
|
||||
&mut self.namespace,
|
||||
Rc::clone(&self.global_exports),
|
||||
debug_info,
|
||||
|
||||
@@ -60,12 +60,13 @@ impl<'data> RawCompiledModule<'data> {
|
||||
fn new(
|
||||
compiler: &mut Compiler,
|
||||
data: &'data [u8],
|
||||
module_name: Option<String>,
|
||||
resolver: &mut dyn Resolver,
|
||||
debug_info: bool,
|
||||
) -> Result<Self, SetupError> {
|
||||
let environ = ModuleEnvironment::new(compiler.frontend_config(), compiler.tunables());
|
||||
|
||||
let translation = environ
|
||||
let mut translation = environ
|
||||
.translate(data)
|
||||
.map_err(|error| SetupError::Compile(CompileError::Wasm(error)))?;
|
||||
|
||||
@@ -75,6 +76,8 @@ impl<'data> RawCompiledModule<'data> {
|
||||
None
|
||||
};
|
||||
|
||||
translation.module.name = module_name;
|
||||
|
||||
let (allocated_functions, jt_offsets, relocations, dbg_image) = compiler.compile(
|
||||
&translation.module,
|
||||
translation.module_translation.as_ref().unwrap(),
|
||||
@@ -152,11 +155,13 @@ impl CompiledModule {
|
||||
pub fn new<'data>(
|
||||
compiler: &mut Compiler,
|
||||
data: &'data [u8],
|
||||
module_name: Option<String>,
|
||||
resolver: &mut dyn Resolver,
|
||||
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
|
||||
debug_info: bool,
|
||||
) -> Result<Self, SetupError> {
|
||||
let raw = RawCompiledModule::<'data>::new(compiler, data, resolver, debug_info)?;
|
||||
let raw =
|
||||
RawCompiledModule::<'data>::new(compiler, data, module_name, resolver, debug_info)?;
|
||||
|
||||
Ok(Self::from_parts(
|
||||
raw.module,
|
||||
@@ -258,11 +263,12 @@ impl OwnedDataInitializer {
|
||||
pub fn instantiate(
|
||||
compiler: &mut Compiler,
|
||||
data: &[u8],
|
||||
module_name: Option<String>,
|
||||
resolver: &mut dyn Resolver,
|
||||
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
|
||||
debug_info: bool,
|
||||
) -> Result<InstanceHandle, SetupError> {
|
||||
let raw = RawCompiledModule::new(compiler, data, resolver, debug_info)?;
|
||||
let raw = RawCompiledModule::new(compiler, data, module_name, resolver, debug_info)?;
|
||||
|
||||
InstanceHandle::new(
|
||||
Rc::new(raw.module),
|
||||
|
||||
@@ -25,6 +25,13 @@ fn test_environ_translate() {
|
||||
let mut resolver = NullResolver {};
|
||||
let mut compiler = Compiler::new(isa, CompilationStrategy::Auto);
|
||||
let global_exports = Rc::new(RefCell::new(HashMap::new()));
|
||||
let instance = instantiate(&mut compiler, &data, &mut resolver, global_exports, false);
|
||||
let instance = instantiate(
|
||||
&mut compiler,
|
||||
&data,
|
||||
None,
|
||||
&mut resolver,
|
||||
global_exports,
|
||||
false,
|
||||
);
|
||||
assert!(instance.is_ok());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user