#[cfg(feature = "component-model")]
use crate::component;
use crate::{
BuiltinFunctionIndex, DefinedFuncIndex, HostCall, ModuleInternedTypeIndex, StaticModuleIndex,
};
use core::{cmp, fmt};
use serde_derive::{Deserialize, Serialize};
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(test, derive(arbitrary::Arbitrary))]
pub enum FuncKeyKind {
DefinedWasmFunction = FuncKey::new_kind(0b0000),
ArrayToWasmTrampoline = FuncKey::new_kind(0b0001),
WasmToArrayTrampoline = FuncKey::new_kind(0b0010),
WasmToBuiltinTrampoline = FuncKey::new_kind(0b0011),
PatchableToBuiltinTrampoline = FuncKey::new_kind(0b0100),
PulleyHostCall = FuncKey::new_kind(0b0101),
#[cfg(feature = "component-model")]
ComponentTrampoline = FuncKey::new_kind(0b0110),
#[cfg(feature = "component-model")]
ResourceDropTrampoline = FuncKey::new_kind(0b0111),
#[cfg(feature = "component-model")]
UnsafeIntrinsic = FuncKey::new_kind(0b1000),
}
impl From<FuncKeyKind> for u32 {
fn from(kind: FuncKeyKind) -> Self {
kind as u32
}
}
impl FuncKeyKind {
pub fn into_raw(self) -> u32 {
self.into()
}
pub fn from_raw(raw: u32) -> Self {
match raw {
x if x == Self::DefinedWasmFunction.into() => Self::DefinedWasmFunction,
x if x == Self::ArrayToWasmTrampoline.into() => Self::ArrayToWasmTrampoline,
x if x == Self::WasmToArrayTrampoline.into() => Self::WasmToArrayTrampoline,
x if x == Self::WasmToBuiltinTrampoline.into() => Self::WasmToBuiltinTrampoline,
x if x == Self::PatchableToBuiltinTrampoline.into() => {
Self::PatchableToBuiltinTrampoline
}
x if x == Self::PulleyHostCall.into() => Self::PulleyHostCall,
#[cfg(feature = "component-model")]
x if x == Self::ComponentTrampoline.into() => Self::ComponentTrampoline,
#[cfg(feature = "component-model")]
x if x == Self::ResourceDropTrampoline.into() => Self::ResourceDropTrampoline,
#[cfg(feature = "component-model")]
x if x == Self::UnsafeIntrinsic.into() => Self::UnsafeIntrinsic,
_ => panic!("invalid raw value passed to `FuncKind::from_raw`: {raw}"),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct FuncKeyNamespace(u32);
impl fmt::Debug for FuncKeyNamespace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct Hex<T: fmt::LowerHex>(T);
impl<T: fmt::LowerHex> fmt::Debug for Hex<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:#x}", self.0)
}
}
f.debug_struct("FuncKeyNamespace")
.field("raw", &Hex(self.0))
.field("kind", &self.kind())
.field("module", &self.module())
.finish()
}
}
impl From<FuncKeyNamespace> for u32 {
fn from(ns: FuncKeyNamespace) -> Self {
ns.0
}
}
impl FuncKeyNamespace {
pub fn into_raw(self) -> u32 {
self.0
}
pub fn from_raw(raw: u32) -> Self {
match FuncKeyKind::from_raw(raw & FuncKey::KIND_MASK) {
FuncKeyKind::DefinedWasmFunction | FuncKeyKind::ArrayToWasmTrampoline => Self(raw),
FuncKeyKind::WasmToArrayTrampoline
| FuncKeyKind::WasmToBuiltinTrampoline
| FuncKeyKind::PatchableToBuiltinTrampoline
| FuncKeyKind::PulleyHostCall => {
assert_eq!(raw & FuncKey::MODULE_MASK, 0);
Self(raw)
}
#[cfg(feature = "component-model")]
FuncKeyKind::ComponentTrampoline => {
let _ = Abi::from_raw(raw & FuncKey::MODULE_MASK);
Self(raw)
}
#[cfg(feature = "component-model")]
FuncKeyKind::ResourceDropTrampoline => {
assert_eq!(raw & FuncKey::MODULE_MASK, 0);
Self(raw)
}
#[cfg(feature = "component-model")]
FuncKeyKind::UnsafeIntrinsic => {
let _ = Abi::from_raw(raw & FuncKey::MODULE_MASK);
Self(raw)
}
}
}
pub fn kind(&self) -> FuncKeyKind {
let raw = self.0 & FuncKey::KIND_MASK;
FuncKeyKind::from_raw(raw)
}
fn module(&self) -> u32 {
self.0 & FuncKey::MODULE_MASK
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct FuncKeyIndex(u32);
impl From<FuncKeyIndex> for u32 {
fn from(index: FuncKeyIndex) -> Self {
index.0
}
}
impl FuncKeyIndex {
pub fn into_raw(self) -> u32 {
self.0
}
pub fn from_raw(raw: u32) -> Self {
FuncKeyIndex(raw)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(test, derive(arbitrary::Arbitrary))]
pub enum Abi {
Wasm = 0,
Array = 1,
Patchable = 2,
}
#[cfg(feature = "component-model")]
impl Abi {
fn from_raw(raw: u32) -> Self {
match raw {
x if x == Self::Wasm.into_raw() => Self::Wasm,
x if x == Self::Array.into_raw() => Self::Array,
x if x == Self::Patchable.into_raw() => Self::Patchable,
_ => panic!("invalid raw representation passed to `Abi::from_raw`: {raw}"),
}
}
fn into_raw(self) -> u32 {
(self as u8).into()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum FuncKey {
DefinedWasmFunction(StaticModuleIndex, DefinedFuncIndex),
ArrayToWasmTrampoline(StaticModuleIndex, DefinedFuncIndex),
WasmToArrayTrampoline(ModuleInternedTypeIndex),
WasmToBuiltinTrampoline(BuiltinFunctionIndex),
PulleyHostCall(HostCall),
PatchableToBuiltinTrampoline(BuiltinFunctionIndex),
#[cfg(feature = "component-model")]
ComponentTrampoline(Abi, component::TrampolineIndex),
#[cfg(feature = "component-model")]
ResourceDropTrampoline,
#[cfg(feature = "component-model")]
UnsafeIntrinsic(Abi, component::UnsafeIntrinsic),
}
impl Ord for FuncKey {
fn cmp(&self, other: &Self) -> cmp::Ordering {
let raw_self = self.into_raw_parts();
let raw_other = other.into_raw_parts();
raw_self.cmp(&raw_other)
}
}
impl PartialOrd for FuncKey {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl FuncKey {
const KIND_BITS: u32 = 4;
const KIND_OFFSET: u32 = 32 - Self::KIND_BITS;
const KIND_MASK: u32 = ((1 << Self::KIND_BITS) - 1) << Self::KIND_OFFSET;
const MODULE_MASK: u32 = !Self::KIND_MASK;
const fn new_kind(kind: u32) -> u32 {
assert!(kind < (1 << Self::KIND_BITS));
kind << Self::KIND_OFFSET
}
#[inline]
pub fn into_parts(self) -> (FuncKeyNamespace, FuncKeyIndex) {
let (namespace, index) = match self {
FuncKey::DefinedWasmFunction(module, def_func) => {
assert_eq!(module.as_u32() & Self::KIND_MASK, 0);
let namespace = FuncKeyKind::DefinedWasmFunction.into_raw() | module.as_u32();
let index = def_func.as_u32();
(namespace, index)
}
FuncKey::ArrayToWasmTrampoline(module, def_func) => {
assert_eq!(module.as_u32() & Self::KIND_MASK, 0);
let namespace = FuncKeyKind::ArrayToWasmTrampoline.into_raw() | module.as_u32();
let index = def_func.as_u32();
(namespace, index)
}
FuncKey::WasmToArrayTrampoline(ty) => {
let namespace = FuncKeyKind::WasmToArrayTrampoline.into_raw();
let index = ty.as_u32();
(namespace, index)
}
FuncKey::WasmToBuiltinTrampoline(builtin) => {
let namespace = FuncKeyKind::WasmToBuiltinTrampoline.into_raw();
let index = builtin.index();
(namespace, index)
}
FuncKey::PatchableToBuiltinTrampoline(builtin) => {
let namespace = FuncKeyKind::PatchableToBuiltinTrampoline.into_raw();
let index = builtin.index();
(namespace, index)
}
FuncKey::PulleyHostCall(host_call) => {
let namespace = FuncKeyKind::PulleyHostCall.into_raw();
let index = host_call.index();
(namespace, index)
}
#[cfg(feature = "component-model")]
FuncKey::ComponentTrampoline(abi, trampoline) => {
let abi = abi.into_raw();
assert_eq!(abi & Self::KIND_MASK, 0);
let namespace = FuncKeyKind::ComponentTrampoline.into_raw() | abi;
let index = trampoline.as_u32();
(namespace, index)
}
#[cfg(feature = "component-model")]
FuncKey::ResourceDropTrampoline => {
let namespace = FuncKeyKind::ResourceDropTrampoline.into_raw();
let index = 0;
(namespace, index)
}
#[cfg(feature = "component-model")]
FuncKey::UnsafeIntrinsic(abi, intrinsic) => {
let abi = abi.into_raw();
assert_eq!(abi & Self::KIND_MASK, 0);
let namespace = FuncKeyKind::UnsafeIntrinsic.into_raw() | abi;
let index = intrinsic.index();
(namespace, index)
}
};
(FuncKeyNamespace(namespace), FuncKeyIndex(index))
}
pub fn kind(self) -> FuncKeyKind {
self.namespace().kind()
}
pub fn namespace(self) -> FuncKeyNamespace {
self.into_parts().0
}
pub fn index(self) -> FuncKeyIndex {
self.into_parts().1
}
pub fn abi(self) -> Abi {
match self {
FuncKey::DefinedWasmFunction(_, _) => Abi::Wasm,
FuncKey::ArrayToWasmTrampoline(_, _) => Abi::Array,
FuncKey::WasmToArrayTrampoline(_) => Abi::Wasm,
FuncKey::WasmToBuiltinTrampoline(_) => Abi::Wasm,
FuncKey::PatchableToBuiltinTrampoline(_) => Abi::Patchable,
FuncKey::PulleyHostCall(_) => Abi::Wasm,
#[cfg(feature = "component-model")]
FuncKey::ComponentTrampoline(abi, _) => abi,
#[cfg(feature = "component-model")]
FuncKey::ResourceDropTrampoline => Abi::Wasm,
#[cfg(feature = "component-model")]
FuncKey::UnsafeIntrinsic(abi, _) => abi,
}
}
pub fn into_raw_parts(self) -> (u32, u32) {
let (ns, index) = self.into_parts();
(ns.into_raw(), index.into_raw())
}
pub fn from_parts(namespace: FuncKeyNamespace, index: FuncKeyIndex) -> Self {
Self::from_raw_parts(namespace.into_raw(), index.into_raw())
}
pub fn from_raw_parts(a: u32, b: u32) -> Self {
match FuncKeyKind::from_raw(a & Self::KIND_MASK) {
FuncKeyKind::DefinedWasmFunction => {
let module = StaticModuleIndex::from_u32(a & Self::MODULE_MASK);
let def_func = DefinedFuncIndex::from_u32(b);
Self::DefinedWasmFunction(module, def_func)
}
FuncKeyKind::ArrayToWasmTrampoline => {
let module = StaticModuleIndex::from_u32(a & Self::MODULE_MASK);
let def_func = DefinedFuncIndex::from_u32(b);
Self::ArrayToWasmTrampoline(module, def_func)
}
FuncKeyKind::WasmToArrayTrampoline => {
assert_eq!(a & Self::MODULE_MASK, 0);
let ty = ModuleInternedTypeIndex::from_u32(b);
Self::WasmToArrayTrampoline(ty)
}
FuncKeyKind::WasmToBuiltinTrampoline => {
assert_eq!(a & Self::MODULE_MASK, 0);
let builtin = BuiltinFunctionIndex::from_u32(b);
Self::WasmToBuiltinTrampoline(builtin)
}
FuncKeyKind::PatchableToBuiltinTrampoline => {
assert_eq!(a & Self::MODULE_MASK, 0);
let builtin = BuiltinFunctionIndex::from_u32(b);
Self::PatchableToBuiltinTrampoline(builtin)
}
FuncKeyKind::PulleyHostCall => {
assert_eq!(a & Self::MODULE_MASK, 0);
let host_call = HostCall::from_index(b);
Self::PulleyHostCall(host_call)
}
#[cfg(feature = "component-model")]
FuncKeyKind::ComponentTrampoline => {
let abi = Abi::from_raw(a & Self::MODULE_MASK);
let trampoline = component::TrampolineIndex::from_u32(b);
Self::ComponentTrampoline(abi, trampoline)
}
#[cfg(feature = "component-model")]
FuncKeyKind::ResourceDropTrampoline => {
assert_eq!(a & Self::MODULE_MASK, 0);
assert_eq!(b, 0);
Self::ResourceDropTrampoline
}
#[cfg(feature = "component-model")]
FuncKeyKind::UnsafeIntrinsic => {
let abi = Abi::from_raw(a & Self::MODULE_MASK);
let intrinsic = component::UnsafeIntrinsic::from_u32(b);
Self::UnsafeIntrinsic(abi, intrinsic)
}
}
}
pub fn from_raw_u64(value: u64) -> Self {
let hi = u32::try_from(value >> 32).unwrap();
let lo = u32::try_from(value & 0xffff_ffff).unwrap();
FuncKey::from_raw_parts(hi, lo)
}
pub fn into_raw_u64(&self) -> u64 {
let (hi, lo) = self.into_raw_parts();
(u64::from(hi) << 32) | u64::from(lo)
}
pub fn unwrap_defined_wasm_function(self) -> (StaticModuleIndex, DefinedFuncIndex) {
match self {
Self::DefinedWasmFunction(module, def_func) => (module, def_func),
_ => panic!("`FuncKey::unwrap_defined_wasm_function` called on {self:?}"),
}
}
pub fn unwrap_array_to_wasm_trampoline(self) -> (StaticModuleIndex, DefinedFuncIndex) {
match self {
Self::ArrayToWasmTrampoline(module, def_func) => (module, def_func),
_ => panic!("`FuncKey::unwrap_array_to_wasm_trampoline` called on {self:?}"),
}
}
pub fn unwrap_wasm_to_array_trampoline(self) -> ModuleInternedTypeIndex {
match self {
Self::WasmToArrayTrampoline(ty) => ty,
_ => panic!("`FuncKey::unwrap_wasm_to_array_trampoline` called on {self:?}"),
}
}
pub fn unwrap_wasm_to_builtin_trampoline(self) -> BuiltinFunctionIndex {
match self {
Self::WasmToBuiltinTrampoline(builtin) => builtin,
_ => panic!("`FuncKey::unwrap_wasm_to_builtin_trampoline` called on {self:?}"),
}
}
pub fn unwrap_pulley_host_call(self) -> HostCall {
match self {
Self::PulleyHostCall(host_call) => host_call,
_ => panic!("`FuncKey::unwrap_pulley_host_call` called on {self:?}"),
}
}
#[cfg(feature = "component-model")]
pub fn unwrap_component_trampoline(self) -> (crate::Abi, component::TrampolineIndex) {
match self {
Self::ComponentTrampoline(abi, trampoline) => (abi, trampoline),
_ => panic!("`FuncKey::unwrap_component_trampoline` called on {self:?}"),
}
}
#[cfg(feature = "component-model")]
pub fn unwrap_resource_drop_trampoline(self) {
match self {
Self::ResourceDropTrampoline => {}
_ => panic!("`FuncKey::unwrap_resource_drop_trampoline` called on {self:?}"),
}
}
pub fn is_store_invariant(&self) -> bool {
match self {
Self::DefinedWasmFunction(..) | Self::ArrayToWasmTrampoline(..) => false,
Self::WasmToArrayTrampoline(..)
| Self::WasmToBuiltinTrampoline(..)
| Self::PatchableToBuiltinTrampoline(..)
| Self::PulleyHostCall(..) => true,
#[cfg(feature = "component-model")]
Self::ComponentTrampoline(..)
| Self::ResourceDropTrampoline
| Self::UnsafeIntrinsic(..) => true,
}
}
}