Align order of wasm types/values across Wasmtime (#3292)

Wasmtime has a few representations of `Val` and `ValType` across the
internal crates, the `wasmtime` crate, and the C API. These were
previously sometimes mentioned in different orders which means that
converting between the two took a little extra code than before. This
commit is a micro-optimization to align the types across the various
places we define these to help reduce the codegen burden when converting
between these types.

This is not expected to have a major impact on performance, rather it's
a small cleanup which should be easy-ish to preserve I've noticed while
staring at assembly.
This commit is contained in:
Alex Crichton
2021-09-03 11:43:56 -05:00
committed by GitHub
parent e3ccff0249
commit c33700087d
2 changed files with 30 additions and 10 deletions

View File

@@ -22,6 +22,8 @@ pub enum Mutability {
/// A list of all possible value types in WebAssembly. /// A list of all possible value types in WebAssembly.
#[derive(Debug, Clone, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum ValType { pub enum ValType {
// NB: the ordering here is intended to match the ordering in
// `wasmtime_types::WasmType` to help improve codegen when converting.
/// Signed 32 bit integer. /// Signed 32 bit integer.
I32, I32,
/// Signed 64 bit integer. /// Signed 64 bit integer.
@@ -32,10 +34,10 @@ pub enum ValType {
F64, F64,
/// A 128 bit number. /// A 128 bit number.
V128, V128,
/// A reference to opaque data in the Wasm instance.
ExternRef, /* = 128 */
/// A reference to a Wasm function. /// A reference to a Wasm function.
FuncRef, FuncRef,
/// A reference to opaque data in the Wasm instance.
ExternRef,
} }
impl fmt::Display for ValType { impl fmt::Display for ValType {

View File

@@ -9,6 +9,8 @@ use wasmtime_runtime::{self as runtime, VMExternRef};
/// produce. /// produce.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Val { pub enum Val {
// NB: the ordering here is intended to match the ordering in
// `ValType` to improve codegen when learning the type of a value.
/// A 32-bit integer /// A 32-bit integer
I32(i32), I32(i32),
@@ -27,12 +29,8 @@ pub enum Val {
/// `f64::from_bits` to create an `f64` value. /// `f64::from_bits` to create an `f64` value.
F64(u64), F64(u64),
/// An `externref` value which can hold opaque data to the Wasm instance /// A 128-bit number
/// itself. V128(u128),
///
/// `ExternRef(None)` is the null external reference, created by `ref.null
/// extern` in Wasm.
ExternRef(Option<ExternRef>),
/// A first-class reference to a WebAssembly function. /// A first-class reference to a WebAssembly function.
/// ///
@@ -40,14 +38,19 @@ pub enum Val {
/// func` in Wasm. /// func` in Wasm.
FuncRef(Option<Func>), FuncRef(Option<Func>),
/// A 128-bit number /// An `externref` value which can hold opaque data to the Wasm instance
V128(u128), /// itself.
///
/// `ExternRef(None)` is the null external reference, created by `ref.null
/// extern` in Wasm.
ExternRef(Option<ExternRef>),
} }
macro_rules! accessors { macro_rules! accessors {
($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($( ($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
/// Attempt to access the underlying value of this `Val`, returning /// Attempt to access the underlying value of this `Val`, returning
/// `None` if it is not the correct type. /// `None` if it is not the correct type.
#[inline]
pub fn $get(&self) -> Option<$ty> { pub fn $get(&self) -> Option<$ty> {
if let Val::$variant($bind) = self { if let Val::$variant($bind) = self {
Some($cvt) Some($cvt)
@@ -62,6 +65,7 @@ macro_rules! accessors {
/// # Panics /// # Panics
/// ///
/// Panics if `self` is not of the right type. /// Panics if `self` is not of the right type.
#[inline]
pub fn $unwrap(&self) -> $ty { pub fn $unwrap(&self) -> $ty {
self.$get().expect(concat!("expected ", stringify!($ty))) self.$get().expect(concat!("expected ", stringify!($ty)))
} }
@@ -70,11 +74,13 @@ macro_rules! accessors {
impl Val { impl Val {
/// Returns a null `externref` value. /// Returns a null `externref` value.
#[inline]
pub fn null() -> Val { pub fn null() -> Val {
Val::ExternRef(None) Val::ExternRef(None)
} }
/// Returns the corresponding [`ValType`] for this `Val`. /// Returns the corresponding [`ValType`] for this `Val`.
#[inline]
pub fn ty(&self) -> ValType { pub fn ty(&self) -> ValType {
match self { match self {
Val::I32(_) => ValType::I32, Val::I32(_) => ValType::I32,
@@ -156,6 +162,7 @@ impl Val {
/// If this is a null `externref`, then `Some(None)` is returned. /// If this is a null `externref`, then `Some(None)` is returned.
/// ///
/// If this is a non-null `externref`, then `Some(Some(..))` is returned. /// If this is a non-null `externref`, then `Some(Some(..))` is returned.
#[inline]
pub fn externref(&self) -> Option<Option<ExternRef>> { pub fn externref(&self) -> Option<Option<ExternRef>> {
match self { match self {
Val::ExternRef(e) => Some(e.clone()), Val::ExternRef(e) => Some(e.clone()),
@@ -173,6 +180,7 @@ impl Val {
/// # Panics /// # Panics
/// ///
/// Panics if `self` is not a (nullable) `externref`. /// Panics if `self` is not a (nullable) `externref`.
#[inline]
pub fn unwrap_externref(&self) -> Option<ExternRef> { pub fn unwrap_externref(&self) -> Option<ExternRef> {
self.externref().expect("expected externref") self.externref().expect("expected externref")
} }
@@ -204,6 +212,7 @@ impl Val {
} }
} }
#[inline]
pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque<'_>) -> bool { pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque<'_>) -> bool {
match self { match self {
Val::FuncRef(Some(f)) => f.comes_from_same_store(store), Val::FuncRef(Some(f)) => f.comes_from_same_store(store),
@@ -223,54 +232,63 @@ impl Val {
} }
impl From<i32> for Val { impl From<i32> for Val {
#[inline]
fn from(val: i32) -> Val { fn from(val: i32) -> Val {
Val::I32(val) Val::I32(val)
} }
} }
impl From<i64> for Val { impl From<i64> for Val {
#[inline]
fn from(val: i64) -> Val { fn from(val: i64) -> Val {
Val::I64(val) Val::I64(val)
} }
} }
impl From<f32> for Val { impl From<f32> for Val {
#[inline]
fn from(val: f32) -> Val { fn from(val: f32) -> Val {
Val::F32(val.to_bits()) Val::F32(val.to_bits())
} }
} }
impl From<f64> for Val { impl From<f64> for Val {
#[inline]
fn from(val: f64) -> Val { fn from(val: f64) -> Val {
Val::F64(val.to_bits()) Val::F64(val.to_bits())
} }
} }
impl From<ExternRef> for Val { impl From<ExternRef> for Val {
#[inline]
fn from(val: ExternRef) -> Val { fn from(val: ExternRef) -> Val {
Val::ExternRef(Some(val)) Val::ExternRef(Some(val))
} }
} }
impl From<Option<ExternRef>> for Val { impl From<Option<ExternRef>> for Val {
#[inline]
fn from(val: Option<ExternRef>) -> Val { fn from(val: Option<ExternRef>) -> Val {
Val::ExternRef(val) Val::ExternRef(val)
} }
} }
impl From<Option<Func>> for Val { impl From<Option<Func>> for Val {
#[inline]
fn from(val: Option<Func>) -> Val { fn from(val: Option<Func>) -> Val {
Val::FuncRef(val) Val::FuncRef(val)
} }
} }
impl From<Func> for Val { impl From<Func> for Val {
#[inline]
fn from(val: Func) -> Val { fn from(val: Func) -> Val {
Val::FuncRef(Some(val)) Val::FuncRef(Some(val))
} }
} }
impl From<u128> for Val { impl From<u128> for Val {
#[inline]
fn from(val: u128) -> Val { fn from(val: u128) -> Val {
Val::V128(val) Val::V128(val)
} }