Module name (#775)
This commit is contained in:
@@ -29,6 +29,7 @@ impl Resolver for SimpleResolver {
|
|||||||
pub fn instantiate_in_context(
|
pub fn instantiate_in_context(
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
imports: Vec<(String, String, Extern)>,
|
imports: Vec<(String, String, Extern)>,
|
||||||
|
module_name: Option<String>,
|
||||||
context: Context,
|
context: Context,
|
||||||
exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
|
exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
|
||||||
) -> Result<(InstanceHandle, HashSet<Context>), Error> {
|
) -> Result<(InstanceHandle, HashSet<Context>), Error> {
|
||||||
@@ -38,6 +39,7 @@ pub fn instantiate_in_context(
|
|||||||
let instance = instantiate(
|
let instance = instantiate(
|
||||||
&mut context.compiler(),
|
&mut context.compiler(),
|
||||||
data,
|
data,
|
||||||
|
module_name,
|
||||||
&mut resolver,
|
&mut resolver,
|
||||||
exports,
|
exports,
|
||||||
debug_info,
|
debug_info,
|
||||||
@@ -77,8 +79,13 @@ impl Instance {
|
|||||||
.zip(externs.iter())
|
.zip(externs.iter())
|
||||||
.map(|(i, e)| (i.module().to_string(), i.name().to_string(), e.clone()))
|
.map(|(i, e)| (i.module().to_string(), i.name().to_string(), e.clone()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let (mut instance_handle, contexts) =
|
let (mut instance_handle, contexts) = instantiate_in_context(
|
||||||
instantiate_in_context(module.binary().expect("binary"), imports, context, exports)?;
|
module.binary().expect("binary"),
|
||||||
|
imports,
|
||||||
|
module.name().cloned(),
|
||||||
|
context,
|
||||||
|
exports,
|
||||||
|
)?;
|
||||||
|
|
||||||
let exports = {
|
let exports = {
|
||||||
let mut exports = Vec::with_capacity(module.exports().len());
|
let mut exports = Vec::with_capacity(module.exports().len());
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ use crate::types::{
|
|||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use wasmparser::{
|
use wasmparser::{
|
||||||
validate, ExternalKind, ImportSectionEntryType, ModuleReader, OperatorValidatorConfig,
|
validate, CustomSectionKind, ExternalKind, ImportSectionEntryType, ModuleReader, Name,
|
||||||
SectionCode, ValidatingParserConfig,
|
OperatorValidatorConfig, SectionCode, ValidatingParserConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn into_memory_type(mt: wasmparser::MemoryType) -> MemoryType {
|
fn into_memory_type(mt: wasmparser::MemoryType) -> MemoryType {
|
||||||
@@ -56,7 +56,9 @@ fn into_table_type(tt: wasmparser::TableType) -> TableType {
|
|||||||
TableType::new(ty, limits)
|
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 reader = ModuleReader::new(binary)?;
|
||||||
let mut imports = Vec::new();
|
let mut imports = Vec::new();
|
||||||
let mut exports = 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 func_sig = Vec::new();
|
||||||
let mut sigs = Vec::new();
|
let mut sigs = Vec::new();
|
||||||
let mut globals = Vec::new();
|
let mut globals = Vec::new();
|
||||||
|
let mut module_name = None;
|
||||||
while !reader.eof() {
|
while !reader.eof() {
|
||||||
let section = reader.read()?;
|
let section = reader.read()?;
|
||||||
match section.code {
|
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));
|
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
|
// 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)]
|
#[derive(Clone)]
|
||||||
@@ -196,6 +219,7 @@ struct ModuleInner {
|
|||||||
source: ModuleCodeSource,
|
source: ModuleCodeSource,
|
||||||
imports: Box<[ImportType]>,
|
imports: Box<[ImportType]>,
|
||||||
exports: Box<[ExportType]>,
|
exports: Box<[ExportType]>,
|
||||||
|
name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
@@ -239,7 +263,16 @@ impl Module {
|
|||||||
// Note that the call to `unsafe` here should be ok because we
|
// Note that the call to `unsafe` here should be ok because we
|
||||||
// previously validated the binary, meaning we're guaranteed to pass a
|
// previously validated the binary, meaning we're guaranteed to pass a
|
||||||
// valid binary for `store`.
|
// 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`
|
/// 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
|
/// be somewhat valid for decoding purposes, and the basics of decoding can
|
||||||
/// still fail.
|
/// still fail.
|
||||||
pub unsafe fn new_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
|
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 {
|
Ok(Module {
|
||||||
inner: Rc::new(ModuleInner {
|
inner: Rc::new(ModuleInner {
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
source: ModuleCodeSource::Binary(binary.into()),
|
source: ModuleCodeSource::Binary(binary.into()),
|
||||||
imports,
|
imports,
|
||||||
exports,
|
exports,
|
||||||
|
name: name_override.or(name),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -320,6 +362,7 @@ impl Module {
|
|||||||
source: ModuleCodeSource::Unknown,
|
source: ModuleCodeSource::Unknown,
|
||||||
imports: Box::new([]),
|
imports: Box::new([]),
|
||||||
exports,
|
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
|
/// Returns the list of imports that this [`Module`] has and must be
|
||||||
/// satisfied.
|
/// satisfied.
|
||||||
pub fn imports(&self) -> &[ImportType] {
|
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.
|
/// WebAssembly table initializers.
|
||||||
pub table_elements: Vec<TableElements>,
|
pub table_elements: Vec<TableElements>,
|
||||||
|
|
||||||
|
/// Module name.
|
||||||
|
pub name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
@@ -186,6 +189,7 @@ impl Module {
|
|||||||
exports: IndexMap::new(),
|
exports: IndexMap::new(),
|
||||||
start_func: None,
|
start_func: None,
|
||||||
table_elements: Vec::new(),
|
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 compiler = Compiler::new(isa, compilation_strategy);
|
||||||
let mut resolver = NullResolver {};
|
let mut resolver = NullResolver {};
|
||||||
let global_exports = Rc::new(RefCell::new(HashMap::new()));
|
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.
|
/// Invoke the given API calls.
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ impl Context {
|
|||||||
instantiate(
|
instantiate(
|
||||||
&mut *self.compiler,
|
&mut *self.compiler,
|
||||||
&data,
|
&data,
|
||||||
|
None,
|
||||||
&mut self.namespace,
|
&mut self.namespace,
|
||||||
Rc::clone(&self.global_exports),
|
Rc::clone(&self.global_exports),
|
||||||
debug_info,
|
debug_info,
|
||||||
@@ -154,6 +155,7 @@ impl Context {
|
|||||||
CompiledModule::new(
|
CompiledModule::new(
|
||||||
&mut *self.compiler,
|
&mut *self.compiler,
|
||||||
data,
|
data,
|
||||||
|
None,
|
||||||
&mut self.namespace,
|
&mut self.namespace,
|
||||||
Rc::clone(&self.global_exports),
|
Rc::clone(&self.global_exports),
|
||||||
debug_info,
|
debug_info,
|
||||||
|
|||||||
@@ -60,12 +60,13 @@ impl<'data> RawCompiledModule<'data> {
|
|||||||
fn new(
|
fn new(
|
||||||
compiler: &mut Compiler,
|
compiler: &mut Compiler,
|
||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
|
module_name: Option<String>,
|
||||||
resolver: &mut dyn Resolver,
|
resolver: &mut dyn Resolver,
|
||||||
debug_info: bool,
|
debug_info: bool,
|
||||||
) -> Result<Self, SetupError> {
|
) -> Result<Self, SetupError> {
|
||||||
let environ = ModuleEnvironment::new(compiler.frontend_config(), compiler.tunables());
|
let environ = ModuleEnvironment::new(compiler.frontend_config(), compiler.tunables());
|
||||||
|
|
||||||
let translation = environ
|
let mut translation = environ
|
||||||
.translate(data)
|
.translate(data)
|
||||||
.map_err(|error| SetupError::Compile(CompileError::Wasm(error)))?;
|
.map_err(|error| SetupError::Compile(CompileError::Wasm(error)))?;
|
||||||
|
|
||||||
@@ -75,6 +76,8 @@ impl<'data> RawCompiledModule<'data> {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
translation.module.name = module_name;
|
||||||
|
|
||||||
let (allocated_functions, jt_offsets, relocations, dbg_image) = compiler.compile(
|
let (allocated_functions, jt_offsets, relocations, dbg_image) = compiler.compile(
|
||||||
&translation.module,
|
&translation.module,
|
||||||
translation.module_translation.as_ref().unwrap(),
|
translation.module_translation.as_ref().unwrap(),
|
||||||
@@ -152,11 +155,13 @@ impl CompiledModule {
|
|||||||
pub fn new<'data>(
|
pub fn new<'data>(
|
||||||
compiler: &mut Compiler,
|
compiler: &mut Compiler,
|
||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
|
module_name: Option<String>,
|
||||||
resolver: &mut dyn Resolver,
|
resolver: &mut dyn Resolver,
|
||||||
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
|
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
|
||||||
debug_info: bool,
|
debug_info: bool,
|
||||||
) -> Result<Self, SetupError> {
|
) -> 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(
|
Ok(Self::from_parts(
|
||||||
raw.module,
|
raw.module,
|
||||||
@@ -258,11 +263,12 @@ impl OwnedDataInitializer {
|
|||||||
pub fn instantiate(
|
pub fn instantiate(
|
||||||
compiler: &mut Compiler,
|
compiler: &mut Compiler,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
|
module_name: Option<String>,
|
||||||
resolver: &mut dyn Resolver,
|
resolver: &mut dyn Resolver,
|
||||||
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
|
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
|
||||||
debug_info: bool,
|
debug_info: bool,
|
||||||
) -> Result<InstanceHandle, SetupError> {
|
) -> 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(
|
InstanceHandle::new(
|
||||||
Rc::new(raw.module),
|
Rc::new(raw.module),
|
||||||
|
|||||||
@@ -25,6 +25,13 @@ fn test_environ_translate() {
|
|||||||
let mut resolver = NullResolver {};
|
let mut resolver = NullResolver {};
|
||||||
let mut compiler = Compiler::new(isa, CompilationStrategy::Auto);
|
let mut compiler = Compiler::new(isa, CompilationStrategy::Auto);
|
||||||
let global_exports = Rc::new(RefCell::new(HashMap::new()));
|
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());
|
assert!(instance.is_ok());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user