Browse Source

Module name (#775)

pull/770/head
Yury Delendik 5 years ago
committed by GitHub
parent
commit
d651408b5a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      crates/api/src/instance.rs
  2. 61
      crates/api/src/module.rs
  3. 54
      crates/api/tests/name.rs
  4. 4
      crates/environ/src/module.rs
  5. 9
      crates/fuzzing/src/oracles.rs
  6. 2
      crates/jit/src/context.rs
  7. 12
      crates/jit/src/instantiate.rs
  8. 9
      tests/instantiate.rs

11
crates/api/src/instance.rs

@ -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());

61
crates/api/src/module.rs

@ -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

@ -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(())
}

4
crates/environ/src/module.rs

@ -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,
}
}

9
crates/fuzzing/src/oracles.rs

@ -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.

2
crates/jit/src/context.rs

@ -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,

12
crates/jit/src/instantiate.rs

@ -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),

9
tests/instantiate.rs

@ -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());
}

Loading…
Cancel
Save