Publish with externvals (#81)
* Publish with_externvals constructor. * Add examples to Signature::new. * Use Iterators for ExternVal imports
This commit is contained in:
parent
a6b5574704
commit
d12a04f8ff
110
src/module.rs
110
src/module.rs
|
@ -213,9 +213,9 @@ impl ModuleInstance {
|
||||||
self.exports.borrow_mut().insert(name.into(), extern_val);
|
self.exports.borrow_mut().insert(name.into(), extern_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_module(
|
fn alloc_module<'i, I: Iterator<Item = &'i ExternVal>>(
|
||||||
loaded_module: &Module,
|
loaded_module: &Module,
|
||||||
extern_vals: &[ExternVal]
|
extern_vals: I,
|
||||||
) -> Result<ModuleRef, Error> {
|
) -> Result<ModuleRef, Error> {
|
||||||
let module = loaded_module.module();
|
let module = loaded_module.module();
|
||||||
let instance = ModuleRef(Rc::new(ModuleInstance::default()));
|
let instance = ModuleRef(Rc::new(ModuleInstance::default()));
|
||||||
|
@ -226,18 +226,26 @@ impl ModuleInstance {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let imports = module.import_section().map(|is| is.entries()).unwrap_or(
|
let mut imports = module
|
||||||
&[],
|
.import_section()
|
||||||
);
|
.map(|is| is.entries())
|
||||||
if imports.len() != extern_vals.len() {
|
.unwrap_or(&[])
|
||||||
return Err(Error::Instantiation(
|
.into_iter();
|
||||||
"extern_vals length is not equal to import section entries".to_owned()
|
let mut extern_vals = extern_vals;
|
||||||
));
|
loop {
|
||||||
}
|
// Iterate on imports and extern_vals in lockstep, a-la `Iterator:zip`.
|
||||||
|
// We can't use `Iterator::zip` since we want to check if lengths of both iterators are same and
|
||||||
|
// `Iterator::zip` just returns `None` if either of iterators return `None`.
|
||||||
|
let (import, extern_val) = match (imports.next(), extern_vals.next()) {
|
||||||
|
(Some(import), Some(extern_val)) => (import, extern_val),
|
||||||
|
(None, None) => break,
|
||||||
|
(Some(_), None) | (None, Some(_)) => {
|
||||||
|
return Err(Error::Instantiation(
|
||||||
|
"extern_vals length is not equal to import section entries".to_owned(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for (import, extern_val) in
|
|
||||||
Iterator::zip(imports.into_iter(), extern_vals.into_iter())
|
|
||||||
{
|
|
||||||
match (import.external(), extern_val) {
|
match (import.external(), extern_val) {
|
||||||
(&External::Function(fn_type_idx), &ExternVal::Func(ref func)) => {
|
(&External::Function(fn_type_idx), &ExternVal::Func(ref func)) => {
|
||||||
let expected_fn_type = instance.signature_by_index(fn_type_idx).expect(
|
let expected_fn_type = instance.signature_by_index(fn_type_idx).expect(
|
||||||
|
@ -383,10 +391,16 @@ impl ModuleInstance {
|
||||||
Ok(instance)
|
Ok(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instantiate_with_externvals(
|
/// Instantiate a module with given [external values][ExternVal] as imports.
|
||||||
loaded_module: &Module,
|
///
|
||||||
extern_vals: &[ExternVal],
|
/// See [new] for details.
|
||||||
) -> Result<ModuleRef, Error> {
|
///
|
||||||
|
/// [new]: #method.new
|
||||||
|
/// [ExternVal]: https://webassembly.github.io/spec/core/exec/runtime.html#syntax-externval
|
||||||
|
pub fn with_externvals<'a, 'i, I: Iterator<Item = &'i ExternVal>>(
|
||||||
|
loaded_module: &'a Module,
|
||||||
|
extern_vals: I,
|
||||||
|
) -> Result<NotStartedModuleRef<'a>, Error> {
|
||||||
let module = loaded_module.module();
|
let module = loaded_module.module();
|
||||||
|
|
||||||
let module_ref = ModuleInstance::alloc_module(loaded_module, extern_vals)?;
|
let module_ref = ModuleInstance::alloc_module(loaded_module, extern_vals)?;
|
||||||
|
@ -433,7 +447,10 @@ impl ModuleInstance {
|
||||||
memory_inst.set(offset_val, data_segment.value())?;
|
memory_inst.set(offset_val, data_segment.value())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(module_ref)
|
Ok(NotStartedModuleRef {
|
||||||
|
loaded_module,
|
||||||
|
instance: module_ref,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiate a [module][`Module`].
|
/// Instantiate a [module][`Module`].
|
||||||
|
@ -535,11 +552,7 @@ impl ModuleInstance {
|
||||||
extern_vals.push(extern_val);
|
extern_vals.push(extern_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
let instance = Self::instantiate_with_externvals(loaded_module, &extern_vals)?;
|
Self::with_externvals(loaded_module, extern_vals.iter())
|
||||||
Ok(NotStartedModuleRef {
|
|
||||||
loaded_module,
|
|
||||||
instance,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoke exported function by a name.
|
/// Invoke exported function by a name.
|
||||||
|
@ -752,7 +765,9 @@ pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use imports::ImportsBuilder;
|
use imports::ImportsBuilder;
|
||||||
use super::{ModuleInstance};
|
use func::FuncInstance;
|
||||||
|
use types::{Signature, ValueType};
|
||||||
|
use super::{ModuleInstance, ExternVal};
|
||||||
use tests::parse_wat;
|
use tests::parse_wat;
|
||||||
|
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
|
@ -770,4 +785,51 @@ mod tests {
|
||||||
&ImportsBuilder::default()
|
&ImportsBuilder::default()
|
||||||
).unwrap().assert_no_start();
|
).unwrap().assert_no_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn imports_provided_by_externvals() {
|
||||||
|
let module_with_single_import = parse_wat(
|
||||||
|
r#"
|
||||||
|
(module
|
||||||
|
(import "foo" "bar" (func))
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
ModuleInstance::with_externvals(
|
||||||
|
&module_with_single_import,
|
||||||
|
[
|
||||||
|
ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0),)
|
||||||
|
].iter(),
|
||||||
|
).is_ok()
|
||||||
|
);
|
||||||
|
|
||||||
|
// externval vector is longer than import count.
|
||||||
|
assert!(
|
||||||
|
ModuleInstance::with_externvals(
|
||||||
|
&module_with_single_import,
|
||||||
|
[
|
||||||
|
ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0)),
|
||||||
|
ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 1)),
|
||||||
|
].iter(),
|
||||||
|
).is_err()
|
||||||
|
);
|
||||||
|
|
||||||
|
// externval vector is shorter than import count.
|
||||||
|
assert!(ModuleInstance::with_externvals(&module_with_single_import, [].iter(),).is_err());
|
||||||
|
|
||||||
|
// externval vector has an unexpected type.
|
||||||
|
assert!(
|
||||||
|
ModuleInstance::with_externvals(
|
||||||
|
&module_with_single_import,
|
||||||
|
[
|
||||||
|
ExternVal::Func(FuncInstance::alloc_host(
|
||||||
|
Signature::new(&[][..], Some(ValueType::I32)),
|
||||||
|
0
|
||||||
|
),)
|
||||||
|
].iter(),
|
||||||
|
).is_err()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/types.rs
16
src/types.rs
|
@ -20,6 +20,22 @@ pub struct Signature {
|
||||||
impl Signature {
|
impl Signature {
|
||||||
/// Creates new signature with givens
|
/// Creates new signature with givens
|
||||||
/// parameter types and optional return type.
|
/// parameter types and optional return type.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use wasmi::{Signature, ValueType};
|
||||||
|
///
|
||||||
|
/// // s1: (i32) -> ()
|
||||||
|
/// let s1 = Signature::new(&[ValueType::I32][..], None);
|
||||||
|
///
|
||||||
|
/// // s2: () -> i32
|
||||||
|
/// let s2 = Signature::new(&[][..], Some(ValueType::I32));
|
||||||
|
///
|
||||||
|
/// // s3: (I64) -> ()
|
||||||
|
/// let dynamic_params = vec![ValueType::I64];
|
||||||
|
/// let s3 = Signature::new(dynamic_params, None);
|
||||||
|
/// ```
|
||||||
pub fn new<C: Into<Cow<'static, [ValueType]>>>(
|
pub fn new<C: Into<Cow<'static, [ValueType]>>>(
|
||||||
params: C,
|
params: C,
|
||||||
return_type: Option<ValueType>
|
return_type: Option<ValueType>
|
||||||
|
|
Loading…
Reference in New Issue