Implement imported/exported modules/instances (#2461)
* Implement imported/exported modules/instances This commit implements the final piece of the module linking proposal which is to flesh out the support for importing/exporting instances and modules. This ended up having a few changes: * Two more `PrimaryMap` instances are now stored in an `Instance`. The value for instances is `InstanceHandle` (pretty easy) and for modules it's `Box<dyn Any>` (less easy). * The custom host state for `InstanceHandle` for `wasmtime` is now `Arc<TypeTables` to be able to fully reconstruct an instance's types just from its instance. * Type matching for imports now has been updated to take instances/modules into account. One of the main downsides of this implementation is that type matching of imports is duplicated between wasmparser and wasmtime, leading to posssible bugs especially in the subtelties of module linking. I'm not sure how best to unify these two pieces of validation, however, and it may be more trouble than it's worth. cc #2094 * Update wat/wast/wasmparser * Review comments * Fix a bug in publish script to vendor the right witx Currently there's two witx binaries in our repository given the two wasi spec submodules, so this updates the publication script to vendor the right one.
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
use crate::vmcontext::{
|
||||
VMCallerCheckedAnyfunc, VMContext, VMGlobalDefinition, VMMemoryDefinition, VMTableDefinition,
|
||||
};
|
||||
use crate::InstanceHandle;
|
||||
use std::any::Any;
|
||||
use std::ptr::NonNull;
|
||||
use wasmtime_environ::wasm::Global;
|
||||
use wasmtime_environ::{MemoryPlan, TablePlan};
|
||||
|
||||
/// The value of an export passed from one instance to another.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Export {
|
||||
pub enum Export<'a> {
|
||||
/// A function export value.
|
||||
Function(ExportFunction),
|
||||
|
||||
@@ -19,6 +20,12 @@ pub enum Export {
|
||||
|
||||
/// A global export value.
|
||||
Global(ExportGlobal),
|
||||
|
||||
/// An instance
|
||||
Instance(&'a InstanceHandle),
|
||||
|
||||
/// A module
|
||||
Module(&'a dyn Any),
|
||||
}
|
||||
|
||||
/// A function export value.
|
||||
@@ -31,8 +38,8 @@ pub struct ExportFunction {
|
||||
pub anyfunc: NonNull<VMCallerCheckedAnyfunc>,
|
||||
}
|
||||
|
||||
impl From<ExportFunction> for Export {
|
||||
fn from(func: ExportFunction) -> Export {
|
||||
impl<'a> From<ExportFunction> for Export<'a> {
|
||||
fn from(func: ExportFunction) -> Export<'a> {
|
||||
Export::Function(func)
|
||||
}
|
||||
}
|
||||
@@ -48,8 +55,8 @@ pub struct ExportTable {
|
||||
pub table: TablePlan,
|
||||
}
|
||||
|
||||
impl From<ExportTable> for Export {
|
||||
fn from(func: ExportTable) -> Export {
|
||||
impl<'a> From<ExportTable> for Export<'a> {
|
||||
fn from(func: ExportTable) -> Export<'a> {
|
||||
Export::Table(func)
|
||||
}
|
||||
}
|
||||
@@ -65,8 +72,8 @@ pub struct ExportMemory {
|
||||
pub memory: MemoryPlan,
|
||||
}
|
||||
|
||||
impl From<ExportMemory> for Export {
|
||||
fn from(func: ExportMemory) -> Export {
|
||||
impl<'a> From<ExportMemory> for Export<'a> {
|
||||
fn from(func: ExportMemory) -> Export<'a> {
|
||||
Export::Memory(func)
|
||||
}
|
||||
}
|
||||
@@ -82,8 +89,8 @@ pub struct ExportGlobal {
|
||||
pub global: Global,
|
||||
}
|
||||
|
||||
impl From<ExportGlobal> for Export {
|
||||
fn from(func: ExportGlobal) -> Export {
|
||||
impl<'a> From<ExportGlobal> for Export<'a> {
|
||||
fn from(func: ExportGlobal) -> Export<'a> {
|
||||
Export::Global(func)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
use crate::vmcontext::{VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport};
|
||||
use crate::InstanceHandle;
|
||||
use std::any::Any;
|
||||
use wasmtime_environ::entity::PrimaryMap;
|
||||
use wasmtime_environ::wasm::{InstanceIndex, ModuleIndex};
|
||||
|
||||
/// Resolved import pointers.
|
||||
///
|
||||
/// Note that each of these fields are slices, not `PrimaryMap`. They should be
|
||||
/// Note that some of these fields are slices, not `PrimaryMap`. They should be
|
||||
/// stored in index-order as with the module that we're providing the imports
|
||||
/// for, and indexing is all done the same way as the main module's index
|
||||
/// spaces.
|
||||
#[derive(Clone, Default)]
|
||||
///
|
||||
/// Also note that the way we compile modules means that for the module linking
|
||||
/// proposal all `alias` directives should map to imported items. This means
|
||||
/// that each of these items aren't necessarily directly imported, but may be
|
||||
/// aliased.
|
||||
#[derive(Default)]
|
||||
pub struct Imports<'a> {
|
||||
/// Resolved addresses for imported functions.
|
||||
pub functions: &'a [VMFunctionImport],
|
||||
@@ -19,4 +28,15 @@ pub struct Imports<'a> {
|
||||
|
||||
/// Resolved addresses for imported globals.
|
||||
pub globals: &'a [VMGlobalImport],
|
||||
|
||||
/// Resolved imported instances.
|
||||
pub instances: PrimaryMap<InstanceIndex, InstanceHandle>,
|
||||
|
||||
/// Resolved imported modules.
|
||||
///
|
||||
/// Note that `Box<Any>` here is chosen to allow the embedder of this crate
|
||||
/// to pick an appropriate representation of what module type should be. For
|
||||
/// example for the `wasmtime` crate it's `wasmtime::Module` but that's not
|
||||
/// defined way down here in this low crate.
|
||||
pub modules: PrimaryMap<ModuleIndex, Box<dyn Any>>,
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ use thiserror::Error;
|
||||
use wasmtime_environ::entity::{packed_option::ReservedValue, BoxedSlice, EntityRef, PrimaryMap};
|
||||
use wasmtime_environ::wasm::{
|
||||
DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex,
|
||||
ElemIndex, EntityIndex, FuncIndex, GlobalIndex, GlobalInit, MemoryIndex, SignatureIndex,
|
||||
TableElementType, TableIndex, WasmType,
|
||||
ElemIndex, EntityIndex, FuncIndex, GlobalIndex, GlobalInit, InstanceIndex, MemoryIndex,
|
||||
ModuleIndex, SignatureIndex, TableElementType, TableIndex, WasmType,
|
||||
};
|
||||
use wasmtime_environ::{ir, DataInitializer, Module, ModuleType, TableElements, VMOffsets};
|
||||
|
||||
@@ -50,6 +50,15 @@ pub(crate) struct Instance {
|
||||
/// WebAssembly table data.
|
||||
tables: BoxedSlice<DefinedTableIndex, Table>,
|
||||
|
||||
/// Instances our module defined and their handles.
|
||||
instances: PrimaryMap<InstanceIndex, InstanceHandle>,
|
||||
|
||||
/// Modules that are located in our index space.
|
||||
///
|
||||
/// For now these are `Box<Any>` so the caller can define the type of what a
|
||||
/// module looks like.
|
||||
modules: PrimaryMap<ModuleIndex, Box<dyn Any>>,
|
||||
|
||||
/// Passive elements in this instantiation. As `elem.drop`s happen, these
|
||||
/// entries get removed. A missing entry is considered equivalent to an
|
||||
/// empty slice.
|
||||
@@ -268,7 +277,7 @@ impl Instance {
|
||||
}
|
||||
|
||||
/// Lookup an export with the given export declaration.
|
||||
pub fn lookup_by_declaration(&self, export: &EntityIndex) -> Export {
|
||||
pub fn lookup_by_declaration(&self, export: &EntityIndex) -> Export<'_> {
|
||||
match export {
|
||||
EntityIndex::Function(index) => {
|
||||
let anyfunc = self.get_caller_checked_anyfunc(*index).unwrap();
|
||||
@@ -317,9 +326,8 @@ impl Instance {
|
||||
}
|
||||
.into(),
|
||||
|
||||
// FIXME(#2094)
|
||||
EntityIndex::Instance(_index) => unimplemented!(),
|
||||
EntityIndex::Module(_index) => unimplemented!(),
|
||||
EntityIndex::Instance(index) => Export::Instance(&self.instances[*index]),
|
||||
EntityIndex::Module(index) => Export::Module(&*self.modules[*index]),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -847,6 +855,8 @@ impl InstanceHandle {
|
||||
passive_elements: Default::default(),
|
||||
passive_data,
|
||||
host_state,
|
||||
instances: imports.instances,
|
||||
modules: imports.modules,
|
||||
vmctx: VMContext {},
|
||||
};
|
||||
let layout = instance.alloc_layout();
|
||||
|
||||
Reference in New Issue
Block a user