Skip to content

Commit 81f348f

Browse files
committed
implement fixed size lists host side
1 parent 1cd3904 commit 81f348f

8 files changed

Lines changed: 291 additions & 16 deletions

File tree

crates/environ/src/component/types.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,23 @@ impl CanonicalAbiInfo {
722722
return ret;
723723
}
724724

725+
/// Returns the abi for a fixed size list
726+
pub const fn fixed_size_list_static(
727+
element: &CanonicalAbiInfo,
728+
count: u32,
729+
) -> CanonicalAbiInfo {
730+
CanonicalAbiInfo {
731+
size32: element.size32 * count,
732+
align32: element.align32,
733+
size64: element.size64 * count,
734+
align64: element.align64,
735+
flat_count: match element.flat_count {
736+
None => None,
737+
Some(c) => Some(c.saturating_mul(if count > 255 { 255u8 } else { count as u8 })),
738+
},
739+
}
740+
}
741+
725742
/// Returns the delta from the current value of `offset` to align properly
726743
/// and read the next record field of type `abi` for 32-bit memories.
727744
pub fn next_field32(&self, offset: &mut u32) -> u32 {

crates/wasmtime/src/runtime/component/func/typed.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2866,6 +2866,142 @@ macro_rules! impl_component_ty_for_tuples {
28662866

28672867
for_each_function_signature!(impl_component_ty_for_tuples);
28682868

2869+
unsafe impl<T, const N: usize> ComponentType for [T; N]
2870+
where
2871+
T: ComponentType,
2872+
{
2873+
type Lower = [T::Lower; N];
2874+
2875+
const ABI: CanonicalAbiInfo = CanonicalAbiInfo::fixed_size_list_static(&T::ABI, N as u32);
2876+
2877+
fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2878+
match ty {
2879+
InterfaceType::FixedSizeList(t) => T::typecheck(&types.types[*t].element, types),
2880+
other => bail!("expected `list<_, N>` found `{}`", desc(other)),
2881+
}
2882+
}
2883+
}
2884+
2885+
unsafe impl<T, const N: usize> Lower for [T; N]
2886+
where
2887+
T: Lower,
2888+
{
2889+
fn linear_lower_to_flat<U>(
2890+
&self,
2891+
cx: &mut LowerContext<'_, U>,
2892+
ty: InterfaceType,
2893+
dst: &mut MaybeUninit<Self::Lower>,
2894+
) -> Result<()> {
2895+
let element = match ty {
2896+
InterfaceType::FixedSizeList(ty) => cx.types[ty].element,
2897+
_ => bad_type_info(),
2898+
};
2899+
for (i, val) in self.iter().enumerate() {
2900+
val.linear_lower_to_flat(cx, element, map_maybe_uninit!(dst[i]))?;
2901+
}
2902+
Ok(())
2903+
}
2904+
2905+
fn linear_lower_to_memory<U>(
2906+
&self,
2907+
cx: &mut LowerContext<'_, U>,
2908+
ty: InterfaceType,
2909+
offset: usize,
2910+
) -> Result<()> {
2911+
debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2912+
let element = match ty {
2913+
InterfaceType::FixedSizeList(ty) => cx.types[ty].element,
2914+
_ => bad_type_info(),
2915+
};
2916+
for (i, val) in self.iter().enumerate() {
2917+
val.linear_lower_to_memory(cx, element, offset + i * T::SIZE32)?;
2918+
}
2919+
Ok(())
2920+
}
2921+
}
2922+
2923+
unsafe impl<T, const N: usize> Lift for [T; N]
2924+
where
2925+
T: Lift + Sized,
2926+
{
2927+
fn linear_lift_from_flat(
2928+
cx: &mut LiftContext<'_>,
2929+
ty: InterfaceType,
2930+
src: &Self::Lower,
2931+
) -> Result<Self> {
2932+
let element = match ty {
2933+
InterfaceType::FixedSizeList(ty) => cx.types[ty].element,
2934+
_ => bad_type_info(),
2935+
};
2936+
// this is reimplementation of array::try_from_fn
2937+
let mut valid = 0;
2938+
let mut result: [MaybeUninit<T>; N] = [const { MaybeUninit::uninit() }; N];
2939+
let mut error: Option<crate::error::Error> = None;
2940+
for n in 0..N {
2941+
match T::linear_lift_from_flat(cx, element, &src[n]) {
2942+
Ok(v) => {
2943+
result[valid].write(v);
2944+
valid += 1;
2945+
}
2946+
Err(e) => {
2947+
error = Some(e);
2948+
// continue to consume all input
2949+
}
2950+
}
2951+
}
2952+
if let Some(e) = error {
2953+
for n in 0..valid {
2954+
unsafe {
2955+
result[n].assume_init_drop();
2956+
}
2957+
}
2958+
return Err(e);
2959+
}
2960+
assert!(valid == N);
2961+
Ok(unsafe { core::mem::transmute::<_, Self>(result) })
2962+
}
2963+
2964+
fn linear_lift_from_memory(
2965+
cx: &mut LiftContext<'_>,
2966+
ty: InterfaceType,
2967+
bytes: &[u8],
2968+
) -> Result<Self> {
2969+
debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2970+
let element = match ty {
2971+
InterfaceType::FixedSizeList(ty) => cx.types[ty].element,
2972+
_ => bad_type_info(),
2973+
};
2974+
// this is reimplementation of array::try_from_fn
2975+
let mut valid = 0;
2976+
let mut result: [MaybeUninit<T>; N] = [const { MaybeUninit::uninit() }; N];
2977+
let mut error: Option<crate::error::Error> = None;
2978+
let mut offset = 0;
2979+
for _ in 0..N {
2980+
match T::linear_lift_from_memory(cx, element, &bytes[offset..offset + T::SIZE32]) {
2981+
Ok(v) => {
2982+
result[valid].write(v);
2983+
valid += 1;
2984+
}
2985+
Err(e) => {
2986+
error = Some(e);
2987+
// continue to consume all input
2988+
}
2989+
}
2990+
offset += T::SIZE32;
2991+
}
2992+
if let Some(e) = error {
2993+
for n in 0..valid {
2994+
unsafe {
2995+
result[n].assume_init_drop();
2996+
}
2997+
}
2998+
return Err(e);
2999+
}
3000+
assert!(valid == N);
3001+
Ok(unsafe { core::mem::transmute::<_, Self>(result) })
3002+
}
3003+
}
3004+
28693005
pub fn desc(ty: &InterfaceType) -> &'static str {
28703006
match ty {
28713007
InterfaceType::U8 => "u8",

crates/wasmtime/src/runtime/component/types.rs

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ use core::ops::Deref;
1010
use wasmtime_environ::PrimaryMap;
1111
use wasmtime_environ::component::{
1212
ComponentTypes, Export, InterfaceType, ResourceIndex, TypeComponentIndex,
13-
TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFlagsIndex, TypeFuncIndex,
14-
TypeFutureIndex, TypeFutureTableIndex, TypeListIndex, TypeModuleIndex, TypeOptionIndex,
15-
TypeRecordIndex, TypeResourceTable, TypeResourceTableIndex, TypeResultIndex, TypeStreamIndex,
16-
TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex,
13+
TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFixedSizeListIndex, TypeFlagsIndex,
14+
TypeFuncIndex, TypeFutureIndex, TypeFutureTableIndex, TypeListIndex, TypeModuleIndex,
15+
TypeOptionIndex, TypeRecordIndex, TypeResourceTable, TypeResourceTableIndex, TypeResultIndex,
16+
TypeStreamIndex, TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex,
1717
};
1818

1919
pub use crate::component::resources::ResourceType;
@@ -158,7 +158,10 @@ impl TypeChecker<'_> {
158158
(InterfaceType::Stream(_), _) => false,
159159
(InterfaceType::ErrorContext(_), InterfaceType::ErrorContext(_)) => true,
160160
(InterfaceType::ErrorContext(_), _) => false,
161-
(InterfaceType::FixedSizeList(_), _) => todo!(), // FIXME(#12279)
161+
(InterfaceType::FixedSizeList(t1), InterfaceType::FixedSizeList(t2)) => {
162+
self.fixed_size_lists_equal(t1, t2)
163+
}
164+
(InterfaceType::FixedSizeList(_), _) => false,
162165
}
163166
}
164167

@@ -168,6 +171,19 @@ impl TypeChecker<'_> {
168171
self.interface_types_equal(a.element, b.element)
169172
}
170173

174+
fn fixed_size_lists_equal(
175+
&self,
176+
l1: wasmtime_environ::component::TypeFixedSizeListIndex,
177+
l2: wasmtime_environ::component::TypeFixedSizeListIndex,
178+
) -> bool {
179+
let a = &self.a_types[l1];
180+
let b = &self.b_types[l2];
181+
if a.size != b.size {
182+
return false;
183+
}
184+
self.interface_types_equal(a.element, b.element)
185+
}
186+
171187
fn resources_equal(&self, o1: TypeResourceTableIndex, o2: TypeResourceTableIndex) -> bool {
172188
match (&self.a_types[o1], &self.b_types[o2]) {
173189
// Concrete resource types are the same if they map back to the
@@ -325,6 +341,35 @@ impl List {
325341
}
326342
}
327343

344+
/// A `list` interface type
345+
#[derive(Clone, Debug)]
346+
pub struct FixedSizeList(Handle<TypeFixedSizeListIndex>);
347+
348+
impl PartialEq for FixedSizeList {
349+
fn eq(&self, other: &Self) -> bool {
350+
self.0
351+
.equivalent(&other.0, TypeChecker::fixed_size_lists_equal)
352+
}
353+
}
354+
355+
impl Eq for FixedSizeList {}
356+
357+
impl FixedSizeList {
358+
pub(crate) fn from(index: TypeFixedSizeListIndex, ty: &InstanceType<'_>) -> Self {
359+
FixedSizeList(Handle::new(index, ty))
360+
}
361+
362+
/// Retrieve the element type of this `list`.
363+
pub fn ty(&self) -> Type {
364+
Type::from(&self.0.types[self.0.index].element, &self.0.instance())
365+
}
366+
367+
/// Retrieve the size of this `list`.
368+
pub fn size(&self) -> u32 {
369+
self.0.types[self.0.index].size
370+
}
371+
}
372+
328373
/// A field declaration belonging to a `record`
329374
#[derive(Debug)]
330375
pub struct Field<'a> {
@@ -696,6 +741,7 @@ pub enum Type {
696741
Future(FutureType),
697742
Stream(StreamType),
698743
ErrorContext,
744+
FixedSizeList(FixedSizeList),
699745
}
700746

701747
impl Type {
@@ -856,7 +902,9 @@ impl Type {
856902
InterfaceType::Future(index) => Type::Future(instance.future_type(*index)),
857903
InterfaceType::Stream(index) => Type::Stream(instance.stream_type(*index)),
858904
InterfaceType::ErrorContext(_) => Type::ErrorContext,
859-
InterfaceType::FixedSizeList(_) => todo!(), // FIXME(#12279)
905+
InterfaceType::FixedSizeList(index) => {
906+
Type::FixedSizeList(FixedSizeList::from(*index, instance))
907+
}
860908
}
861909
}
862910

@@ -888,6 +936,7 @@ impl Type {
888936
Type::Future(_) => "future",
889937
Type::Stream(_) => "stream",
890938
Type::ErrorContext => "error-context",
939+
Type::FixedSizeList(_) => "list<_, N>",
891940
}
892941
}
893942
}

crates/wasmtime/src/runtime/component/values.rs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ pub enum Val {
9090
Future(FutureAny),
9191
Stream(StreamAny),
9292
ErrorContext(ErrorContextAny),
93+
FixedSizeList(Vec<Val>),
9394
}
9495

9596
impl Val {
@@ -215,7 +216,11 @@ impl Val {
215216
InterfaceType::ErrorContext(_) => {
216217
ErrorContext::linear_lift_from_flat(cx, ty, next(src))?.into_val()
217218
}
218-
InterfaceType::FixedSizeList(_) => todo!(), // FIXME(#12279)
219+
InterfaceType::FixedSizeList(i) => Val::FixedSizeList(
220+
(0..cx.types[i].size)
221+
.map(|_| Self::lift(cx, cx.types[i].element, src))
222+
.collect::<Result<_>>()?,
223+
),
219224
})
220225
}
221226

@@ -342,7 +347,20 @@ impl Val {
342347
InterfaceType::ErrorContext(_) => {
343348
ErrorContext::linear_lift_from_memory(cx, ty, bytes)?.into_val()
344349
}
345-
InterfaceType::FixedSizeList(_) => todo!(), // FIXME(#12279)
350+
InterfaceType::FixedSizeList(i) => {
351+
let element = cx.types[i].element.clone();
352+
let abi = cx.types.canonical_abi(&element);
353+
Val::Tuple(
354+
(0..cx.types[i].size)
355+
.map(|n| {
356+
let offset = abi.size32 * n;
357+
let offset = usize::try_from(offset).unwrap();
358+
let size = usize::try_from(abi.size32).unwrap();
359+
Val::load(cx, element, &bytes[offset..][..size])
360+
})
361+
.collect::<Result<_>>()?,
362+
)
363+
}
346364
})
347365
}
348366

@@ -493,7 +511,17 @@ impl Val {
493511
)
494512
}
495513
(InterfaceType::ErrorContext(_), _) => unexpected(ty, self),
496-
(InterfaceType::FixedSizeList(_), _) => todo!(), // FIXME(#12279)
514+
(InterfaceType::FixedSizeList(ty), Val::FixedSizeList(values)) => {
515+
let ty = &cx.types[ty];
516+
if ty.size as usize != values.len() {
517+
bail!("expected vec of size {}, got {}", ty.size, values.len());
518+
}
519+
for value in values {
520+
value.lower(cx, ty.element, dst)?;
521+
}
522+
Ok(())
523+
}
524+
(InterfaceType::FixedSizeList(_), _) => unexpected(ty, self),
497525
}
498526
}
499527

@@ -647,7 +675,18 @@ impl Val {
647675
)
648676
}
649677
(InterfaceType::ErrorContext(_), _) => unexpected(ty, self),
650-
(InterfaceType::FixedSizeList(_), _) => todo!(), // FIXME(#12279)
678+
(InterfaceType::FixedSizeList(ty), Val::FixedSizeList(values)) => {
679+
let ty = &cx.types[ty];
680+
if ty.size as usize != values.len() {
681+
bail!("expected {} types, got {}", ty.size, values.len());
682+
}
683+
let elemsize = cx.types.canonical_abi(&ty.element).size32 as usize;
684+
for (n, value) in values.iter().enumerate() {
685+
value.store(cx, ty.element, elemsize * n)?;
686+
}
687+
Ok(())
688+
}
689+
(InterfaceType::FixedSizeList(_), _) => unexpected(ty, self),
651690
}
652691
}
653692

@@ -678,6 +717,7 @@ impl Val {
678717
Val::Future(_) => "future",
679718
Val::Stream(_) => "stream",
680719
Val::ErrorContext(_) => "error-context",
720+
Val::FixedSizeList(_) => "list<_, N>",
681721
}
682722
}
683723

@@ -762,6 +802,8 @@ impl PartialEq for Val {
762802
(Self::Stream(_), _) => false,
763803
(Self::ErrorContext(l), Self::ErrorContext(r)) => l == r,
764804
(Self::ErrorContext(_), _) => false,
805+
(Self::FixedSizeList(l), Self::FixedSizeList(r)) => l == r,
806+
(Self::FixedSizeList(_), _) => false,
765807
}
766808
}
767809
}

crates/wasmtime/src/runtime/wave/component.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ impl WasmType for component::Type {
4040
Self::Option(_) => WasmTypeKind::Option,
4141
Self::Result(_) => WasmTypeKind::Result,
4242
Self::Flags(_) => WasmTypeKind::Flags,
43+
Self::FixedSizeList(_) => WasmTypeKind::FixedSizeList,
4344

4445
Self::Own(_)
4546
| Self::Borrow(_)
@@ -138,6 +139,7 @@ impl WasmValue for component::Val {
138139
Self::Option(_) => WasmTypeKind::Option,
139140
Self::Result(_) => WasmTypeKind::Result,
140141
Self::Flags(_) => WasmTypeKind::Flags,
142+
Self::FixedSizeList(_) => WasmTypeKind::FixedSizeList,
141143
Self::Resource(_) | Self::Stream(_) | Self::Future(_) | Self::ErrorContext(_) => {
142144
WasmTypeKind::Unsupported
143145
}

0 commit comments

Comments
 (0)