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

Commit

Permalink
Improve support for reftypes (#168)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
eqrion authored and yurydelendik committed Jan 9, 2020
1 parent 4341537 commit fb3185b
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 13 deletions.
13 changes: 13 additions & 0 deletions src/binary_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ impl<'a> BinaryReader<'a> {
-0x05 => Ok(Type::V128),
-0x10 => Ok(Type::AnyFunc),
-0x11 => Ok(Type::AnyRef),
-0x12 => Ok(Type::NullRef),
-0x20 => Ok(Type::Func),
-0x40 => Ok(Type::EmptyBlockType),
_ => Err(BinaryReaderError {
Expand Down Expand Up @@ -987,6 +988,18 @@ impl<'a> BinaryReader<'a> {
},
0x1a => Operator::Drop,
0x1b => Operator::Select,
0x1c => {
let results = self.read_var_u32()?;
if results != 1 {
return Err(BinaryReaderError {
message: "bad number of results",
offset: self.position,
});
}
Operator::TypedSelect {
ty: self.read_type()?,
}
}
0x20 => Operator::LocalGet {
local_index: self.read_var_u32()?,
},
Expand Down
31 changes: 21 additions & 10 deletions src/operators_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ use crate::primitives::{
pub(crate) fn is_subtype_supertype(subtype: Type, supertype: Type) -> bool {
match supertype {
Type::AnyRef => {
subtype == Type::AnyRef || subtype == Type::AnyFunc || subtype == Type::Null
subtype == Type::AnyRef || subtype == Type::AnyFunc || subtype == Type::NullRef
}
Type::AnyFunc => subtype == Type::AnyFunc || subtype == Type::Null,
Type::AnyFunc => subtype == Type::AnyFunc || subtype == Type::NullRef,
_ => subtype == supertype,
}
}
Expand Down Expand Up @@ -624,28 +624,35 @@ impl OperatorValidator {
self.check_frame_size(3)?;
let func_state = &self.func_state;
let last_block = func_state.last_block();
Ok(if last_block.is_stack_polymorphic() {

let ty = if last_block.is_stack_polymorphic() {
match func_state.stack_types.len() - last_block.stack_starts_at {
0 => None,
0 => return Ok(None),
1 => {
self.check_operands_1(Type::I32)?;
None
return Ok(None);
}
2 => {
self.check_operands_1(Type::I32)?;
Some(func_state.stack_types[func_state.stack_types.len() - 2])
func_state.stack_types[func_state.stack_types.len() - 2]
}
_ => {
let ty = func_state.stack_types[func_state.stack_types.len() - 3];
self.check_operands_2(ty, Type::I32)?;
Some(ty)
ty
}
}
} else {
let ty = func_state.stack_types[func_state.stack_types.len() - 3];
self.check_operands_2(ty, Type::I32)?;
Some(ty)
})
ty
};

if !ty.is_valid_for_old_select() {
return Err("invalid type for select");
}

Ok(Some(ty))
}

pub(crate) fn process_operator(
Expand Down Expand Up @@ -761,6 +768,10 @@ impl OperatorValidator {
let ty = self.check_select()?;
self.func_state.change_frame_after_select(ty)?;
}
Operator::TypedSelect { ty } => {
self.check_operands(&[Type::I32, ty, ty])?;
self.func_state.change_frame_after_select(Some(ty))?;
}
Operator::LocalGet { local_index } => {
if local_index as usize >= self.func_state.local_types.len() {
return Err("local index out of bounds");
Expand Down Expand Up @@ -1323,7 +1334,7 @@ impl OperatorValidator {
}
Operator::RefNull => {
self.check_reference_types_enabled()?;
self.func_state.change_frame_with_type(0, Type::Null)?;
self.func_state.change_frame_with_type(0, Type::NullRef)?;
}
Operator::RefIsNull => {
self.check_reference_types_enabled()?;
Expand Down
12 changes: 11 additions & 1 deletion src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,18 @@ pub enum Type {
V128,
AnyFunc,
AnyRef,
NullRef,
Func,
EmptyBlockType,
Null,
}

impl Type {
pub(crate) fn is_valid_for_old_select(&self) -> bool {
match self {
Type::I32 | Type::I64 | Type::F32 | Type::F64 => true,
_ => false,
}
}
}

/// Either a value type or a function type.
Expand Down Expand Up @@ -246,6 +255,7 @@ pub enum Operator<'a> {
CallIndirect { index: u32, table_index: u32 },
Drop,
Select,
TypedSelect { ty: Type },
LocalGet { local_index: u32 },
LocalSet { local_index: u32 },
LocalTee { local_index: u32 },
Expand Down
4 changes: 2 additions & 2 deletions src/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ impl<'a> ValidatingParser<'a> {
fn check_value_type(&self, ty: Type) -> ValidatorResult<'a, ()> {
match ty {
Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()),
Type::Null | Type::AnyFunc | Type::AnyRef => {
Type::NullRef | Type::AnyFunc | Type::AnyRef => {
if !self.config.operator_config.enable_reference_types {
return self.create_error("reference types support is not enabled");
}
Expand Down Expand Up @@ -316,7 +316,7 @@ impl<'a> ValidatingParser<'a> {
if !self.config.operator_config.enable_reference_types {
return self.create_error("reference types support is not enabled");
}
Type::Null
Type::NullRef
}
Operator::V128Const { .. } => {
if !self.config.operator_config.enable_simd {
Expand Down

0 comments on commit fb3185b

Please sign in to comment.