Skip to content

Commit

Permalink
threads: add shared composite types (#1646)
Browse files Browse the repository at this point in the history
* threads: add `shared` composite types

This continues the work of #1600 to expand the surface area of a
WebAssembly module that can be marked `shared`. This is for support of
the shared-everything-threads [proposal]. The key change is to convert
`CompositeType` in each of the crates from an `enum` to a `struct` in
order to add a `shared` boolean field. The original variants (`Func`,
`Array`, `Struct`) are moved to a separate `enum` and fill an `inner`
field. Propagating this throughout the code base is the bulk of this PR,
with occasional, small refactors to avoid larger match patterns.

[proposal]: https://github.com/WebAssembly/shared-everything-threads

* Add `wast` parsing of shared composite types

This finishes the work of the previous commit, allowing us to express
shared composite types in the text format: `(type $t (shared (...)))`.
This also finishes up the heap type testing by allowing the tests to
express concrete heap types (e.g., `ref $t`).

* Fix some un-formatted files

* Add shared check to rec groups

For now, this explicitly checks that both subtypes are shared. But it
isn't yet clear whether an shared type might be able to match an
unshared one. Once that is resolved, this might need to be updated.

* Add @tlively `struct` and `array` tests

These proposed spec tests are slightly modified from @tlively's
originals:
- they use this crate's choice of error message
- they avoid the shorthand form of a single-field struct, ~(struct
  <type>)` because this crate does not yet know how to parse that
- they avoid the shorthand form for `(elem)` for the same reason

All of these minor issues can be resolved later.
  • Loading branch information
abrown authored Jul 3, 2024
1 parent 3ca2d7c commit 6fc1601
Show file tree
Hide file tree
Showing 53 changed files with 1,281 additions and 437 deletions.
43 changes: 29 additions & 14 deletions crates/wasm-encoder/src/core/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,46 @@ impl Encode for SubType {

/// Represents a composite type in a WebAssembly module.
#[derive(Debug, Clone)]
pub enum CompositeType {
/// The type is for a function.
Func(FuncType),
/// The type is for an array.
Array(ArrayType),
/// The type is for a struct.
Struct(StructType),
pub struct CompositeType {
/// The type defined inside the composite type.
pub inner: CompositeInnerType,
/// Whether the type is shared. This is part of the
/// shared-everything-threads proposal.
pub shared: bool,
}

impl Encode for CompositeType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
CompositeType::Func(ty) => TypeSection::encode_function(
if self.shared {
sink.push(0x65);
}
match &self.inner {
CompositeInnerType::Func(ty) => TypeSection::encode_function(
sink,
ty.params().iter().copied(),
ty.results().iter().copied(),
),
CompositeType::Array(ArrayType(ty)) => {
CompositeInnerType::Array(ArrayType(ty)) => {
TypeSection::encode_array(sink, &ty.element_type, ty.mutable)
}
CompositeType::Struct(ty) => {
CompositeInnerType::Struct(ty) => {
TypeSection::encode_struct(sink, ty.fields.iter().cloned())
}
}
}
}

/// A [`CompositeType`] can contain one of these types.
#[derive(Debug, Clone)]
pub enum CompositeInnerType {
/// The type is for a function.
Func(FuncType),
/// The type is for an array.
Array(ArrayType),
/// The type is for a struct.
Struct(StructType),
}

/// Represents a type of a function in a WebAssembly module.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct FuncType {
Expand Down Expand Up @@ -635,18 +648,20 @@ impl Section for TypeSection {

#[cfg(test)]
mod tests {
use wasmparser::WasmFeatures;

use super::*;
use crate::Module;
use wasmparser::WasmFeatures;

#[test]
fn func_types_dont_require_wasm_gc() {
let mut types = TypeSection::new();
types.subtype(&SubType {
is_final: true,
supertype_idx: None,
composite_type: CompositeType::Func(FuncType::new([], [])),
composite_type: CompositeType {
inner: CompositeInnerType::Func(FuncType::new([], [])),
shared: false,
},
});

let mut module = Module::new();
Expand Down
18 changes: 11 additions & 7 deletions crates/wasm-encoder/src/reencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1001,16 +1001,20 @@ pub mod utils {
reencoder: &mut T,
composite_ty: wasmparser::CompositeType,
) -> Result<crate::CompositeType, Error<T::Error>> {
Ok(match composite_ty {
wasmparser::CompositeType::Func(f) => {
crate::CompositeType::Func(reencoder.func_type(f)?)
let inner = match composite_ty.inner {
wasmparser::CompositeInnerType::Func(f) => {
crate::CompositeInnerType::Func(reencoder.func_type(f)?)
}
wasmparser::CompositeType::Array(a) => {
crate::CompositeType::Array(reencoder.array_type(a)?)
wasmparser::CompositeInnerType::Array(a) => {
crate::CompositeInnerType::Array(reencoder.array_type(a)?)
}
wasmparser::CompositeType::Struct(s) => {
crate::CompositeType::Struct(reencoder.struct_type(s)?)
wasmparser::CompositeInnerType::Struct(s) => {
crate::CompositeInnerType::Struct(reencoder.struct_type(s)?)
}
};
Ok(crate::CompositeType {
inner,
shared: composite_ty.shared,
})
}

Expand Down
22 changes: 15 additions & 7 deletions crates/wasm-smith/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -714,9 +714,12 @@ impl ComponentBuilder {
});
let ty_idx = u32::try_from(types.len()).unwrap();
types.push(realloc_ty.clone());
defs.push(ModuleTypeDef::TypeDef(crate::core::CompositeType::Func(
realloc_ty.clone(),
)));
defs.push(ModuleTypeDef::TypeDef(
crate::core::CompositeType::new_func(
realloc_ty.clone(),
false, // TODO: handle shared
),
));
defs.push(ModuleTypeDef::Export(
"canonical_abi_realloc".into(),
crate::core::EntityType::Func(ty_idx, realloc_ty),
Expand All @@ -737,9 +740,12 @@ impl ComponentBuilder {
});
let ty_idx = u32::try_from(types.len()).unwrap();
types.push(free_ty.clone());
defs.push(ModuleTypeDef::TypeDef(crate::core::CompositeType::Func(
free_ty.clone(),
)));
defs.push(ModuleTypeDef::TypeDef(
crate::core::CompositeType::new_func(
free_ty.clone(),
false, // TODO: handle shared
),
));
defs.push(ModuleTypeDef::Export(
"canonical_abi_free".into(),
crate::core::EntityType::Func(ty_idx, free_ty),
Expand Down Expand Up @@ -832,7 +838,9 @@ impl ComponentBuilder {
0,
)?;
types.push(ty.clone());
defs.push(ModuleTypeDef::TypeDef(crate::core::CompositeType::Func(ty)));
defs.push(ModuleTypeDef::TypeDef(
crate::core::CompositeType::new_func(ty, false),
)); // TODO: handle shared
}

// Alias
Expand Down
7 changes: 6 additions & 1 deletion crates/wasm-smith/src/component/encode.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::borrow::Cow;

use crate::core::{CompositeInnerType, CompositeType};

use super::*;
use wasm_encoder::{ComponentExportKind, ComponentOuterAliasKind, ExportKind};

Expand Down Expand Up @@ -124,7 +126,10 @@ impl CoreType {
let mut enc_mod_ty = wasm_encoder::ModuleType::new();
for def in &mod_ty.defs {
match def {
ModuleTypeDef::TypeDef(crate::core::CompositeType::Func(func_ty)) => {
ModuleTypeDef::TypeDef(CompositeType {
inner: CompositeInnerType::Func(func_ty),
..
}) => {
enc_mod_ty.ty().function(
func_ty.params.iter().copied(),
func_ty.results.iter().copied(),
Expand Down
Loading

0 comments on commit 6fc1601

Please sign in to comment.