Skip to content
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

support dynamic function calls in component model #4442

Merged
merged 10 commits into from
Jul 25, 2022
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/component-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ proc-macro = true
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0", features = ["extra-traits"] }
wasmtime-component-util = { path = "../component-util", version = "=0.40.0" }

[badges]
maintenance = { status = "actively-developed" }
105 changes: 23 additions & 82 deletions crates/component-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::fmt;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::{braced, parse_macro_input, parse_quote, Data, DeriveInput, Error, Result, Token};
use wasmtime_component_util::{DiscriminantSize, FlagsSize};

#[derive(Debug, Copy, Clone)]
enum VariantStyle {
Expand Down Expand Up @@ -147,64 +148,6 @@ fn add_trait_bounds(generics: &syn::Generics, bound: syn::TypeParamBound) -> syn
generics
}

#[derive(Debug, Copy, Clone)]
enum DiscriminantSize {
Size1,
Size2,
Size4,
}

impl DiscriminantSize {
fn quote(self, discriminant: usize) -> TokenStream {
match self {
Self::Size1 => {
let discriminant = u8::try_from(discriminant).unwrap();
quote!(#discriminant)
}
Self::Size2 => {
let discriminant = u16::try_from(discriminant).unwrap();
quote!(#discriminant)
}
Self::Size4 => {
let discriminant = u32::try_from(discriminant).unwrap();
quote!(#discriminant)
}
}
}
}

impl From<DiscriminantSize> for u32 {
fn from(size: DiscriminantSize) -> u32 {
match size {
DiscriminantSize::Size1 => 1,
DiscriminantSize::Size2 => 2,
DiscriminantSize::Size4 => 4,
}
}
}

impl From<DiscriminantSize> for usize {
fn from(size: DiscriminantSize) -> usize {
match size {
DiscriminantSize::Size1 => 1,
DiscriminantSize::Size2 => 2,
DiscriminantSize::Size4 => 4,
}
}
}

fn discriminant_size(case_count: usize) -> Option<DiscriminantSize> {
if case_count <= 0xFF {
Some(DiscriminantSize::Size1)
} else if case_count <= 0xFFFF {
Some(DiscriminantSize::Size2)
} else if case_count <= 0xFFFF_FFFF {
Some(DiscriminantSize::Size4)
} else {
None
}
}

struct VariantCase<'a> {
attrs: &'a [syn::Attribute],
ident: &'a syn::Ident,
Expand Down Expand Up @@ -288,7 +231,7 @@ fn expand_variant(
));
}

let discriminant_size = discriminant_size(body.variants.len()).ok_or_else(|| {
let discriminant_size = DiscriminantSize::from_count(body.variants.len()).ok_or_else(|| {
Error::new(
input.ident.span(),
"`enum`s with more than 2^32 variants are not supported",
Expand Down Expand Up @@ -417,7 +360,7 @@ fn expand_record_for_component_type(
const SIZE32: usize = {
let mut size = 0;
#sizes
size
#internal::align_to(size, Self::ALIGN32)
};

const ALIGN32: u32 = {
Expand All @@ -439,6 +382,23 @@ fn expand_record_for_component_type(
Ok(quote!(const _: () = { #expanded };))
}

fn quote(size: DiscriminantSize, discriminant: usize) -> TokenStream {
match size {
DiscriminantSize::Size1 => {
let discriminant = u8::try_from(discriminant).unwrap();
quote!(#discriminant)
}
DiscriminantSize::Size2 => {
let discriminant = u16::try_from(discriminant).unwrap();
quote!(#discriminant)
}
DiscriminantSize::Size4 => {
let discriminant = u32::try_from(discriminant).unwrap();
quote!(#discriminant)
}
}
}

#[proc_macro_derive(Lift, attributes(component))]
pub fn lift(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
expand(&LiftExpander, &parse_macro_input!(input as DeriveInput))
Expand Down Expand Up @@ -523,7 +483,7 @@ impl Expander for LiftExpander {
for (index, VariantCase { ident, ty, .. }) in cases.iter().enumerate() {
let index_u32 = u32::try_from(index).unwrap();

let index_quoted = discriminant_size.quote(index);
let index_quoted = quote(discriminant_size, index);

if let Some(ty) = ty {
lifts.extend(
Expand Down Expand Up @@ -666,7 +626,7 @@ impl Expander for LowerExpander {
for (index, VariantCase { ident, ty, .. }) in cases.iter().enumerate() {
let index_u32 = u32::try_from(index).unwrap();

let index_quoted = discriminant_size.quote(index);
let index_quoted = quote(discriminant_size, index);

let discriminant_size = usize::from(discriminant_size);

Expand Down Expand Up @@ -989,19 +949,6 @@ impl Parse for Flags {
}
}

enum FlagsSize {
/// Flags can fit in a u8
Size1,
/// Flags can fit in a u16
Size2,
/// Flags can fit in a specified number of u32 fields
Size4Plus(usize),
}

fn ceiling_divide(n: usize, d: usize) -> usize {
(n + d - 1) / d
}

#[proc_macro]
pub fn flags(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
expand_flags(&parse_macro_input!(input as Flags))
Expand All @@ -1010,13 +957,7 @@ pub fn flags(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
}

fn expand_flags(flags: &Flags) -> Result<TokenStream> {
let size = if flags.flags.len() <= 8 {
FlagsSize::Size1
} else if flags.flags.len() <= 16 {
FlagsSize::Size2
} else {
FlagsSize::Size4Plus(ceiling_divide(flags.flags.len(), 32))
};
let size = FlagsSize::from_count(flags.flags.len());

let ty;
let eq;
Expand Down
11 changes: 11 additions & 0 deletions crates/component-util/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "wasmtime-component-util"
version = "0.40.0"
authors = ["The Wasmtime Project Developers"]
description = "Utility types and functions to support the component model in Wasmtime"
license = "Apache-2.0 WITH LLVM-exception"
repository = "https://github.com/bytecodealliance/wasmtime"
documentation = "https://docs.rs/wasmtime-component-util/"
categories = ["wasm"]
keywords = ["webassembly", "wasm"]
edition = "2021"
75 changes: 75 additions & 0 deletions crates/component-util/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/// Represents the possible sizes in bytes of the discriminant of a variant type in the component model
#[derive(Debug, Copy, Clone)]
pub enum DiscriminantSize {
/// 8-bit discriminant
Size1,
/// 16-bit discriminant
Size2,
/// 32-bit discriminant
Size4,
}

impl DiscriminantSize {
/// Calculate the size of discriminant needed to represent a variant with the specified number of cases.
pub fn from_count(count: usize) -> Option<Self> {
if count <= 0xFF {
Some(Self::Size1)
} else if count <= 0xFFFF {
Some(Self::Size2)
} else if count <= 0xFFFF_FFFF {
Some(Self::Size4)
} else {
None
}
}
}

impl From<DiscriminantSize> for u32 {
/// Size of the discriminant as a `u32`
fn from(size: DiscriminantSize) -> u32 {
match size {
DiscriminantSize::Size1 => 1,
DiscriminantSize::Size2 => 2,
DiscriminantSize::Size4 => 4,
}
}
}

impl From<DiscriminantSize> for usize {
/// Size of the discriminant as a `usize`
fn from(size: DiscriminantSize) -> usize {
match size {
DiscriminantSize::Size1 => 1,
DiscriminantSize::Size2 => 2,
DiscriminantSize::Size4 => 4,
}
}
}

/// Represents the number of bytes required to store a flags value in the component model
pub enum FlagsSize {
/// Flags can fit in a u8
Size1,
/// Flags can fit in a u16
Size2,
/// Flags can fit in a specified number of u32 fields
Size4Plus(usize),
}

impl FlagsSize {
/// Calculate the size needed to represent a value with the specified number of flags.
pub fn from_count(count: usize) -> FlagsSize {
if count <= 8 {
FlagsSize::Size1
} else if count <= 16 {
FlagsSize::Size2
} else {
FlagsSize::Size4Plus(ceiling_divide(count, 32))
}
}
}

/// Divide `n` by `d`, rounding up in the case of a non-zero remainder.
fn ceiling_divide(n: usize, d: usize) -> usize {
(n + d - 1) / d
}
2 changes: 2 additions & 0 deletions crates/wasmtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ wasmtime-cache = { path = "../cache", version = "=0.40.0", optional = true }
wasmtime-fiber = { path = "../fiber", version = "=0.40.0", optional = true }
wasmtime-cranelift = { path = "../cranelift", version = "=0.40.0", optional = true }
wasmtime-component-macro = { path = "../component-macro", version = "=0.40.0", optional = true }
wasmtime-component-util = { path = "../component-util", version = "=0.40.0", optional = true }
target-lexicon = { version = "0.12.0", default-features = false }
wasmparser = "0.87.0"
anyhow = "1.0.19"
Expand Down Expand Up @@ -115,4 +116,5 @@ component-model = [
"wasmtime-cranelift?/component-model",
"wasmtime-runtime/component-model",
"dep:wasmtime-component-macro",
"dep:wasmtime-component-util",
]
Loading