Skip to content

Commit

Permalink
Enable the ref_{test,cast}.wast GC spec tests
Browse files Browse the repository at this point in the history
This involved implementing a few new instructions:

* `struct.new_default`
* `array.new_default`
* `any.convert_extern`
* `extern.convert_any`

These new instructions will be more thoroughly tested when I get to enabling
their relevant spec tests (which require even more new instructions).
  • Loading branch information
fitzgen committed Dec 14, 2023
1 parent 0f9476a commit c07d230
Show file tree
Hide file tree
Showing 13 changed files with 1,237 additions and 52 deletions.
13 changes: 13 additions & 0 deletions crates/wasmparser/src/binary_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1001,11 +1001,24 @@ impl<'a> BinaryReader<'a> {
{
let code = self.read_var_u32()?;
Ok(match code {
0x01 => {
let type_index = self.read_var_u32()?;
visitor.visit_struct_new_default(type_index)
}

0x07 => {
let type_index = self.read_var_u32()?;
visitor.visit_array_new_default(type_index)
}

0x14 => visitor.visit_ref_test_non_null(self.read()?),
0x15 => visitor.visit_ref_test_nullable(self.read()?),
0x16 => visitor.visit_ref_cast_non_null(self.read()?),
0x17 => visitor.visit_ref_cast_nullable(self.read()?),

0x1a => visitor.visit_any_convert_extern(),
0x1b => visitor.visit_extern_convert_any(),

0x1c => visitor.visit_ref_i31(),
0x1d => visitor.visit_i31_get_s(),
0x1e => visitor.visit_i31_get_u(),
Expand Down
10 changes: 7 additions & 3 deletions crates/wasmparser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,13 +316,17 @@ macro_rules! for_each_operator {
// 0xFB prefixed operators
// Garbage Collection
// http://github.com/WebAssembly/gc
@gc RefI31 => visit_ref_i31
@gc I31GetS => visit_i31_get_s
@gc I31GetU => visit_i31_get_u
@gc StructNewDefault { type_index: u32 } => visit_struct_new_default
@gc ArrayNewDefault { type_index: u32 } => visit_array_new_default
@gc RefTestNonNull { hty: $crate::HeapType } => visit_ref_test_non_null
@gc RefTestNullable { hty: $crate::HeapType } => visit_ref_test_nullable
@gc RefCastNonNull { hty: $crate::HeapType } => visit_ref_cast_non_null
@gc RefCastNullable { hty: $crate::HeapType } => visit_ref_cast_nullable
@gc AnyConvertExtern => visit_any_convert_extern
@gc ExternConvertAny => visit_extern_convert_any
@gc RefI31 => visit_ref_i31
@gc I31GetS => visit_i31_get_s
@gc I31GetU => visit_i31_get_u

// 0xFC operators
// Non-trapping Float-to-int Conversions
Expand Down
39 changes: 39 additions & 0 deletions crates/wasmparser/src/readers/core/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,24 @@ pub struct SubType {
pub composite_type: CompositeType,
}

impl std::fmt::Display for SubType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_final && self.supertype_idx.is_none() {
std::fmt::Display::fmt(&self.composite_type, f)
} else {
write!(f, "(sub ")?;
if self.is_final {
write!(f, "final ")?;
}
if let Some(idx) = self.supertype_idx {
write!(f, "{idx} ")?;
}
std::fmt::Display::fmt(&self.composite_type, f)?;
write!(f, ")")
}
}
}

impl SubType {
/// Unwrap an `ArrayType` or panic.
///
Expand Down Expand Up @@ -472,6 +490,16 @@ pub enum CompositeType {
Struct(StructType),
}

impl std::fmt::Display for CompositeType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Array(_) => write!(f, "(array ...)"),
Self::Func(_) => write!(f, "(func ...)"),
Self::Struct(_) => write!(f, "(struct ...)"),
}
}
}

impl CompositeType {
/// Unwrap a `FuncType` or panic.
pub fn unwrap_func(&self) -> &FuncType {
Expand Down Expand Up @@ -629,6 +657,17 @@ pub enum StorageType {
Val(ValType),
}

impl StorageType {
/// Unpack this storage type into the valtype that it is represented as on
/// the operand stack.
pub fn unpack(&self) -> ValType {
match *self {
Self::Val(ty) => ty,
Self::I8 | Self::I16 => ValType::I32,
}
}
}

/// Represents a type of a struct in a WebAssembly module.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct StructType {
Expand Down
103 changes: 93 additions & 10 deletions crates/wasmparser/src/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,39 @@
* limitations under the License.
*/

use crate::types::CoreTypeId;
use crate::{
BinaryReaderError, FuncType, GlobalType, HeapType, MemoryType, RefType, TableType, ValType,
WasmFeatures,
types::CoreTypeId, ArrayType, BinaryReaderError, CompositeType, FuncType, GlobalType, HeapType,
MemoryType, RefType, StructType, SubType, TableType, ValType, WasmFeatures,
};
use std::ops::Range;

/// Types that qualify as Wasm sub types for validation purposes.
pub trait WasmSubType: Clone + std::fmt::Display {
/// The associated array type.
type ArrayType: WasmArrayType;

/// The associated function type.
type FuncType: WasmFuncType;

/// The associated struct type.
type StructType: WasmStructType;

/// Get the underlying array type, if any.
fn as_array_type(&self) -> Option<&Self::ArrayType>;

/// Get the underlying func type, if any.
fn as_func_type(&self) -> Option<&Self::FuncType>;

/// Get the underlying struct type, if any.
fn as_struct_type(&self) -> Option<&Self::StructType>;
}

/// Types that qualify as Wasm array types for validation purposes.
pub trait WasmArrayType: Clone {
/// Get the array's field type.
fn field_type(&self) -> crate::FieldType;
}

/// Types that qualify as Wasm function types for validation purposes.
pub trait WasmFuncType: Clone {
/// Returns the number of input types.
Expand Down Expand Up @@ -73,6 +99,15 @@ pub trait WasmFuncType: Clone {
}
}

/// Types that qualify as Wasm struct types for validation purposes.
pub trait WasmStructType: Clone {
/// Get the number of fields in this struct.
fn len_fields(&self) -> usize;

/// Get the field at the given index.
fn field_at(&self, at: u32) -> Option<crate::FieldType>;
}

impl<T> WasmFuncType for &'_ T
where
T: ?Sized + WasmFuncType,
Expand Down Expand Up @@ -192,6 +227,9 @@ where
/// structure while parsing and also validate at the same time without
/// the need of an additional parsing or validation step or copying data around.
pub trait WasmModuleResources {
/// The sub type used for validation.
type SubType: WasmSubType<FuncType = Self::FuncType>;

/// The function type used for validation.
type FuncType: WasmFuncType;

Expand All @@ -213,10 +251,10 @@ pub trait WasmModuleResources {
/// The global's value type must be canonicalized.
fn global_at(&self, at: u32) -> Option<GlobalType>;

/// Returns the `FuncType` associated with the given type index.
/// Returns the `SubType` associated with the given type index.
///
/// The function type must be canonicalized.
fn func_type_at(&self, type_idx: u32) -> Option<&Self::FuncType>;
/// The sub type must be canonicalized.
fn sub_type_at(&self, type_index: u32) -> Option<&Self::SubType>;

/// Returns the type id associated with the given function
/// index.
Expand Down Expand Up @@ -289,6 +327,7 @@ impl<T> WasmModuleResources for &'_ T
where
T: ?Sized + WasmModuleResources,
{
type SubType = T::SubType;
type FuncType = T::FuncType;

fn table_at(&self, at: u32) -> Option<TableType> {
Expand All @@ -303,8 +342,8 @@ where
fn global_at(&self, at: u32) -> Option<GlobalType> {
T::global_at(self, at)
}
fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> {
T::func_type_at(self, at)
fn sub_type_at(&self, at: u32) -> Option<&Self::SubType> {
T::sub_type_at(self, at)
}
fn type_id_of_function(&self, func_idx: u32) -> Option<CoreTypeId> {
T::type_id_of_function(self, func_idx)
Expand Down Expand Up @@ -340,6 +379,7 @@ impl<T> WasmModuleResources for std::sync::Arc<T>
where
T: WasmModuleResources,
{
type SubType = T::SubType;
type FuncType = T::FuncType;

fn table_at(&self, at: u32) -> Option<TableType> {
Expand All @@ -358,8 +398,8 @@ where
T::global_at(self, at)
}

fn func_type_at(&self, type_idx: u32) -> Option<&Self::FuncType> {
T::func_type_at(self, type_idx)
fn sub_type_at(&self, type_idx: u32) -> Option<&Self::SubType> {
T::sub_type_at(self, type_idx)
}

fn type_id_of_function(&self, func_idx: u32) -> Option<CoreTypeId> {
Expand Down Expand Up @@ -399,6 +439,39 @@ where
}
}

impl WasmSubType for SubType {
type ArrayType = ArrayType;
type FuncType = FuncType;
type StructType = StructType;

fn as_array_type(&self) -> Option<&Self::ArrayType> {
match &self.composite_type {
CompositeType::Array(a) => Some(a),
_ => None,
}
}

fn as_func_type(&self) -> Option<&Self::FuncType> {
match &self.composite_type {
CompositeType::Func(f) => Some(f),
_ => None,
}
}

fn as_struct_type(&self) -> Option<&Self::StructType> {
match &self.composite_type {
CompositeType::Struct(s) => Some(s),
_ => None,
}
}
}

impl WasmArrayType for ArrayType {
fn field_type(&self) -> crate::FieldType {
self.0
}
}

impl WasmFuncType for FuncType {
fn len_inputs(&self) -> usize {
self.params().len()
Expand All @@ -416,3 +489,13 @@ impl WasmFuncType for FuncType {
self.results().get(at as usize).copied()
}
}

impl WasmStructType for StructType {
fn len_fields(&self) -> usize {
self.fields.len()
}

fn field_at(&self, at: u32) -> Option<crate::FieldType> {
self.fields.get(usize::try_from(at).unwrap()).copied()
}
}
30 changes: 13 additions & 17 deletions crates/wasmparser/src/validator/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use super::{
operators::{ty_to_str, OperatorValidator, OperatorValidatorAllocations},
types::{CoreTypeId, EntityType, RecGroupId, TypeAlloc, TypeList},
};
use crate::validator::types::TypeIdentifier;
use crate::{
limits::*, BinaryReaderError, CompositeType, ConstExpr, Data, DataKind, Element, ElementKind,
ExternalKind, FuncType, Global, GlobalType, HeapType, MemoryType, PackedIndex, RecGroup,
RefType, Result, StorageType, SubType, Table, TableInit, TableType, TagType, TypeRef,
UnpackedIndex, ValType, VisitOperator, WasmFeatures, WasmModuleResources,
limits::*, validator::types::TypeIdentifier, BinaryReaderError, CompositeType, ConstExpr, Data,
DataKind, Element, ElementKind, ExternalKind, FuncType, Global, GlobalType, HeapType,
MemoryType, PackedIndex, RecGroup, RefType, Result, StorageType, SubType, Table, TableInit,
TableType, TagType, TypeRef, UnpackedIndex, ValType, VisitOperator, WasmFeatures,
WasmModuleResources, WasmSubType,
};
use indexmap::IndexMap;
use std::mem;
Expand Down Expand Up @@ -1155,6 +1155,7 @@ struct OperatorValidatorResources<'a> {
}

impl WasmModuleResources for OperatorValidatorResources<'_> {
type SubType = crate::SubType;
type FuncType = crate::FuncType;

fn table_at(&self, at: u32) -> Option<TableType> {
Expand All @@ -1174,12 +1175,9 @@ impl WasmModuleResources for OperatorValidatorResources<'_> {
self.module.globals.get(at as usize).cloned()
}

fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> {
fn sub_type_at(&self, at: u32) -> Option<&Self::SubType> {
let id = *self.module.types.get(at as usize)?;
match &self.types[id].composite_type {
CompositeType::Func(f) => Some(f),
_ => None,
}
Some(&self.types[id])
}

fn type_id_of_function(&self, at: u32) -> Option<CoreTypeId> {
Expand All @@ -1189,7 +1187,7 @@ impl WasmModuleResources for OperatorValidatorResources<'_> {

fn type_of_function(&self, at: u32) -> Option<&Self::FuncType> {
let type_index = self.module.functions.get(at as usize)?;
self.func_type_at(*type_index)
self.sub_type_at(*type_index)?.as_func_type()
}

fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<()> {
Expand Down Expand Up @@ -1226,6 +1224,7 @@ impl WasmModuleResources for OperatorValidatorResources<'_> {
pub struct ValidatorResources(pub(crate) Arc<Module>);

impl WasmModuleResources for ValidatorResources {
type SubType = crate::SubType;
type FuncType = crate::FuncType;

fn table_at(&self, at: u32) -> Option<TableType> {
Expand All @@ -1249,13 +1248,10 @@ impl WasmModuleResources for ValidatorResources {
self.0.globals.get(at as usize).cloned()
}

fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> {
fn sub_type_at(&self, at: u32) -> Option<&Self::SubType> {
let id = *self.0.types.get(at as usize)?;
let types = self.0.snapshot.as_ref().unwrap();
match &types[id].composite_type {
CompositeType::Func(f) => Some(f),
_ => None,
}
Some(&types[id])
}

fn type_id_of_function(&self, at: u32) -> Option<CoreTypeId> {
Expand All @@ -1265,7 +1261,7 @@ impl WasmModuleResources for ValidatorResources {

fn type_of_function(&self, at: u32) -> Option<&Self::FuncType> {
let type_index = *self.0.functions.get(at as usize)?;
self.func_type_at(type_index)
self.sub_type_at(type_index)?.as_func_type()
}

fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<()> {
Expand Down
Loading

0 comments on commit c07d230

Please sign in to comment.