Deduplicate some size/align calculations (#4658)
This commit is an effort to reduce the amount of complexity around managing the size/alignment calculations of types in the canonical ABI. Previously the logic for the size/alignment of a type was spread out across a number of locations. While each individual calculation is not really the most complicated thing in the world having the duplication in so many places was constantly worrying me. I've opted in this commit to centralize all of this within the runtime at least, and now there's only one "duplicate" of this information in the fuzzing infrastructure which is to some degree less important to deduplicate. This commit introduces a new `CanonicalAbiInfo` type to house all abi size/align information for both memory32 and memory64. This new type is then used pervasively throughout fused adapter compilation, dynamic `Val` management, and typed functions. This type was also able to reduce the complexity of the macro-generated code meaning that even `wasmtime-component-macro` is performing less math than it was before. One other major feature of this commit is that this ABI information is now saved within a `ComponentTypes` structure. This avoids recursive querying of size/align information frequently and instead effectively caching it. This was a worry I had for the fused adapter compiler which frequently sought out size/align information and would recursively descend each type tree each time. The `fact-valid-module` fuzzer is now nearly 10x faster in terms of iterations/s which I suspect is due to this caching.
This commit is contained in:
@@ -298,7 +298,7 @@ fn expand_record_for_component_type(
|
||||
let mut lower_generic_params = TokenStream::new();
|
||||
let mut lower_generic_args = TokenStream::new();
|
||||
let mut lower_field_declarations = TokenStream::new();
|
||||
let mut sizes = TokenStream::new();
|
||||
let mut abi_list = TokenStream::new();
|
||||
let mut unique_types = HashSet::new();
|
||||
|
||||
for (index, syn::Field { ident, ty, .. }) in fields.iter().enumerate() {
|
||||
@@ -309,24 +309,13 @@ fn expand_record_for_component_type(
|
||||
|
||||
lower_field_declarations.extend(quote!(#ident: #generic,));
|
||||
|
||||
sizes.extend(quote!(
|
||||
size = #internal::align_to(size, <#ty as wasmtime::component::ComponentType>::ALIGN32);
|
||||
size += <#ty as wasmtime::component::ComponentType>::SIZE32;
|
||||
abi_list.extend(quote!(
|
||||
<#ty as wasmtime::component::ComponentType>::ABI,
|
||||
));
|
||||
|
||||
unique_types.insert(ty);
|
||||
}
|
||||
|
||||
let alignments = unique_types
|
||||
.into_iter()
|
||||
.map(|ty| {
|
||||
let align = quote!(<#ty as wasmtime::component::ComponentType>::ALIGN32);
|
||||
quote!(if #align > align {
|
||||
align = #align;
|
||||
})
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::ComponentType));
|
||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||
let lower = format_ident!("Lower{}", name);
|
||||
@@ -358,17 +347,8 @@ fn expand_record_for_component_type(
|
||||
unsafe impl #impl_generics wasmtime::component::ComponentType for #name #ty_generics #where_clause {
|
||||
type Lower = #lower <#lower_generic_args>;
|
||||
|
||||
const SIZE32: usize = {
|
||||
let mut size = 0;
|
||||
#sizes
|
||||
#internal::align_to(size, Self::ALIGN32)
|
||||
};
|
||||
|
||||
const ALIGN32: u32 = {
|
||||
let mut align = 1;
|
||||
#alignments
|
||||
align
|
||||
};
|
||||
const ABI: #internal::CanonicalAbiInfo =
|
||||
#internal::CanonicalAbiInfo::record_static(&[#abi_list]);
|
||||
|
||||
#[inline]
|
||||
fn typecheck(
|
||||
@@ -429,7 +409,7 @@ impl Expander for LiftExpander {
|
||||
loads.extend(quote!(#ident: <#ty as wasmtime::component::Lift>::load(
|
||||
memory,
|
||||
&bytes
|
||||
[#internal::next_field::<#ty>(&mut offset)..]
|
||||
[<#ty as wasmtime::component::ComponentType>::ABI.next_field32_size(&mut offset)..]
|
||||
[..<#ty as wasmtime::component::ComponentType>::SIZE32]
|
||||
)?,));
|
||||
}
|
||||
@@ -514,8 +494,6 @@ impl Expander for LiftExpander {
|
||||
DiscriminantSize::Size4 => quote!(u32::from_le_bytes(bytes[0..4].try_into()?)),
|
||||
};
|
||||
|
||||
let payload_offset = usize::from(discriminant_size);
|
||||
|
||||
let expanded = quote! {
|
||||
unsafe impl #impl_generics wasmtime::component::Lift for #name #ty_generics #where_clause {
|
||||
#[inline]
|
||||
@@ -535,7 +513,8 @@ impl Expander for LiftExpander {
|
||||
let align = <Self as wasmtime::component::ComponentType>::ALIGN32;
|
||||
debug_assert!((bytes.as_ptr() as usize) % (align as usize) == 0);
|
||||
let discrim = #from_bytes;
|
||||
let payload = &bytes[#internal::align_to(#payload_offset, align)..];
|
||||
let payload_offset = <Self as #internal::ComponentVariant>::PAYLOAD_OFFSET32;
|
||||
let payload = &bytes[payload_offset..];
|
||||
Ok(match discrim {
|
||||
#loads
|
||||
discrim => #internal::anyhow::bail!("unexpected discriminant: {}", discrim),
|
||||
@@ -575,7 +554,9 @@ impl Expander for LowerExpander {
|
||||
)?;));
|
||||
|
||||
stores.extend(quote!(wasmtime::component::Lower::store(
|
||||
&self.#ident, memory, #internal::next_field::<#ty>(&mut offset)
|
||||
&self.#ident,
|
||||
memory,
|
||||
<#ty as wasmtime::component::ComponentType>::ABI.next_field32_size(&mut offset),
|
||||
)?;));
|
||||
}
|
||||
|
||||
@@ -640,10 +621,7 @@ impl Expander for LowerExpander {
|
||||
lower = quote!(value.lower(store, options, #internal::map_maybe_uninit!(dst.payload.#ident)));
|
||||
store = quote!(value.store(
|
||||
memory,
|
||||
offset + #internal::align_to(
|
||||
#discriminant_size,
|
||||
<Self as wasmtime::component::ComponentType>::ALIGN32
|
||||
)
|
||||
offset + <Self as #internal::ComponentVariant>::PAYLOAD_OFFSET32,
|
||||
));
|
||||
} else {
|
||||
pattern = quote!(Self::#ident);
|
||||
@@ -749,7 +727,7 @@ impl Expander for ComponentTypeExpander {
|
||||
&self,
|
||||
name: &syn::Ident,
|
||||
generics: &syn::Generics,
|
||||
discriminant_size: DiscriminantSize,
|
||||
_discriminant_size: DiscriminantSize,
|
||||
cases: &[VariantCase],
|
||||
style: VariantStyle,
|
||||
) -> Result<TokenStream> {
|
||||
@@ -760,7 +738,7 @@ impl Expander for ComponentTypeExpander {
|
||||
let mut lower_payload_generic_args = TokenStream::new();
|
||||
let mut lower_payload_case_declarations = TokenStream::new();
|
||||
let mut lower_generic_args = TokenStream::new();
|
||||
let mut sizes = TokenStream::new();
|
||||
let mut abi_list = TokenStream::new();
|
||||
let mut unique_types = HashSet::new();
|
||||
|
||||
for (index, VariantCase { attrs, ident, ty }) in cases.iter().enumerate() {
|
||||
@@ -776,12 +754,7 @@ impl Expander for ComponentTypeExpander {
|
||||
let name = rename.unwrap_or_else(|| Literal::string(&ident.to_string()));
|
||||
|
||||
if let Some(ty) = ty {
|
||||
sizes.extend({
|
||||
let size = quote!(<#ty as wasmtime::component::ComponentType>::SIZE32);
|
||||
quote!(if #size > size {
|
||||
size = #size;
|
||||
})
|
||||
});
|
||||
abi_list.extend(quote!(<#ty as wasmtime::component::ComponentType>::ABI,));
|
||||
|
||||
case_names_and_checks.extend(match style {
|
||||
VariantStyle::Variant => {
|
||||
@@ -808,6 +781,7 @@ impl Expander for ComponentTypeExpander {
|
||||
|
||||
unique_types.insert(ty);
|
||||
} else {
|
||||
abi_list.extend(quote!(<() as wasmtime::component::ComponentType>::ABI,));
|
||||
case_names_and_checks.extend(match style {
|
||||
VariantStyle::Variant => {
|
||||
quote!((#name, <() as wasmtime::component::ComponentType>::typecheck),)
|
||||
@@ -824,16 +798,6 @@ impl Expander for ComponentTypeExpander {
|
||||
lower_payload_case_declarations.extend(quote!(_dummy: ()));
|
||||
}
|
||||
|
||||
let alignments = unique_types
|
||||
.into_iter()
|
||||
.map(|ty| {
|
||||
let align = quote!(<#ty as wasmtime::component::ComponentType>::ALIGN32);
|
||||
quote!(if #align > align {
|
||||
align = #align;
|
||||
})
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
let typecheck = match style {
|
||||
VariantStyle::Variant => quote!(typecheck_variant),
|
||||
VariantStyle::Union => quote!(typecheck_union),
|
||||
@@ -844,7 +808,6 @@ impl Expander for ComponentTypeExpander {
|
||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||
let lower = format_ident!("Lower{}", name);
|
||||
let lower_payload = format_ident!("LowerPayload{}", name);
|
||||
let discriminant_size = u32::from(discriminant_size);
|
||||
|
||||
// You may wonder why we make the types of all the fields of the #lower struct and #lower_payload union
|
||||
// generic. This is to work around a [normalization bug in
|
||||
@@ -882,20 +845,12 @@ impl Expander for ComponentTypeExpander {
|
||||
#internal::#typecheck(ty, types, &[#case_names_and_checks])
|
||||
}
|
||||
|
||||
const SIZE32: usize = {
|
||||
let mut size = 0;
|
||||
#sizes
|
||||
#internal::align_to(
|
||||
#internal::align_to(#discriminant_size as usize, Self::ALIGN32) + size,
|
||||
Self::ALIGN32
|
||||
)
|
||||
};
|
||||
const ABI: #internal::CanonicalAbiInfo =
|
||||
#internal::CanonicalAbiInfo::variant_static(&[#abi_list]);
|
||||
}
|
||||
|
||||
const ALIGN32: u32 = {
|
||||
let mut align = #discriminant_size;
|
||||
#alignments
|
||||
align
|
||||
};
|
||||
unsafe impl #impl_generics #internal::ComponentVariant for #name #ty_generics #where_clause {
|
||||
const CASES: &'static [#internal::CanonicalAbiInfo] = &[#abi_list];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user