Skip to content

Commit 1606da1

Browse files
committed
Added flat abi extraction for interface types
1 parent bc16bc7 commit 1606da1

File tree

2 files changed

+192
-17
lines changed

2 files changed

+192
-17
lines changed

crates/environ/src/component/types.rs

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::component::{MAX_FLAT_PARAMS, MAX_FLAT_RESULTS};
1+
use crate::component::{FlatTypesStorage, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS};
22
use crate::{EntityType, ModuleInternedTypeIndex, ModuleTypes, PrimaryMap};
33
use crate::{TypeTrace, prelude::*};
44
use core::hash::{Hash, Hasher};
@@ -364,6 +364,162 @@ impl ComponentTypes {
364364
}
365365
}
366366

367+
/// Returns the flat storage representation for an interface type.
368+
pub fn flat_types_storage(&self, ty: &InterfaceType) -> FlatTypesStorage {
369+
let mut storage_buf = FlatTypesStorage::new();
370+
371+
let push_discrim =
372+
|storage: &mut FlatTypesStorage| storage.push(FlatType::I32, FlatType::I32);
373+
374+
let push_storage = |storage: &mut FlatTypesStorage, other: FlatTypesStorage| -> bool {
375+
let len = usize::from(storage.len);
376+
let other_len = usize::from(other.len);
377+
if len < (MAX_FLAT_TYPES - other_len + 1) {
378+
storage.memory32[len..len + other_len]
379+
.copy_from_slice(&other.memory32[..other_len]);
380+
storage.memory64[len..len + other_len]
381+
.copy_from_slice(&other.memory64[..other_len]);
382+
storage.len += other.len;
383+
true
384+
} else {
385+
storage.len = MAX_FLAT_TYPES as u8 + 1;
386+
false
387+
}
388+
};
389+
390+
let push_storage_variant_case =
391+
|storage: &mut FlatTypesStorage, case: Option<FlatTypesStorage>| -> bool {
392+
if let Some(case) = case {
393+
if case.len as usize >= MAX_FLAT_TYPES {
394+
storage.len = u8::try_from(MAX_FLAT_TYPES + 1).unwrap();
395+
false
396+
} else {
397+
let dst = storage
398+
.memory32
399+
.iter_mut()
400+
.zip(&mut storage.memory64)
401+
.skip(1);
402+
for (i, ((t32, t64), (dst32, dst64))) in case
403+
.memory32
404+
.iter()
405+
.zip(case.memory64.iter())
406+
.zip(dst)
407+
.enumerate()
408+
{
409+
if i + 1 < usize::from(storage.len) {
410+
// Populated Index
411+
dst32.join(*t32);
412+
dst64.join(*t64);
413+
} else {
414+
// New Index
415+
storage.len += 1;
416+
*dst32 = *t32;
417+
*dst64 = *t64;
418+
}
419+
}
420+
true
421+
}
422+
} else {
423+
true
424+
}
425+
};
426+
427+
let storage = &mut storage_buf;
428+
429+
match ty {
430+
InterfaceType::U8
431+
| InterfaceType::S8
432+
| InterfaceType::Bool
433+
| InterfaceType::U16
434+
| InterfaceType::S16
435+
| InterfaceType::U32
436+
| InterfaceType::S32
437+
| InterfaceType::Char
438+
| InterfaceType::Own(_)
439+
| InterfaceType::Future(_)
440+
| InterfaceType::Stream(_)
441+
| InterfaceType::ErrorContext(_)
442+
| InterfaceType::Borrow(_)
443+
| InterfaceType::Enum(_) => {
444+
storage.push(FlatType::I32, FlatType::I32);
445+
}
446+
447+
InterfaceType::U64 | InterfaceType::S64 => {
448+
storage.push(FlatType::I64, FlatType::I64);
449+
}
450+
InterfaceType::Float32 => {
451+
storage.push(FlatType::F32, FlatType::F32);
452+
}
453+
InterfaceType::Float64 => {
454+
storage.push(FlatType::F64, FlatType::F64);
455+
}
456+
InterfaceType::String | InterfaceType::List(_) => {
457+
// Pointer pair
458+
storage.push(FlatType::I32, FlatType::I64);
459+
storage.push(FlatType::I32, FlatType::I64);
460+
}
461+
462+
InterfaceType::Record(i) => {
463+
for field in self[*i].fields.iter() {
464+
if !push_storage(storage, self.flat_types_storage(&field.ty)) {
465+
break;
466+
}
467+
}
468+
}
469+
InterfaceType::Tuple(i) => {
470+
for ty in self[*i].types.iter() {
471+
if !push_storage(storage, self.flat_types_storage(ty)) {
472+
break;
473+
}
474+
}
475+
}
476+
InterfaceType::Flags(i) => match FlagsSize::from_count(self[*i].names.len()) {
477+
FlagsSize::Size0 => {}
478+
FlagsSize::Size1 | FlagsSize::Size2 => {
479+
storage.push(FlatType::I32, FlatType::I32);
480+
}
481+
FlagsSize::Size4Plus(n) => {
482+
for _ in 0..n {
483+
if !storage.push(FlatType::I32, FlatType::I32) {
484+
break;
485+
}
486+
}
487+
}
488+
},
489+
InterfaceType::Variant(i) => {
490+
push_discrim(storage);
491+
for case in self[*i].cases.values() {
492+
let case_flat = case.as_ref().map(|ty| self.flat_types_storage(ty));
493+
if !push_storage_variant_case(storage, case_flat) {
494+
break;
495+
}
496+
}
497+
}
498+
InterfaceType::Option(i) => {
499+
push_discrim(storage);
500+
push_storage_variant_case(storage, None);
501+
push_storage_variant_case(storage, Some(self.flat_types_storage(&self[*i].ty)));
502+
}
503+
InterfaceType::Result(i) => {
504+
push_discrim(storage);
505+
let result = &self[*i];
506+
push_storage_variant_case(
507+
storage,
508+
result.ok.map(|ty| self.flat_types_storage(&ty)),
509+
);
510+
push_storage_variant_case(
511+
storage,
512+
result.err.map(|ty| self.flat_types_storage(&ty)),
513+
);
514+
}
515+
}
516+
assert_eq!(
517+
storage.len as usize,
518+
self.canonical_abi(ty).flat_count(usize::MAX).unwrap()
519+
);
520+
storage_buf
521+
}
522+
367523
/// Adds a new `table` to the list of resource tables for this component.
368524
pub fn push_resource_table(&mut self, table: TypeResourceTable) -> TypeResourceTableIndex {
369525
self.resource_tables.push(table)
@@ -1185,3 +1341,12 @@ pub enum FlatType {
11851341
F32,
11861342
F64,
11871343
}
1344+
1345+
impl FlatType {
1346+
const fn byte_size(&self) -> u8 {
1347+
match self {
1348+
FlatType::I32 | FlatType::F32 => 4,
1349+
FlatType::I64 | FlatType::F64 => 8,
1350+
}
1351+
}
1352+
}

crates/environ/src/component/types_builder.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -812,30 +812,39 @@ where
812812
return idx;
813813
}
814814

815-
struct FlatTypesStorage {
816-
// This could be represented as `Vec<FlatType>` but on 64-bit architectures
817-
// that's 24 bytes. Otherwise `FlatType` is 1 byte large and
818-
// `MAX_FLAT_TYPES` is 16, so it should ideally be more space-efficient to
819-
// use a flat array instead of a heap-based vector.
820-
memory32: [FlatType; MAX_FLAT_TYPES],
821-
memory64: [FlatType; MAX_FLAT_TYPES],
822-
823-
// Tracks the number of flat types pushed into this storage. If this is
824-
// `MAX_FLAT_TYPES + 1` then this storage represents an un-reprsentable
825-
// type in flat types.
826-
len: u8,
815+
/// Representation of flat types in 32-bit and 64-bit memory
816+
///
817+
/// This could be represented as `Vec<FlatType>` but on 64-bit architectures
818+
/// that's 24 bytes. Otherwise `FlatType` is 1 byte large and
819+
/// `MAX_FLAT_TYPES` is 16, so it should ideally be more space-efficient to
820+
/// use a flat array instead of a heap-based vector.
821+
#[derive(Debug)]
822+
pub struct FlatTypesStorage {
823+
/// Representation for 32-bit memory
824+
pub memory32: [FlatType; MAX_FLAT_TYPES],
825+
/// Representation for 64-bit memory
826+
pub memory64: [FlatType; MAX_FLAT_TYPES],
827+
828+
/// Tracks the number of flat types pushed into this storage. If this is
829+
/// `MAX_FLAT_TYPES + 1` then this storage represents an un-reprsentable
830+
/// type in flat types.
831+
///
832+
/// This value should be the same on both `memory32` and `memory64`
833+
pub len: u8,
827834
}
828835

829836
impl FlatTypesStorage {
830-
const fn new() -> FlatTypesStorage {
837+
/// Create a new, empty storage for flat types
838+
pub const fn new() -> FlatTypesStorage {
831839
FlatTypesStorage {
832840
memory32: [FlatType::I32; MAX_FLAT_TYPES],
833841
memory64: [FlatType::I32; MAX_FLAT_TYPES],
834842
len: 0,
835843
}
836844
}
837845

838-
fn as_flat_types(&self) -> Option<FlatTypes<'_>> {
846+
/// Returns a reference to flat type representation
847+
pub fn as_flat_types(&self) -> Option<FlatTypes<'_>> {
839848
let len = usize::from(self.len);
840849
if len > MAX_FLAT_TYPES {
841850
assert_eq!(len, MAX_FLAT_TYPES + 1);
@@ -854,7 +863,7 @@ impl FlatTypesStorage {
854863
/// Returns whether the type was actually pushed or whether this list of
855864
/// flat types just exceeded the maximum meaning that it is now
856865
/// unrepresentable with a flat list of types.
857-
fn push(&mut self, t32: FlatType, t64: FlatType) -> bool {
866+
pub fn push(&mut self, t32: FlatType, t64: FlatType) -> bool {
858867
let len = usize::from(self.len);
859868
if len < MAX_FLAT_TYPES {
860869
self.memory32[len] = t32;
@@ -873,7 +882,8 @@ impl FlatTypesStorage {
873882
}
874883

875884
impl FlatType {
876-
fn join(&mut self, other: FlatType) {
885+
/// Constructs the "joined" representation for two flat types
886+
pub fn join(&mut self, other: FlatType) {
877887
if *self == other {
878888
return;
879889
}

0 commit comments

Comments
 (0)