Skip to content
This repository was archived by the owner on Jun 16, 2020. It is now read-only.

Commit fb3185b

Browse files
eqrionyurydelendik
authored andcommitted
Improve support for reftypes (#168)
* Add nullref as an externally specifiable type Spec commit: WebAssembly/reference-types@d4bc208 * Add typed select operator for reference types proposal The reftypes proposal adds a typed select operator to simplify type checking for reference types. The existing select operator is henceforth limited to operate on the original MVP types only. Spec change: WebAssembly/reference-types#43
1 parent 4341537 commit fb3185b

File tree

4 files changed

+47
-13
lines changed

4 files changed

+47
-13
lines changed

src/binary_reader.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ impl<'a> BinaryReader<'a> {
188188
-0x05 => Ok(Type::V128),
189189
-0x10 => Ok(Type::AnyFunc),
190190
-0x11 => Ok(Type::AnyRef),
191+
-0x12 => Ok(Type::NullRef),
191192
-0x20 => Ok(Type::Func),
192193
-0x40 => Ok(Type::EmptyBlockType),
193194
_ => Err(BinaryReaderError {
@@ -987,6 +988,18 @@ impl<'a> BinaryReader<'a> {
987988
},
988989
0x1a => Operator::Drop,
989990
0x1b => Operator::Select,
991+
0x1c => {
992+
let results = self.read_var_u32()?;
993+
if results != 1 {
994+
return Err(BinaryReaderError {
995+
message: "bad number of results",
996+
offset: self.position,
997+
});
998+
}
999+
Operator::TypedSelect {
1000+
ty: self.read_type()?,
1001+
}
1002+
}
9901003
0x20 => Operator::LocalGet {
9911004
local_index: self.read_var_u32()?,
9921005
},

src/operators_validator.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ use crate::primitives::{
2626
pub(crate) fn is_subtype_supertype(subtype: Type, supertype: Type) -> bool {
2727
match supertype {
2828
Type::AnyRef => {
29-
subtype == Type::AnyRef || subtype == Type::AnyFunc || subtype == Type::Null
29+
subtype == Type::AnyRef || subtype == Type::AnyFunc || subtype == Type::NullRef
3030
}
31-
Type::AnyFunc => subtype == Type::AnyFunc || subtype == Type::Null,
31+
Type::AnyFunc => subtype == Type::AnyFunc || subtype == Type::NullRef,
3232
_ => subtype == supertype,
3333
}
3434
}
@@ -624,28 +624,35 @@ impl OperatorValidator {
624624
self.check_frame_size(3)?;
625625
let func_state = &self.func_state;
626626
let last_block = func_state.last_block();
627-
Ok(if last_block.is_stack_polymorphic() {
627+
628+
let ty = if last_block.is_stack_polymorphic() {
628629
match func_state.stack_types.len() - last_block.stack_starts_at {
629-
0 => None,
630+
0 => return Ok(None),
630631
1 => {
631632
self.check_operands_1(Type::I32)?;
632-
None
633+
return Ok(None);
633634
}
634635
2 => {
635636
self.check_operands_1(Type::I32)?;
636-
Some(func_state.stack_types[func_state.stack_types.len() - 2])
637+
func_state.stack_types[func_state.stack_types.len() - 2]
637638
}
638639
_ => {
639640
let ty = func_state.stack_types[func_state.stack_types.len() - 3];
640641
self.check_operands_2(ty, Type::I32)?;
641-
Some(ty)
642+
ty
642643
}
643644
}
644645
} else {
645646
let ty = func_state.stack_types[func_state.stack_types.len() - 3];
646647
self.check_operands_2(ty, Type::I32)?;
647-
Some(ty)
648-
})
648+
ty
649+
};
650+
651+
if !ty.is_valid_for_old_select() {
652+
return Err("invalid type for select");
653+
}
654+
655+
Ok(Some(ty))
649656
}
650657

651658
pub(crate) fn process_operator(
@@ -761,6 +768,10 @@ impl OperatorValidator {
761768
let ty = self.check_select()?;
762769
self.func_state.change_frame_after_select(ty)?;
763770
}
771+
Operator::TypedSelect { ty } => {
772+
self.check_operands(&[Type::I32, ty, ty])?;
773+
self.func_state.change_frame_after_select(Some(ty))?;
774+
}
764775
Operator::LocalGet { local_index } => {
765776
if local_index as usize >= self.func_state.local_types.len() {
766777
return Err("local index out of bounds");
@@ -1323,7 +1334,7 @@ impl OperatorValidator {
13231334
}
13241335
Operator::RefNull => {
13251336
self.check_reference_types_enabled()?;
1326-
self.func_state.change_frame_with_type(0, Type::Null)?;
1337+
self.func_state.change_frame_with_type(0, Type::NullRef)?;
13271338
}
13281339
Operator::RefIsNull => {
13291340
self.check_reference_types_enabled()?;

src/primitives.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,18 @@ pub enum Type {
7878
V128,
7979
AnyFunc,
8080
AnyRef,
81+
NullRef,
8182
Func,
8283
EmptyBlockType,
83-
Null,
84+
}
85+
86+
impl Type {
87+
pub(crate) fn is_valid_for_old_select(&self) -> bool {
88+
match self {
89+
Type::I32 | Type::I64 | Type::F32 | Type::F64 => true,
90+
_ => false,
91+
}
92+
}
8493
}
8594

8695
/// Either a value type or a function type.
@@ -246,6 +255,7 @@ pub enum Operator<'a> {
246255
CallIndirect { index: u32, table_index: u32 },
247256
Drop,
248257
Select,
258+
TypedSelect { ty: Type },
249259
LocalGet { local_index: u32 },
250260
LocalSet { local_index: u32 },
251261
LocalTee { local_index: u32 },

src/validator.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ impl<'a> ValidatingParser<'a> {
195195
fn check_value_type(&self, ty: Type) -> ValidatorResult<'a, ()> {
196196
match ty {
197197
Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()),
198-
Type::Null | Type::AnyFunc | Type::AnyRef => {
198+
Type::NullRef | Type::AnyFunc | Type::AnyRef => {
199199
if !self.config.operator_config.enable_reference_types {
200200
return self.create_error("reference types support is not enabled");
201201
}
@@ -316,7 +316,7 @@ impl<'a> ValidatingParser<'a> {
316316
if !self.config.operator_config.enable_reference_types {
317317
return self.create_error("reference types support is not enabled");
318318
}
319-
Type::Null
319+
Type::NullRef
320320
}
321321
Operator::V128Const { .. } => {
322322
if !self.config.operator_config.enable_simd {

0 commit comments

Comments
 (0)