Propagate module-linking types to wasmtime (#2115)

This commit adds lots of plumbing to get the type section from the
module linking proposal plumbed all the way through to the `wasmtime`
crate and the `wasmtime-c-api` crate. This isn't all that useful right
now because Wasmtime doesn't support imported/exported
modules/instances, but this is all necessary groundwork to getting that
exported at some point. I've added some light tests but I suspect the
bulk of the testing will come in a future commit.

One major change in this commit is that `SignatureIndex` no longer
follows type type index space in a wasm module. Instead a new
`TypeIndex` type is used to track that. Function signatures, still
indexed by `SignatureIndex`, are then packed together tightly.
This commit is contained in:
Alex Crichton
2020-11-06 14:48:09 -06:00
committed by GitHub
parent 77827a48a9
commit 73cda83548
27 changed files with 782 additions and 213 deletions

View File

@@ -10,8 +10,8 @@
use crate::environ::{ModuleEnvironment, WasmError, WasmResult};
use crate::state::ModuleTranslationState;
use crate::translation_utils::{
tabletype_to_type, type_to_type, DataIndex, ElemIndex, FuncIndex, Global, GlobalIndex,
GlobalInit, Memory, MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex,
tabletype_to_type, type_to_type, DataIndex, ElemIndex, EntityType, FuncIndex, Global,
GlobalIndex, GlobalInit, Memory, MemoryIndex, Table, TableElementType, TableIndex, TypeIndex,
};
use crate::wasm_unsupported;
use core::convert::TryFrom;
@@ -27,18 +27,71 @@ use wasmparser::{
ElementSectionReader, Export, ExportSectionReader, ExternalKind, FunctionSectionReader,
GlobalSectionReader, GlobalType, ImportSectionEntryType, ImportSectionReader,
MemorySectionReader, MemoryType, NameSectionReader, Naming, Operator, TableSectionReader,
TypeDef, TypeSectionReader,
TableType, TypeDef, TypeSectionReader,
};
fn entity_type(
ty: ImportSectionEntryType,
environ: &mut dyn ModuleEnvironment<'_>,
) -> WasmResult<EntityType> {
Ok(match ty {
ImportSectionEntryType::Function(sig) => EntityType::Function(TypeIndex::from_u32(sig)),
ImportSectionEntryType::Module(sig) => EntityType::Module(TypeIndex::from_u32(sig)),
ImportSectionEntryType::Instance(sig) => EntityType::Instance(TypeIndex::from_u32(sig)),
ImportSectionEntryType::Memory(ty) => EntityType::Memory(memory(ty)),
ImportSectionEntryType::Global(ty) => {
EntityType::Global(global(ty, environ, GlobalInit::Import)?)
}
ImportSectionEntryType::Table(ty) => EntityType::Table(table(ty, environ)?),
})
}
fn memory(ty: MemoryType) -> Memory {
match ty {
MemoryType::M32 { limits, shared } => Memory {
minimum: limits.initial,
maximum: limits.maximum,
shared: shared,
},
// FIXME(#2361)
MemoryType::M64 { .. } => unimplemented!(),
}
}
fn table(ty: TableType, environ: &mut dyn ModuleEnvironment<'_>) -> WasmResult<Table> {
Ok(Table {
wasm_ty: ty.element_type.try_into()?,
ty: match tabletype_to_type(ty.element_type, environ)? {
Some(t) => TableElementType::Val(t),
None => TableElementType::Func,
},
minimum: ty.limits.initial,
maximum: ty.limits.maximum,
})
}
fn global(
ty: GlobalType,
environ: &mut dyn ModuleEnvironment<'_>,
initializer: GlobalInit,
) -> WasmResult<Global> {
Ok(Global {
wasm_ty: ty.content_type.try_into()?,
ty: type_to_type(ty.content_type, environ).unwrap(),
mutability: ty.mutable,
initializer,
})
}
/// Parses the Type section of the wasm module.
pub fn parse_type_section(
types: TypeSectionReader,
pub fn parse_type_section<'a>(
types: TypeSectionReader<'a>,
module_translation_state: &mut ModuleTranslationState,
environ: &mut dyn ModuleEnvironment,
environ: &mut dyn ModuleEnvironment<'a>,
) -> WasmResult<()> {
let count = types.get_count();
module_translation_state.wasm_types.reserve(count as usize);
environ.reserve_signatures(count)?;
environ.reserve_types(count)?;
for entry in types {
match entry? {
@@ -55,28 +108,31 @@ pub fn parse_type_section(
.expect("only numeric types are supported in function signatures");
AbiParam::new(cret_arg)
}));
environ.declare_signature(wasm_func_ty.clone().try_into()?, sig)?;
environ.declare_type_func(wasm_func_ty.clone().try_into()?, sig)?;
module_translation_state
.wasm_types
.push((wasm_func_ty.params, wasm_func_ty.returns));
}
// Not implemented yet for module linking. Push dummy function types
// though to keep the function type index space consistent. We'll
// want an actual implementation here that handles this eventually.
TypeDef::Module(_) | TypeDef::Instance(_) => {
let sig =
Signature::new(ModuleEnvironment::target_config(environ).default_call_conv);
environ.declare_signature(
crate::environ::WasmFuncType {
params: Box::new([]),
returns: Box::new([]),
},
sig,
)?;
module_translation_state
.wasm_types
.push((Box::new([]), Box::new([])));
TypeDef::Module(t) => {
let imports = t
.imports
.iter()
.map(|i| Ok((i.module, i.field, entity_type(i.ty, environ)?)))
.collect::<WasmResult<Vec<_>>>()?;
let exports = t
.exports
.iter()
.map(|e| Ok((e.name, entity_type(e.ty, environ)?)))
.collect::<WasmResult<Vec<_>>>()?;
environ.declare_type_module(&imports, &exports)?;
}
TypeDef::Instance(t) => {
let exports = t
.exports
.iter()
.map(|e| Ok((e.name, entity_type(e.ty, environ)?)))
.collect::<WasmResult<Vec<_>>>()?;
environ.declare_type_instance(&exports)?;
}
}
}
@@ -94,61 +150,24 @@ pub fn parse_import_section<'data>(
let import = entry?;
let module_name = import.module;
let field_name = import.field.unwrap(); // TODO Handle error when module linking is implemented.
match import.ty {
ImportSectionEntryType::Function(sig) => {
environ.declare_func_import(
SignatureIndex::from_u32(sig),
module_name,
field_name,
)?;
match entity_type(import.ty, environ)? {
EntityType::Function(idx) => {
environ.declare_func_import(idx, module_name, field_name)?;
}
ImportSectionEntryType::Module(_sig) | ImportSectionEntryType::Instance(_sig) => {
unimplemented!("module linking not implemented yet")
EntityType::Module(idx) => {
environ.declare_module_import(idx, module_name, field_name)?;
}
ImportSectionEntryType::Memory(MemoryType::M32 {
limits: ref memlimits,
shared,
}) => {
environ.declare_memory_import(
Memory {
minimum: memlimits.initial,
maximum: memlimits.maximum,
shared,
},
module_name,
field_name,
)?;
EntityType::Instance(idx) => {
environ.declare_instance_import(idx, module_name, field_name)?;
}
ImportSectionEntryType::Memory(MemoryType::M64 { .. }) => {
unimplemented!();
EntityType::Memory(ty) => {
environ.declare_memory_import(ty, module_name, field_name)?;
}
ImportSectionEntryType::Global(ref ty) => {
environ.declare_global_import(
Global {
wasm_ty: ty.content_type.try_into()?,
ty: type_to_type(ty.content_type, environ).unwrap(),
mutability: ty.mutable,
initializer: GlobalInit::Import,
},
module_name,
field_name,
)?;
EntityType::Global(ty) => {
environ.declare_global_import(ty, module_name, field_name)?;
}
ImportSectionEntryType::Table(ref tab) => {
environ.declare_table_import(
Table {
wasm_ty: tab.element_type.try_into()?,
ty: match tabletype_to_type(tab.element_type, environ)? {
Some(t) => TableElementType::Val(t),
None => TableElementType::Func,
},
minimum: tab.limits.initial,
maximum: tab.limits.maximum,
},
module_name,
field_name,
)?;
EntityType::Table(ty) => {
environ.declare_table_import(ty, module_name, field_name)?;
}
}
}
@@ -172,7 +191,7 @@ pub fn parse_function_section(
for entry in functions {
let sigindex = entry?;
environ.declare_func_type(SignatureIndex::from_u32(sigindex))?;
environ.declare_func_type(TypeIndex::from_u32(sigindex))?;
}
Ok(())
@@ -186,16 +205,8 @@ pub fn parse_table_section(
environ.reserve_tables(tables.get_count())?;
for entry in tables {
let table = entry?;
environ.declare_table(Table {
wasm_ty: table.element_type.try_into()?,
ty: match tabletype_to_type(table.element_type, environ)? {
Some(t) => TableElementType::Val(t),
None => TableElementType::Func,
},
minimum: table.limits.initial,
maximum: table.limits.maximum,
})?;
let ty = table(entry?, environ)?;
environ.declare_table(ty)?;
}
Ok(())
@@ -209,17 +220,8 @@ pub fn parse_memory_section(
environ.reserve_memories(memories.get_count())?;
for entry in memories {
let memory = entry?;
match memory {
MemoryType::M32 { limits, shared } => {
environ.declare_memory(Memory {
minimum: limits.initial,
maximum: limits.maximum,
shared: shared,
})?;
}
MemoryType::M64 { .. } => unimplemented!(),
}
let memory = memory(entry?);
environ.declare_memory(memory)?;
}
Ok(())
@@ -233,13 +235,7 @@ pub fn parse_global_section(
environ.reserve_globals(globals.get_count())?;
for entry in globals {
let wasmparser::Global {
ty: GlobalType {
content_type,
mutable,
},
init_expr,
} = entry?;
let wasmparser::Global { ty, init_expr } = entry?;
let mut init_expr_reader = init_expr.get_binary_reader();
let initializer = match init_expr_reader.read_operator()? {
Operator::I32Const { value } => GlobalInit::I32Const(value),
@@ -263,13 +259,8 @@ pub fn parse_global_section(
));
}
};
let global = Global {
wasm_ty: content_type.try_into()?,
ty: type_to_type(content_type, environ).unwrap(),
mutability: mutable,
initializer,
};
environ.declare_global(global)?;
let ty = global(ty, environ, initializer)?;
environ.declare_global(ty)?;
}
Ok(())