Revert "Remove the need for HostRef<Module> (#778)"
This reverts commit 7b33f1c619.
Pushed a few extra commits by accident, so reverting this.
This commit is contained in:
@@ -38,10 +38,11 @@ fn main() -> anyhow::Result<()> {
|
|||||||
// `Module` which is attached to a `Store` cache.
|
// `Module` which is attached to a `Store` cache.
|
||||||
let wasm = wat::parse_str(WAT)?;
|
let wasm = wat::parse_str(WAT)?;
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let module = Module::new(&store, &wasm)?;
|
let module = HostRef::new(Module::new(&store, &wasm)?);
|
||||||
|
|
||||||
// Find index of the `gcd` export.
|
// Find index of the `gcd` export.
|
||||||
let gcd_index = module
|
let gcd_index = module
|
||||||
|
.borrow()
|
||||||
.exports()
|
.exports()
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
// Compiler the `*.wasm` binary into an in-memory instance of a `Module`.
|
// Compiler the `*.wasm` binary into an in-memory instance of a `Module`.
|
||||||
println!("Compiling module...");
|
println!("Compiling module...");
|
||||||
let module = Module::new(&store, &binary).context("> Error compiling module!")?;
|
let module = HostRef::new(Module::new(&store, &binary).context("> Error compiling module!")?);
|
||||||
|
|
||||||
// Here we handle the imports of the module, which in this case is our
|
// Here we handle the imports of the module, which in this case is our
|
||||||
// `HelloCallback` type and its associated implementation of `Callback.
|
// `HelloCallback` type and its associated implementation of `Callback.
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ fn main() -> Result<(), Error> {
|
|||||||
|
|
||||||
// Compile.
|
// Compile.
|
||||||
println!("Compiling module...");
|
println!("Compiling module...");
|
||||||
let module = Module::new(&store, &binary).context("> Error compiling module!")?;
|
let module = HostRef::new(Module::new(&store, &binary).context("> Error compiling module!")?);
|
||||||
|
|
||||||
// Instantiate.
|
// Instantiate.
|
||||||
println!("Instantiating module...");
|
println!("Instantiating module...");
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
// Compile.
|
// Compile.
|
||||||
println!("Compiling module...");
|
println!("Compiling module...");
|
||||||
let module = Module::new(&store, &binary).context("Error compiling module!")?;
|
let module = HostRef::new(Module::new(&store, &binary).context("Error compiling module!")?);
|
||||||
|
|
||||||
// Create external print functions.
|
// Create external print functions.
|
||||||
println!("Creating callback...");
|
println!("Creating callback...");
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ use wasmtime_runtime::Export;
|
|||||||
///
|
///
|
||||||
/// // Initialise environment and our module.
|
/// // Initialise environment and our module.
|
||||||
/// let store = wasmtime::Store::default();
|
/// let store = wasmtime::Store::default();
|
||||||
/// let module = wasmtime::Module::new(&store, &binary)?;
|
/// let module = HostRef::new(wasmtime::Module::new(&store, &binary)?);
|
||||||
///
|
///
|
||||||
/// // Define the type of the function we're going to call.
|
/// // Define the type of the function we're going to call.
|
||||||
/// let times_two_type = wasmtime::FuncType::new(
|
/// let times_two_type = wasmtime::FuncType::new(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::externals::Extern;
|
use crate::externals::Extern;
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
|
use crate::r#ref::HostRef;
|
||||||
use crate::runtime::Store;
|
use crate::runtime::Store;
|
||||||
use crate::trampoline::take_api_trap;
|
use crate::trampoline::take_api_trap;
|
||||||
use crate::trap::Trap;
|
use crate::trap::Trap;
|
||||||
@@ -59,7 +60,7 @@ pub fn instantiate_in_context(
|
|||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
instance_handle: InstanceHandle,
|
instance_handle: InstanceHandle,
|
||||||
|
|
||||||
module: Module,
|
module: HostRef<Module>,
|
||||||
|
|
||||||
// We need to keep CodeMemory alive.
|
// We need to keep CodeMemory alive.
|
||||||
contexts: HashSet<Context>,
|
contexts: HashSet<Context>,
|
||||||
@@ -68,19 +69,29 @@ pub struct Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
pub fn new(store: &Store, module: &Module, externs: &[Extern]) -> Result<Instance, Error> {
|
pub fn new(
|
||||||
|
store: &Store,
|
||||||
|
module: &HostRef<Module>,
|
||||||
|
externs: &[Extern],
|
||||||
|
) -> Result<Instance, Error> {
|
||||||
let context = store.context().clone();
|
let context = store.context().clone();
|
||||||
let exports = store.global_exports().clone();
|
let exports = store.global_exports().clone();
|
||||||
let imports = module
|
let imports = module
|
||||||
|
.borrow()
|
||||||
.imports()
|
.imports()
|
||||||
.iter()
|
.iter()
|
||||||
.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.borrow().binary().expect("binary"),
|
||||||
|
imports,
|
||||||
|
context,
|
||||||
|
exports,
|
||||||
|
)?;
|
||||||
|
|
||||||
let exports = {
|
let exports = {
|
||||||
|
let module = module.borrow();
|
||||||
let mut exports = Vec::with_capacity(module.exports().len());
|
let mut exports = Vec::with_capacity(module.exports().len());
|
||||||
for export in module.exports() {
|
for export in module.exports() {
|
||||||
let name = export.name().to_string();
|
let name = export.name().to_string();
|
||||||
@@ -105,13 +116,14 @@ impl Instance {
|
|||||||
&self.exports
|
&self.exports
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn module(&self) -> &Module {
|
pub fn module(&self) -> &HostRef<Module> {
|
||||||
&self.module
|
&self.module
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_export_by_name(&self, name: &str) -> Option<&Extern> {
|
pub fn find_export_by_name(&self, name: &str) -> Option<&Extern> {
|
||||||
let (i, _) = self
|
let (i, _) = self
|
||||||
.module
|
.module
|
||||||
|
.borrow()
|
||||||
.exports()
|
.exports()
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@@ -142,7 +154,10 @@ impl Instance {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let module = Module::from_exports(store, exports_types.into_boxed_slice());
|
let module = HostRef::new(Module::from_exports(
|
||||||
|
store,
|
||||||
|
exports_types.into_boxed_slice(),
|
||||||
|
));
|
||||||
|
|
||||||
Instance {
|
Instance {
|
||||||
instance_handle,
|
instance_handle,
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use crate::types::{
|
|||||||
TableType, ValType,
|
TableType, ValType,
|
||||||
};
|
};
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use std::rc::Rc;
|
|
||||||
use wasmparser::{
|
use wasmparser::{
|
||||||
validate, ExternalKind, ImportSectionEntryType, ModuleReader, OperatorValidatorConfig,
|
validate, ExternalKind, ImportSectionEntryType, ModuleReader, OperatorValidatorConfig,
|
||||||
SectionCode, ValidatingParserConfig,
|
SectionCode, ValidatingParserConfig,
|
||||||
@@ -171,27 +170,8 @@ pub(crate) enum ModuleCodeSource {
|
|||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A compiled WebAssembly module, ready to be instantiated.
|
|
||||||
///
|
|
||||||
/// A `Module` is a compiled in-memory representation of an input WebAssembly
|
|
||||||
/// binary. A `Module` is then used to create an [`Instance`](crate::Instance)
|
|
||||||
/// through an instantiation process. You cannot call functions or fetch
|
|
||||||
/// globals, for example, on a `Module` because it's purely a code
|
|
||||||
/// representation. Instead you'll need to create an
|
|
||||||
/// [`Instance`](crate::Instance) to interact with the wasm module.
|
|
||||||
///
|
|
||||||
/// ## Modules and `Clone`
|
|
||||||
///
|
|
||||||
/// Using `clone` on a `Module` is a cheap operation. It will not create an
|
|
||||||
/// entirely new module, but rather just a new reference to the existing module.
|
|
||||||
/// In other words it's a shallow copy, not a deep copy.
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
// FIXME(#777) should be `Arc` and this type should be thread-safe
|
|
||||||
inner: Rc<ModuleInner>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ModuleInner {
|
|
||||||
store: Store,
|
store: Store,
|
||||||
source: ModuleCodeSource,
|
source: ModuleCodeSource,
|
||||||
imports: Box<[ImportType]>,
|
imports: Box<[ImportType]>,
|
||||||
@@ -199,106 +179,29 @@ struct ModuleInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
/// Validate and decode the raw wasm data in `binary` and create a new
|
||||||
/// data.
|
/// `Module` in the given `store`.
|
||||||
///
|
|
||||||
/// The `binary` data provided must be a [binary-encoded][binary]
|
|
||||||
/// WebAssembly module. This means that the data for the wasm module must be
|
|
||||||
/// loaded in-memory if it's present elsewhere, for example on disk.
|
|
||||||
/// Additionally this requires that the entire binary is loaded into memory
|
|
||||||
/// all at once, this API does not support streaming compilation of a
|
|
||||||
/// module.
|
|
||||||
///
|
|
||||||
/// The WebAssembly binary will be decoded and validated. It will also be
|
|
||||||
/// compiled according to the configuration of the provided `store` and
|
|
||||||
/// cached in this type.
|
|
||||||
///
|
|
||||||
/// The provided `store` is a global cache for compiled resources as well as
|
|
||||||
/// configuration for what wasm features are enabled. It's recommended to
|
|
||||||
/// share a `store` among modules if possible.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// This function may fail and return an error. Errors may include
|
|
||||||
/// situations such as:
|
|
||||||
///
|
|
||||||
/// * The binary provided could not be decoded because it's not a valid
|
|
||||||
/// WebAssembly binary
|
|
||||||
/// * The WebAssembly binary may not validate (e.g. contains type errors)
|
|
||||||
/// * Implementation-specific limits were exceeded with a valid binary (for
|
|
||||||
/// example too many locals)
|
|
||||||
/// * The wasm binary may use features that are not enabled in the
|
|
||||||
/// configuration of `store`
|
|
||||||
///
|
|
||||||
/// The error returned should contain full information about why module
|
|
||||||
/// creation failed if one is returned.
|
|
||||||
///
|
|
||||||
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
|
|
||||||
pub fn new(store: &Store, binary: &[u8]) -> Result<Module> {
|
pub fn new(store: &Store, binary: &[u8]) -> Result<Module> {
|
||||||
Self::validate(store, binary)?;
|
Self::validate(store, binary)?;
|
||||||
// Note that the call to `unsafe` here should be ok because we
|
Self::new_unchecked(store, binary)
|
||||||
// previously validated the binary, meaning we're guaranteed to pass a
|
|
||||||
// valid binary for `store`.
|
|
||||||
unsafe { Self::new_unchecked(store, binary) }
|
|
||||||
}
|
}
|
||||||
|
/// Similar to `new`, but does not perform any validation. Only use this
|
||||||
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
/// on modules which are known to have been validated already!
|
||||||
/// data, skipping validation and asserting that `binary` is a valid
|
pub fn new_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
|
||||||
/// WebAssembly module.
|
|
||||||
///
|
|
||||||
/// This function is the same as [`Module::new`] except that it skips the
|
|
||||||
/// call to [`Module::validate`]. This means that the WebAssembly binary is
|
|
||||||
/// not validated for correctness and it is simply assumed as valid.
|
|
||||||
///
|
|
||||||
/// For more information about creation of a module and the `store` argument
|
|
||||||
/// see the documentation of [`Module::new`].
|
|
||||||
///
|
|
||||||
/// # Unsafety
|
|
||||||
///
|
|
||||||
/// This function is `unsafe` due to the unchecked assumption that the input
|
|
||||||
/// `binary` is valid. If the `binary` is not actually a valid wasm binary it
|
|
||||||
/// may cause invalid machine code to get generated, cause panics, etc.
|
|
||||||
///
|
|
||||||
/// It is only safe to call this method if [`Module::validate`] succeeds on
|
|
||||||
/// the same arguments passed to this function.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// This function may fail for many of the same reasons as [`Module::new`].
|
|
||||||
/// While this assumes that the binary is valid it still needs to actually
|
|
||||||
/// 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)?;
|
let (imports, exports) = read_imports_and_exports(binary)?;
|
||||||
Ok(Module {
|
Ok(Module {
|
||||||
inner: Rc::new(ModuleInner {
|
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
source: ModuleCodeSource::Binary(binary.into()),
|
source: ModuleCodeSource::Binary(binary.into()),
|
||||||
imports,
|
imports,
|
||||||
exports,
|
exports,
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
pub(crate) fn binary(&self) -> Option<&[u8]> {
|
||||||
/// Validates `binary` input data as a WebAssembly binary given the
|
match &self.source {
|
||||||
/// configuration in `store`.
|
ModuleCodeSource::Binary(b) => Some(b),
|
||||||
///
|
_ => None,
|
||||||
/// This function will perform a speedy validation of the `binary` input
|
}
|
||||||
/// WebAssembly module (which is in [binary form][binary]) and return either
|
}
|
||||||
/// `Ok` or `Err` depending on the results of validation. The `store`
|
|
||||||
/// argument indicates configuration for WebAssembly features, for example,
|
|
||||||
/// which are used to indicate what should be valid and what shouldn't be.
|
|
||||||
///
|
|
||||||
/// Validation automatically happens as part of [`Module::new`], but is a
|
|
||||||
/// requirement for [`Module::new_unchecked`] to be safe.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// If validation fails for any reason (type check error, usage of a feature
|
|
||||||
/// that wasn't enabled, etc) then an error with a description of the
|
|
||||||
/// validation issue will be returned.
|
|
||||||
///
|
|
||||||
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
|
|
||||||
pub fn validate(store: &Store, binary: &[u8]) -> Result<()> {
|
pub fn validate(store: &Store, binary: &[u8]) -> Result<()> {
|
||||||
let features = store.engine().config.features.clone();
|
let features = store.engine().config.features.clone();
|
||||||
let config = ValidatingParserConfig {
|
let config = ValidatingParserConfig {
|
||||||
@@ -312,39 +215,18 @@ impl Module {
|
|||||||
};
|
};
|
||||||
validate(binary, Some(config)).map_err(Error::new)
|
validate(binary, Some(config)).map_err(Error::new)
|
||||||
}
|
}
|
||||||
|
pub fn imports(&self) -> &[ImportType] {
|
||||||
|
&self.imports
|
||||||
|
}
|
||||||
|
pub fn exports(&self) -> &[ExportType] {
|
||||||
|
&self.exports
|
||||||
|
}
|
||||||
pub fn from_exports(store: &Store, exports: Box<[ExportType]>) -> Self {
|
pub fn from_exports(store: &Store, exports: Box<[ExportType]>) -> Self {
|
||||||
Module {
|
Module {
|
||||||
inner: Rc::new(ModuleInner {
|
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
source: ModuleCodeSource::Unknown,
|
source: ModuleCodeSource::Unknown,
|
||||||
imports: Box::new([]),
|
imports: Box::new([]),
|
||||||
exports,
|
exports,
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn binary(&self) -> Option<&[u8]> {
|
|
||||||
match &self.inner.source {
|
|
||||||
ModuleCodeSource::Binary(b) => Some(b),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the list of imports that this [`Module`] has and must be
|
|
||||||
/// satisfied.
|
|
||||||
pub fn imports(&self) -> &[ImportType] {
|
|
||||||
&self.inner.imports
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the list of exports that this [`Module`] has and will be
|
|
||||||
/// available after instantiation.
|
|
||||||
pub fn exports(&self) -> &[ExportType] {
|
|
||||||
&self.inner.exports
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the [`Store`] that this [`Module`] was compiled into.
|
|
||||||
pub fn store(&self) -> &Store {
|
|
||||||
&self.inner.store
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -331,7 +331,6 @@ impl Engine {
|
|||||||
/// ocnfiguration (see [`Config`] for more information).
|
/// ocnfiguration (see [`Config`] for more information).
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Store {
|
pub struct Store {
|
||||||
// FIXME(#777) should be `Arc` and this type should be thread-safe
|
|
||||||
inner: Rc<StoreInner>,
|
inner: Rc<StoreInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -662,7 +662,7 @@ pub unsafe extern "C" fn wasm_instance_new(
|
|||||||
let import = *imports.add(i);
|
let import = *imports.add(i);
|
||||||
externs.push((*import).ext.clone());
|
externs.push((*import).ext.clone());
|
||||||
}
|
}
|
||||||
let module = &(*module).module.borrow();
|
let module = &(*module).module;
|
||||||
match Instance::new(store, module, &externs) {
|
match Instance::new(store, module, &externs) {
|
||||||
Ok(instance) => {
|
Ok(instance) => {
|
||||||
let instance = Box::new(wasm_instance_t {
|
let instance = Box::new(wasm_instance_t {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ fn test_import_calling_export() {
|
|||||||
|
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let wasm = wat::parse_str(WAT).unwrap();
|
let wasm = wat::parse_str(WAT).unwrap();
|
||||||
let module = Module::new(&store, &wasm).expect("failed to create module");
|
let module = HostRef::new(Module::new(&store, &wasm).expect("failed to create module"));
|
||||||
|
|
||||||
let callback = Rc::new(Callback {
|
let callback = Rc::new(Callback {
|
||||||
other: RefCell::new(None),
|
other: RefCell::new(None),
|
||||||
|
|||||||
8
crates/api/tests/import_calling_export.wat
Normal file
8
crates/api/tests/import_calling_export.wat
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
(module
|
||||||
|
(type $t0 (func))
|
||||||
|
(import "" "imp" (func $.imp (type $t0)))
|
||||||
|
(func $run call $.imp)
|
||||||
|
(func $other)
|
||||||
|
(export "run" (func $run))
|
||||||
|
(export "other" (func $other))
|
||||||
|
)
|
||||||
@@ -23,8 +23,9 @@ fn test_trap_return() -> Result<(), String> {
|
|||||||
)
|
)
|
||||||
.map_err(|e| format!("failed to parse WebAssembly text source: {}", e))?;
|
.map_err(|e| format!("failed to parse WebAssembly text source: {}", e))?;
|
||||||
|
|
||||||
let module =
|
let module = HostRef::new(
|
||||||
Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?;
|
Module::new(&store, &binary).map_err(|e| format!("failed to compile module: {}", e))?,
|
||||||
|
);
|
||||||
let hello_type = FuncType::new(Box::new([]), Box::new([]));
|
let hello_type = FuncType::new(Box::new([]), Box::new([]));
|
||||||
let hello_func = HostRef::new(Func::new(&store, hello_type, Rc::new(HelloCallback)));
|
let hello_func = HostRef::new(Func::new(&store, hello_type, Rc::new(HelloCallback)));
|
||||||
|
|
||||||
|
|||||||
@@ -44,9 +44,12 @@ pub fn instantiate(wasm: &[u8], strategy: Strategy) {
|
|||||||
let engine = Engine::new(&config);
|
let engine = Engine::new(&config);
|
||||||
let store = Store::new(&engine);
|
let store = Store::new(&engine);
|
||||||
|
|
||||||
let module = Module::new(&store, wasm).expect("Failed to compile a valid Wasm module!");
|
let module =
|
||||||
|
HostRef::new(Module::new(&store, wasm).expect("Failed to compile a valid Wasm module!"));
|
||||||
|
|
||||||
let imports = match dummy_imports(&store, module.imports()) {
|
let imports = {
|
||||||
|
let module = module.borrow();
|
||||||
|
match dummy_imports(&store, module.imports()) {
|
||||||
Ok(imps) => imps,
|
Ok(imps) => imps,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// There are some value types that we can't synthesize a
|
// There are some value types that we can't synthesize a
|
||||||
@@ -54,6 +57,7 @@ pub fn instantiate(wasm: &[u8], strategy: Strategy) {
|
|||||||
// import things of these types we skip instantiation.
|
// import things of these types we skip instantiation.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Don't unwrap this: there can be instantiation-/link-time errors that
|
// Don't unwrap this: there can be instantiation-/link-time errors that
|
||||||
@@ -88,7 +92,7 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
|||||||
let mut config: Option<Config> = None;
|
let mut config: Option<Config> = None;
|
||||||
let mut engine: Option<Engine> = None;
|
let mut engine: Option<Engine> = None;
|
||||||
let mut store: Option<Store> = None;
|
let mut store: Option<Store> = None;
|
||||||
let mut modules: HashMap<usize, Module> = Default::default();
|
let mut modules: HashMap<usize, HostRef<Module>> = Default::default();
|
||||||
let mut instances: HashMap<usize, HostRef<Instance>> = Default::default();
|
let mut instances: HashMap<usize, HostRef<Instance>> = Default::default();
|
||||||
|
|
||||||
for call in api.calls {
|
for call in api.calls {
|
||||||
@@ -113,10 +117,10 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ApiCall::ModuleNew { id, wasm } => {
|
ApiCall::ModuleNew { id, wasm } => {
|
||||||
let module = match Module::new(store.as_ref().unwrap(), &wasm.wasm) {
|
let module = HostRef::new(match Module::new(store.as_ref().unwrap(), &wasm.wasm) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
};
|
});
|
||||||
let old = modules.insert(id, module);
|
let old = modules.insert(id, module);
|
||||||
assert!(old.is_none());
|
assert!(old.is_none());
|
||||||
}
|
}
|
||||||
@@ -131,7 +135,9 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
|||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
let imports = match dummy_imports(store.as_ref().unwrap(), module.imports()) {
|
let imports = {
|
||||||
|
let module = module.borrow();
|
||||||
|
match dummy_imports(store.as_ref().unwrap(), module.imports()) {
|
||||||
Ok(imps) => imps,
|
Ok(imps) => imps,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// There are some value types that we can't synthesize a
|
// There are some value types that we can't synthesize a
|
||||||
@@ -139,6 +145,7 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
|||||||
// import things of these types we skip instantiation.
|
// import things of these types we skip instantiation.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Don't unwrap this: there can be instantiation-/link-time errors that
|
// Don't unwrap this: there can be instantiation-/link-time errors that
|
||||||
|
|||||||
@@ -14,11 +14,6 @@ pub struct CodeMemory {
|
|||||||
published: usize,
|
published: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _assert() {
|
|
||||||
fn _assert_send_sync<T: Send + Sync>() {}
|
|
||||||
_assert_send_sync::<CodeMemory>();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CodeMemory {
|
impl CodeMemory {
|
||||||
/// Create a new `CodeMemory` instance.
|
/// Create a new `CodeMemory` instance.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ impl Instance {
|
|||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let exports = PyDict::new(py);
|
let exports = PyDict::new(py);
|
||||||
let module = self.instance.borrow().module().clone();
|
let module = self.instance.borrow().module().clone();
|
||||||
for (i, e) in module.exports().iter().enumerate() {
|
for (i, e) in module.borrow().exports().iter().enumerate() {
|
||||||
match e.ty() {
|
match e.ty() {
|
||||||
wasmtime::ExternType::Func(ft) => {
|
wasmtime::ExternType::Func(ft) => {
|
||||||
let mut args_types = Vec::new();
|
let mut args_types = Vec::new();
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ pub fn instantiate(
|
|||||||
let engine = wasmtime::Engine::new(&wasmtime::Config::new().wasm_multi_value(true));
|
let engine = wasmtime::Engine::new(&wasmtime::Config::new().wasm_multi_value(true));
|
||||||
let store = wasmtime::Store::new(&engine);
|
let store = wasmtime::Store::new(&engine);
|
||||||
|
|
||||||
let module = wasmtime::Module::new(&store, wasm_data).map_err(err2py)?;
|
let module = wasmtime::HostRef::new(wasmtime::Module::new(&store, wasm_data).map_err(err2py)?);
|
||||||
|
|
||||||
let data = Rc::new(ModuleData::new(wasm_data).map_err(err2py)?);
|
let data = Rc::new(ModuleData::new(wasm_data).map_err(err2py)?);
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ pub fn instantiate(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut imports: Vec<wasmtime::Extern> = Vec::new();
|
let mut imports: Vec<wasmtime::Extern> = Vec::new();
|
||||||
for i in module.imports() {
|
for i in module.borrow().imports() {
|
||||||
let module_name = i.module();
|
let module_name = i.module();
|
||||||
if let Some(m) = import_obj.get_item(module_name) {
|
if let Some(m) = import_obj.get_item(module_name) {
|
||||||
let e = find_export_in(m, &store, i.name())?;
|
let e = find_export_in(m, &store, i.name())?;
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ use pyo3::prelude::*;
|
|||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
pub module: wasmtime::Module,
|
pub module: wasmtime::HostRef<wasmtime::Module>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,13 +57,13 @@ fn generate_load(item: &syn::ItemTrait) -> syn::Result<TokenStream> {
|
|||||||
|
|
||||||
let data = #root::wasmtime_interface_types::ModuleData::new(&bytes)?;
|
let data = #root::wasmtime_interface_types::ModuleData::new(&bytes)?;
|
||||||
|
|
||||||
let module = Module::new(&store, &bytes)?;
|
let module = HostRef::new(Module::new(&store, &bytes)?);
|
||||||
|
|
||||||
let mut imports: Vec<Extern> = Vec::new();
|
let mut imports: Vec<Extern> = Vec::new();
|
||||||
if let Some(module_name) = data.find_wasi_module_name() {
|
if let Some(module_name) = data.find_wasi_module_name() {
|
||||||
let wasi_instance = #root::wasmtime_wasi::create_wasi_instance(&store, &[], &[], &[])
|
let wasi_instance = #root::wasmtime_wasi::create_wasi_instance(&store, &[], &[], &[])
|
||||||
.map_err(|e| format_err!("wasm instantiation error: {:?}", e))?;
|
.map_err(|e| format_err!("wasm instantiation error: {:?}", e))?;
|
||||||
for i in module.imports().iter() {
|
for i in module.borrow().imports().iter() {
|
||||||
if i.module() != module_name {
|
if i.module() != module_name {
|
||||||
bail!("unknown import module {}", i.module());
|
bail!("unknown import module {}", i.module());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
//! Low-level abstraction for allocating and managing zero-filled pages
|
//! Low-level abstraction for allocating and managing zero-filled pages
|
||||||
//! of memory.
|
//! of memory.
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
use libc;
|
||||||
use more_asserts::assert_le;
|
use more_asserts::assert_le;
|
||||||
use more_asserts::assert_lt;
|
use more_asserts::assert_lt;
|
||||||
|
use region;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
@@ -16,7 +19,7 @@ fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
|
|||||||
/// and initially-zeroed memory and a length.
|
/// and initially-zeroed memory and a length.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Mmap {
|
pub struct Mmap {
|
||||||
offset: usize,
|
ptr: *mut u8,
|
||||||
len: usize,
|
len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,8 +29,10 @@ impl Mmap {
|
|||||||
// Rust's slices require non-null pointers, even when empty. `Vec`
|
// Rust's slices require non-null pointers, even when empty. `Vec`
|
||||||
// contains code to create a non-null dangling pointer value when
|
// contains code to create a non-null dangling pointer value when
|
||||||
// constructed empty, so we reuse that here.
|
// constructed empty, so we reuse that here.
|
||||||
let empty = Vec::<u8>::new();
|
Self {
|
||||||
Self { offset: empty.as_ptr() as usize, len: 0 }
|
ptr: Vec::new().as_mut_ptr(),
|
||||||
|
len: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `Mmap` pointing to at least `size` bytes of page-aligned accessible memory.
|
/// Create a new `Mmap` pointing to at least `size` bytes of page-aligned accessible memory.
|
||||||
@@ -73,7 +78,7 @@ impl Mmap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
offset: ptr as usize,
|
ptr: ptr as *mut u8,
|
||||||
len: mapping_size,
|
len: mapping_size,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -93,7 +98,7 @@ impl Mmap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut result = Self {
|
let mut result = Self {
|
||||||
offset: ptr as usize,
|
ptr: ptr as *mut u8,
|
||||||
len: mapping_size,
|
len: mapping_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -137,7 +142,7 @@ impl Mmap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
offset: ptr as usize,
|
ptr: ptr as *mut u8,
|
||||||
len: mapping_size,
|
len: mapping_size,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -149,7 +154,7 @@ impl Mmap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut result = Self {
|
let mut result = Self {
|
||||||
offset: ptr as usize,
|
ptr: ptr as *mut u8,
|
||||||
len: mapping_size,
|
len: mapping_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -174,8 +179,7 @@ impl Mmap {
|
|||||||
assert_lt!(start, self.len - len);
|
assert_lt!(start, self.len - len);
|
||||||
|
|
||||||
// Commit the accessible size.
|
// Commit the accessible size.
|
||||||
let ptr = self.offset as *const u8;
|
unsafe { region::protect(self.ptr.add(start), len, region::Protection::ReadWrite) }
|
||||||
unsafe { region::protect(ptr.add(start), len, region::Protection::ReadWrite) }
|
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,10 +198,9 @@ impl Mmap {
|
|||||||
assert_lt!(start, self.len - len);
|
assert_lt!(start, self.len - len);
|
||||||
|
|
||||||
// Commit the accessible size.
|
// Commit the accessible size.
|
||||||
let ptr = self.offset as *const u8;
|
|
||||||
if unsafe {
|
if unsafe {
|
||||||
VirtualAlloc(
|
VirtualAlloc(
|
||||||
ptr.add(start) as *mut c_void,
|
self.ptr.add(start) as *mut c_void,
|
||||||
len,
|
len,
|
||||||
MEM_COMMIT,
|
MEM_COMMIT,
|
||||||
PAGE_READWRITE,
|
PAGE_READWRITE,
|
||||||
@@ -213,22 +216,22 @@ impl Mmap {
|
|||||||
|
|
||||||
/// Return the allocated memory as a slice of u8.
|
/// Return the allocated memory as a slice of u8.
|
||||||
pub fn as_slice(&self) -> &[u8] {
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
unsafe { slice::from_raw_parts(self.offset as *const u8, self.len) }
|
unsafe { slice::from_raw_parts(self.ptr, self.len) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the allocated memory as a mutable slice of u8.
|
/// Return the allocated memory as a mutable slice of u8.
|
||||||
pub fn as_mut_slice(&mut self) -> &mut [u8] {
|
pub fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||||
unsafe { slice::from_raw_parts_mut(self.offset as *mut u8, self.len) }
|
unsafe { slice::from_raw_parts_mut(self.ptr, self.len) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the allocated memory as a pointer to u8.
|
/// Return the allocated memory as a pointer to u8.
|
||||||
pub fn as_ptr(&self) -> *const u8 {
|
pub fn as_ptr(&self) -> *const u8 {
|
||||||
self.offset as *const u8
|
self.ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the allocated memory as a mutable pointer to u8.
|
/// Return the allocated memory as a mutable pointer to u8.
|
||||||
pub fn as_mut_ptr(&mut self) -> *mut u8 {
|
pub fn as_mut_ptr(&mut self) -> *mut u8 {
|
||||||
self.offset as *mut u8
|
self.ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the length of the allocated memory.
|
/// Return the length of the allocated memory.
|
||||||
@@ -246,7 +249,7 @@ impl Drop for Mmap {
|
|||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.len != 0 {
|
if self.len != 0 {
|
||||||
let r = unsafe { libc::munmap(self.offset as *mut libc::c_void, self.len) };
|
let r = unsafe { libc::munmap(self.ptr as *mut libc::c_void, self.len) };
|
||||||
assert_eq!(r, 0, "munmap failed: {}", io::Error::last_os_error());
|
assert_eq!(r, 0, "munmap failed: {}", io::Error::last_os_error());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,17 +260,12 @@ impl Drop for Mmap {
|
|||||||
use winapi::ctypes::c_void;
|
use winapi::ctypes::c_void;
|
||||||
use winapi::um::memoryapi::VirtualFree;
|
use winapi::um::memoryapi::VirtualFree;
|
||||||
use winapi::um::winnt::MEM_RELEASE;
|
use winapi::um::winnt::MEM_RELEASE;
|
||||||
let r = unsafe { VirtualFree(self.offset as *mut c_void, 0, MEM_RELEASE) };
|
let r = unsafe { VirtualFree(self.ptr as *mut c_void, 0, MEM_RELEASE) };
|
||||||
assert_ne!(r, 0);
|
assert_ne!(r, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _assert() {
|
|
||||||
fn _assert_send_sync<T: Send + Sync>() {}
|
|
||||||
_assert_send_sync::<Mmap>();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -43,8 +43,9 @@ pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> any
|
|||||||
.context("failed to instantiate wasi")?,
|
.context("failed to instantiate wasi")?,
|
||||||
);
|
);
|
||||||
|
|
||||||
let module = Module::new(&store, &data).context("failed to create wasm module")?;
|
let module = HostRef::new(Module::new(&store, &data).context("failed to create wasm module")?);
|
||||||
let imports = module
|
let imports = module
|
||||||
|
.borrow()
|
||||||
.imports()
|
.imports()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ impl WastContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn instantiate(&self, module: &[u8]) -> Result<Outcome<HostRef<Instance>>> {
|
fn instantiate(&self, module: &[u8]) -> Result<Outcome<HostRef<Instance>>> {
|
||||||
let module = Module::new(&self.store, module)?;
|
let module = HostRef::new(Module::new(&self.store, module)?);
|
||||||
let mut imports = Vec::new();
|
let mut imports = Vec::new();
|
||||||
for import in module.imports() {
|
for import in module.borrow().imports() {
|
||||||
if import.module() == "spectest" {
|
if import.module() == "spectest" {
|
||||||
let spectest = self
|
let spectest = self
|
||||||
.spectest
|
.spectest
|
||||||
|
|||||||
@@ -234,14 +234,15 @@ impl RunCommand {
|
|||||||
store: &Store,
|
store: &Store,
|
||||||
module_registry: &HashMap<String, HostRef<Instance>>,
|
module_registry: &HashMap<String, HostRef<Instance>>,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
) -> Result<(HostRef<Instance>, Module, Vec<u8>)> {
|
) -> Result<(HostRef<Instance>, HostRef<Module>, Vec<u8>)> {
|
||||||
// Read the wasm module binary either as `*.wat` or a raw binary
|
// Read the wasm module binary either as `*.wat` or a raw binary
|
||||||
let data = wat::parse_file(path)?;
|
let data = wat::parse_file(path)?;
|
||||||
|
|
||||||
let module = Module::new(store, &data)?;
|
let module = HostRef::new(Module::new(store, &data)?);
|
||||||
|
|
||||||
// Resolve import using module_registry.
|
// Resolve import using module_registry.
|
||||||
let imports = module
|
let imports = module
|
||||||
|
.borrow()
|
||||||
.imports()
|
.imports()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
@@ -284,6 +285,7 @@ impl RunCommand {
|
|||||||
let data = ModuleData::new(&data)?;
|
let data = ModuleData::new(&data)?;
|
||||||
self.invoke_export(instance, &data, name)?;
|
self.invoke_export(instance, &data, name)?;
|
||||||
} else if module
|
} else if module
|
||||||
|
.borrow()
|
||||||
.exports()
|
.exports()
|
||||||
.iter()
|
.iter()
|
||||||
.any(|export| export.name().is_empty())
|
.any(|export| export.name().is_empty())
|
||||||
|
|||||||
Reference in New Issue
Block a user