From 2502e1a8db768ee71e53d90beae5ca011f407b6c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 30 Nov 2020 11:49:10 -0800 Subject: [PATCH 1/4] 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` (less easy). * The custom host state for `InstanceHandle` for `wasmtime` is now `Arc wasm_externkind_t { Extern::Global(_) => crate::WASM_EXTERN_GLOBAL, Extern::Table(_) => crate::WASM_EXTERN_TABLE, Extern::Memory(_) => crate::WASM_EXTERN_MEMORY, + + // FIXME(#2094) + Extern::Instance(_) => unimplemented!(), + Extern::Module(_) => unimplemented!(), } } diff --git a/crates/environ/src/module.rs b/crates/environ/src/module.rs index d78efadf0f33..c555a4435b8f 100644 --- a/crates/environ/src/module.rs +++ b/crates/environ/src/module.rs @@ -346,6 +346,30 @@ impl Module { pub fn is_imported_global(&self, index: GlobalIndex) -> bool { index.index() < self.num_imported_globals } + + /// Test whether the given global index is for an imported global. + pub fn imports(&self) -> impl Iterator, EntityType)> { + self.initializers.iter().filter_map(move |i| match i { + Initializer::Import { + module, + field, + index, + } => Some((module.as_str(), field.as_deref(), self.type_of(*index))), + _ => None, + }) + } + + /// Returns the type of an item based on its index + pub fn type_of(&self, index: EntityIndex) -> EntityType { + match index { + EntityIndex::Global(i) => EntityType::Global(self.globals[i]), + EntityIndex::Table(i) => EntityType::Table(self.table_plans[i].table), + EntityIndex::Memory(i) => EntityType::Memory(self.memory_plans[i].memory), + EntityIndex::Function(i) => EntityType::Function(self.functions[i]), + EntityIndex::Instance(i) => EntityType::Instance(self.instances[i]), + EntityIndex::Module(i) => EntityType::Module(self.modules[i]), + } + } } /// All types which are recorded for the entirety of a translation. @@ -376,7 +400,7 @@ pub struct ModuleSignature { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InstanceSignature { /// The name of what's being exported as well as its type signature. - pub exports: Vec<(String, EntityType)>, + pub exports: IndexMap, } mod passive_data_serde { diff --git a/crates/environ/src/module_environ.rs b/crates/environ/src/module_environ.rs index f1af5c4ea023..6d36b4e7a9f7 100644 --- a/crates/environ/src/module_environ.rs +++ b/crates/environ/src/module_environ.rs @@ -857,7 +857,7 @@ and for re-adding support for interface types you can see this issue: // instance. Alias::Child { instance, export } => { let ty = self.result.module.instances[instance]; - match &self.types.instance_signatures[ty].exports[export].1 { + match &self.types.instance_signatures[ty].exports[export] { EntityType::Global(g) => { self.result.module.globals.push(g.clone()); self.result.module.num_imported_globals += 1; diff --git a/crates/runtime/src/export.rs b/crates/runtime/src/export.rs index edfa51e1f290..0161e56a6809 100644 --- a/crates/runtime/src/export.rs +++ b/crates/runtime/src/export.rs @@ -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, } -impl From for Export { - fn from(func: ExportFunction) -> Export { +impl<'a> From for Export<'a> { + fn from(func: ExportFunction) -> Export<'a> { Export::Function(func) } } @@ -48,8 +55,8 @@ pub struct ExportTable { pub table: TablePlan, } -impl From for Export { - fn from(func: ExportTable) -> Export { +impl<'a> From for Export<'a> { + fn from(func: ExportTable) -> Export<'a> { Export::Table(func) } } @@ -65,8 +72,8 @@ pub struct ExportMemory { pub memory: MemoryPlan, } -impl From for Export { - fn from(func: ExportMemory) -> Export { +impl<'a> From for Export<'a> { + fn from(func: ExportMemory) -> Export<'a> { Export::Memory(func) } } @@ -82,8 +89,8 @@ pub struct ExportGlobal { pub global: Global, } -impl From for Export { - fn from(func: ExportGlobal) -> Export { +impl<'a> From for Export<'a> { + fn from(func: ExportGlobal) -> Export<'a> { Export::Global(func) } } diff --git a/crates/runtime/src/imports.rs b/crates/runtime/src/imports.rs index 2f85ba220199..19696307503a 100644 --- a/crates/runtime/src/imports.rs +++ b/crates/runtime/src/imports.rs @@ -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, + + /// Resolved imported modules. + /// + /// Note that `Box` 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>, } diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index 1f39b171a032..9ff7c4ee6db6 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -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, + /// Instances our module defined and their handles. + instances: PrimaryMap, + + /// Modules that are located in our index space. + /// + /// For now these are `Box` so the caller can define the type of what a + /// module looks like. + modules: PrimaryMap>, + /// 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(); diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 57cdec42a5f2..e0316847263b 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -29,6 +29,7 @@ wat = { version = "1.0.18", optional = true } smallvec = "1.4.0" serde = { version = "1.0.94", features = ["derive"] } bincode = "1.2.1" +indexmap = "1.6" [target.'cfg(target_os = "windows")'.dependencies] winapi = "0.3.7" diff --git a/crates/wasmtime/src/externals.rs b/crates/wasmtime/src/externals.rs index 63f2e2678f4d..9a075e308efc 100644 --- a/crates/wasmtime/src/externals.rs +++ b/crates/wasmtime/src/externals.rs @@ -3,8 +3,8 @@ use crate::trampoline::{ }; use crate::values::{from_checked_anyfunc, into_checked_anyfunc, Val}; use crate::{ - ExternRef, ExternType, Func, GlobalType, MemoryType, Mutability, Store, TableType, Trap, - ValType, + ExternRef, ExternType, Func, GlobalType, Instance, MemoryType, Module, Mutability, Store, + TableType, Trap, ValType, }; use anyhow::{anyhow, bail, Result}; use std::mem; @@ -33,6 +33,10 @@ pub enum Extern { Table(Table), /// A WebAssembly linear memory. Memory(Memory), + /// A WebAssembly instance. + Instance(Instance), + /// A WebAssembly module. + Module(Module), } impl Extern { @@ -76,6 +80,26 @@ impl Extern { } } + /// Returns the underlying `Instance`, if this external is a instance. + /// + /// Returns `None` if this is not a instance. + pub fn into_instance(self) -> Option { + match self { + Extern::Instance(instance) => Some(instance), + _ => None, + } + } + + /// Returns the underlying `Module`, if this external is a module. + /// + /// Returns `None` if this is not a module. + pub fn into_module(self) -> Option { + match self { + Extern::Module(module) => Some(module), + _ => None, + } + } + /// Returns the type associated with this `Extern`. pub fn ty(&self) -> ExternType { match self { @@ -83,6 +107,8 @@ impl Extern { Extern::Memory(ft) => ExternType::Memory(ft.ty()), Extern::Table(tt) => ExternType::Table(tt.ty()), Extern::Global(gt) => ExternType::Global(gt.ty()), + Extern::Instance(i) => ExternType::Instance(i.ty()), + Extern::Module(m) => ExternType::Module(m.ty()), } } @@ -103,6 +129,13 @@ impl Extern { wasmtime_runtime::Export::Table(t) => { Extern::Table(Table::from_wasmtime_table(t, instance)) } + wasmtime_runtime::Export::Instance(i) => { + let handle = unsafe { instance.store.existing_instance_handle(i.clone()) }; + Extern::Instance(Instance::from_wasmtime(handle)) + } + wasmtime_runtime::Export::Module(m) => { + Extern::Module(m.downcast_ref::().unwrap().clone()) + } } } @@ -112,6 +145,10 @@ impl Extern { Extern::Global(g) => &g.instance.store, Extern::Memory(m) => &m.instance.store, Extern::Table(t) => &t.instance.store, + Extern::Instance(i) => i.store(), + // Modules don't live in stores right now, so they're compatible + // with all stores. + Extern::Module(_) => return true, }; Store::same(my_store, store) } @@ -122,6 +159,8 @@ impl Extern { Extern::Table(_) => "table", Extern::Memory(_) => "memory", Extern::Global(_) => "global", + Extern::Instance(_) => "instance", + Extern::Module(_) => "module", } } } @@ -150,6 +189,18 @@ impl From for Extern { } } +impl From for Extern { + fn from(r: Instance) -> Self { + Extern::Instance(r) + } +} + +impl From for Extern { + fn from(r: Module) -> Self { + Extern::Module(r) + } +} + /// A WebAssembly `global` value which can be read and written to. /// /// A `global` in WebAssembly is sort of like a global variable within an @@ -294,11 +345,8 @@ impl Global { } } - pub(crate) fn matches_expected(&self, expected: &wasmtime_environ::wasm::Global) -> bool { - let actual = &self.wasmtime_export.global; - expected.ty == actual.ty - && expected.wasm_ty == actual.wasm_ty - && expected.mutability == actual.mutability + pub(crate) fn wasmtime_ty(&self) -> &wasmtime_environ::wasm::Global { + &self.wasmtime_export.global } pub(crate) fn vmimport(&self) -> wasmtime_runtime::VMGlobalImport { @@ -538,19 +586,8 @@ impl Table { } } - pub(crate) fn matches_expected(&self, ty: &wasmtime_environ::TablePlan) -> bool { - let expected = &ty.table; - let actual = &self.wasmtime_export.table.table; - expected.wasm_ty == actual.wasm_ty - && expected.ty == actual.ty - && expected.minimum <= actual.minimum - && match expected.maximum { - Some(expected) => match actual.maximum { - Some(actual) => expected >= actual, - None => false, - }, - None => true, - } + pub(crate) fn wasmtime_ty(&self) -> &wasmtime_environ::wasm::Table { + &self.wasmtime_export.table.table } pub(crate) fn vmimport(&self) -> wasmtime_runtime::VMTableImport { @@ -960,18 +997,8 @@ impl Memory { } } - pub(crate) fn matches_expected(&self, ty: &wasmtime_environ::MemoryPlan) -> bool { - let expected = &ty.memory; - let actual = &self.wasmtime_export.memory.memory; - expected.shared == actual.shared - && expected.minimum <= actual.minimum - && match expected.maximum { - Some(expected) => match actual.maximum { - Some(actual) => expected >= actual, - None => false, - }, - None => true, - } + pub(crate) fn wasmtime_ty(&self) -> &wasmtime_environ::wasm::Memory { + &self.wasmtime_export.memory.memory } pub(crate) fn vmimport(&self) -> wasmtime_runtime::VMMemoryImport { diff --git a/crates/wasmtime/src/func.rs b/crates/wasmtime/src/func.rs index b57936d67d98..630c5f736d24 100644 --- a/crates/wasmtime/src/func.rs +++ b/crates/wasmtime/src/func.rs @@ -798,10 +798,6 @@ impl Func { &self.instance.store } - pub(crate) fn matches_expected(&self, expected: VMSharedSignatureIndex) -> bool { - self.sig_index() == expected - } - pub(crate) fn vmimport(&self) -> wasmtime_runtime::VMFunctionImport { unsafe { let f = self.caller_checked_anyfunc(); @@ -1503,7 +1499,6 @@ impl Caller<'_> { return None; } let instance = InstanceHandle::from_vmctx(self.caller_vmctx); - let export = instance.lookup(name)?; // Our `Weak` pointer is used only to break a cycle where `Store` // stores instance handles which have this weak pointer as their // custom host data. This function should only be invoke-able while @@ -1511,6 +1506,7 @@ impl Caller<'_> { debug_assert!(self.store.upgrade().is_some()); let handle = Store::from_inner(self.store.upgrade()?).existing_instance_handle(instance); + let export = handle.lookup(name)?; match export { Export::Memory(m) => Some(Extern::Memory(Memory::from_wasmtime_memory(m, handle))), Export::Function(f) => Some(Extern::Func(Func::from_wasmtime_function(f, handle))), diff --git a/crates/wasmtime/src/instance.rs b/crates/wasmtime/src/instance.rs index 066a61864036..678ced4f52bd 100644 --- a/crates/wasmtime/src/instance.rs +++ b/crates/wasmtime/src/instance.rs @@ -1,16 +1,23 @@ use crate::trampoline::StoreInstanceHandle; -use crate::{Engine, Export, Extern, Func, Global, Memory, Module, Store, Table, Trap}; +use crate::types::matching; +use crate::{ + Engine, Export, Extern, ExternType, Func, Global, InstanceType, Memory, Module, Store, Table, + Trap, +}; use anyhow::{bail, Context, Error, Result}; use std::mem; +use std::sync::Arc; use wasmtime_environ::entity::PrimaryMap; use wasmtime_environ::wasm::{ - EntityIndex, FuncIndex, GlobalIndex, InstanceIndex, MemoryIndex, ModuleIndex, TableIndex, + EntityIndex, EntityType, FuncIndex, GlobalIndex, InstanceIndex, MemoryIndex, ModuleIndex, + TableIndex, }; use wasmtime_environ::Initializer; -use wasmtime_jit::{CompiledModule, TypeTables}; +use wasmtime_jit::TypeTables; use wasmtime_runtime::{ - Imports, InstantiationError, StackMapRegistry, VMContext, VMExternRefActivationsTable, - VMFunctionBody, VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport, + Imports, InstanceHandle, InstantiationError, StackMapRegistry, VMContext, + VMExternRefActivationsTable, VMFunctionBody, VMFunctionImport, VMGlobalImport, VMMemoryImport, + VMTableImport, }; /// Performs all low-level steps necessary for instantiation. @@ -35,17 +42,16 @@ use wasmtime_runtime::{ /// into the provided builder. The expected entity that it's defining is also /// passed in for the top-level case where type-checking is performed. This is /// fallible because type checks may fail. -fn instantiate<'a>( - store: &'a Store, - compiled_module: &'a CompiledModule, - all_modules: &'a [CompiledModule], - types: &'a TypeTables, - parent_modules: &PrimaryMap, - define_import: &mut dyn FnMut(&EntityIndex, &mut ImportsBuilder<'a>) -> Result<()>, +fn instantiate( + store: &Store, + module: &Module, + parent_modules: &PrimaryMap, + define_import: &mut dyn FnMut(&EntityIndex, &mut ImportsBuilder<'_>) -> Result<()>, ) -> Result { + let compiled_module = module.compiled_module(); let env_module = compiled_module.module(); - let mut imports = ImportsBuilder::new(env_module, types, store); + let mut imports = ImportsBuilder::new(store, module); for initializer in env_module.initializers.iter() { match initializer { // Definition of an import depends on how our parent is providing @@ -67,24 +73,28 @@ fn instantiate<'a>( // This one's pretty easy, we're just picking up our parent's module // and putting it into our own index space. Initializer::AliasParentModule(idx) => { - imports.modules.push(parent_modules[*idx]); + imports.modules.push(parent_modules[*idx].clone()); } // Turns out defining any kind of module is pretty easy, we're just // slinging around pointers. Initializer::DefineModule(idx) => { - imports.modules.push(&all_modules[*idx]); + imports.modules.push(module.submodule(*idx)); } // Here we lookup our instance handle, ask it for the nth export, // and then push that item into our own index space. We eschew // type-checking since only valid modules reach this point. + // + // Note that the unsafety here is because we're asserting that the + // handle comes from our same store, but this should be true because + // we acquired fthe handle from an instance in the store. Initializer::AliasInstanceExport { instance, export } => { let handle = &imports.instances[*instance]; let export_index = &handle.module().exports[*export]; let item = Extern::from_wasmtime_export( handle.lookup_by_declaration(export_index), - handle.clone(), + unsafe { store.existing_instance_handle(handle.clone()) }, ); imports.push_extern(&item); } @@ -100,14 +110,16 @@ fn instantiate<'a>( // to be a DAG. Additionally the recursion should also be bounded // due to validation. We may one day need to make this an iterative // loop, however. + // + // Also note that there's some unsafety here around cloning + // `InstanceHandle` because the handle may not live long enough, but + // we're doing all of this in the context of our `Store` argument + // above so we should be safe here. Initializer::Instantiate { module, args } => { - let module_to_instantiate = imports.modules[*module]; let mut args = args.iter(); let handle = instantiate( store, - module_to_instantiate, - all_modules, - types, + &imports.modules[*module], &imports.modules, &mut |_, builder| { match *args.next().unwrap() { @@ -124,16 +136,18 @@ fn instantiate<'a>( builder.memories.push(imports.memories[i]); } EntityIndex::Module(i) => { - builder.modules.push(imports.modules[i]); + builder.modules.push(imports.modules[i].clone()); } EntityIndex::Instance(i) => { - builder.instances.push(imports.instances[i].clone()); + builder + .instances + .push(unsafe { imports.instances[i].clone() }); } } Ok(()) }, )?; - imports.instances.push(handle); + imports.instances.push(unsafe { (*handle).clone() }); } } } @@ -146,16 +160,16 @@ fn instantiate<'a>( // Register the module just before instantiation to ensure we have a // trampoline registered for every signature and to preserve the module's // compiled JIT code within the `Store`. - store.register_module(compiled_module, types); + store.register_module(module); let config = store.engine().config(); let instance = unsafe { let instance = compiled_module.instantiate( imports, - &store.lookup_shared_signature(types), + &store.lookup_shared_signature(module.types()), config.memory_creator.as_ref().map(|a| a as _), store.interrupts(), - Box::new(()), + Box::new(module.types().clone()), store.externref_activations_table() as *const VMExternRefActivationsTable as *mut _, store.stack_map_registry() as *const StackMapRegistry as *mut _, )?; @@ -230,7 +244,6 @@ fn instantiate<'a>( #[derive(Clone)] pub struct Instance { pub(crate) handle: StoreInstanceHandle, - module: Module, } impl Instance { @@ -294,16 +307,7 @@ impl Instance { // Perform some pre-flight checks before we get into the meat of // instantiation. - let expected = module - .compiled_module() - .module() - .initializers - .iter() - .filter(|e| match e { - Initializer::Import { .. } => true, - _ => false, - }) - .count(); + let expected = module.compiled_module().module().imports().count(); if expected != imports.len() { bail!("expected {} imports, found {}", expected, imports.len()); } @@ -314,22 +318,34 @@ impl Instance { } let mut imports = imports.iter(); - let handle = instantiate( - store, - module.compiled_module(), - module.all_compiled_modules(), - module.types(), - &PrimaryMap::new(), - &mut |idx, builder| { - let import = imports.next().expect("already checked the length"); - builder.define_extern(idx, import) - }, - )?; + let handle = instantiate(store, module, &PrimaryMap::new(), &mut |idx, builder| { + let import = imports.next().expect("already checked the length"); + builder.define_extern(idx, import) + })?; - Ok(Instance { - handle, - module: module.clone(), - }) + Ok(Instance { handle }) + } + + pub(crate) fn from_wasmtime(handle: StoreInstanceHandle) -> Instance { + Instance { handle } + } + + /// Returns the type signature of this instance. + pub fn ty(&self) -> InstanceType { + let mut ty = InstanceType::new(); + let module = self.handle.module(); + let types = self + .handle + .host_state() + .downcast_ref::>() + .unwrap(); + for (name, index) in module.exports.iter() { + ty.add_named_export( + name, + ExternType::from_wasmtime(types, &module.type_of(*index)), + ); + } + return ty; } /// Returns the associated [`Store`] that this `Instance` is compiled into. @@ -400,24 +416,20 @@ struct ImportsBuilder<'a> { tables: PrimaryMap, memories: PrimaryMap, globals: PrimaryMap, - instances: PrimaryMap, - modules: PrimaryMap, + instances: PrimaryMap, + modules: PrimaryMap, module: &'a wasmtime_environ::Module, - store: &'a Store, - types: &'a TypeTables, + matcher: matching::MatchCx<'a>, } impl<'a> ImportsBuilder<'a> { - fn new( - module: &'a wasmtime_environ::Module, - types: &'a TypeTables, - store: &'a Store, - ) -> ImportsBuilder<'a> { + fn new(store: &'a Store, module: &'a Module) -> ImportsBuilder<'a> { + let types = module.types(); + let module = module.compiled_module().module(); ImportsBuilder { module, - store, - types, + matcher: matching::MatchCx { store, types }, functions: PrimaryMap::with_capacity(module.num_imported_funcs), tables: PrimaryMap::with_capacity(module.num_imported_tables), memories: PrimaryMap::with_capacity(module.num_imported_memories), @@ -428,59 +440,38 @@ impl<'a> ImportsBuilder<'a> { } fn define_extern(&mut self, expected: &EntityIndex, actual: &Extern) -> Result<()> { - match *expected { - EntityIndex::Table(i) => { - self.tables.push(match actual { - Extern::Table(e) if e.matches_expected(&self.module.table_plans[i]) => { - e.vmimport() - } - Extern::Table(_) => bail!("table types incompatible"), - _ => bail!("expected table, but found {}", actual.desc()), - }); - } - EntityIndex::Memory(i) => { - self.memories.push(match actual { - Extern::Memory(e) if e.matches_expected(&self.module.memory_plans[i]) => { - e.vmimport() - } - Extern::Memory(_) => bail!("memory types incompatible"), - _ => bail!("expected memory, but found {}", actual.desc()), - }); - } - EntityIndex::Global(i) => { - self.globals.push(match actual { - Extern::Global(e) if e.matches_expected(&self.module.globals[i]) => { - e.vmimport() - } - Extern::Global(_) => bail!("global types incompatible"), - _ => bail!("expected global, but found {}", actual.desc()), - }); - } - EntityIndex::Function(i) => { - let func = match actual { - Extern::Func(e) => e, - _ => bail!("expected function, but found {}", actual.desc()), - }; - // Look up the `i`th function's type from the module in our - // signature registry. If it's not present then we have no - // functions registered with that type, so `func` is guaranteed - // to not match. - let ty = self - .store - .signatures() - .borrow() - .lookup(&self.types.wasm_signatures[self.module.functions[i]]) - .ok_or_else(|| anyhow::format_err!("function types incompatible"))?; - if !func.matches_expected(ty) { - bail!("function types incompatible"); - } - self.functions.push(func.vmimport()); - } - - // FIXME(#2094) - EntityIndex::Module(_i) => unimplemented!(), - EntityIndex::Instance(_i) => unimplemented!(), + let expected_ty = self.module.type_of(*expected); + let compatible = match &expected_ty { + EntityType::Table(i) => match actual { + Extern::Table(e) => self.matcher.table(i, e), + _ => bail!("expected table, but found {}", actual.desc()), + }, + EntityType::Memory(i) => match actual { + Extern::Memory(e) => self.matcher.memory(i, e), + _ => bail!("expected memory, but found {}", actual.desc()), + }, + EntityType::Global(i) => match actual { + Extern::Global(e) => self.matcher.global(i, e), + _ => bail!("expected global, but found {}", actual.desc()), + }, + EntityType::Function(i) => match actual { + Extern::Func(e) => self.matcher.func(*i, e), + _ => bail!("expected func, but found {}", actual.desc()), + }, + EntityType::Instance(i) => match actual { + Extern::Instance(e) => self.matcher.instance(*i, e), + _ => bail!("expected instance, but found {}", actual.desc()), + }, + EntityType::Module(i) => match actual { + Extern::Module(e) => self.matcher.module(*i, e), + _ => bail!("expected module, but found {}", actual.desc()), + }, + EntityType::Event(_) => unimplemented!(), + }; + if !compatible { + bail!("{} types incompatible", actual.desc()); } + self.push_extern(actual); Ok(()) } @@ -498,15 +489,27 @@ impl<'a> ImportsBuilder<'a> { Extern::Memory(i) => { self.memories.push(i.vmimport()); } + Extern::Instance(i) => { + debug_assert!(Store::same(i.store(), self.matcher.store)); + self.instances.push(unsafe { (*i.handle).clone() }); + } + Extern::Module(m) => { + self.modules.push(m.clone()); + } } } - fn imports(&self) -> Imports<'_> { + fn imports(&mut self) -> Imports<'_> { Imports { tables: self.tables.values().as_slice(), globals: self.globals.values().as_slice(), memories: self.memories.values().as_slice(), functions: self.functions.values().as_slice(), + instances: mem::take(&mut self.instances), + modules: mem::take(&mut self.modules) + .into_iter() + .map(|(_, m)| Box::new(m) as Box<_>) + .collect(), } } } diff --git a/crates/wasmtime/src/linker.rs b/crates/wasmtime/src/linker.rs index e04052789898..763d0fa3cb3d 100644 --- a/crates/wasmtime/src/linker.rs +++ b/crates/wasmtime/src/linker.rs @@ -58,6 +58,8 @@ enum ImportKind { Global(GlobalType), Memory, Table, + Module, + Instance, } impl Linker { @@ -516,10 +518,8 @@ impl Linker { ExternType::Global(f) => ImportKind::Global(f), ExternType::Memory(_) => ImportKind::Memory, ExternType::Table(_) => ImportKind::Table, - - // FIXME(#2094) - ExternType::Module(_) => unimplemented!(), - ExternType::Instance(_) => unimplemented!(), + ExternType::Module(_) => ImportKind::Module, + ExternType::Instance(_) => ImportKind::Instance, } } diff --git a/crates/wasmtime/src/module.rs b/crates/wasmtime/src/module.rs index 37f068af6c14..b3d19f5ff496 100644 --- a/crates/wasmtime/src/module.rs +++ b/crates/wasmtime/src/module.rs @@ -1,5 +1,5 @@ -use crate::types::{EntityType, ExportType, ExternType, ImportType}; -use crate::Engine; +use crate::types::{ExportType, ExternType, ImportType}; +use crate::{Engine, ModuleType}; use anyhow::{bail, Context, Result}; use bincode::Options; use std::hash::Hash; @@ -86,7 +86,7 @@ pub struct Module { } pub(crate) struct ModuleData { - pub(crate) types: TypeTables, + pub(crate) types: Arc, pub(crate) modules: Vec, } @@ -258,6 +258,7 @@ impl Module { &*engine.config().profiler, )?; + let types = Arc::new(types); Ok(Module { engine: engine.clone(), index: 0, @@ -291,6 +292,23 @@ impl Module { Ok(()) } + /// Returns the type signature of this module. + pub fn ty(&self) -> ModuleType { + let mut sig = ModuleType::new(); + let env_module = self.compiled_module().module(); + let types = self.types(); + for (module, field, ty) in env_module.imports() { + sig.add_named_import(module, field, ExternType::from_wasmtime(types, &ty)); + } + for (name, index) in env_module.exports.iter() { + sig.add_named_export( + name, + ExternType::from_wasmtime(types, &env_module.type_of(*index)), + ); + } + return sig; + } + /// Serialize compilation artifacts to the buffer. See also `deseriaize`. pub fn serialize(&self) -> Result> { let artifacts = ( @@ -300,7 +318,7 @@ impl Module { .iter() .map(|i| i.compilation_artifacts()) .collect::>(), - &self.data.types, + &*self.data.types, self.index, ); @@ -333,6 +351,7 @@ impl Module { &*engine.config().profiler, )?; + let types = Arc::new(types); Ok(Module { engine: engine.clone(), index, @@ -344,11 +363,16 @@ impl Module { &self.data.modules[self.index] } - pub(crate) fn all_compiled_modules(&self) -> &[CompiledModule] { - &self.data.modules + pub(crate) fn submodule(&self, index: usize) -> Module { + assert!(index < self.data.modules.len()); + Module { + engine: self.engine.clone(), + data: self.data.clone(), + index, + } } - pub(crate) fn types(&self) -> &TypeTables { + pub(crate) fn types(&self) -> &Arc { &self.data.types } @@ -433,20 +457,10 @@ impl Module { &'module self, ) -> impl ExactSizeIterator> + 'module { let module = self.compiled_module().module(); + let types = self.types(); module - .initializers - .iter() - .filter_map(move |initializer| match initializer { - wasmtime_environ::Initializer::Import { - module, - field, - index, - } => { - let ty = EntityType::new(index, self); - Some(ImportType::new(module, field.as_deref(), ty)) - } - _ => None, - }) + .imports() + .map(move |(module, field, ty)| ImportType::new(module, field, ty, types)) .collect::>() .into_iter() } @@ -509,9 +523,9 @@ impl Module { &'module self, ) -> impl ExactSizeIterator> + 'module { let module = self.compiled_module().module(); + let types = self.types(); module.exports.iter().map(move |(name, entity_index)| { - let ty = EntityType::new(entity_index, self); - ExportType::new(name, ty) + ExportType::new(name, module.type_of(*entity_index), types) }) } @@ -561,7 +575,10 @@ impl Module { pub fn get_export<'module>(&'module self, name: &'module str) -> Option { let module = self.compiled_module().module(); let entity_index = module.exports.get(name)?; - Some(EntityType::new(entity_index, self).extern_type()) + Some(ExternType::from_wasmtime( + self.types(), + &module.type_of(*entity_index), + )) } /// Returns the [`Engine`] that this [`Module`] was compiled by. diff --git a/crates/wasmtime/src/store.rs b/crates/wasmtime/src/store.rs index 9761b40b9190..6b314f6ac16b 100644 --- a/crates/wasmtime/src/store.rs +++ b/crates/wasmtime/src/store.rs @@ -1,7 +1,7 @@ use crate::frame_info::StoreFrameInfo; use crate::sig_registry::SignatureRegistry; use crate::trampoline::StoreInstanceHandle; -use crate::Engine; +use crate::{Engine, Module}; use anyhow::{bail, Result}; use std::any::Any; use std::cell::RefCell; @@ -147,7 +147,7 @@ impl Store { } } - pub(crate) fn register_module(&self, module: &CompiledModule, types: &TypeTables) { + pub(crate) fn register_module(&self, module: &Module) { // All modules register their JIT code in a store for two reasons // currently: // @@ -158,18 +158,18 @@ impl Store { // * Second when generating a backtrace we'll use this mapping to // only generate wasm frames for instruction pointers that fall // within jit code. - self.register_jit_code(module); + self.register_jit_code(module.compiled_module()); // We need to know about all the stack maps of all instantiated modules // so when performing a GC we know about all wasm frames that we find // on the stack. - self.register_stack_maps(module); + self.register_stack_maps(module.compiled_module()); // Signatures are loaded into our `SignatureRegistry` here // once-per-module (and once-per-signature). This allows us to create // a `Func` wrapper for any function in the module, which requires that // we know about the signature and trampoline for all instances. - self.register_signatures(module, types); + self.register_signatures(module); // And finally with a module being instantiated into this `Store` we // need to preserve its jit-code. References to this module's code and @@ -178,7 +178,7 @@ impl Store { self.inner .modules .borrow_mut() - .insert(ArcModuleCode(module.code().clone())); + .insert(ArcModuleCode(module.compiled_module().code().clone())); } fn register_jit_code(&self, module: &CompiledModule) { @@ -205,10 +205,10 @@ impl Store { })); } - fn register_signatures(&self, module: &CompiledModule, types: &TypeTables) { - let trampolines = module.trampolines(); + fn register_signatures(&self, module: &Module) { + let trampolines = module.compiled_module().trampolines(); let mut signatures = self.signatures().borrow_mut(); - for (index, wasm) in types.wasm_signatures.iter() { + for (index, wasm) in module.types().wasm_signatures.iter() { signatures.register(wasm, trampolines[index]); } } diff --git a/crates/wasmtime/src/types.rs b/crates/wasmtime/src/types.rs index 9e992aa8e89c..3a7076a764aa 100644 --- a/crates/wasmtime/src/types.rs +++ b/crates/wasmtime/src/types.rs @@ -1,7 +1,9 @@ -use crate::Module; use std::fmt; -use wasmtime_environ::wasm::WasmFuncType; +use wasmtime_environ::wasm::{EntityType, WasmFuncType}; use wasmtime_environ::{ir, wasm}; +use wasmtime_jit::TypeTables; + +pub(crate) mod matching; // Type Representations @@ -196,23 +198,25 @@ impl ExternType { (Instance(InstanceType) instance unwrap_instance) } - fn from_wasmtime(module: &Module, ty: &wasmtime_environ::wasm::EntityType) -> ExternType { - use wasmtime_environ::wasm::EntityType; + pub(crate) fn from_wasmtime( + types: &TypeTables, + ty: &wasmtime_environ::wasm::EntityType, + ) -> ExternType { match ty { EntityType::Function(idx) => { - let sig = &module.types().wasm_signatures[*idx]; + let sig = &types.wasm_signatures[*idx]; FuncType::from_wasm_func_type(sig).into() } EntityType::Global(ty) => GlobalType::from_wasmtime_global(ty).into(), EntityType::Memory(ty) => MemoryType::from_wasmtime_memory(ty).into(), EntityType::Table(ty) => TableType::from_wasmtime_table(ty).into(), EntityType::Module(ty) => { - let ty = &module.types().module_signatures[*ty]; - ModuleType::from_wasmtime(module, ty).into() + let ty = &types.module_signatures[*ty]; + ModuleType::from_wasmtime(types, ty).into() } EntityType::Instance(ty) => { - let ty = &module.types().instance_signatures[*ty]; - InstanceType::from_wasmtime(module, ty).into() + let ty = &types.instance_signatures[*ty]; + InstanceType::from_wasmtime(types, ty).into() } EntityType::Event(_) => unimplemented!("wasm event support"), } @@ -490,14 +494,14 @@ impl ModuleType { } pub(crate) fn from_wasmtime( - module: &Module, + types: &TypeTables, ty: &wasmtime_environ::ModuleSignature, ) -> ModuleType { - let exports = &module.types().instance_signatures[ty.exports].exports; + let exports = &types.instance_signatures[ty.exports].exports; ModuleType { exports: exports .iter() - .map(|(name, ty)| (name.to_string(), ExternType::from_wasmtime(module, ty))) + .map(|(name, ty)| (name.to_string(), ExternType::from_wasmtime(types, ty))) .collect(), imports: ty .imports @@ -506,7 +510,7 @@ impl ModuleType { ( m.to_string(), name.as_ref().map(|n| n.to_string()), - ExternType::from_wasmtime(module, ty), + ExternType::from_wasmtime(types, ty), ) }) .collect(), @@ -548,83 +552,19 @@ impl InstanceType { } pub(crate) fn from_wasmtime( - module: &Module, + types: &TypeTables, ty: &wasmtime_environ::InstanceSignature, ) -> InstanceType { InstanceType { exports: ty .exports .iter() - .map(|(name, ty)| (name.to_string(), ExternType::from_wasmtime(module, ty))) + .map(|(name, ty)| (name.to_string(), ExternType::from_wasmtime(types, ty))) .collect(), } } } -// Entity Types - -#[derive(Clone)] -pub(crate) enum EntityType<'module> { - Function(&'module wasm::WasmFuncType), - Table(&'module wasm::Table), - Memory(&'module wasm::Memory), - Global(&'module wasm::Global), - Module { - ty: &'module wasmtime_environ::ModuleSignature, - module: &'module Module, - }, - Instance { - ty: &'module wasmtime_environ::InstanceSignature, - module: &'module Module, - }, -} - -impl<'module> EntityType<'module> { - /// Translate from a `EntityIndex` into an `ExternType`. - pub(crate) fn new( - entity_index: &wasm::EntityIndex, - module: &'module Module, - ) -> EntityType<'module> { - let env_module = module.compiled_module().module(); - match entity_index { - wasm::EntityIndex::Function(func_index) => { - let sig_index = env_module.functions[*func_index]; - let sig = &module.types().wasm_signatures[sig_index]; - EntityType::Function(sig) - } - wasm::EntityIndex::Table(table_index) => { - EntityType::Table(&env_module.table_plans[*table_index].table) - } - wasm::EntityIndex::Memory(memory_index) => { - EntityType::Memory(&env_module.memory_plans[*memory_index].memory) - } - wasm::EntityIndex::Global(global_index) => { - EntityType::Global(&env_module.globals[*global_index]) - } - wasm::EntityIndex::Module(idx) => { - let ty = &module.types().module_signatures[env_module.modules[*idx]]; - EntityType::Module { ty, module } - } - wasm::EntityIndex::Instance(idx) => { - let ty = &module.types().instance_signatures[env_module.instances[*idx]]; - EntityType::Instance { ty, module } - } - } - } - - /// Convert this `EntityType` to an `ExternType`. - pub(crate) fn extern_type(&self) -> ExternType { - match self { - EntityType::Function(sig) => FuncType::from_wasm_func_type(sig).into(), - EntityType::Table(table) => TableType::from_wasmtime_table(table).into(), - EntityType::Memory(memory) => MemoryType::from_wasmtime_memory(memory).into(), - EntityType::Global(global) => GlobalType::from_wasmtime_global(global).into(), - EntityType::Instance { module, ty } => InstanceType::from_wasmtime(module, ty).into(), - EntityType::Module { module, ty } => ModuleType::from_wasmtime(module, ty).into(), - } - } -} - // Import Types /// A descriptor for an imported value into a wasm module. @@ -647,7 +587,7 @@ pub struct ImportType<'module> { #[derive(Clone)] enum EntityOrExtern<'a> { - Entity(EntityType<'a>), + Entity(EntityType, &'a TypeTables), Extern(&'a ExternType), } @@ -657,12 +597,13 @@ impl<'module> ImportType<'module> { pub(crate) fn new( module: &'module str, name: Option<&'module str>, - ty: EntityType<'module>, + ty: EntityType, + types: &'module TypeTables, ) -> ImportType<'module> { ImportType { module, name, - ty: EntityOrExtern::Entity(ty), + ty: EntityOrExtern::Entity(ty, types), } } @@ -683,7 +624,7 @@ impl<'module> ImportType<'module> { /// Returns the expected type of this import. pub fn ty(&self) -> ExternType { match &self.ty { - EntityOrExtern::Entity(e) => e.extern_type(), + EntityOrExtern::Entity(e, types) => ExternType::from_wasmtime(types, e), EntityOrExtern::Extern(e) => (*e).clone(), } } @@ -719,10 +660,14 @@ pub struct ExportType<'module> { impl<'module> ExportType<'module> { /// Creates a new export which is exported with the given `name` and has the /// given `ty`. - pub(crate) fn new(name: &'module str, ty: EntityType<'module>) -> ExportType<'module> { + pub(crate) fn new( + name: &'module str, + ty: EntityType, + types: &'module TypeTables, + ) -> ExportType<'module> { ExportType { name, - ty: EntityOrExtern::Entity(ty), + ty: EntityOrExtern::Entity(ty, types), } } @@ -734,7 +679,7 @@ impl<'module> ExportType<'module> { /// Returns the type of this export. pub fn ty(&self) -> ExternType { match &self.ty { - EntityOrExtern::Entity(e) => e.extern_type(), + EntityOrExtern::Entity(e, types) => ExternType::from_wasmtime(types, e), EntityOrExtern::Extern(e) => (*e).clone(), } } diff --git a/crates/wasmtime/src/types/matching.rs b/crates/wasmtime/src/types/matching.rs new file mode 100644 index 000000000000..c9ef03c26c12 --- /dev/null +++ b/crates/wasmtime/src/types/matching.rs @@ -0,0 +1,195 @@ +use crate::Store; +use std::sync::Arc; +use wasmtime_environ::wasm::{ + EntityType, Global, InstanceTypeIndex, Memory, ModuleTypeIndex, SignatureIndex, Table, +}; +use wasmtime_jit::TypeTables; + +pub struct MatchCx<'a> { + pub types: &'a TypeTables, + pub store: &'a Store, +} + +impl MatchCx<'_> { + pub fn global(&self, expected: &Global, actual: &crate::Global) -> bool { + self.global_ty(expected, actual.wasmtime_ty()) + } + + fn global_ty(&self, expected: &Global, actual: &Global) -> bool { + expected.ty == actual.ty + && expected.wasm_ty == actual.wasm_ty + && expected.mutability == actual.mutability + } + + pub fn table(&self, expected: &Table, actual: &crate::Table) -> bool { + self.table_ty(expected, actual.wasmtime_ty()) + } + + fn table_ty(&self, expected: &Table, actual: &Table) -> bool { + expected.wasm_ty == actual.wasm_ty + && expected.ty == actual.ty + && expected.minimum <= actual.minimum + && match expected.maximum { + Some(expected) => match actual.maximum { + Some(actual) => expected >= actual, + None => false, + }, + None => true, + } + } + + pub fn memory(&self, expected: &Memory, actual: &crate::Memory) -> bool { + self.memory_ty(expected, actual.wasmtime_ty()) + } + + fn memory_ty(&self, expected: &Memory, actual: &Memory) -> bool { + expected.shared == actual.shared + && expected.minimum <= actual.minimum + && match expected.maximum { + Some(expected) => match actual.maximum { + Some(actual) => expected >= actual, + None => false, + }, + None => true, + } + } + + pub fn func(&self, expected: SignatureIndex, actual: &crate::Func) -> bool { + match self + .store + .signatures() + .borrow() + .lookup(&self.types.wasm_signatures[expected]) + { + Some(idx) => actual.sig_index() == idx, + // If our expected signature isn't registered, then there's no way + // that `actual` can match it. + None => false, + } + } + + pub fn instance(&self, expected: InstanceTypeIndex, actual: &crate::Instance) -> bool { + let module = actual.handle.module(); + self.exports_match( + expected, + actual + .handle + .host_state() + .downcast_ref::>() + .unwrap(), + |name| module.exports.get(name).map(|idx| module.type_of(*idx)), + ) + } + + /// Validates that the type signature of `actual` matches the `expected` + /// module type signature. + pub fn module(&self, expected: ModuleTypeIndex, actual: &crate::Module) -> bool { + let expected_sig = &self.types.module_signatures[expected]; + let module = actual.compiled_module().module(); + self.imports_match(expected, actual.types(), module.imports()) + && self.exports_match(expected_sig.exports, actual.types(), |name| { + module.exports.get(name).map(|idx| module.type_of(*idx)) + }) + } + + /// Validaates that the `actual_imports` list of module imports matches the + /// `expected` module type signature. + /// + /// Types specified in `actual_imports` are relative to `actual_types`. + fn imports_match<'a>( + &self, + expected: ModuleTypeIndex, + actual_types: &TypeTables, + mut actual_imports: impl Iterator, EntityType)>, + ) -> bool { + let expected_sig = &self.types.module_signatures[expected]; + for (_, _, expected) in expected_sig.imports.iter() { + let (_, _, ty) = match actual_imports.next() { + Some(e) => e, + None => return false, + }; + if !self.extern_ty_matches(expected, &ty, actual_types) { + return false; + } + } + actual_imports.next().is_none() + } + + /// Validates that all exports in `expected` are defined by `lookup` within + /// `actual_types`. + fn exports_match( + &self, + expected: InstanceTypeIndex, + actual_types: &TypeTables, + lookup: impl Fn(&str) -> Option, + ) -> bool { + // The `expected` type must be a subset of `actual`, meaning that all + // names in `expected` must be present in `actual`. Note that we do + // name-based lookup here instead of index-based lookup. + self.types.instance_signatures[expected].exports.iter().all( + |(name, expected)| match lookup(name) { + Some(ty) => self.extern_ty_matches(expected, &ty, actual_types), + None => false, + }, + ) + } + + /// Validates that the `expected` entity matches the `actual_ty` defined + /// within `actual_types`. + fn extern_ty_matches( + &self, + expected: &EntityType, + actual_ty: &EntityType, + actual_types: &TypeTables, + ) -> bool { + match expected { + EntityType::Global(expected) => match actual_ty { + EntityType::Global(actual) => self.global_ty(expected, actual), + _ => false, + }, + EntityType::Table(expected) => match actual_ty { + EntityType::Table(actual) => self.table_ty(expected, actual), + _ => false, + }, + EntityType::Memory(expected) => match actual_ty { + EntityType::Memory(actual) => self.memory_ty(expected, actual), + _ => false, + }, + EntityType::Function(expected) => match *actual_ty { + EntityType::Function(actual) => { + self.types.wasm_signatures[*expected] == actual_types.wasm_signatures[actual] + } + _ => false, + }, + EntityType::Instance(expected) => match actual_ty { + EntityType::Instance(actual) => { + let sig = &actual_types.instance_signatures[*actual]; + self.exports_match(*expected, actual_types, |name| { + sig.exports.get(name).cloned() + }) + } + _ => false, + }, + EntityType::Module(expected) => match actual_ty { + EntityType::Module(actual) => { + let expected_module_sig = &self.types.module_signatures[*expected]; + let actual_module_sig = &actual_types.module_signatures[*actual]; + let actual_instance_sig = + &actual_types.instance_signatures[actual_module_sig.exports]; + + self.imports_match( + *expected, + actual_types, + actual_module_sig.imports.iter().map(|(module, field, ty)| { + (module.as_str(), field.as_deref(), ty.clone()) + }), + ) && self.exports_match(expected_module_sig.exports, actual_types, |name| { + actual_instance_sig.exports.get(name).cloned() + }) + } + _ => false, + }, + EntityType::Event(_) => unimplemented!(), + } + } +} diff --git a/tests/all/wast.rs b/tests/all/wast.rs index 9b069c2ebe0f..9227079a0f85 100644 --- a/tests/all/wast.rs +++ b/tests/all/wast.rs @@ -23,8 +23,8 @@ fn run_wast(wast: &str, strategy: Strategy) -> anyhow::Result<()> { let mut cfg = Config::new(); cfg.wasm_simd(simd) .wasm_bulk_memory(bulk_mem) - .wasm_reference_types(reftypes) - .wasm_multi_memory(multi_memory) + .wasm_reference_types(reftypes || module_linking) + .wasm_multi_memory(multi_memory || module_linking) .wasm_module_linking(module_linking) .strategy(strategy)? .cranelift_debug_verifier(true); diff --git a/tests/misc_testsuite/module-linking/alias.wast b/tests/misc_testsuite/module-linking/alias.wast index 73324b251b9f..0c69b4084c7c 100644 --- a/tests/misc_testsuite/module-linking/alias.wast +++ b/tests/misc_testsuite/module-linking/alias.wast @@ -54,7 +54,38 @@ ) (assert_return (invoke "get") (i32.const 4)) -;; TODO instances/modules -- needs import/export of modules/instances to work +;; modules +(module + (module $m + (module $sub (export "module") + (func $f (export "") (result i32) + i32.const 5)) + ) + (instance $a (instantiate $m)) + (instance $b (instantiate $a.$sub)) + (alias $b.$f (instance $b) (func 0)) + + (func (export "get") (result i32) + call $b.$f) +) +(assert_return (invoke "get") (i32.const 5)) + +;; instances +(module + (module $m + (module $sub + (func $f (export "") (result i32) + i32.const 6)) + (instance $i (export "") (instantiate $sub)) + ) + (instance $a (instantiate $m)) + (alias $a.$i (instance $a) (instance 0)) + (alias $a.$i.$f (instance $a.$i) (func 0)) + + (func (export "get") (result i32) + call $a.$i.$f) +) +(assert_return (invoke "get") (i32.const 6)) ;; alias parent -- type (module diff --git a/tests/misc_testsuite/module-linking/import-subtyping.wast b/tests/misc_testsuite/module-linking/import-subtyping.wast new file mode 100644 index 000000000000..4ac16580706c --- /dev/null +++ b/tests/misc_testsuite/module-linking/import-subtyping.wast @@ -0,0 +1,348 @@ +;; subsets of imports +(module $a + (module (export "m") + (func (export "")) + (func (export "a")) + (global (export "b") i32 (i32.const 0)) + ) +) + +(module + (import "a" "m" (module)) + (import "a" "m" (module (export "" (func)))) + (import "a" "m" (module (export "a" (func)))) + (import "a" "m" (module (export "b" (global i32)))) + (import "a" "m" (module + (export "" (func)) + (export "a" (func)) + )) + (import "a" "m" (module + (export "a" (func)) + (export "" (func)) + )) + (import "a" "m" (module + (export "a" (func)) + (export "" (func)) + (export "b" (global i32)) + )) + (import "a" "m" (module + (export "b" (global i32)) + (export "a" (func)) + (export "" (func)) + )) +) + +;; functions +(module $a + (module (export "m") + (func (export "")))) + +(module + (import "a" "m" (module)) + (import "a" "m" (module (export "" (func)))) +) +(assert_unlinkable + (module (import "a" "m" (module (export "" (func (param i32)))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (func (result i32)))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (global i32))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (table 1 funcref))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (memory 1))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (module))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (instance))))) + "module types incompatible") + +(module $a + (module (export "m") + (global (export "") i32 (i32.const 0)))) + +;; globals +(module + (import "a" "m" (module)) + (import "a" "m" (module (export "" (global i32)))) +) +(assert_unlinkable + (module + (import "a" "m" (module (export "" (global (mut i32))))) + ) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (global f32))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (func))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (table 1 funcref))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (memory 1))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (module))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (instance))))) + "module types incompatible") + +;; tables +(module $a + (module (export "m") + (table (export "") 1 funcref) + (table (export "max") 1 10 funcref) + ) +) +(module + (import "a" "m" (module)) + (import "a" "m" (module (export "" (table 1 funcref)))) + (import "a" "m" (module (export "" (table 0 funcref)))) + (import "a" "m" (module (export "max" (table 1 10 funcref)))) + (import "a" "m" (module (export "max" (table 0 10 funcref)))) + (import "a" "m" (module (export "max" (table 0 11 funcref)))) + (import "a" "m" (module (export "max" (table 0 funcref)))) +) +(assert_unlinkable + (module (import "a" "m" (module (export "" (global f32))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (func))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (table 2 funcref))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (table 1 10 funcref))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "max" (table 2 10 funcref))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "max" (table 1 9 funcref))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (memory 1))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (module))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (instance))))) + "module types incompatible") + +;; memories +(module $a + (module (export "m") + (memory (export "") 1) + (memory (export "max") 1 10) + ) +) +(module + (import "a" "m" (module)) + (import "a" "m" (module (export "" (memory 1)))) + (import "a" "m" (module (export "" (memory 0)))) + (import "a" "m" (module (export "max" (memory 1 10)))) + (import "a" "m" (module (export "max" (memory 0 10)))) + (import "a" "m" (module (export "max" (memory 0 11)))) + (import "a" "m" (module (export "max" (memory 0)))) +) +(assert_unlinkable + (module (import "a" "m" (module (export "" (global f32))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (func))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (table 1 funcref))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (memory 2))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (memory 1 10))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "max" (memory 2 10))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "max" (memory 2))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (module))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (instance))))) + "module types incompatible") + +;; modules +(module $a + (module (export "m") + ;; export nothing + (module (export "a")) + ;; export one thing + (module (export "b") + (func (export "")) + ) + ;; export a mixture + (module (export "c") + (func (export "a")) + (func (export "b") (result i32) + i32.const 0) + (global (export "c") i32 (i32.const 0)) + ) + ;; import one thing + (module (export "d") + (import "" (func)) + ) + ;; import a mixture + (module (export "e") + (import "" (func)) + (import "" (func)) + (import "" (global i32)) + ) + ) +) +(module + (import "a" "m" (module)) + (import "a" "m" (module (export "a" (module)))) + (import "a" "m" (module (export "b" (module)))) + (import "a" "m" (module (export "b" (module (export "" (func)))))) + (import "a" "m" (module (export "c" (module)))) + (import "a" "m" (module (export "c" (module + (export "a" (func)) + )))) + (import "a" "m" (module (export "c" (module + (export "a" (func)) + (export "b" (func (result i32))) + )))) + (import "a" "m" (module (export "c" (module + (export "c" (global i32)) + )))) + (import "a" "m" (module (export "c" (module + (export "c" (global i32)) + (export "a" (func)) + )))) + + ;; for now import strings aren't matched at all, imports must simply pairwise + ;; line up + (import "a" "m" (module (export "d" (module (import "" (func)))))) + (import "a" "m" (module (export "d" (module (import "x" (func)))))) + (import "a" "m" (module (export "d" (module (import "x" "y" (func)))))) + + (import "a" "m" (module (export "e" (module + (import "x" "y" (func)) + (import "a" (func)) + (import "z" (global i32)) + )))) +) +(assert_unlinkable + (module (import "a" "m" (module (export "" (module (export "a" (func))))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "d" (module))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "d" (module (import "" (module))))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (global f32))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (func))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (table 1 funcref))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (memory 2))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (module (export "foo" (func))))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (instance))))) + "module types incompatible") + +;; instances +(module $a + ;; export nothing + (module $m1) + (instance (export "a") (instantiate $m1)) + ;; export one thing + (module $m2 + (func (export "")) + ) + (instance (export "b") (instantiate $m2)) + ;; export a mixture + (module $m3 + (func (export "a")) + (func (export "b") (result i32) + i32.const 0) + (global (export "c") i32 (i32.const 0)) + ) + (instance (export "c") (instantiate $m3)) + + (module (export "m") + ;; export one thing + (module $m2 + (func (export "")) + ) + (instance (export "i") (instantiate $m2)) + ) + +) +(module + (import "a" "a" (instance)) + (import "a" "b" (instance)) + (import "a" "b" (instance (export "" (func)))) + (import "a" "c" (instance)) + (import "a" "c" (instance (export "a" (func)))) + (import "a" "c" (instance (export "b" (func (result i32))))) + (import "a" "c" (instance (export "c" (global i32)))) + (import "a" "c" (instance + (export "a" (func)) + (export "b" (func (result i32))) + (export "c" (global i32)) + )) + (import "a" "c" (instance + (export "c" (global i32)) + (export "a" (func)) + )) + + (import "a" "m" (module (export "i" (instance)))) + (import "a" "m" (module (export "i" (instance (export "" (func)))))) +) +(assert_unlinkable + (module (import "a" "a" (instance (export "" (global f32))))) + "instance types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "i" (instance (export "x" (func))))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (func))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (table 1 funcref))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (memory 2))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (memory 1 10))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "max" (memory 2 10))))) + "module types incompatible") +(assert_unlinkable + (module (import "a" "m" (module (export "" (module))))) + "module types incompatible") diff --git a/tests/misc_testsuite/module-linking/instantiate.wast b/tests/misc_testsuite/module-linking/instantiate.wast index a0e24c7a7bac..c04929257f56 100644 --- a/tests/misc_testsuite/module-linking/instantiate.wast +++ b/tests/misc_testsuite/module-linking/instantiate.wast @@ -117,6 +117,24 @@ ) (assert_return (invoke "get") (i32.const 5)) +;; imported modules again +(module + (module $m + (import "" (module $m (export "get" (func (result i32))))) + (instance $i (instantiate $m)) + (alias $f (instance $i) (func 0)) + (export "" (func $f)) + ) + (module $m2 + (func (export "get") (result i32) + i32.const 6)) + (instance $a (instantiate $m (module $m2))) + + (func (export "get") (result i32) + call $a.$f) +) +(assert_return (invoke "get") (i32.const 6)) + ;; all at once (module (import "a" "inc" (func $f)) @@ -195,3 +213,23 @@ (instance (instantiate 0 (func 0))) ) (assert_return (invoke $a "get") (i32.const 1)) + +;; module/instance top-level imports work +(module $b + (module (export "m")) + (instance (export "i") (instantiate 0)) +) +(module + (import "b" "m" (module)) + (import "b" "i" (instance)) +) +(assert_unlinkable + (module + (import "b" "m" (module (import "" (func)))) + ) + "module types incompatible") +(assert_unlinkable + (module + (import "b" "i" (instance (export "" (func)))) + ) + "instance types incompatible") From bbab8a1e0a02184658688e4b6beab62cc81e2c51 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 2 Dec 2020 14:57:37 -0800 Subject: [PATCH 2/4] Update wat/wast/wasmparser --- Cargo.toml | 7 ++----- cranelift/codegen/Cargo.toml | 2 +- cranelift/peepmatic/Cargo.toml | 2 +- cranelift/peepmatic/crates/fuzzing/Cargo.toml | 2 +- cranelift/peepmatic/crates/runtime/Cargo.toml | 2 +- cranelift/peepmatic/crates/souper/Cargo.toml | 2 +- cranelift/peepmatic/crates/test-operator/Cargo.toml | 2 +- cranelift/wasm/Cargo.toml | 2 +- crates/debug/Cargo.toml | 2 +- crates/environ/Cargo.toml | 2 +- crates/fuzzing/Cargo.toml | 4 ++-- crates/jit/Cargo.toml | 2 +- crates/lightbeam/Cargo.toml | 2 +- crates/lightbeam/wasmtime/Cargo.toml | 2 +- crates/wasmtime/Cargo.toml | 2 +- crates/wast/Cargo.toml | 2 +- 16 files changed, 18 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ed703cbe3341..aff7e98e3350 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,12 +38,12 @@ anyhow = "1.0.19" target-lexicon = { version = "0.11.0", default-features = false } pretty_env_logger = "0.4.0" file-per-thread-logger = "0.1.1" -wat = "1.0.27" +wat = "1.0.29" libc = "0.2.60" log = "0.4.8" rayon = "1.2.1" humantime = "2.0.0" -wasmparser = "0.68" +wasmparser = "0.69" [dev-dependencies] env_logger = "0.8.1" @@ -96,6 +96,3 @@ harness = false [profile.dev.package.backtrace] debug = false # FIXME(#1813) - -[patch.crates-io] -wasmparser = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'fix-validate-submodule' } diff --git a/cranelift/codegen/Cargo.toml b/cranelift/codegen/Cargo.toml index 9a06ede0ce76..bdf7dfd08068 100644 --- a/cranelift/codegen/Cargo.toml +++ b/cranelift/codegen/Cargo.toml @@ -30,7 +30,7 @@ peepmatic-traits = { path = "../peepmatic/crates/traits", optional = true, versi peepmatic-runtime = { path = "../peepmatic/crates/runtime", optional = true, version = "0.68.0" } regalloc = { version = "0.0.31" } souper-ir = { version = "1", optional = true } -wast = { version = "27.0.0", optional = true } +wast = { version = "28.0.0", optional = true } # It is a goal of the cranelift-codegen crate to have minimal external dependencies. # Please don't add any unless they are essential to the task of creating binary # machine code. Integration tests that need external dependencies can be diff --git a/cranelift/peepmatic/Cargo.toml b/cranelift/peepmatic/Cargo.toml index 8040d3cd9dad..3691cf713e60 100644 --- a/cranelift/peepmatic/Cargo.toml +++ b/cranelift/peepmatic/Cargo.toml @@ -15,7 +15,7 @@ peepmatic-macro = { version = "0.68.0", path = "crates/macro" } peepmatic-runtime = { version = "0.68.0", path = "crates/runtime", features = ["construct"] } peepmatic-traits = { version = "0.68.0", path = "crates/traits" } serde = { version = "1.0.105", features = ["derive"] } -wast = "27.0.0" +wast = "28.0.0" z3 = { version = "0.7.1", features = ["static-link-z3"] } [dev-dependencies] diff --git a/cranelift/peepmatic/crates/fuzzing/Cargo.toml b/cranelift/peepmatic/crates/fuzzing/Cargo.toml index bcaaafca10e3..83a57c943f81 100644 --- a/cranelift/peepmatic/crates/fuzzing/Cargo.toml +++ b/cranelift/peepmatic/crates/fuzzing/Cargo.toml @@ -21,4 +21,4 @@ peepmatic-test-operator = { path = "../test-operator" } peepmatic-traits = { path = "../traits" } rand = { version = "0.7.3", features = ["small_rng"] } serde = "1.0.106" -wast = "27.0.0" +wast = "28.0.0" diff --git a/cranelift/peepmatic/crates/runtime/Cargo.toml b/cranelift/peepmatic/crates/runtime/Cargo.toml index 9c7b417dfa2e..2b60e7d5576e 100644 --- a/cranelift/peepmatic/crates/runtime/Cargo.toml +++ b/cranelift/peepmatic/crates/runtime/Cargo.toml @@ -16,7 +16,7 @@ peepmatic-automata = { version = "0.68.0", path = "../automata", features = ["se peepmatic-traits = { version = "0.68.0", path = "../traits" } serde = { version = "1.0.105", features = ["derive"] } thiserror = "1.0.15" -wast = { version = "27.0.0", optional = true } +wast = { version = "28.0.0", optional = true } [dev-dependencies] peepmatic-test-operator = { version = "0.68.0", path = "../test-operator" } diff --git a/cranelift/peepmatic/crates/souper/Cargo.toml b/cranelift/peepmatic/crates/souper/Cargo.toml index 7e9a69c84b0d..7792f5268a63 100644 --- a/cranelift/peepmatic/crates/souper/Cargo.toml +++ b/cranelift/peepmatic/crates/souper/Cargo.toml @@ -16,4 +16,4 @@ log = "0.4.8" [dev-dependencies] peepmatic = { path = "../..", version = "0.68.0" } peepmatic-test-operator = { version = "0.68.0", path = "../test-operator" } -wast = "27.0.0" +wast = "28.0.0" diff --git a/cranelift/peepmatic/crates/test-operator/Cargo.toml b/cranelift/peepmatic/crates/test-operator/Cargo.toml index d3b2d7d8667c..59ce9a15c643 100644 --- a/cranelift/peepmatic/crates/test-operator/Cargo.toml +++ b/cranelift/peepmatic/crates/test-operator/Cargo.toml @@ -9,4 +9,4 @@ edition = "2018" [dependencies] peepmatic-traits = { version = "0.68.0", path = "../traits" } serde = { version = "1.0.105", features = ["derive"] } -wast = "27.0.0" +wast = "28.0.0" diff --git a/cranelift/wasm/Cargo.toml b/cranelift/wasm/Cargo.toml index 95a362698376..515391382d1d 100644 --- a/cranelift/wasm/Cargo.toml +++ b/cranelift/wasm/Cargo.toml @@ -12,7 +12,7 @@ keywords = ["webassembly", "wasm"] edition = "2018" [dependencies] -wasmparser = { version = "0.68.0", default-features = false } +wasmparser = { version = "0.69.1", default-features = false } cranelift-codegen = { path = "../codegen", version = "0.68.0", default-features = false } cranelift-entity = { path = "../entity", version = "0.68.0" } cranelift-frontend = { path = "../frontend", version = "0.68.0", default-features = false } diff --git a/crates/debug/Cargo.toml b/crates/debug/Cargo.toml index 31caf0777c44..401c4436187e 100644 --- a/crates/debug/Cargo.toml +++ b/crates/debug/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" [dependencies] gimli = "0.23.0" -wasmparser = "0.68.0" +wasmparser = "0.69.0" object = { version = "0.22.0", default-features = false, features = ["read", "write"] } wasmtime-environ = { path = "../environ", version = "0.21.0" } target-lexicon = { version = "0.11.0", default-features = false } diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml index 847b749c7101..1b944282e152 100644 --- a/crates/environ/Cargo.toml +++ b/crates/environ/Cargo.toml @@ -16,7 +16,7 @@ anyhow = "1.0" cranelift-codegen = { path = "../../cranelift/codegen", version = "0.68.0", features = ["enable-serde"] } cranelift-entity = { path = "../../cranelift/entity", version = "0.68.0", features = ["enable-serde"] } cranelift-wasm = { path = "../../cranelift/wasm", version = "0.68.0", features = ["enable-serde"] } -wasmparser = "0.68.0" +wasmparser = "0.69.0" indexmap = { version = "1.0.2", features = ["serde-1"] } thiserror = "1.0.4" serde = { version = "1.0.94", features = ["derive"] } diff --git a/crates/fuzzing/Cargo.toml b/crates/fuzzing/Cargo.toml index 452698282369..12a9842c00d8 100644 --- a/crates/fuzzing/Cargo.toml +++ b/crates/fuzzing/Cargo.toml @@ -12,8 +12,8 @@ arbitrary = { version = "0.4.1", features = ["derive"] } env_logger = "0.8.1" log = "0.4.8" rayon = "1.2.1" -wasmparser = "0.68.0" -wasmprinter = "0.2.15" +wasmparser = "0.69.0" +wasmprinter = "0.2.16" wasmtime = { path = "../wasmtime" } wasmtime-wast = { path = "../wast" } wasm-smith = "0.1.12" diff --git a/crates/jit/Cargo.toml b/crates/jit/Cargo.toml index 4f4ceba8e989..4a3b9101d58e 100644 --- a/crates/jit/Cargo.toml +++ b/crates/jit/Cargo.toml @@ -28,7 +28,7 @@ rayon = { version = "1.0", optional = true } region = "2.1.0" thiserror = "1.0.4" target-lexicon = { version = "0.11.0", default-features = false } -wasmparser = "0.68.0" +wasmparser = "0.69.0" more-asserts = "0.2.1" anyhow = "1.0" cfg-if = "1.0" diff --git a/crates/lightbeam/Cargo.toml b/crates/lightbeam/Cargo.toml index 9308b8918a49..ff7d095e1095 100644 --- a/crates/lightbeam/Cargo.toml +++ b/crates/lightbeam/Cargo.toml @@ -24,7 +24,7 @@ more-asserts = "0.2.1" smallvec = "1.0.0" thiserror = "1.0.9" typemap = "0.3" -wasmparser = "0.68.0" +wasmparser = "0.69.0" [dev-dependencies] lazy_static = "1.2" diff --git a/crates/lightbeam/wasmtime/Cargo.toml b/crates/lightbeam/wasmtime/Cargo.toml index f636577df06d..2d3163ce061b 100644 --- a/crates/lightbeam/wasmtime/Cargo.toml +++ b/crates/lightbeam/wasmtime/Cargo.toml @@ -13,6 +13,6 @@ edition = "2018" [dependencies] lightbeam = { path = "..", version = "0.21.0" } -wasmparser = "0.68" +wasmparser = "0.69" cranelift-codegen = { path = "../../../cranelift/codegen", version = "0.68.0" } wasmtime-environ = { path = "../../environ", version = "0.21.0" } diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index e0316847263b..881f1f872467 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -16,7 +16,7 @@ wasmtime-jit = { path = "../jit", version = "0.21.0" } wasmtime-cache = { path = "../cache", version = "0.21.0", optional = true } wasmtime-profiling = { path = "../profiling", version = "0.21.0" } target-lexicon = { version = "0.11.0", default-features = false } -wasmparser = "0.68.0" +wasmparser = "0.69.0" anyhow = "1.0.19" region = "2.2.0" libc = "0.2" diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index 02d48e87c4f9..aaa130acecbf 100644 --- a/crates/wast/Cargo.toml +++ b/crates/wast/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" [dependencies] anyhow = "1.0.19" wasmtime = { path = "../wasmtime", version = "0.21.0", default-features = false } -wast = "27.0.0" +wast = "28.0.0" [badges] maintenance = { status = "actively-developed" } From d11c1ee96200d2d470a61b7c2b2a48e28ce8d063 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 3 Dec 2020 07:17:28 -0800 Subject: [PATCH 3/4] Review comments --- Cargo.lock | 53 ++++++++++++++------------- crates/environ/src/module.rs | 3 +- crates/wasmtime/src/instance.rs | 8 ++-- crates/wasmtime/src/module.rs | 2 +- crates/wasmtime/src/types/matching.rs | 2 +- 5 files changed, 35 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2044cd3a6dd4..b5e646f2a653 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -394,7 +394,7 @@ dependencies = [ "souper-ir", "target-lexicon", "thiserror", - "wast 27.0.0", + "wast 28.0.0", ] [[package]] @@ -596,7 +596,7 @@ dependencies = [ "smallvec", "target-lexicon", "thiserror", - "wasmparser 0.68.0", + "wasmparser 0.69.1", "wat", ] @@ -1166,7 +1166,7 @@ dependencies = [ "smallvec", "thiserror", "typemap", - "wasmparser 0.68.0", + "wasmparser 0.69.1", "wat", ] @@ -1410,7 +1410,7 @@ dependencies = [ "peepmatic-test-operator", "peepmatic-traits", "serde", - "wast 27.0.0", + "wast 28.0.0", "z3", ] @@ -1438,7 +1438,7 @@ dependencies = [ "peepmatic-traits", "rand", "serde", - "wast 27.0.0", + "wast 28.0.0", ] [[package]] @@ -1463,7 +1463,7 @@ dependencies = [ "serde", "serde_test", "thiserror", - "wast 27.0.0", + "wast 28.0.0", ] [[package]] @@ -1475,7 +1475,7 @@ dependencies = [ "peepmatic", "peepmatic-test-operator", "souper-ir", - "wast 27.0.0", + "wast 28.0.0", ] [[package]] @@ -1496,7 +1496,7 @@ version = "0.68.0" dependencies = [ "peepmatic-traits", "serde", - "wast 27.0.0", + "wast 28.0.0", ] [[package]] @@ -2405,18 +2405,18 @@ checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" [[package]] name = "wasmparser" -version = "0.68.0" +version = "0.69.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a00e14eed9c2ecbbdbdd4fb284f49d21b6808965de24769a6379a13ec47d4c" +checksum = "fd19c6066bcf391a9d6f81db9b809f31d31723da2652c8416cb81cd5aabed944" [[package]] name = "wasmprinter" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f39a73b5f09cfcb1b568b61968d39b19e4ddec9b49040cfc091adf3b0788bca6" +checksum = "dba006f5c5bf41a2a5c3b45e861ea6eb067382acb022b6a35a00a0390f9547f6" dependencies = [ "anyhow", - "wasmparser 0.68.0", + "wasmparser 0.69.1", ] [[package]] @@ -2428,6 +2428,7 @@ dependencies = [ "bincode", "cfg-if 1.0.0", "cpp_demangle", + "indexmap", "libc", "log", "region", @@ -2436,7 +2437,7 @@ dependencies = [ "smallvec", "target-lexicon", "tempfile", - "wasmparser 0.68.0", + "wasmparser 0.69.1", "wasmtime-cache", "wasmtime-environ", "wasmtime-jit", @@ -2514,7 +2515,7 @@ dependencies = [ "test-programs", "tracing-subscriber", "wasi-common", - "wasmparser 0.68.0", + "wasmparser 0.69.1", "wasmtime", "wasmtime-cache", "wasmtime-debug", @@ -2550,7 +2551,7 @@ dependencies = [ "object", "target-lexicon", "thiserror", - "wasmparser 0.68.0", + "wasmparser 0.69.1", "wasmtime-environ", ] @@ -2569,7 +2570,7 @@ dependencies = [ "more-asserts", "serde", "thiserror", - "wasmparser 0.68.0", + "wasmparser 0.69.1", ] [[package]] @@ -2598,7 +2599,7 @@ dependencies = [ "rayon", "wasm-smith", "wasmi", - "wasmparser 0.68.0", + "wasmparser 0.69.1", "wasmprinter", "wasmtime", "wasmtime-wast", @@ -2626,7 +2627,7 @@ dependencies = [ "serde", "target-lexicon", "thiserror", - "wasmparser 0.68.0", + "wasmparser 0.69.1", "wasmtime-cranelift", "wasmtime-debug", "wasmtime-environ", @@ -2643,7 +2644,7 @@ version = "0.21.0" dependencies = [ "cranelift-codegen", "lightbeam", - "wasmparser 0.68.0", + "wasmparser 0.69.1", "wasmtime-environ", ] @@ -2750,7 +2751,7 @@ version = "0.21.0" dependencies = [ "anyhow", "wasmtime", - "wast 27.0.0", + "wast 28.0.0", ] [[package]] @@ -2786,20 +2787,20 @@ dependencies = [ [[package]] name = "wast" -version = "27.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2c3ef5f6a72dffa44c24d5811123f704e18a1dbc83637d347b1852b41d3835c" +checksum = "9c0586061bfacc035034672c8d760802b428ab4c80a92e2a392425c516df9be1" dependencies = [ "leb128", ] [[package]] name = "wat" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835cf59c907f67e2bbc20f50157e08f35006fe2a8444d8ec9f5683e22f937045" +checksum = "c06d55b5ec4f9d9396fa99abaafa0688597395e57827dffd89731412ae90c9bf" dependencies = [ - "wast 27.0.0", + "wast 28.0.0", ] [[package]] diff --git a/crates/environ/src/module.rs b/crates/environ/src/module.rs index c555a4435b8f..226d96134db1 100644 --- a/crates/environ/src/module.rs +++ b/crates/environ/src/module.rs @@ -347,7 +347,8 @@ impl Module { index.index() < self.num_imported_globals } - /// Test whether the given global index is for an imported global. + /// Returns an iterator of all the imports in this module, along with their + /// module name, field name, and type that's being imported. pub fn imports(&self) -> impl Iterator, EntityType)> { self.initializers.iter().filter_map(move |i| match i { Initializer::Import { diff --git a/crates/wasmtime/src/instance.rs b/crates/wasmtime/src/instance.rs index 678ced4f52bd..6f69b66a364b 100644 --- a/crates/wasmtime/src/instance.rs +++ b/crates/wasmtime/src/instance.rs @@ -88,7 +88,7 @@ fn instantiate( // // Note that the unsafety here is because we're asserting that the // handle comes from our same store, but this should be true because - // we acquired fthe handle from an instance in the store. + // we acquired the handle from an instance in the store. Initializer::AliasInstanceExport { instance, export } => { let handle = &imports.instances[*instance]; let export_index = &handle.module().exports[*export]; @@ -155,7 +155,7 @@ fn instantiate( // With the above initialization done we've now acquired the final set of // imports in all the right index spaces and everything. Time to carry on // with the creation of our own instance. - let imports = imports.imports(); + let imports = imports.build(); // Register the module just before instantiation to ensure we have a // trampoline registered for every signature and to preserve the module's @@ -345,7 +345,7 @@ impl Instance { ExternType::from_wasmtime(types, &module.type_of(*index)), ); } - return ty; + ty } /// Returns the associated [`Store`] that this `Instance` is compiled into. @@ -499,7 +499,7 @@ impl<'a> ImportsBuilder<'a> { } } - fn imports(&mut self) -> Imports<'_> { + fn build(&mut self) -> Imports<'_> { Imports { tables: self.tables.values().as_slice(), globals: self.globals.values().as_slice(), diff --git a/crates/wasmtime/src/module.rs b/crates/wasmtime/src/module.rs index b3d19f5ff496..d30309c5fc50 100644 --- a/crates/wasmtime/src/module.rs +++ b/crates/wasmtime/src/module.rs @@ -306,7 +306,7 @@ impl Module { ExternType::from_wasmtime(types, &env_module.type_of(*index)), ); } - return sig; + sig } /// Serialize compilation artifacts to the buffer. See also `deseriaize`. diff --git a/crates/wasmtime/src/types/matching.rs b/crates/wasmtime/src/types/matching.rs index c9ef03c26c12..018ab35fd962 100644 --- a/crates/wasmtime/src/types/matching.rs +++ b/crates/wasmtime/src/types/matching.rs @@ -92,7 +92,7 @@ impl MatchCx<'_> { }) } - /// Validaates that the `actual_imports` list of module imports matches the + /// Validates that the `actual_imports` list of module imports matches the /// `expected` module type signature. /// /// Types specified in `actual_imports` are relative to `actual_types`. From 40218b00c1e4f4330b93867c95d1504996c1bd94 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 3 Dec 2020 07:32:29 -0800 Subject: [PATCH 4/4] 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. --- scripts/publish.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/publish.rs b/scripts/publish.rs index 9cff25a4a076..a56e03b35129 100644 --- a/scripts/publish.rs +++ b/scripts/publish.rs @@ -293,7 +293,10 @@ fn verify(crates: &[Crate]) { // Vendor witx which wasn't vendored because it's a path dependency, but // it'll need to be in our directory registry for crates that depend on it. - let witx = crates.iter().find(|c| c.name == "witx").unwrap(); + let witx = crates + .iter() + .find(|c| c.name == "witx" && c.manifest.iter().any(|p| p == "wasi-common")) + .unwrap(); verify_and_vendor(&witx); for krate in crates {