Skip to content

Commit e75f45c

Browse files
committed
Update implementation of reference types
Update the implementation given WebAssembly/reference-types#87 which has a number of changes to the reference types implementation: * Subtyping is removed * `nullref` as a type was removed * `anyref` was renamed to `externref` * `ref.null` and `ref.is_null` take immediate type arguments as to what kind of `null` they're producing. The spec testsuite repo has not yet updated with this change yet, so the tests are temporarily vendored here in the `tests/wast` directory.
1 parent 75c40a0 commit e75f45c

39 files changed

+28083
-83
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ edition = "2018"
1515
anyhow = "1.0"
1616
criterion = "0.3"
1717
getopts = "0.2"
18-
wast = "15.0.0"
18+
wast = { path = "../wat/crates/wast" }
1919
wat = "1.0.16"
2020
rayon = "1.3"
2121

src/binary_reader.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,8 @@ impl<'a> BinaryReader<'a> {
186186
-0x03 => Ok(Type::F32),
187187
-0x04 => Ok(Type::F64),
188188
-0x05 => Ok(Type::V128),
189-
-0x10 => Ok(Type::AnyFunc),
190-
-0x11 => Ok(Type::AnyRef),
191-
-0x12 => Ok(Type::NullRef),
189+
-0x10 => Ok(Type::FuncRef),
190+
-0x11 => Ok(Type::ExternRef),
192191
-0x20 => Ok(Type::Func),
193192
-0x40 => Ok(Type::EmptyBlockType),
194193
_ => Err(BinaryReaderError::new(
@@ -984,7 +983,7 @@ impl<'a> BinaryReader<'a> {
984983
let results = self.read_var_u32()?;
985984
if results != 1 {
986985
return Err(BinaryReaderError::new(
987-
"bad number of results",
986+
"invalid result arity",
988987
self.position,
989988
));
990989
}
@@ -1230,8 +1229,12 @@ impl<'a> BinaryReader<'a> {
12301229
0xc3 => Operator::I64Extend16S,
12311230
0xc4 => Operator::I64Extend32S,
12321231

1233-
0xd0 => Operator::RefNull,
1234-
0xd1 => Operator::RefIsNull,
1232+
0xd0 => Operator::RefNull {
1233+
ty: self.read_type()?,
1234+
},
1235+
0xd1 => Operator::RefIsNull {
1236+
ty: self.read_type()?,
1237+
},
12351238
0xd2 => Operator::RefFunc {
12361239
function_index: self.read_var_u32()?,
12371240
},

src/operators_validator.rs

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,6 @@ use crate::{
2121
WasmMemoryType, WasmModuleResources, WasmTableType, WasmType,
2222
};
2323

24-
/// Test if `subtype` is a subtype of `supertype`.
25-
pub(crate) fn is_subtype_supertype(subtype: Type, supertype: Type) -> bool {
26-
match supertype {
27-
Type::AnyRef => {
28-
subtype == Type::AnyRef || subtype == Type::AnyFunc || subtype == Type::NullRef
29-
}
30-
Type::AnyFunc => subtype == Type::AnyFunc || subtype == Type::NullRef,
31-
_ => subtype == supertype,
32-
}
33-
}
34-
3524
#[derive(Debug)]
3625
struct BlockState {
3726
start_types: Vec<Type>,
@@ -79,10 +68,7 @@ impl FuncState {
7968
return true;
8069
}
8170
assert!(stack_starts_at + index < self.stack_types.len());
82-
is_subtype_supertype(
83-
self.stack_types[self.stack_types.len() - 1 - index],
84-
expected,
85-
)
71+
self.stack_types[self.stack_types.len() - 1 - index] == expected
8672
}
8773
fn assert_block_stack_len(&self, depth: usize, minimal_len: usize) -> bool {
8874
assert!(depth < self.blocks.len());
@@ -364,7 +350,7 @@ pub(crate) fn check_value_type(
364350
) -> OperatorValidatorResult<()> {
365351
match ty {
366352
Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()),
367-
Type::NullRef | Type::AnyFunc | Type::AnyRef => {
353+
Type::FuncRef | Type::ExternRef => {
368354
if !operator_config.enable_reference_types {
369355
return Err(OperatorValidatorError::new(
370356
"reference types support is not enabled",
@@ -784,7 +770,7 @@ impl OperatorValidator {
784770
| TypeOrFuncType::Type(Type::I64)
785771
| TypeOrFuncType::Type(Type::F32)
786772
| TypeOrFuncType::Type(Type::F64) => Ok(()),
787-
TypeOrFuncType::Type(Type::AnyRef) | TypeOrFuncType::Type(Type::AnyFunc) => {
773+
TypeOrFuncType::Type(Type::ExternRef) | TypeOrFuncType::Type(Type::FuncRef) => {
788774
self.check_reference_types_enabled()
789775
}
790776
TypeOrFuncType::Type(Type::V128) => self.check_simd_enabled(),
@@ -879,10 +865,6 @@ impl OperatorValidator {
879865
ty
880866
};
881867

882-
if !ty.is_valid_for_old_select() {
883-
return Err(OperatorValidatorError::new("invalid type for select"));
884-
}
885-
886868
Ok(Some(ty))
887869
}
888870

@@ -1033,10 +1015,17 @@ impl OperatorValidator {
10331015
}
10341016
Operator::Select => {
10351017
let ty = self.check_select()?;
1018+
match ty {
1019+
Some(Type::I32) | Some(Type::I64) | Some(Type::F32) | Some(Type::F64) => {}
1020+
Some(_) => {
1021+
bail_op_err!("type mismatch: only integer types allowed with bare `select`")
1022+
}
1023+
None => {}
1024+
}
10361025
self.func_state.change_frame_after_select(ty)?;
10371026
}
10381027
Operator::TypedSelect { ty } => {
1039-
self.check_operands_3(Type::I32, ty, ty)?;
1028+
self.check_operands_3(ty, ty, Type::I32)?;
10401029
self.func_state.change_frame_after_select(Some(ty))?;
10411030
}
10421031
Operator::LocalGet { local_index } => {
@@ -1608,13 +1597,29 @@ impl OperatorValidator {
16081597
));
16091598
}
16101599
}
1611-
Operator::RefNull => {
1600+
Operator::RefNull { ty } => {
16121601
self.check_reference_types_enabled()?;
1613-
self.func_state.change_frame_with_type(0, Type::NullRef)?;
1602+
match ty {
1603+
Type::FuncRef | Type::ExternRef => {}
1604+
_ => {
1605+
return Err(OperatorValidatorError::new(
1606+
"invalid reference type in ref.null",
1607+
))
1608+
}
1609+
}
1610+
self.func_state.change_frame_with_type(0, ty)?;
16141611
}
1615-
Operator::RefIsNull => {
1612+
Operator::RefIsNull { ty } => {
16161613
self.check_reference_types_enabled()?;
1617-
self.check_operands_1(Type::AnyRef)?;
1614+
match ty {
1615+
Type::FuncRef | Type::ExternRef => {}
1616+
_ => {
1617+
return Err(OperatorValidatorError::new(
1618+
"invalid reference type in ref.is_null",
1619+
))
1620+
}
1621+
}
1622+
self.check_operands_1(ty)?;
16181623
self.func_state.change_frame_with_type(1, Type::I32)?;
16191624
}
16201625
Operator::RefFunc { function_index } => {
@@ -1624,7 +1629,7 @@ impl OperatorValidator {
16241629
"unknown function: function index out of bounds",
16251630
));
16261631
}
1627-
self.func_state.change_frame_with_type(0, Type::AnyFunc)?;
1632+
self.func_state.change_frame_with_type(0, Type::FuncRef)?;
16281633
}
16291634
Operator::V128Load { memarg } => {
16301635
self.check_simd_enabled()?;
@@ -1966,9 +1971,7 @@ impl OperatorValidator {
19661971
Operator::DataDrop { segment } => {
19671972
self.check_bulk_memory_enabled()?;
19681973
if segment >= resources.data_count() {
1969-
return Err(OperatorValidatorError::new(
1970-
"unknown data segment: segment index out of bounds",
1971-
));
1974+
bail_op_err!("unknown data segment {}", segment);
19721975
}
19731976
}
19741977
Operator::MemoryCopy | Operator::MemoryFill => {
@@ -1993,7 +1996,7 @@ impl OperatorValidator {
19931996
segment
19941997
),
19951998
};
1996-
if !is_subtype_supertype(segment_ty, table.element_type().to_parser_type()) {
1999+
if segment_ty != table.element_type().to_parser_type() {
19972000
return Err(OperatorValidatorError::new("type mismatch"));
19982001
}
19992002
self.check_operands_3(Type::I32, Type::I32, Type::I32)?;
@@ -2021,10 +2024,7 @@ impl OperatorValidator {
20212024
(Some(a), Some(b)) => (a, b),
20222025
_ => return Err(OperatorValidatorError::new("table index out of bounds")),
20232026
};
2024-
if !is_subtype_supertype(
2025-
src.element_type().to_parser_type(),
2026-
dst.element_type().to_parser_type(),
2027-
) {
2027+
if src.element_type().to_parser_type() != dst.element_type().to_parser_type() {
20282028
return Err(OperatorValidatorError::new("type mismatch"));
20292029
}
20302030
self.check_operands_3(Type::I32, Type::I32, Type::I32)?;

src/primitives.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,22 +107,12 @@ pub enum Type {
107107
F32,
108108
F64,
109109
V128,
110-
AnyFunc,
111-
AnyRef,
112-
NullRef,
110+
FuncRef,
111+
ExternRef,
113112
Func,
114113
EmptyBlockType,
115114
}
116115

117-
impl Type {
118-
pub(crate) fn is_valid_for_old_select(self) -> bool {
119-
match self {
120-
Type::I32 | Type::I64 | Type::F32 | Type::F64 => true,
121-
_ => false,
122-
}
123-
}
124-
}
125-
126116
/// Either a value type or a function type.
127117
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
128118
pub enum TypeOrFuncType {
@@ -321,8 +311,8 @@ pub enum Operator<'a> {
321311
I64Const { value: i64 },
322312
F32Const { value: Ieee32 },
323313
F64Const { value: Ieee64 },
324-
RefNull,
325-
RefIsNull,
314+
RefNull { ty: Type },
315+
RefIsNull { ty: Type },
326316
RefFunc { function_index: u32 },
327317
I32Eqz,
328318
I32Eq,

src/readers/element_section.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub struct ElementItems<'a> {
4545

4646
#[derive(Debug)]
4747
pub enum ElementItem {
48-
Null,
48+
Null(Type),
4949
Func(u32),
5050
}
5151

@@ -91,7 +91,7 @@ impl<'a> ElementItemsReader<'a> {
9191
if self.exprs {
9292
let offset = self.reader.original_position();
9393
let ret = match self.reader.read_operator()? {
94-
Operator::RefNull => ElementItem::Null,
94+
Operator::RefNull { ty } => ElementItem::Null(ty),
9595
Operator::RefFunc { function_index } => ElementItem::Func(function_index),
9696
_ => return Err(BinaryReaderError::new("invalid passive segment", offset)),
9797
};
@@ -229,7 +229,7 @@ impl<'a> ElementSectionReader<'a> {
229229
self.reader.read_type()?
230230
} else {
231231
match self.reader.read_external_kind()? {
232-
ExternalKind::Function => Type::AnyFunc,
232+
ExternalKind::Function => Type::FuncRef,
233233
_ => {
234234
return Err(BinaryReaderError::new(
235235
"only the function external type is supported in elem segment",
@@ -239,7 +239,7 @@ impl<'a> ElementSectionReader<'a> {
239239
}
240240
}
241241
} else {
242-
Type::AnyFunc
242+
Type::FuncRef
243243
};
244244
let data_start = self.reader.position;
245245
let items_count = self.reader.read_var_u32()?;

src/validator.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ use crate::primitives::{
3030
};
3131

3232
use crate::operators_validator::{
33-
check_value_type, is_subtype_supertype, FunctionEnd, OperatorValidator,
34-
OperatorValidatorConfig, OperatorValidatorError, DEFAULT_OPERATOR_VALIDATOR_CONFIG,
33+
check_value_type, FunctionEnd, OperatorValidator, OperatorValidatorConfig,
34+
OperatorValidatorError, DEFAULT_OPERATOR_VALIDATOR_CONFIG,
3535
};
3636
use crate::parser::{Parser, ParserInput, ParserState, WasmDecoder};
3737
use crate::{ElemSectionEntryTable, ElementItem};
@@ -251,7 +251,7 @@ impl<'a> ValidatingParser<'a> {
251251

252252
fn check_table_type(&self, table_type: &TableType) -> ValidatorResult<'a, ()> {
253253
match table_type.element_type {
254-
Type::AnyFunc => {}
254+
Type::FuncRef => {}
255255
_ => {
256256
if !self.config.operator_config.enable_reference_types {
257257
return self.create_error("element is not anyfunc");
@@ -332,11 +332,11 @@ impl<'a> ValidatingParser<'a> {
332332
Operator::I64Const { .. } => Type::I64,
333333
Operator::F32Const { .. } => Type::F32,
334334
Operator::F64Const { .. } => Type::F64,
335-
Operator::RefNull => {
335+
Operator::RefNull { ty } => {
336336
if !self.config.operator_config.enable_reference_types {
337337
return self.create_error("reference types support is not enabled");
338338
}
339-
Type::NullRef
339+
ty
340340
}
341341
Operator::V128Const { .. } => {
342342
if !self.config.operator_config.enable_simd {
@@ -358,14 +358,14 @@ impl<'a> ValidatingParser<'a> {
358358
function_index
359359
));
360360
}
361-
Type::AnyFunc
361+
Type::FuncRef
362362
}
363363
_ => {
364364
return self
365365
.create_error("constant expression required: invalid init_expr operator")
366366
}
367367
};
368-
if !is_subtype_supertype(ty, state.ty) {
368+
if ty != state.ty {
369369
return self.create_error("type mismatch: invalid init_expr type");
370370
}
371371
Ok(())
@@ -566,7 +566,7 @@ impl<'a> ValidatingParser<'a> {
566566
return;
567567
}
568568
};
569-
if !is_subtype_supertype(ty, table.element_type) {
569+
if ty != table.element_type {
570570
self.set_validation_error("element_type != table type");
571571
return;
572572
}
@@ -584,9 +584,19 @@ impl<'a> ValidatingParser<'a> {
584584
}
585585
}
586586
}
587-
if !self.config.operator_config.enable_reference_types && ty != Type::AnyFunc {
588-
self.set_validation_error("element_type != anyfunc is not supported yet");
589-
return;
587+
match ty {
588+
Type::FuncRef => {}
589+
Type::ExternRef if self.config.operator_config.enable_reference_types => {}
590+
Type::ExternRef => {
591+
self.set_validation_error(
592+
"reference types must be enabled for anyref elem segment",
593+
);
594+
return;
595+
}
596+
_ => {
597+
self.set_validation_error("invalid reference type");
598+
return;
599+
}
590600
}
591601
}
592602
ParserState::ElementSectionEntryBody(ref indices) => {

0 commit comments

Comments
 (0)