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

@@ -24,9 +24,5 @@ pub mod entity {
}
pub mod wasm {
pub use cranelift_wasm::{
get_vmctx_value_label, DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex,
DefinedTableIndex, ElemIndex, FuncIndex, Global, GlobalIndex, GlobalInit, Memory,
MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex, WasmFuncType, WasmType,
};
pub use cranelift_wasm::*;
}

View File

@@ -37,10 +37,7 @@ pub use crate::address_map::*;
pub use crate::builtin::*;
pub use crate::compilation::*;
pub use crate::data_structures::*;
// pub use crate::func_environ::BuiltinFunctionIndex;
pub use crate::module::{
EntityIndex, MemoryPlan, MemoryStyle, Module, TableElements, TablePlan, TableStyle,
};
pub use crate::module::*;
pub use crate::module_environ::*;
pub use crate::tunables::Tunables;
pub use crate::vmoffsets::{TargetSharedSignatureIndex, VMOffsets, INTERRUPTED};

View File

@@ -5,8 +5,8 @@ use crate::WASM_MAX_PAGES;
use cranelift_entity::{EntityRef, PrimaryMap};
use cranelift_wasm::{
DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex,
ElemIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table,
TableIndex, WasmFuncType,
ElemIndex, EntityIndex, EntityType, FuncIndex, Global, GlobalIndex, InstanceIndex, Memory,
MemoryIndex, ModuleIndex, SignatureIndex, Table, TableIndex, TypeIndex, WasmFuncType,
};
use indexmap::IndexMap;
use more_asserts::assert_ge;
@@ -30,19 +30,6 @@ pub struct TableElements {
pub elements: Box<[FuncIndex]>,
}
/// An index of an entity.
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum EntityIndex {
/// Function index.
Function(FuncIndex),
/// Table index.
Table(TableIndex),
/// Memory index.
Memory(MemoryIndex),
/// Global index.
Global(GlobalIndex),
}
/// Implemenation styles for WebAssembly linear memory.
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
pub enum MemoryStyle {
@@ -134,6 +121,36 @@ impl TablePlan {
}
}
/// Different types that can appear in a module
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ModuleType {
/// A function type, indexed further into the `signatures` table.
Function(SignatureIndex),
/// A module type
Module {
/// The module's imports
imports: Vec<(String, Option<String>, EntityType)>,
/// The module's exports
exports: Vec<(String, EntityType)>,
},
/// An instance type
Instance {
/// the instance's exports
exports: Vec<(String, EntityType)>,
},
}
impl ModuleType {
/// Asserts this is a `ModuleType::Function`, returning the underlying
/// `SignatureIndex`.
pub fn unwrap_function(&self) -> SignatureIndex {
match self {
ModuleType::Function(f) => *f,
_ => panic!("not a function type"),
}
}
}
/// A translated WebAssembly module, excluding the function bodies and
/// memory initializers.
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -170,6 +187,9 @@ pub struct Module {
/// Unprocessed signatures exactly as provided by `declare_signature()`.
pub signatures: PrimaryMap<SignatureIndex, WasmFuncType>,
/// Types declared in the wasm module.
pub types: PrimaryMap<TypeIndex, ModuleType>,
/// Number of imported functions in the module.
pub num_imported_funcs: usize,
@@ -193,6 +213,27 @@ pub struct Module {
/// WebAssembly global variables.
pub globals: PrimaryMap<GlobalIndex, Global>,
/// WebAssembly instances.
pub instances: PrimaryMap<InstanceIndex, Instance>,
/// WebAssembly modules.
pub modules: PrimaryMap<ModuleIndex, TypeIndex>,
}
/// Different forms an instance can take in a wasm module
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Instance {
/// This is an imported instance with the specified type
Import(TypeIndex),
/// This is a locally created instance which instantiates the specified
/// module with the given list of entities.
Instantiate {
/// The module that this instance is instantiating.
module: ModuleIndex,
/// The arguments provided to instantiation.
args: Vec<EntityIndex>,
},
}
impl Module {
@@ -217,6 +258,9 @@ impl Module {
table_plans: PrimaryMap::new(),
memory_plans: PrimaryMap::new(),
globals: PrimaryMap::new(),
instances: PrimaryMap::new(),
modules: PrimaryMap::new(),
types: PrimaryMap::new(),
}
}

View File

@@ -1,13 +1,13 @@
use crate::module::{EntityIndex, MemoryPlan, Module, TableElements, TablePlan};
use crate::module::{MemoryPlan, Module, ModuleType, TableElements, TablePlan};
use crate::tunables::Tunables;
use cranelift_codegen::ir;
use cranelift_codegen::ir::{AbiParam, ArgumentPurpose};
use cranelift_codegen::isa::TargetFrontendConfig;
use cranelift_entity::PrimaryMap;
use cranelift_wasm::{
self, translate_module, DataIndex, DefinedFuncIndex, ElemIndex, FuncIndex, Global, GlobalIndex,
Memory, MemoryIndex, SignatureIndex, Table, TableIndex, TargetEnvironment, WasmError,
WasmFuncType, WasmResult,
self, translate_module, DataIndex, DefinedFuncIndex, ElemIndex, EntityIndex, EntityType,
FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, TableIndex,
TargetEnvironment, TypeIndex, WasmError, WasmFuncType, WasmResult,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
@@ -201,18 +201,54 @@ impl<'data> TargetEnvironment for ModuleEnvironment<'data> {
/// This trait is useful for `translate_module` because it tells how to translate
/// environment-dependent wasm instructions. These functions should not be called by the user.
impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data> {
fn reserve_signatures(&mut self, num: u32) -> WasmResult<()> {
fn reserve_types(&mut self, num: u32) -> WasmResult<()> {
let num = usize::try_from(num).unwrap();
self.result.module.signatures.reserve_exact(num);
self.result.module.types.reserve_exact(num);
self.result.native_signatures.reserve_exact(num);
Ok(())
}
fn declare_signature(&mut self, wasm: WasmFuncType, sig: ir::Signature) -> WasmResult<()> {
fn declare_type_func(&mut self, wasm: WasmFuncType, sig: ir::Signature) -> WasmResult<()> {
let sig = translate_signature(sig, self.pointer_type());
// TODO: Deduplicate signatures.
self.result.module.signatures.push(wasm);
self.result.native_signatures.push(sig);
let sig_index = self.result.module.signatures.push(wasm);
self.result
.module
.types
.push(ModuleType::Function(sig_index));
Ok(())
}
fn declare_type_module(
&mut self,
imports: &[(&'data str, Option<&'data str>, EntityType)],
exports: &[(&'data str, EntityType)],
) -> WasmResult<()> {
let imports = imports
.iter()
.map(|i| (i.0.to_string(), i.1.map(|s| s.to_string()), i.2.clone()))
.collect();
let exports = exports
.iter()
.map(|e| (e.0.to_string(), e.1.clone()))
.collect();
self.result
.module
.types
.push(ModuleType::Module { imports, exports });
Ok(())
}
fn declare_type_instance(&mut self, exports: &[(&'data str, EntityType)]) -> WasmResult<()> {
let exports = exports
.iter()
.map(|e| (e.0.to_string(), e.1.clone()))
.collect();
self.result
.module
.types
.push(ModuleType::Instance { exports });
Ok(())
}
@@ -226,7 +262,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
fn declare_func_import(
&mut self,
sig_index: SignatureIndex,
index: TypeIndex,
module: &str,
field: &str,
) -> WasmResult<()> {
@@ -235,6 +271,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
self.result.module.num_imported_funcs,
"Imported functions must be declared first"
);
let sig_index = self.result.module.types[index].unwrap_function();
let func_index = self.result.module.functions.push(sig_index);
self.result.module.imports.push((
module.to_owned(),
@@ -320,7 +357,8 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
Ok(())
}
fn declare_func_type(&mut self, sig_index: SignatureIndex) -> WasmResult<()> {
fn declare_func_type(&mut self, index: TypeIndex) -> WasmResult<()> {
let sig_index = self.result.module.types[index].unwrap_function();
self.result.module.functions.push(sig_index);
Ok(())
}