Skip to content

Commit b110e85

Browse files
committed
Implement the module linking alias section
This commit is intended to do almost everything necessary for processing the alias section of module linking. Most of this is internal refactoring, the highlights being: * Type contents are now stored separately from a `wasmtime_env::Module`. Given that modules can freely alias types and have them used all over the place, it seemed best to have one canonical location to type storage which everywhere else points to (with indices). A new `TypeTables` structure is produced during compilation which is shared amongst all member modules in a wasm blob. * Instantiation is heavily refactored to account for module linking. The main gotcha here is that imports are now listed as "initializers". We have a sort of pseudo-bytecode-interpreter which interprets the initialization of a module. This is more complicated than just matching imports at this point because in the module linking proposal the module, alias, import, and instance sections may all be interleaved. This means that imports aren't guaranteed to show up at the beginning of the address space for modules/instances. Otherwise most of the changes here largely fell out from these two design points. Aliases are recorded as initializers in this scheme. Copying around type information and/or just knowing type information during compilation is also pretty easy since everything is just a pointer into a `TypeTables` and we don't have to actually copy any types themselves. Lots of various refactorings were necessary to accomodate these changes. Tests are hoped to cover a breadth of functionality here, but not necessarily a depth. There's still one more piece of the module linking proposal missing which is exporting instances/modules, which will come in a future PR. It's also worth nothing that there's one large TODO which isn't implemented in this change that I plan on opening an issue for. With module linking when a set of modules comes back from compilation each modules has all the trampolines for the entire set of modules. This is quite a lot of duplicate trampolines across module-linking modules. We'll want to refactor this at some point to instead have only one set of trampolines per set of module linking modules and have them shared from there. I figured it was best to separate out this change, however, since it's purely related to resource usage, and doesn't impact non-module-linking modules at all. cc bytecodealliance#2094
1 parent 88a8a89 commit b110e85

File tree

34 files changed

+1321
-520
lines changed

34 files changed

+1321
-520
lines changed

cranelift/wasm/src/environ/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ mod spec;
66

77
pub use crate::environ::dummy::DummyEnvironment;
88
pub use crate::environ::spec::{
9-
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment, WasmError,
10-
WasmFuncType, WasmResult, WasmType,
9+
Alias, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment,
10+
WasmError, WasmFuncType, WasmResult, WasmType,
1111
};

cranelift/wasm/src/environ/spec.rs

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
use crate::state::FuncTranslationState;
1010
use crate::translation_utils::{
1111
DataIndex, ElemIndex, EntityIndex, EntityType, Event, EventIndex, FuncIndex, Global,
12-
GlobalIndex, Memory, MemoryIndex, ModuleIndex, Table, TableIndex, TypeIndex,
12+
GlobalIndex, InstanceIndex, InstanceTypeIndex, Memory, MemoryIndex, ModuleIndex,
13+
ModuleTypeIndex, SignatureIndex, Table, TableIndex, TypeIndex,
1314
};
1415
use core::convert::From;
1516
use core::convert::TryFrom;
@@ -202,6 +203,30 @@ pub enum ReturnMode {
202203
FallthroughReturn,
203204
}
204205

206+
/// An entry in the alias section of a wasm module (from the module linking
207+
/// proposal)
208+
pub enum Alias {
209+
/// A parent's module is being aliased into our own index space.
210+
///
211+
/// Note that the index here is in the parent's index space, not our own.
212+
ParentModule(ModuleIndex),
213+
214+
/// A parent's type is being aliased into our own index space
215+
///
216+
/// Note that the index here is in the parent's index space, not our own.
217+
ParentType(TypeIndex),
218+
219+
/// A previously created instance is having one of its exports aliased into
220+
/// our index space.
221+
Child {
222+
/// The index we're aliasing.
223+
instance: InstanceIndex,
224+
/// The nth export that we're inserting into our own index space
225+
/// locally.
226+
export: usize,
227+
},
228+
}
229+
205230
/// Environment affecting the translation of a WebAssembly.
206231
pub trait TargetEnvironment {
207232
/// Get the information needed to produce Cranelift IR for the given target.
@@ -684,6 +709,27 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment {
684709
Err(WasmError::Unsupported("module linking".to_string()))
685710
}
686711

712+
/// Translates a type index to its signature index, only called for type
713+
/// indices which point to functions.
714+
fn type_to_signature(&self, index: TypeIndex) -> WasmResult<SignatureIndex> {
715+
drop(index);
716+
Err(WasmError::Unsupported("module linking".to_string()))
717+
}
718+
719+
/// Translates a type index to its module type index, only called for type
720+
/// indices which point to modules.
721+
fn type_to_module_type(&self, index: TypeIndex) -> WasmResult<ModuleTypeIndex> {
722+
drop(index);
723+
Err(WasmError::Unsupported("module linking".to_string()))
724+
}
725+
726+
/// Translates a type index to its instance type index, only called for type
727+
/// indices which point to instances.
728+
fn type_to_instance_type(&self, index: TypeIndex) -> WasmResult<InstanceTypeIndex> {
729+
drop(index);
730+
Err(WasmError::Unsupported("module linking".to_string()))
731+
}
732+
687733
/// Provides the number of imports up front. By default this does nothing, but
688734
/// implementations can use this to preallocate memory if desired.
689735
fn reserve_imports(&mut self, _num: u32) -> WasmResult<()> {
@@ -845,6 +891,22 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment {
845891
name: &'data str,
846892
) -> WasmResult<()>;
847893

894+
/// Declares an instance export to the environment.
895+
fn declare_instance_export(
896+
&mut self,
897+
index: InstanceIndex,
898+
name: &'data str,
899+
) -> WasmResult<()> {
900+
drop((index, name));
901+
Err(WasmError::Unsupported("module linking".to_string()))
902+
}
903+
904+
/// Declares an instance export to the environment.
905+
fn declare_module_export(&mut self, index: ModuleIndex, name: &'data str) -> WasmResult<()> {
906+
drop((index, name));
907+
Err(WasmError::Unsupported("module linking".to_string()))
908+
}
909+
848910
/// Notifies the implementation that all exports have been declared.
849911
fn finish_exports(&mut self) -> WasmResult<()> {
850912
Ok(())
@@ -952,6 +1014,12 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment {
9521014
drop(amount);
9531015
}
9541016

1017+
/// Declares that a module will come later with the type signature provided.
1018+
fn declare_module(&mut self, ty: TypeIndex) -> WasmResult<()> {
1019+
drop(ty);
1020+
Err(WasmError::Unsupported("module linking".to_string()))
1021+
}
1022+
9551023
/// Called at the beginning of translating a module.
9561024
///
9571025
/// The `index` argument is a monotonically increasing index which
@@ -982,4 +1050,14 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment {
9821050
drop((module, args));
9831051
Err(WasmError::Unsupported("wasm instance".to_string()))
9841052
}
1053+
1054+
/// Declares a new alias being added to this module.
1055+
///
1056+
/// The alias comes from the `instance` specified (or the parent if `None`
1057+
/// is supplied) and the index is either in the module's own index spaces
1058+
/// for the parent or an index into the exports for nested instances.
1059+
fn declare_alias(&mut self, alias: Alias) -> WasmResult<()> {
1060+
drop(alias);
1061+
Err(WasmError::Unsupported("wasm alias".to_string()))
1062+
}
9851063
}

cranelift/wasm/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ mod state;
5757
mod translation_utils;
5858

5959
pub use crate::environ::{
60-
DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode,
60+
Alias, DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode,
6161
TargetEnvironment, WasmError, WasmFuncType, WasmResult, WasmType,
6262
};
6363
pub use crate::func_translator::FuncTranslator;

cranelift/wasm/src/module_translator.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
//! to deal with each part of it.
33
use crate::environ::{ModuleEnvironment, WasmResult};
44
use crate::sections_translator::{
5-
parse_data_section, parse_element_section, parse_event_section, parse_export_section,
6-
parse_function_section, parse_global_section, parse_import_section, parse_instance_section,
7-
parse_memory_section, parse_name_section, parse_start_section, parse_table_section,
8-
parse_type_section,
5+
parse_alias_section, parse_data_section, parse_element_section, parse_event_section,
6+
parse_export_section, parse_function_section, parse_global_section, parse_import_section,
7+
parse_instance_section, parse_memory_section, parse_module_section, parse_name_section,
8+
parse_start_section, parse_table_section, parse_type_section,
99
};
1010
use crate::state::ModuleTranslationState;
1111
use cranelift_codegen::timing;
@@ -113,15 +113,15 @@ pub fn translate_module<'data>(
113113

114114
Payload::ModuleSection(s) => {
115115
validator.module_section(&s)?;
116-
environ.reserve_modules(s.get_count());
116+
parse_module_section(s, environ)?;
117117
}
118118
Payload::InstanceSection(s) => {
119119
validator.instance_section(&s)?;
120120
parse_instance_section(s, environ)?;
121121
}
122122
Payload::AliasSection(s) => {
123123
validator.alias_section(&s)?;
124-
unimplemented!("module linking not implemented yet")
124+
parse_alias_section(s, environ)?;
125125
}
126126
Payload::ModuleCodeSectionStart {
127127
count,

cranelift/wasm/src/sections_translator.rs

Lines changed: 86 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! The special case of the initialize expressions for table elements offsets or global variables
88
//! is handled, according to the semantics of WebAssembly, to only specific expressions that are
99
//! interpreted on the fly.
10-
use crate::environ::{ModuleEnvironment, WasmError, WasmResult};
10+
use crate::environ::{Alias, ModuleEnvironment, WasmError, WasmResult};
1111
use crate::state::ModuleTranslationState;
1212
use crate::translation_utils::{
1313
tabletype_to_type, type_to_type, DataIndex, ElemIndex, EntityIndex, EntityType, Event,
@@ -36,9 +36,15 @@ fn entity_type(
3636
environ: &mut dyn ModuleEnvironment<'_>,
3737
) -> WasmResult<EntityType> {
3838
Ok(match ty {
39-
ImportSectionEntryType::Function(sig) => EntityType::Function(TypeIndex::from_u32(sig)),
40-
ImportSectionEntryType::Module(sig) => EntityType::Module(TypeIndex::from_u32(sig)),
41-
ImportSectionEntryType::Instance(sig) => EntityType::Instance(TypeIndex::from_u32(sig)),
39+
ImportSectionEntryType::Function(sig) => {
40+
EntityType::Function(environ.type_to_signature(TypeIndex::from_u32(sig))?)
41+
}
42+
ImportSectionEntryType::Module(sig) => {
43+
EntityType::Module(environ.type_to_module_type(TypeIndex::from_u32(sig))?)
44+
}
45+
ImportSectionEntryType::Instance(sig) => {
46+
EntityType::Instance(environ.type_to_instance_type(TypeIndex::from_u32(sig))?)
47+
}
4248
ImportSectionEntryType::Memory(ty) => EntityType::Memory(memory(ty)),
4349
ImportSectionEntryType::Event(evt) => EntityType::Event(event(evt)),
4450
ImportSectionEntryType::Global(ty) => {
@@ -156,24 +162,40 @@ pub fn parse_import_section<'data>(
156162

157163
for entry in imports {
158164
let import = entry?;
159-
match entity_type(import.ty, environ)? {
160-
EntityType::Function(idx) => {
161-
environ.declare_func_import(idx, import.module, import.field)?;
165+
match import.ty {
166+
ImportSectionEntryType::Function(sig) => {
167+
environ.declare_func_import(
168+
TypeIndex::from_u32(sig),
169+
import.module,
170+
import.field,
171+
)?;
162172
}
163-
EntityType::Module(idx) => {
164-
environ.declare_module_import(idx, import.module, import.field)?;
173+
ImportSectionEntryType::Module(sig) => {
174+
environ.declare_module_import(
175+
TypeIndex::from_u32(sig),
176+
import.module,
177+
import.field,
178+
)?;
179+
}
180+
ImportSectionEntryType::Instance(sig) => {
181+
environ.declare_instance_import(
182+
TypeIndex::from_u32(sig),
183+
import.module,
184+
import.field,
185+
)?;
165186
}
166-
EntityType::Instance(idx) => {
167-
environ.declare_instance_import(idx, import.module, import.field)?;
187+
ImportSectionEntryType::Memory(ty) => {
188+
environ.declare_memory_import(memory(ty), import.module, import.field)?;
168189
}
169-
EntityType::Memory(ty) => {
170-
environ.declare_memory_import(ty, import.module, import.field)?;
190+
ImportSectionEntryType::Event(e) => {
191+
environ.declare_event_import(event(e), import.module, import.field)?;
171192
}
172-
EntityType::Event(e) => environ.declare_event_import(e, import.module, import.field)?,
173-
EntityType::Global(ty) => {
193+
ImportSectionEntryType::Global(ty) => {
194+
let ty = global(ty, environ, GlobalInit::Import)?;
174195
environ.declare_global_import(ty, import.module, import.field)?;
175196
}
176-
EntityType::Table(ty) => {
197+
ImportSectionEntryType::Table(ty) => {
198+
let ty = table(ty, environ)?;
177199
environ.declare_table_import(ty, import.module, import.field)?;
178200
}
179201
}
@@ -316,9 +338,15 @@ pub fn parse_export_section<'data>(
316338
ExternalKind::Global => {
317339
environ.declare_global_export(GlobalIndex::new(index), field)?
318340
}
319-
ExternalKind::Type | ExternalKind::Module | ExternalKind::Instance => {
320-
unimplemented!("module linking not implemented yet")
341+
ExternalKind::Module => {
342+
environ.declare_module_export(ModuleIndex::new(index), field)?
321343
}
344+
ExternalKind::Instance => {
345+
environ.declare_instance_export(InstanceIndex::new(index), field)?
346+
}
347+
348+
// this never gets past validation
349+
ExternalKind::Type => unreachable!(),
322350
}
323351
}
324352

@@ -476,12 +504,25 @@ pub fn parse_name_section<'data>(
476504
Ok(())
477505
}
478506

507+
/// Parses the Module section of the wasm module.
508+
pub fn parse_module_section<'data>(
509+
section: wasmparser::ModuleSectionReader<'data>,
510+
environ: &mut dyn ModuleEnvironment<'data>,
511+
) -> WasmResult<()> {
512+
environ.reserve_modules(section.get_count());
513+
514+
for module_ty in section {
515+
environ.declare_module(TypeIndex::from_u32(module_ty?))?;
516+
}
517+
Ok(())
518+
}
519+
479520
/// Parses the Instance section of the wasm module.
480521
pub fn parse_instance_section<'data>(
481522
section: wasmparser::InstanceSectionReader<'data>,
482523
environ: &mut dyn ModuleEnvironment<'data>,
483524
) -> WasmResult<()> {
484-
environ.reserve_types(section.get_count())?;
525+
environ.reserve_instances(section.get_count());
485526

486527
for instance in section {
487528
let instance = instance?;
@@ -509,3 +550,29 @@ pub fn parse_instance_section<'data>(
509550
}
510551
Ok(())
511552
}
553+
554+
/// Parses the Alias section of the wasm module.
555+
pub fn parse_alias_section<'data>(
556+
section: wasmparser::AliasSectionReader<'data>,
557+
environ: &mut dyn ModuleEnvironment<'data>,
558+
) -> WasmResult<()> {
559+
for alias in section {
560+
let alias = alias?;
561+
let alias = match alias.instance {
562+
wasmparser::AliasedInstance::Parent => {
563+
match alias.kind {
564+
ExternalKind::Module => Alias::ParentModule(ModuleIndex::from_u32(alias.index)),
565+
ExternalKind::Type => Alias::ParentType(TypeIndex::from_u32(alias.index)),
566+
// shouldn't get past validation
567+
_ => unreachable!(),
568+
}
569+
}
570+
wasmparser::AliasedInstance::Child(i) => Alias::Child {
571+
instance: InstanceIndex::from_u32(i),
572+
export: alias.index as usize,
573+
},
574+
};
575+
environ.declare_alias(alias)?;
576+
}
577+
Ok(())
578+
}

cranelift/wasm/src/translation_utils.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,18 @@ entity_impl!(InstanceIndex);
9797
pub struct EventIndex(u32);
9898
entity_impl!(EventIndex);
9999

100+
/// Specialized index for just module types.
101+
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
102+
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
103+
pub struct ModuleTypeIndex(u32);
104+
entity_impl!(ModuleTypeIndex);
105+
106+
/// Specialized index for just instance types.
107+
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
108+
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
109+
pub struct InstanceTypeIndex(u32);
110+
entity_impl!(InstanceTypeIndex);
111+
100112
/// An index of an entity.
101113
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
102114
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
@@ -131,13 +143,13 @@ pub enum EntityType {
131143
Table(Table),
132144
/// A function type where the index points to the type section and records a
133145
/// function signature.
134-
Function(TypeIndex),
146+
Function(SignatureIndex),
135147
/// An instance where the index points to the type section and records a
136148
/// instance's exports.
137-
Instance(TypeIndex),
149+
Instance(InstanceTypeIndex),
138150
/// A module where the index points to the type section and records a
139151
/// module's imports and exports.
140-
Module(TypeIndex),
152+
Module(ModuleTypeIndex),
141153
}
142154

143155
/// A WebAssembly global.

crates/cranelift/src/func_environ.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,6 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
10391039
callee: ir::Value,
10401040
call_args: &[ir::Value],
10411041
) -> WasmResult<ir::Inst> {
1042-
let sig_index = self.module.types[ty_index].unwrap_function();
10431042
let pointer_type = self.pointer_type();
10441043

10451044
let table_entry_addr = pos.ins().table_addr(pointer_type, table, callee, 0);
@@ -1071,7 +1070,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
10711070
let vmctx = self.vmctx(pos.func);
10721071
let base = pos.ins().global_value(pointer_type, vmctx);
10731072
let offset =
1074-
i32::try_from(self.offsets.vmctx_vmshared_signature_id(sig_index)).unwrap();
1073+
i32::try_from(self.offsets.vmctx_vmshared_signature_id(ty_index)).unwrap();
10751074

10761075
// Load the caller ID.
10771076
let mut mem_flags = ir::MemFlags::trusted();

0 commit comments

Comments
 (0)