Skip to content

Commit a8cffb2

Browse files
committed
implement fixed size lists host side
1 parent 8aa579d commit a8cffb2

8 files changed

Lines changed: 288 additions & 13 deletions

File tree

crates/environ/src/component/types.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,23 @@ impl CanonicalAbiInfo {
751751
return ret;
752752
}
753753

754+
/// Returns the abi for a fixed size list
755+
pub const fn fixed_size_list_static(
756+
element: &CanonicalAbiInfo,
757+
count: u32,
758+
) -> CanonicalAbiInfo {
759+
CanonicalAbiInfo {
760+
size32: element.size32 * count,
761+
align32: element.align32,
762+
size64: element.size64 * count,
763+
align64: element.align64,
764+
flat_count: match element.flat_count {
765+
None => None,
766+
Some(c) => Some(c.saturating_mul(if count > 255 { 255u8 } else { count as u8 })),
767+
},
768+
}
769+
}
770+
754771
/// Returns the delta from the current value of `offset` to align properly
755772
/// and read the next record field of type `abi` for 32-bit memories.
756773
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
@@ -2970,6 +2970,142 @@ macro_rules! impl_component_ty_for_tuples {
29702970

29712971
for_each_function_signature!(impl_component_ty_for_tuples);
29722972

2973+
unsafe impl<T, const N: usize> ComponentType for [T; N]
2974+
where
2975+
T: ComponentType,
2976+
{
2977+
type Lower = [T::Lower; N];
2978+
2979+
const ABI: CanonicalAbiInfo = CanonicalAbiInfo::fixed_size_list_static(&T::ABI, N as u32);
2980+
2981+
fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2982+
match ty {
2983+
InterfaceType::FixedSizeList(t) => T::typecheck(&types.types[*t].element, types),
2984+
other => bail!("expected `list<_, N>` found `{}`", desc(other)),
2985+
}
2986+
}
2987+
}
2988+
2989+
unsafe impl<T, const N: usize> Lower for [T; N]
2990+
where
2991+
T: Lower,
2992+
{
2993+
fn linear_lower_to_flat<U>(
2994+
&self,
2995+
cx: &mut LowerContext<'_, U>,
2996+
ty: InterfaceType,
2997+
dst: &mut MaybeUninit<Self::Lower>,
2998+
) -> Result<()> {
2999+
let element = match ty {
3000+
InterfaceType::FixedSizeList(ty) => cx.types[ty].element,
3001+
_ => bad_type_info(),
3002+
};
3003+
for (i, val) in self.iter().enumerate() {
3004+
val.linear_lower_to_flat(cx, element, map_maybe_uninit!(dst[i]))?;
3005+
}
3006+
Ok(())
3007+
}
3008+
3009+
fn linear_lower_to_memory<U>(
3010+
&self,
3011+
cx: &mut LowerContext<'_, U>,
3012+
ty: InterfaceType,
3013+
offset: usize,
3014+
) -> Result<()> {
3015+
debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
3016+
let element = match ty {
3017+
InterfaceType::FixedSizeList(ty) => cx.types[ty].element,
3018+
_ => bad_type_info(),
3019+
};
3020+
for (i, val) in self.iter().enumerate() {
3021+
val.linear_lower_to_memory(cx, element, offset + i * T::SIZE32)?;
3022+
}
3023+
Ok(())
3024+
}
3025+
}
3026+
3027+
unsafe impl<T, const N: usize> Lift for [T; N]
3028+
where
3029+
T: Lift + Sized,
3030+
{
3031+
fn linear_lift_from_flat(
3032+
cx: &mut LiftContext<'_>,
3033+
ty: InterfaceType,
3034+
src: &Self::Lower,
3035+
) -> Result<Self> {
3036+
let element = match ty {
3037+
InterfaceType::FixedSizeList(ty) => cx.types[ty].element,
3038+
_ => bad_type_info(),
3039+
};
3040+
// this is reimplementation of array::try_from_fn
3041+
let mut valid = 0;
3042+
let mut result: [MaybeUninit<T>; N] = [const { MaybeUninit::uninit() }; N];
3043+
let mut error: Option<crate::error::Error> = None;
3044+
for n in 0..N {
3045+
match T::linear_lift_from_flat(cx, element, &src[n]) {
3046+
Ok(v) => {
3047+
result[valid].write(v);
3048+
valid += 1;
3049+
}
3050+
Err(e) => {
3051+
error = Some(e);
3052+
// continue to consume all input
3053+
}
3054+
}
3055+
}
3056+
if let Some(e) = error {
3057+
for n in 0..valid {
3058+
unsafe {
3059+
result[n].assume_init_drop();
3060+
}
3061+
}
3062+
return Err(e);
3063+
}
3064+
assert!(valid == N);
3065+
Ok(unsafe { core::mem::transmute::<_, Self>(result) })
3066+
}
3067+
3068+
fn linear_lift_from_memory(
3069+
cx: &mut LiftContext<'_>,
3070+
ty: InterfaceType,
3071+
bytes: &[u8],
3072+
) -> Result<Self> {
3073+
debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
3074+
let element = match ty {
3075+
InterfaceType::FixedSizeList(ty) => cx.types[ty].element,
3076+
_ => bad_type_info(),
3077+
};
3078+
// this is reimplementation of array::try_from_fn
3079+
let mut valid = 0;
3080+
let mut result: [MaybeUninit<T>; N] = [const { MaybeUninit::uninit() }; N];
3081+
let mut error: Option<crate::error::Error> = None;
3082+
let mut offset = 0;
3083+
for _ in 0..N {
3084+
match T::linear_lift_from_memory(cx, element, &bytes[offset..offset + T::SIZE32]) {
3085+
Ok(v) => {
3086+
result[valid].write(v);
3087+
valid += 1;
3088+
}
3089+
Err(e) => {
3090+
error = Some(e);
3091+
// continue to consume all input
3092+
}
3093+
}
3094+
offset += T::SIZE32;
3095+
}
3096+
if let Some(e) = error {
3097+
for n in 0..valid {
3098+
unsafe {
3099+
result[n].assume_init_drop();
3100+
}
3101+
}
3102+
return Err(e);
3103+
}
3104+
assert!(valid == N);
3105+
Ok(unsafe { core::mem::transmute::<_, Self>(result) })
3106+
}
3107+
}
3108+
29733109
pub fn desc(ty: &InterfaceType) -> &'static str {
29743110
match ty {
29753111
InterfaceType::U8 => "u8",

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

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use core::ops::Deref;
1010
use wasmtime_environ::PanicOnOom as _;
1111
use wasmtime_environ::component::{
1212
ComponentTypes, Export, InterfaceType, ResourceIndex, TypeComponentIndex,
13-
TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFlagsIndex, TypeFuncIndex,
13+
TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFixedSizeListIndex, TypeFlagsIndex, TypeFuncIndex,
1414
TypeFutureIndex, TypeFutureTableIndex, TypeListIndex, TypeMapIndex, TypeModuleIndex,
1515
TypeOptionIndex, TypeRecordIndex, TypeResourceTable, TypeResourceTableIndex, TypeResultIndex,
1616
TypeStreamIndex, TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex, alternate_lookup_key,
@@ -165,7 +165,10 @@ impl TypeChecker<'_> {
165165
(InterfaceType::Stream(_), _) => false,
166166
(InterfaceType::ErrorContext(_), InterfaceType::ErrorContext(_)) => true,
167167
(InterfaceType::ErrorContext(_), _) => false,
168-
(InterfaceType::FixedLengthList(_), _) => todo!(), // FIXME(#12279)
168+
(InterfaceType::FixedLengthList(t1), InterfaceType::FixedSizeList(t2)) => {
169+
self.fixed_length_lists_equal(t1, t2)
170+
}
171+
(InterfaceType::FixedSizeList(_), _) => false,
169172
}
170173
}
171174

@@ -181,6 +184,19 @@ impl TypeChecker<'_> {
181184
self.interface_types_equal(a.key, b.key) && self.interface_types_equal(a.value, b.value)
182185
}
183186

187+
fn fixed_length_lists_equal(
188+
&self,
189+
l1: wasmtime_environ::component::TypeFixedLengthListIndex,
190+
l2: wasmtime_environ::component::TypeFixedLengthListIndex,
191+
) -> bool {
192+
let a = &self.a_types[l1];
193+
let b = &self.b_types[l2];
194+
if a.size != b.size {
195+
return false;
196+
}
197+
self.interface_types_equal(a.element, b.element)
198+
}
199+
184200
fn resources_equal(&self, o1: TypeResourceTableIndex, o2: TypeResourceTableIndex) -> bool {
185201
match (&self.a_types[o1], &self.b_types[o2]) {
186202
// Concrete resource types are the same if they map back to the
@@ -365,6 +381,34 @@ impl Map {
365381
Type::from(&self.0.types[self.0.index].value, &self.0.instance())
366382
}
367383
}
384+
/// A `list` interface type
385+
#[derive(Clone, Debug)]
386+
pub struct FixedLengthList(Handle<TypeFixedLengthListIndex>);
387+
388+
impl PartialEq for FixedLengthList {
389+
fn eq(&self, other: &Self) -> bool {
390+
self.0
391+
.equivalent(&other.0, TypeChecker::fixed_size_lists_equal)
392+
}
393+
}
394+
395+
impl Eq for FixedLengthList {}
396+
397+
impl FixedLengthList {
398+
pub(crate) fn from(index: TypeFixedLengthListIndex, ty: &InstanceType<'_>) -> Self {
399+
FixedLengthList(Handle::new(index, ty))
400+
}
401+
402+
/// Retrieve the element type of this `list`.
403+
pub fn ty(&self) -> Type {
404+
Type::from(&self.0.types[self.0.index].element, &self.0.instance())
405+
}
406+
407+
/// Retrieve the size of this `list`.
408+
pub fn size(&self) -> u32 {
409+
self.0.types[self.0.index].size
410+
}
411+
}
368412

369413
/// A field declaration belonging to a `record`
370414
#[derive(Debug)]
@@ -738,6 +782,7 @@ pub enum Type {
738782
Future(FutureType),
739783
Stream(StreamType),
740784
ErrorContext,
785+
FixedSizeList(FixedSizeList),
741786
}
742787

743788
impl Type {
@@ -899,7 +944,9 @@ impl Type {
899944
InterfaceType::Future(index) => Type::Future(instance.future_type(*index)),
900945
InterfaceType::Stream(index) => Type::Stream(instance.stream_type(*index)),
901946
InterfaceType::ErrorContext(_) => Type::ErrorContext,
902-
InterfaceType::FixedLengthList(_) => todo!(), // FIXME(#12279)
947+
InterfaceType::FixedLengthList(index) => {
948+
Type::FixedLengthList(FixedSizeList::from(*index, instance))
949+
}
903950
}
904951
}
905952

@@ -932,6 +979,7 @@ impl Type {
932979
Type::Future(_) => "future",
933980
Type::Stream(_) => "stream",
934981
Type::ErrorContext => "error-context",
982+
Type::FixedSizeList(_) => "list<_, N>",
935983
}
936984
}
937985
}

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

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ pub enum Val {
9393
Future(FutureAny),
9494
Stream(StreamAny),
9595
ErrorContext(ErrorContextAny),
96+
FixedSizeList(Vec<Val>),
9697
}
9798

9899
impl Val {
@@ -220,7 +221,11 @@ impl Val {
220221
InterfaceType::ErrorContext(_) => {
221222
ErrorContext::linear_lift_from_flat(cx, ty, next(src))?.into_val()
222223
}
223-
InterfaceType::FixedLengthList(_) => todo!(), // FIXME(#12279)
224+
InterfaceType::FixedLengthList(i) => Val::FixedLengthList(
225+
(0..cx.types[i].size)
226+
.map(|_| Self::lift(cx, cx.types[i].element, src))
227+
.collect::<Result<_>>()?,
228+
),
224229
})
225230
}
226231

@@ -349,7 +354,20 @@ impl Val {
349354
InterfaceType::ErrorContext(_) => {
350355
ErrorContext::linear_lift_from_memory(cx, ty, bytes)?.into_val()
351356
}
352-
InterfaceType::FixedLengthList(_) => todo!(), // FIXME(#12279)
357+
InterfaceType::FixedLengthList(i) => {
358+
let element = cx.types[i].element.clone();
359+
let abi = cx.types.canonical_abi(&element);
360+
Val::Tuple(
361+
(0..cx.types[i].size)
362+
.map(|n| {
363+
let offset = abi.size32 * n;
364+
let offset = usize::try_from(offset).unwrap();
365+
let size = usize::try_from(abi.size32).unwrap();
366+
Val::load(cx, element, &bytes[offset..][..size])
367+
})
368+
.collect::<Result<_>>()?,
369+
)
370+
}
353371
})
354372
}
355373

@@ -508,7 +526,17 @@ impl Val {
508526
)
509527
}
510528
(InterfaceType::ErrorContext(_), _) => unexpected(ty, self),
511-
(InterfaceType::FixedLengthList(_), _) => todo!(), // FIXME(#12279)
529+
(InterfaceType::FixedLengthList(ty), Val::FixedSizeList(values)) => {
530+
let ty = &cx.types[ty];
531+
if ty.size as usize != values.len() {
532+
bail!("expected vec of size {}, got {}", ty.size, values.len());
533+
}
534+
for value in values {
535+
value.lower(cx, ty.element, dst)?;
536+
}
537+
Ok(())
538+
}
539+
(InterfaceType::FixedSizeList(_), _) => unexpected(ty, self),
512540
}
513541
}
514542

@@ -671,7 +699,18 @@ impl Val {
671699
)
672700
}
673701
(InterfaceType::ErrorContext(_), _) => unexpected(ty, self),
674-
(InterfaceType::FixedLengthList(_), _) => todo!(), // FIXME(#12279)
702+
(InterfaceType::FixedLengthList(ty), Val::FixedSizeList(values)) => {
703+
let ty = &cx.types[ty];
704+
if ty.size as usize != values.len() {
705+
bail!("expected {} types, got {}", ty.size, values.len());
706+
}
707+
let elemsize = cx.types.canonical_abi(&ty.element).size32 as usize;
708+
for (n, value) in values.iter().enumerate() {
709+
value.store(cx, ty.element, elemsize * n)?;
710+
}
711+
Ok(())
712+
}
713+
(InterfaceType::FixedSizeList(_), _) => unexpected(ty, self),
675714
}
676715
}
677716

@@ -703,6 +742,7 @@ impl Val {
703742
Val::Future(_) => "future",
704743
Val::Stream(_) => "stream",
705744
Val::ErrorContext(_) => "error-context",
745+
Val::FixedSizeList(_) => "list<_, N>",
706746
}
707747
}
708748

@@ -789,6 +829,8 @@ impl PartialEq for Val {
789829
(Self::Stream(_), _) => false,
790830
(Self::ErrorContext(l), Self::ErrorContext(r)) => l == r,
791831
(Self::ErrorContext(_), _) => false,
832+
(Self::FixedSizeList(l), Self::FixedSizeList(r)) => l == r,
833+
(Self::FixedSizeList(_), _) => false,
792834
}
793835
}
794836
}

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(_)
@@ -144,6 +145,7 @@ impl WasmValue for component::Val {
144145
| Self::Future(_)
145146
| Self::ErrorContext(_)
146147
| Self::Map(_) => WasmTypeKind::Unsupported,
148+
Self::FixedLengthList(_) => WasmTypeKind::FixedLengthList,
147149
}
148150
}
149151

0 commit comments

Comments
 (0)