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:
@@ -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(())
|
||||
|
||||
Reference in New Issue
Block a user