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

61
crates/api/src/module.rs

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

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

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

2
crates/jit/src/context.rs

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

12
crates/jit/src/instantiate.rs

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

9
tests/instantiate.rs

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

Loading…
Cancel
Save