-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Minimal implementation of fixed size lists to enable wit-bindgen runtime tests #10619
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,7 @@ pub struct ComponentTypesBuilder { | |
future_tables: HashMap<TypeFutureTable, TypeFutureTableIndex>, | ||
stream_tables: HashMap<TypeStreamTable, TypeStreamTableIndex>, | ||
error_context_tables: HashMap<TypeErrorContextTable, TypeComponentLocalErrorContextTableIndex>, | ||
fixed_size_lists: HashMap<TypeFixedSizeList, TypeFixedSizeListIndex>, | ||
|
||
component_types: ComponentTypes, | ||
module_types: ModuleTypesBuilder, | ||
|
@@ -111,6 +112,7 @@ impl ComponentTypesBuilder { | |
component_types: ComponentTypes::default(), | ||
type_info: TypeInformationCache::default(), | ||
resources: ResourcesBuilder::default(), | ||
fixed_size_lists: HashMap::default(), | ||
} | ||
} | ||
|
||
|
@@ -418,6 +420,9 @@ impl ComponentTypesBuilder { | |
ComponentDefinedType::Stream(ty) => { | ||
InterfaceType::Stream(self.stream_table_type(types, ty)?) | ||
} | ||
ComponentDefinedType::FixedSizeList(ty, size) => { | ||
InterfaceType::FixedSizeList(self.fixed_size_list_type(types, ty, *size)?) | ||
} | ||
}; | ||
let info = self.type_information(&ret); | ||
if info.depth > MAX_TYPE_DEPTH { | ||
|
@@ -531,6 +536,19 @@ impl ComponentTypesBuilder { | |
self.add_tuple_type(TypeTuple { types, abi }) | ||
} | ||
|
||
fn fixed_size_list_type(&mut self, types: TypesRef<'_>, ty: &ComponentValType, size: u32) -> Result<TypeFixedSizeListIndex> { | ||
assert_eq!(types.id(), self.module_types.validator_id()); | ||
let element = self.valtype(types, ty)?; | ||
Ok(self.new_fixed_size_list_type(element, size)) | ||
} | ||
|
||
pub(crate) fn new_fixed_size_list_type(&mut self, element: InterfaceType, size: u32) -> TypeFixedSizeListIndex { | ||
let element_abi = self.component_types.canonical_abi(&element); | ||
let abi = CanonicalAbiInfo::record( | ||
(0..size).into_iter().map(|_| element_abi)); | ||
self.add_fixed_size_list_type(TypeFixedSizeList { element, size, abi }) | ||
} | ||
|
||
fn flags_type(&mut self, flags: &IndexSet<KebabString>) -> TypeFlagsIndex { | ||
let flags = TypeFlags { | ||
names: flags.iter().map(|s| s.to_string()).collect(), | ||
|
@@ -647,6 +665,11 @@ impl ComponentTypesBuilder { | |
intern_and_fill_flat_types!(self, tuples, ty) | ||
} | ||
|
||
/// Interns a new tuple type within this type information. | ||
pub fn add_fixed_size_list_type(&mut self, ty: TypeFixedSizeList) -> TypeFixedSizeListIndex { | ||
intern_and_fill_flat_types!(self, fixed_size_lists, ty) | ||
} | ||
|
||
/// Interns a new variant type within this type information. | ||
pub fn add_variant_type(&mut self, ty: TypeVariant) -> TypeVariantIndex { | ||
intern_and_fill_flat_types!(self, variants, ty) | ||
|
@@ -782,6 +805,7 @@ impl ComponentTypesBuilder { | |
InterfaceType::Enum(i) => &self.type_info.enums[*i], | ||
InterfaceType::Option(i) => &self.type_info.options[*i], | ||
InterfaceType::Result(i) => &self.type_info.results[*i], | ||
InterfaceType::FixedSizeList(i) => &self.type_info.fixed_size_lists[*i], | ||
} | ||
} | ||
} | ||
|
@@ -891,6 +915,7 @@ struct TypeInformationCache { | |
options: PrimaryMap<TypeOptionIndex, TypeInformation>, | ||
results: PrimaryMap<TypeResultIndex, TypeInformation>, | ||
lists: PrimaryMap<TypeListIndex, TypeInformation>, | ||
fixed_size_lists: PrimaryMap<TypeFixedSizeListIndex, TypeInformation>, | ||
} | ||
|
||
struct TypeInformation { | ||
|
@@ -1040,6 +1065,10 @@ impl TypeInformation { | |
self.build_record(ty.types.iter().map(|t| types.type_information(t))); | ||
} | ||
|
||
fn fixed_size_lists(&mut self, types: &ComponentTypesBuilder, ty: &TypeFixedSizeList) { | ||
self.build_record((0..ty.size).into_iter().map(|_| types.type_information(&ty.element))); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above, I think it'd be best to avoid "feigning" a record here and using a dedicated computation for fixed-size lists to avoid O(n) in the length of the list |
||
} | ||
|
||
fn enums(&mut self, _types: &ComponentTypesBuilder, _ty: &TypeEnum) { | ||
self.depth = 1; | ||
self.flat.push(FlatType::I32, FlatType::I32); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,11 +16,7 @@ | |
//! can be somewhat arbitrary, an intentional decision. | ||
|
||
use crate::component::{ | ||
CanonicalAbiInfo, ComponentTypesBuilder, FixedEncoding as FE, FlatType, InterfaceType, | ||
StringEncoding, Transcode, TypeComponentLocalErrorContextTableIndex, TypeEnumIndex, | ||
TypeFlagsIndex, TypeFutureTableIndex, TypeListIndex, TypeOptionIndex, TypeRecordIndex, | ||
TypeResourceTableIndex, TypeResultIndex, TypeStreamTableIndex, TypeTupleIndex, | ||
TypeVariantIndex, VariantInfo, FLAG_MAY_ENTER, FLAG_MAY_LEAVE, MAX_FLAT_PARAMS, | ||
CanonicalAbiInfo, ComponentTypesBuilder, FixedEncoding as FE, FlatType, InterfaceType, StringEncoding, Transcode, TypeComponentLocalErrorContextTableIndex, TypeEnumIndex, TypeFixedSizeListIndex, TypeFlagsIndex, TypeFutureTableIndex, TypeListIndex, TypeOptionIndex, TypeRecordIndex, TypeResourceTableIndex, TypeResultIndex, TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex, VariantInfo, FLAG_MAY_ENTER, FLAG_MAY_LEAVE, MAX_FLAT_PARAMS | ||
}; | ||
use crate::fact::signature::Signature; | ||
use crate::fact::transcode::Transcoder; | ||
|
@@ -1044,6 +1040,7 @@ impl<'a, 'b> Compiler<'a, 'b> { | |
| InterfaceType::Future(_) | ||
| InterfaceType::Stream(_) | ||
| InterfaceType::ErrorContext(_) => 1, | ||
InterfaceType::FixedSizeList(i) => self.types[*i].size as usize, | ||
}; | ||
|
||
match self.fuel.checked_sub(cost) { | ||
|
@@ -1083,6 +1080,9 @@ impl<'a, 'b> Compiler<'a, 'b> { | |
InterfaceType::ErrorContext(t) => { | ||
self.translate_error_context(*t, src, dst_ty, dst) | ||
} | ||
InterfaceType::FixedSizeList(t) => { | ||
self.translate_fixed_size_list(*t, src, dst_ty, dst); | ||
} | ||
} | ||
} | ||
|
||
|
@@ -2628,6 +2628,31 @@ impl<'a, 'b> Compiler<'a, 'b> { | |
} | ||
} | ||
|
||
fn translate_fixed_size_list( | ||
&mut self, | ||
src_ty: TypeFixedSizeListIndex, | ||
src: &Source<'_>, | ||
dst_ty: &InterfaceType, | ||
dst: &Destination, | ||
) { | ||
let src_ty = &self.types[src_ty]; | ||
let dst_ty = match dst_ty { | ||
InterfaceType::FixedSizeList(t) => &self.types[*t], | ||
_ => panic!("expected a fixed size list"), | ||
}; | ||
|
||
// TODO: subtyping | ||
assert_eq!(src_ty.size, dst_ty.size); | ||
|
||
let srcs = src | ||
.record_field_srcs(self.types, (0..src_ty.size).into_iter().map(|_| src_ty.element)); | ||
let dsts = dst | ||
.record_field_dsts(self.types, (0..dst_ty.size).into_iter().map(|_| dst_ty.element)); | ||
for (src, dst) in srcs.zip(dsts) { | ||
self.translate(&src_ty.element, &src, &dst_ty.element, &dst); | ||
} | ||
} | ||
Comment on lines
+2631
to
+2654
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bit of an interesting case. Effectively what this is doing is unrolling Basically what I'm saying is that I think we must implement the loop-based variant of translating lists, not just the fully-unrolled version of translating lists. |
||
|
||
fn translate_variant( | ||
&mut self, | ||
src_ty: TypeVariantIndex, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be done with a new helper? I'm wary of defining an O(n) thing here and relying on LLVM to optimize it. This could make
list<T, BigNumber>
excessively slow in debug builds of Wasmtime for example.