From 061c81c9a851847b040c0bcca17e159968ee9ce6 Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Mon, 6 Jan 2020 13:21:35 -0600 Subject: [PATCH 1/2] Add nullref as an externally specifiable type Spec commit: https://github.com/WebAssembly/reference-types/commit/d4bc208c0f62ac19529e9e734b10c17c960549e5 --- src/binary_reader.rs | 1 + src/operators_validator.rs | 6 +++--- src/primitives.rs | 2 +- src/validator.rs | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/binary_reader.rs b/src/binary_reader.rs index c97b8b82..afa4e221 100644 --- a/src/binary_reader.rs +++ b/src/binary_reader.rs @@ -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 { diff --git a/src/operators_validator.rs b/src/operators_validator.rs index 8a0aafc8..f2967cd7 100644 --- a/src/operators_validator.rs +++ b/src/operators_validator.rs @@ -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, } } @@ -1323,7 +1323,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()?; diff --git a/src/primitives.rs b/src/primitives.rs index 52583752..f1d40046 100644 --- a/src/primitives.rs +++ b/src/primitives.rs @@ -78,9 +78,9 @@ pub enum Type { V128, AnyFunc, AnyRef, + NullRef, Func, EmptyBlockType, - Null, } /// Either a value type or a function type. diff --git a/src/validator.rs b/src/validator.rs index c1a763f1..21269c63 100644 --- a/src/validator.rs +++ b/src/validator.rs @@ -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"); } @@ -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 { From 1525554e0cf9bcf1115ea9267e0177c47238d951 Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Mon, 6 Jan 2020 13:54:03 -0600 Subject: [PATCH 2/2] 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: https://github.com/WebAssembly/reference-types/pull/43 --- src/binary_reader.rs | 12 ++++++++++++ src/operators_validator.rs | 25 ++++++++++++++++++------- src/primitives.rs | 10 ++++++++++ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/binary_reader.rs b/src/binary_reader.rs index afa4e221..1bfbb7f6 100644 --- a/src/binary_reader.rs +++ b/src/binary_reader.rs @@ -988,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()?, }, diff --git a/src/operators_validator.rs b/src/operators_validator.rs index f2967cd7..7e36ef2a 100644 --- a/src/operators_validator.rs +++ b/src/operators_validator.rs @@ -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( @@ -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"); diff --git a/src/primitives.rs b/src/primitives.rs index f1d40046..d6bae3da 100644 --- a/src/primitives.rs +++ b/src/primitives.rs @@ -83,6 +83,15 @@ pub enum Type { EmptyBlockType, } +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. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum TypeOrFuncType { @@ -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 },