Remove the module linking implementation in Wasmtime (#3958)

* Remove the module linking implementation in Wasmtime

This commit removes the experimental implementation of the module
linking WebAssembly proposal from Wasmtime. The module linking is no
longer intended for core WebAssembly but is instead incorporated into
the component model now at this point. This means that very large parts
of Wasmtime's implementation of module linking are no longer applicable
and would change greatly with an implementation of the component model.

The main purpose of this is to remove Wasmtime's reliance on the support
for module-linking in `wasmparser` and tooling crates. With this
reliance removed we can move over to the `component-model` branch of
`wasmparser` and use the updated support for the component model.
Additionally given the trajectory of the component model proposal the
embedding API of Wasmtime will not look like what it looks like today
for WebAssembly. For example the core wasm `Instance` will not change
and instead a `Component` is likely to be added instead.

Some more rationale for this is in #3941, but the basic idea is that I
feel that it's not going to be viable to develop support for the
component model on a non-`main` branch of Wasmtime. Additionaly I don't
think it's viable, for the same reasons as `wasm-tools`, to support the
old module linking proposal and the new component model at the same
time.

This commit takes a moment to not only delete the existing module
linking implementation but some abstractions are also simplified. For
example module serialization is a bit simpler that there's only one
module. Additionally instantiation is much simpler since the only
initializer we have to deal with are imports and nothing else.

Closes #3941

* Fix doc link

* Update comments
This commit is contained in:
Alex Crichton
2022-03-23 14:57:34 -05:00
committed by GitHub
parent 6a60e8363f
commit 76b82910c9
51 changed files with 400 additions and 4555 deletions

View File

@@ -6,5 +6,5 @@ mod spec;
pub use crate::environ::dummy::DummyEnvironment;
pub use crate::environ::spec::{
Alias, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment,
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment,
};

View File

@@ -8,9 +8,9 @@
use crate::state::FuncTranslationState;
use crate::{
DataIndex, ElemIndex, EntityIndex, EntityType, FuncIndex, Global, GlobalIndex, InstanceIndex,
InstanceTypeIndex, Memory, MemoryIndex, ModuleIndex, ModuleTypeIndex, SignatureIndex, Table,
TableIndex, Tag, TagIndex, TypeIndex, WasmError, WasmFuncType, WasmResult, WasmType,
DataIndex, ElemIndex, EntityType, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex,
SignatureIndex, Table, TableIndex, Tag, TagIndex, TypeIndex, WasmError, WasmFuncType,
WasmResult, WasmType,
};
use core::convert::From;
use cranelift_codegen::cursor::FuncCursor;
@@ -20,7 +20,6 @@ use cranelift_codegen::isa::TargetFrontendConfig;
use cranelift_frontend::FunctionBuilder;
use std::boxed::Box;
use std::string::ToString;
use std::vec::Vec;
use wasmparser::{FuncValidator, FunctionBody, Operator, ValidatorResources, WasmFeatures};
/// The value of a WebAssembly global variable.
@@ -52,39 +51,6 @@ pub enum ReturnMode {
FallthroughReturn,
}
/// An entry in the alias section of a wasm module (from the module linking
/// proposal)
pub enum Alias<'a> {
/// An outer module's module is being aliased into our own index space.
OuterModule {
/// The number of modules above us that we're referencing.
relative_depth: u32,
/// The module index in the outer module's index space we're referencing.
index: ModuleIndex,
},
/// An outer module's type is being aliased into our own index space
///
/// Note that the index here is in the outer module's index space, not our
/// own.
OuterType {
/// The number of modules above us that we're referencing.
relative_depth: u32,
/// The type index in the outer module's index space we're referencing.
index: TypeIndex,
},
/// A previously created instance is having one of its exports aliased into
/// our index space.
InstanceExport {
/// The index we're aliasing.
instance: InstanceIndex,
/// The nth export that we're inserting into our own index space
/// locally.
export: &'a str,
},
}
/// Environment affecting the translation of a WebAssembly.
pub trait TargetEnvironment {
/// Get the information needed to produce Cranelift IR for the given target.
@@ -588,20 +554,6 @@ pub trait ModuleEnvironment<'data> {
Err(WasmError::Unsupported("module linking".to_string()))
}
/// Translates a type index to its module type index, only called for type
/// indices which point to modules.
fn type_to_module_type(&self, index: TypeIndex) -> WasmResult<ModuleTypeIndex> {
drop(index);
Err(WasmError::Unsupported("module linking".to_string()))
}
/// Translates a type index to its instance type index, only called for type
/// indices which point to instances.
fn type_to_instance_type(&self, index: TypeIndex) -> WasmResult<InstanceTypeIndex> {
drop(index);
Err(WasmError::Unsupported("module linking".to_string()))
}
/// Provides the number of imports up front. By default this does nothing, but
/// implementations can use this to preallocate memory if desired.
fn reserve_imports(&mut self, _num: u32) -> WasmResult<()> {
@@ -662,17 +614,6 @@ pub trait ModuleEnvironment<'data> {
Err(WasmError::Unsupported("module linking".to_string()))
}
/// Declares an instance import to the environment.
fn declare_instance_import(
&mut self,
ty_index: TypeIndex,
module: &'data str,
field: Option<&'data str>,
) -> WasmResult<()> {
drop((ty_index, module, field));
Err(WasmError::Unsupported("module linking".to_string()))
}
/// Notifies the implementation that all imports have been declared.
fn finish_imports(&mut self) -> WasmResult<()> {
Ok(())
@@ -759,22 +700,6 @@ pub trait ModuleEnvironment<'data> {
name: &'data str,
) -> WasmResult<()>;
/// Declares an instance export to the environment.
fn declare_instance_export(
&mut self,
index: InstanceIndex,
name: &'data str,
) -> WasmResult<()> {
drop((index, name));
Err(WasmError::Unsupported("module linking".to_string()))
}
/// Declares an instance export to the environment.
fn declare_module_export(&mut self, index: ModuleIndex, name: &'data str) -> WasmResult<()> {
drop((index, name));
Err(WasmError::Unsupported("module linking".to_string()))
}
/// Notifies the implementation that all exports have been declared.
fn finish_exports(&mut self) -> WasmResult<()> {
Ok(())
@@ -880,48 +805,4 @@ pub trait ModuleEnvironment<'data> {
fn wasm_features(&self) -> WasmFeatures {
WasmFeatures::default()
}
/// Indicates that this module will have `amount` submodules.
///
/// Note that this is just child modules of this module, and each child
/// module may have yet more submodules.
fn reserve_modules(&mut self, amount: u32) {
drop(amount);
}
/// Called at the beginning of translating a module.
///
/// Note that for nested modules this may be called multiple times.
fn module_start(&mut self) {}
/// Called at the end of translating a module.
///
/// Note that for nested modules this may be called multiple times.
fn module_end(&mut self) {}
/// Indicates that this module will have `amount` instances.
fn reserve_instances(&mut self, amount: u32) {
drop(amount);
}
/// Declares a new instance which this module will instantiate before it's
/// instantiated.
fn declare_instance(
&mut self,
module: ModuleIndex,
args: Vec<(&'data str, EntityIndex)>,
) -> WasmResult<()> {
drop((module, args));
Err(WasmError::Unsupported("wasm instance".to_string()))
}
/// Declares a new alias being added to this module.
///
/// The alias comes from the `instance` specified (or the parent if `None`
/// is supplied) and the index is either in the module's own index spaces
/// for the parent or an index into the exports for nested instances.
fn declare_alias(&mut self, alias: Alias<'data>) -> WasmResult<()> {
drop(alias);
Err(WasmError::Unsupported("wasm alias".to_string()))
}
}

View File

@@ -57,7 +57,7 @@ mod state;
mod translation_utils;
pub use crate::environ::{
Alias, DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode,
DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode,
TargetEnvironment,
};
pub use crate::func_translator::FuncTranslator;

View File

@@ -2,10 +2,9 @@
//! to deal with each part of it.
use crate::environ::ModuleEnvironment;
use crate::sections_translator::{
parse_alias_section, parse_data_section, parse_element_section, parse_export_section,
parse_function_section, parse_global_section, parse_import_section, parse_instance_section,
parse_memory_section, parse_name_section, parse_start_section, parse_table_section,
parse_tag_section, parse_type_section,
parse_data_section, parse_element_section, parse_export_section, parse_function_section,
parse_global_section, parse_import_section, parse_memory_section, parse_name_section,
parse_start_section, parse_table_section, parse_tag_section, parse_type_section,
};
use crate::state::ModuleTranslationState;
use crate::WasmResult;
@@ -28,11 +27,9 @@ pub fn translate_module<'data>(
match payload? {
Payload::Version { num, range } => {
validator.version(num, &range)?;
environ.module_start();
}
Payload::End => {
validator.end()?;
environ.module_end();
}
Payload::TypeSection(types) => {
@@ -109,11 +106,11 @@ pub fn translate_module<'data>(
Payload::InstanceSection(s) => {
validator.instance_section(&s)?;
parse_instance_section(s, environ)?;
unimplemented!();
}
Payload::AliasSection(s) => {
validator.alias_section(&s)?;
parse_alias_section(s, environ)?;
unimplemented!();
}
Payload::ModuleSectionStart {
count,
@@ -121,11 +118,12 @@ pub fn translate_module<'data>(
size: _,
} => {
validator.module_section_start(count, &range)?;
environ.reserve_modules(count);
unimplemented!();
}
Payload::ModuleSectionEntry { .. } => {
validator.module_section_entry();
unimplemented!();
}
Payload::CustomSection {

View File

@@ -7,13 +7,12 @@
//! The special case of the initialize expressions for table elements offsets or global variables
//! is handled, according to the semantics of WebAssembly, to only specific expressions that are
//! interpreted on the fly.
use crate::environ::{Alias, ModuleEnvironment};
use crate::environ::ModuleEnvironment;
use crate::state::ModuleTranslationState;
use crate::wasm_unsupported;
use crate::{
DataIndex, ElemIndex, EntityIndex, EntityType, FuncIndex, Global, GlobalIndex, GlobalInit,
InstanceIndex, Memory, MemoryIndex, ModuleIndex, Table, TableIndex, Tag, TagIndex, TypeIndex,
WasmError, WasmResult,
DataIndex, ElemIndex, EntityType, FuncIndex, Global, GlobalIndex, GlobalInit, Memory,
MemoryIndex, Table, TableIndex, Tag, TagIndex, TypeIndex, WasmError, WasmResult,
};
use core::convert::TryFrom;
use core::convert::TryInto;
@@ -37,16 +36,15 @@ fn entity_type(
ImportSectionEntryType::Function(sig) => {
EntityType::Function(environ.type_to_signature(TypeIndex::from_u32(sig))?)
}
ImportSectionEntryType::Module(sig) => {
EntityType::Module(environ.type_to_module_type(TypeIndex::from_u32(sig))?)
}
ImportSectionEntryType::Instance(sig) => {
EntityType::Instance(environ.type_to_instance_type(TypeIndex::from_u32(sig))?)
}
ImportSectionEntryType::Memory(ty) => EntityType::Memory(memory(ty)),
ImportSectionEntryType::Tag(t) => EntityType::Tag(tag(t)),
ImportSectionEntryType::Global(ty) => EntityType::Global(global(ty, GlobalInit::Import)?),
ImportSectionEntryType::Table(ty) => EntityType::Table(table(ty)?),
// doesn't get past validation
ImportSectionEntryType::Module(_) | ImportSectionEntryType::Instance(_) => {
unreachable!()
}
})
}
@@ -142,20 +140,6 @@ pub fn parse_import_section<'data>(
import.field,
)?;
}
ImportSectionEntryType::Module(sig) => {
environ.declare_module_import(
TypeIndex::from_u32(sig),
import.module,
import.field,
)?;
}
ImportSectionEntryType::Instance(sig) => {
environ.declare_instance_import(
TypeIndex::from_u32(sig),
import.module,
import.field,
)?;
}
ImportSectionEntryType::Memory(ty) => {
environ.declare_memory_import(memory(ty), import.module, import.field)?;
}
@@ -170,6 +154,10 @@ pub fn parse_import_section<'data>(
let ty = table(ty)?;
environ.declare_table_import(ty, import.module, import.field)?;
}
ImportSectionEntryType::Module(_) | ImportSectionEntryType::Instance(_) => {
unimplemented!()
}
}
}
@@ -310,15 +298,9 @@ pub fn parse_export_section<'data>(
ExternalKind::Global => {
environ.declare_global_export(GlobalIndex::new(index), field)?
}
ExternalKind::Module => {
environ.declare_module_export(ModuleIndex::new(index), field)?
}
ExternalKind::Instance => {
environ.declare_instance_export(InstanceIndex::new(index), field)?
}
// this never gets past validation
ExternalKind::Type => unreachable!(),
ExternalKind::Module | ExternalKind::Instance | ExternalKind::Type => unreachable!(),
}
}
@@ -506,75 +488,3 @@ pub fn parse_name_section<'data>(
}
Ok(())
}
/// Parses the Instance section of the wasm module.
pub fn parse_instance_section<'data>(
section: wasmparser::InstanceSectionReader<'data>,
environ: &mut dyn ModuleEnvironment<'data>,
) -> WasmResult<()> {
environ.reserve_instances(section.get_count());
for instance in section {
let instance = instance?;
let module = ModuleIndex::from_u32(instance.module());
let args = instance
.args()?
.into_iter()
.map(|arg| {
let arg = arg?;
let index = match arg.kind {
ExternalKind::Function => EntityIndex::Function(FuncIndex::from_u32(arg.index)),
ExternalKind::Table => EntityIndex::Table(TableIndex::from_u32(arg.index)),
ExternalKind::Memory => EntityIndex::Memory(MemoryIndex::from_u32(arg.index)),
ExternalKind::Global => EntityIndex::Global(GlobalIndex::from_u32(arg.index)),
ExternalKind::Module => EntityIndex::Module(ModuleIndex::from_u32(arg.index)),
ExternalKind::Instance => {
EntityIndex::Instance(InstanceIndex::from_u32(arg.index))
}
ExternalKind::Tag => unimplemented!(),
// this won't pass validation
ExternalKind::Type => unreachable!(),
};
Ok((arg.name, index))
})
.collect::<WasmResult<Vec<_>>>()?;
environ.declare_instance(module, args)?;
}
Ok(())
}
/// Parses the Alias section of the wasm module.
pub fn parse_alias_section<'data>(
section: wasmparser::AliasSectionReader<'data>,
environ: &mut dyn ModuleEnvironment<'data>,
) -> WasmResult<()> {
for alias in section {
let alias = match alias? {
wasmparser::Alias::OuterType {
relative_depth,
index,
} => Alias::OuterType {
relative_depth,
index: TypeIndex::from_u32(index),
},
wasmparser::Alias::OuterModule {
relative_depth,
index,
} => Alias::OuterModule {
relative_depth,
index: ModuleIndex::from_u32(index),
},
wasmparser::Alias::InstanceExport {
instance,
export,
kind: _,
} => Alias::InstanceExport {
instance: InstanceIndex::from_u32(instance),
export,
},
};
environ.declare_alias(alias)?;
}
Ok(())
}