Skip to content

Commit 51959f2

Browse files
authored
Prepare FACT for supporting more memory types (bytecodealliance#12972)
This commit refactors the internals of FACT, wasmtime's component-to-component trampoline compiler, to better handle memories of different types. When FACT was originally written it had support for memory64, despite components not having support for memory64, but since then more types of memories have showed up in core wasm. For example FACT didn't handle shared memories or custom-page-sizes memories well. This commit manually updates some `memory64: bool` fields/etc to `ty: Memory` to have a full-fledged memory type on-hand during translation. This affects how the memory is imported, for example, as well as bounds checks. Note that components do not currently support 64-bit memories, nor shared memories, nor custom-page-size memories. This refactoring is for future support of these features internally within FACT itself, but more support will be necessary to fully support these features throughout the runtime.
1 parent 1ff5fca commit 51959f2

5 files changed

Lines changed: 116 additions & 137 deletions

File tree

crates/environ/src/component/translate/adapt.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,9 @@
115115
//! time this may want to be revisited if too many adapter modules are being
116116
//! created.
117117
118-
use crate::EntityType;
119118
use crate::component::translate::*;
120119
use crate::fact;
120+
use crate::{EntityType, Memory};
121121
use std::collections::HashSet;
122122

123123
/// Metadata information about a fused adapter.
@@ -150,10 +150,8 @@ pub enum DataModel {
150150

151151
/// Data is stored in a linear memory.
152152
LinearMemory {
153-
/// An optional memory definition supplied.
154-
memory: Option<dfg::CoreExport<MemoryIndex>>,
155-
/// If `memory` is specified, whether it's a 64-bit memory.
156-
memory64: bool,
153+
/// An optional memory definition supplied, and its type.
154+
memory: Option<(dfg::CoreExport<MemoryIndex>, Memory)>,
157155
/// An optional definition of `realloc` to used.
158156
realloc: Option<dfg::CoreDef>,
159157
},
@@ -416,12 +414,8 @@ impl PartitionAdapterModules {
416414
DataModel::Gc {} => {
417415
// Nothing to do here yet.
418416
}
419-
DataModel::LinearMemory {
420-
memory,
421-
memory64: _,
422-
realloc,
423-
} => {
424-
if let Some(memory) = memory {
417+
DataModel::LinearMemory { memory, realloc } => {
418+
if let Some((memory, _ty)) = memory {
425419
self.core_export(dfg, memory);
426420
}
427421
if let Some(def) = realloc {

crates/environ/src/component/translate/inline.rs

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
//! final `Component`.
4747
4848
use crate::component::translate::*;
49-
use crate::{EntityType, IndexType};
49+
use crate::{EntityType, Memory};
5050
use core::str::FromStr;
5151
use std::borrow::Cow;
5252
use wasmparser::component_types::{ComponentAnyTypeId, ComponentCoreModuleTypeId};
@@ -1520,34 +1520,25 @@ impl<'a> Inliner<'a> {
15201520
frame: &InlinerFrame<'a>,
15211521
types: &ComponentTypesBuilder,
15221522
memory: MemoryIndex,
1523-
) -> (dfg::CoreExport<MemoryIndex>, bool) {
1523+
) -> (dfg::CoreExport<MemoryIndex>, Memory) {
15241524
let memory = frame.memories[memory].clone().map_index(|i| match i {
15251525
EntityIndex::Memory(i) => i,
15261526
_ => unreachable!(),
15271527
});
1528-
let memory64 = match &self.runtime_instances[memory.instance] {
1528+
let ty = match &self.runtime_instances[memory.instance] {
15291529
InstanceModule::Static(idx) => match &memory.item {
1530-
ExportItem::Index(i) => {
1531-
let ty = &self.nested_modules[*idx].module.memories[*i];
1532-
match ty.idx_type {
1533-
IndexType::I32 => false,
1534-
IndexType::I64 => true,
1535-
}
1536-
}
1530+
ExportItem::Index(i) => self.nested_modules[*idx].module.memories[*i],
15371531
ExportItem::Name(_) => unreachable!(),
15381532
},
15391533
InstanceModule::Import(ty) => match &memory.item {
15401534
ExportItem::Name(name) => match types[*ty].exports[name] {
1541-
EntityType::Memory(m) => match m.idx_type {
1542-
IndexType::I32 => false,
1543-
IndexType::I64 => true,
1544-
},
1535+
EntityType::Memory(m) => m,
15451536
_ => unreachable!(),
15461537
},
15471538
ExportItem::Index(_) => unreachable!(),
15481539
},
15491540
};
1550-
(memory, memory64)
1541+
(memory, ty)
15511542
}
15521543

15531544
/// Translates a `LocalCanonicalOptions` which indexes into the `frame`
@@ -1562,18 +1553,9 @@ impl<'a> Inliner<'a> {
15621553
let data_model = match options.data_model {
15631554
LocalDataModel::Gc {} => DataModel::Gc {},
15641555
LocalDataModel::LinearMemory { memory, realloc } => {
1565-
let (memory, memory64) = memory
1566-
.map(|i| {
1567-
let (memory, memory64) = self.memory(frame, types, i);
1568-
(Some(memory), memory64)
1569-
})
1570-
.unwrap_or((None, false));
1556+
let memory = memory.map(|i| self.memory(frame, types, i));
15711557
let realloc = realloc.map(|i| frame.funcs[i].1.clone());
1572-
DataModel::LinearMemory {
1573-
memory,
1574-
memory64,
1575-
realloc,
1576-
}
1558+
DataModel::LinearMemory { memory, realloc }
15771559
}
15781560
};
15791561
let callback = options.callback.map(|i| frame.funcs[i].1.clone());
@@ -1603,14 +1585,12 @@ impl<'a> Inliner<'a> {
16031585
fn canonical_options(&mut self, options: AdapterOptions) -> dfg::OptionsId {
16041586
let data_model = match options.data_model {
16051587
DataModel::Gc {} => dfg::CanonicalOptionsDataModel::Gc {},
1606-
DataModel::LinearMemory {
1607-
memory,
1608-
memory64: _,
1609-
realloc,
1610-
} => dfg::CanonicalOptionsDataModel::LinearMemory {
1611-
memory: memory.map(|export| self.result.memories.push(export)),
1612-
realloc: realloc.map(|def| self.result.reallocs.push(def)),
1613-
},
1588+
DataModel::LinearMemory { memory, realloc } => {
1589+
dfg::CanonicalOptionsDataModel::LinearMemory {
1590+
memory: memory.map(|(export, _)| self.result.memories.push(export)),
1591+
realloc: realloc.map(|def| self.result.reallocs.push(def)),
1592+
}
1593+
}
16141594
};
16151595
let callback = options.callback.map(|def| self.result.callbacks.push(def));
16161596
let post_return = options

crates/environ/src/fact.rs

Lines changed: 51 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@
2020
2121
use crate::component::dfg::CoreDef;
2222
use crate::component::{
23-
Adapter, AdapterOptions as AdapterOptionsDfg, ComponentTypesBuilder, FlatType, InterfaceType,
24-
RuntimeComponentInstanceIndex, StringEncoding, Transcode, TypeFuncIndex,
23+
Adapter, AdapterOptions as AdapterOptionsDfg, CanonicalAbiInfo, ComponentTypesBuilder,
24+
FlatType, InterfaceType, RuntimeComponentInstanceIndex, StringEncoding, Transcode,
25+
TypeFuncIndex,
2526
};
2627
use crate::fact::transcode::Transcoder;
27-
use crate::{EntityRef, FuncIndex, GlobalIndex, MemoryIndex, PrimaryMap, Tunables};
28-
use crate::{ModuleInternedTypeIndex, prelude::*};
28+
use crate::prelude::*;
29+
use crate::{
30+
EntityRef, FuncIndex, GlobalIndex, IndexType, Memory, MemoryIndex, ModuleInternedTypeIndex,
31+
PrimaryMap, Tunables,
32+
};
2933
use std::collections::HashMap;
3034
use wasm_encoder::*;
3135

@@ -142,27 +146,40 @@ struct AdapterOptions {
142146
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
143147
/// Linear memory.
144148
struct LinearMemoryOptions {
145-
/// Whether or not the `memory` field, if present, is a 64-bit memory.
146-
memory64: bool,
147149
/// An optionally-specified memory where values may travel through for
148150
/// types like lists.
149-
memory: Option<MemoryIndex>,
151+
memory: Option<(MemoryIndex, Memory)>,
150152
/// An optionally-specified function to be used to allocate space for
151153
/// types such as strings as they go into a module.
152154
realloc: Option<FuncIndex>,
153155
}
154156

155157
impl LinearMemoryOptions {
156158
fn ptr(&self) -> ValType {
157-
if self.memory64 {
159+
if self.memory64() {
158160
ValType::I64
159161
} else {
160162
ValType::I32
161163
}
162164
}
163165

164166
fn ptr_size(&self) -> u8 {
165-
if self.memory64 { 8 } else { 4 }
167+
if self.memory64() { 8 } else { 4 }
168+
}
169+
170+
fn memory64(&self) -> bool {
171+
self.memory
172+
.as_ref()
173+
.map(|(_, ty)| ty.idx_type == IndexType::I64)
174+
.unwrap_or(false)
175+
}
176+
177+
fn sizealign(&self, abi: &CanonicalAbiInfo) -> (u32, u32) {
178+
if self.memory64() {
179+
(abi.size64, abi.align64)
180+
} else {
181+
(abi.size32, abi.align32)
182+
}
166183
}
167184
}
168185

@@ -345,30 +362,32 @@ impl<'a> Module<'a> {
345362

346363
let data_model = match data_model {
347364
crate::component::DataModel::Gc {} => DataModel::Gc {},
348-
crate::component::DataModel::LinearMemory {
349-
memory,
350-
memory64,
351-
realloc,
352-
} => {
353-
let memory = memory.as_ref().map(|memory| {
354-
self.import_memory(
355-
"memory",
356-
&format!("m{}", self.imported_memories.len()),
357-
MemoryType {
358-
minimum: 0,
359-
maximum: None,
360-
shared: false,
361-
memory64: *memory64,
362-
page_size_log2: None,
363-
},
364-
memory.clone().into(),
365+
crate::component::DataModel::LinearMemory { memory, realloc } => {
366+
let memory = memory.as_ref().map(|(memory, ty)| {
367+
(
368+
self.import_memory(
369+
"memory",
370+
&format!("m{}", self.imported_memories.len()),
371+
MemoryType {
372+
minimum: 0,
373+
maximum: None,
374+
shared: ty.shared,
375+
memory64: ty.idx_type == IndexType::I64,
376+
page_size_log2: if ty.page_size_log2 == 16 {
377+
None
378+
} else {
379+
Some(ty.page_size_log2.into())
380+
},
381+
},
382+
memory.clone().into(),
383+
),
384+
*ty,
365385
)
366386
});
367387
let realloc = realloc.as_ref().map(|func| {
368-
let ptr = if *memory64 {
369-
ValType::I64
370-
} else {
371-
ValType::I32
388+
let ptr = match memory.as_ref().unwrap().1.idx_type {
389+
IndexType::I32 => ValType::I32,
390+
IndexType::I64 => ValType::I64,
372391
};
373392
let ty = self.core_types.function(&[ptr, ptr, ptr, ptr], &[ptr]);
374393
self.import_func(
@@ -378,11 +397,7 @@ impl<'a> Module<'a> {
378397
func.clone(),
379398
)
380399
});
381-
DataModel::LinearMemory(LinearMemoryOptions {
382-
memory64: *memory64,
383-
memory,
384-
realloc,
385-
})
400+
DataModel::LinearMemory(LinearMemoryOptions { memory, realloc })
386401
}
387402
};
388403

@@ -907,7 +922,7 @@ impl Options {
907922
let flat = types.flat_types(ty)?;
908923
match self.data_model {
909924
DataModel::Gc {} => todo!("CM+GC"),
910-
DataModel::LinearMemory(mem_opts) => Some(if mem_opts.memory64 {
925+
DataModel::LinearMemory(mem_opts) => Some(if mem_opts.memory64() {
911926
flat.memory64
912927
} else {
913928
flat.memory32

crates/environ/src/fact/signature.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ impl ComponentTypesBuilder {
215215
// seems like it would be best to intern this in some sort of map somewhere.
216216
pub(super) fn size_align(&self, opts: &LinearMemoryOptions, ty: &InterfaceType) -> (u32, u32) {
217217
let abi = self.canonical_abi(ty);
218-
if opts.memory64 {
218+
if opts.memory64() {
219219
(abi.size64, abi.align64)
220220
} else {
221221
(abi.size32, abi.align32)

0 commit comments

Comments
 (0)