1#[cfg(feature = "component-model")]
5use crate::component;
6use crate::{
7 BuiltinFunctionIndex, DefinedFuncIndex, HostCall, ModuleInternedTypeIndex, StaticModuleIndex,
8};
9use core::{cmp, fmt};
10use serde_derive::{Deserialize, Serialize};
11
12#[repr(u32)]
17#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
18#[cfg_attr(test, derive(arbitrary::Arbitrary))]
19pub enum FuncKeyKind {
20 DefinedWasmFunction = FuncKey::new_kind(0b0000),
22
23 ArrayToWasmTrampoline = FuncKey::new_kind(0b0001),
25
26 WasmToArrayTrampoline = FuncKey::new_kind(0b0010),
28
29 WasmToBuiltinTrampoline = FuncKey::new_kind(0b0011),
31
32 PatchableToBuiltinTrampoline = FuncKey::new_kind(0b0100),
34
35 PulleyHostCall = FuncKey::new_kind(0b0101),
37
38 #[cfg(feature = "component-model")]
40 ComponentTrampoline = FuncKey::new_kind(0b0110),
41
42 #[cfg(feature = "component-model")]
44 ResourceDropTrampoline = FuncKey::new_kind(0b0111),
45
46 #[cfg(feature = "component-model")]
48 UnsafeIntrinsic = FuncKey::new_kind(0b1000),
49
50 ModuleStartup = FuncKey::new_kind(0b1001),
53}
54
55impl From<FuncKeyKind> for u32 {
56 fn from(kind: FuncKeyKind) -> Self {
57 kind as u32
58 }
59}
60
61impl FuncKeyKind {
62 pub fn into_raw(self) -> u32 {
64 self.into()
65 }
66
67 pub fn from_raw(raw: u32) -> Self {
71 match raw {
72 x if x == Self::DefinedWasmFunction.into() => Self::DefinedWasmFunction,
73 x if x == Self::ArrayToWasmTrampoline.into() => Self::ArrayToWasmTrampoline,
74 x if x == Self::WasmToArrayTrampoline.into() => Self::WasmToArrayTrampoline,
75 x if x == Self::WasmToBuiltinTrampoline.into() => Self::WasmToBuiltinTrampoline,
76 x if x == Self::PatchableToBuiltinTrampoline.into() => {
77 Self::PatchableToBuiltinTrampoline
78 }
79 x if x == Self::PulleyHostCall.into() => Self::PulleyHostCall,
80 x if x == Self::ModuleStartup.into() => Self::ModuleStartup,
81
82 #[cfg(feature = "component-model")]
83 x if x == Self::ComponentTrampoline.into() => Self::ComponentTrampoline,
84 #[cfg(feature = "component-model")]
85 x if x == Self::ResourceDropTrampoline.into() => Self::ResourceDropTrampoline,
86 #[cfg(feature = "component-model")]
87 x if x == Self::UnsafeIntrinsic.into() => Self::UnsafeIntrinsic,
88
89 _ => panic!("invalid raw value passed to `FuncKind::from_raw`: {raw}"),
90 }
91 }
92}
93
94#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
98pub struct FuncKeyNamespace(u32);
99
100impl fmt::Debug for FuncKeyNamespace {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 struct Hex<T: fmt::LowerHex>(T);
103 impl<T: fmt::LowerHex> fmt::Debug for Hex<T> {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 write!(f, "{:#x}", self.0)
106 }
107 }
108 f.debug_struct("FuncKeyNamespace")
109 .field("raw", &Hex(self.0))
110 .field("kind", &self.kind())
111 .field("module", &self.module())
112 .finish()
113 }
114}
115
116impl From<FuncKeyNamespace> for u32 {
117 fn from(ns: FuncKeyNamespace) -> Self {
118 ns.0
119 }
120}
121
122impl FuncKeyNamespace {
123 pub fn into_raw(self) -> u32 {
125 self.0
126 }
127
128 pub fn from_raw(raw: u32) -> Self {
132 match FuncKeyKind::from_raw(raw & FuncKey::KIND_MASK) {
133 FuncKeyKind::DefinedWasmFunction
134 | FuncKeyKind::ArrayToWasmTrampoline
135 | FuncKeyKind::ModuleStartup => Self(raw),
136 FuncKeyKind::WasmToArrayTrampoline
137 | FuncKeyKind::WasmToBuiltinTrampoline
138 | FuncKeyKind::PatchableToBuiltinTrampoline
139 | FuncKeyKind::PulleyHostCall => {
140 assert_eq!(raw & FuncKey::MODULE_MASK, 0);
141 Self(raw)
142 }
143
144 #[cfg(feature = "component-model")]
145 FuncKeyKind::ComponentTrampoline => {
146 let _ = Abi::from_raw(raw & FuncKey::MODULE_MASK);
147 Self(raw)
148 }
149
150 #[cfg(feature = "component-model")]
151 FuncKeyKind::ResourceDropTrampoline => {
152 assert_eq!(raw & FuncKey::MODULE_MASK, 0);
153 Self(raw)
154 }
155
156 #[cfg(feature = "component-model")]
157 FuncKeyKind::UnsafeIntrinsic => {
158 let _ = Abi::from_raw(raw & FuncKey::MODULE_MASK);
159 Self(raw)
160 }
161 }
162 }
163
164 pub fn kind(&self) -> FuncKeyKind {
166 let raw = self.0 & FuncKey::KIND_MASK;
167 FuncKeyKind::from_raw(raw)
168 }
169
170 fn module(&self) -> u32 {
171 self.0 & FuncKey::MODULE_MASK
172 }
173}
174
175#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
177pub struct FuncKeyIndex(u32);
178
179impl From<FuncKeyIndex> for u32 {
180 fn from(index: FuncKeyIndex) -> Self {
181 index.0
182 }
183}
184
185impl FuncKeyIndex {
186 pub fn into_raw(self) -> u32 {
188 self.0
189 }
190
191 pub fn from_raw(raw: u32) -> Self {
197 FuncKeyIndex(raw)
198 }
199}
200
201#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
203#[cfg_attr(test, derive(arbitrary::Arbitrary))]
204pub enum Abi {
205 Wasm = 0,
207 Array = 1,
209 Patchable = 2,
213}
214
215impl Abi {
216 fn from_raw(raw: u32) -> Self {
217 match raw {
218 x if x == Self::Wasm.into_raw() => Self::Wasm,
219 x if x == Self::Array.into_raw() => Self::Array,
220 x if x == Self::Patchable.into_raw() => Self::Patchable,
221 _ => panic!("invalid raw representation passed to `Abi::from_raw`: {raw}"),
222 }
223 }
224
225 fn into_raw(self) -> u32 {
226 (self as u8).into()
227 }
228}
229
230#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
233pub enum FuncKey {
234 DefinedWasmFunction(StaticModuleIndex, DefinedFuncIndex),
236
237 ArrayToWasmTrampoline(StaticModuleIndex, DefinedFuncIndex),
239
240 WasmToArrayTrampoline(ModuleInternedTypeIndex),
242
243 WasmToBuiltinTrampoline(BuiltinFunctionIndex),
245
246 PulleyHostCall(HostCall),
248
249 PatchableToBuiltinTrampoline(BuiltinFunctionIndex),
251
252 #[cfg(feature = "component-model")]
254 ComponentTrampoline(Abi, component::TrampolineIndex),
255
256 #[cfg(feature = "component-model")]
258 ResourceDropTrampoline,
259
260 #[cfg(feature = "component-model")]
262 UnsafeIntrinsic(Abi, component::UnsafeIntrinsic),
263
264 ModuleStartup(Abi, StaticModuleIndex),
270}
271
272impl Ord for FuncKey {
273 fn cmp(&self, other: &Self) -> cmp::Ordering {
274 let raw_self = self.into_raw_parts();
277 let raw_other = other.into_raw_parts();
278 raw_self.cmp(&raw_other)
279 }
280}
281
282impl PartialOrd for FuncKey {
283 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
284 Some(self.cmp(other))
285 }
286}
287
288impl FuncKey {
289 const KIND_BITS: u32 = 4;
290 const KIND_OFFSET: u32 = 32 - Self::KIND_BITS;
291 const KIND_MASK: u32 = ((1 << Self::KIND_BITS) - 1) << Self::KIND_OFFSET;
292 const MODULE_MASK: u32 = !Self::KIND_MASK;
293
294 const fn new_kind(kind: u32) -> u32 {
295 assert!(kind < (1 << Self::KIND_BITS));
296 kind << Self::KIND_OFFSET
297 }
298
299 #[inline]
301 pub fn into_parts(self) -> (FuncKeyNamespace, FuncKeyIndex) {
302 let (namespace, index) = match self {
303 FuncKey::DefinedWasmFunction(module, def_func) => {
304 assert_eq!(module.as_u32() & Self::KIND_MASK, 0);
305 let namespace = FuncKeyKind::DefinedWasmFunction.into_raw() | module.as_u32();
306 let index = def_func.as_u32();
307 (namespace, index)
308 }
309 FuncKey::ArrayToWasmTrampoline(module, def_func) => {
310 assert_eq!(module.as_u32() & Self::KIND_MASK, 0);
311 let namespace = FuncKeyKind::ArrayToWasmTrampoline.into_raw() | module.as_u32();
312 let index = def_func.as_u32();
313 (namespace, index)
314 }
315 FuncKey::WasmToArrayTrampoline(ty) => {
316 let namespace = FuncKeyKind::WasmToArrayTrampoline.into_raw();
317 let index = ty.as_u32();
318 (namespace, index)
319 }
320 FuncKey::WasmToBuiltinTrampoline(builtin) => {
321 let namespace = FuncKeyKind::WasmToBuiltinTrampoline.into_raw();
322 let index = builtin.index();
323 (namespace, index)
324 }
325 FuncKey::PatchableToBuiltinTrampoline(builtin) => {
326 let namespace = FuncKeyKind::PatchableToBuiltinTrampoline.into_raw();
327 let index = builtin.index();
328 (namespace, index)
329 }
330 FuncKey::PulleyHostCall(host_call) => {
331 let namespace = FuncKeyKind::PulleyHostCall.into_raw();
332 let index = host_call.index();
333 (namespace, index)
334 }
335
336 #[cfg(feature = "component-model")]
337 FuncKey::ComponentTrampoline(abi, trampoline) => {
338 let abi = abi.into_raw();
339 assert_eq!(abi & Self::KIND_MASK, 0);
340 let namespace = FuncKeyKind::ComponentTrampoline.into_raw() | abi;
341 let index = trampoline.as_u32();
342 (namespace, index)
343 }
344 #[cfg(feature = "component-model")]
345 FuncKey::ResourceDropTrampoline => {
346 let namespace = FuncKeyKind::ResourceDropTrampoline.into_raw();
347 let index = 0;
348 (namespace, index)
349 }
350 #[cfg(feature = "component-model")]
351 FuncKey::UnsafeIntrinsic(abi, intrinsic) => {
352 let abi = abi.into_raw();
353 assert_eq!(abi & Self::KIND_MASK, 0);
354 let namespace = FuncKeyKind::UnsafeIntrinsic.into_raw() | abi;
355 let index = intrinsic.index();
356 (namespace, index)
357 }
358
359 FuncKey::ModuleStartup(abi, module) => {
360 assert_eq!(module.as_u32() & Self::KIND_MASK, 0);
361 let namespace = FuncKeyKind::ModuleStartup.into_raw() | module.as_u32();
362 let index = abi.into_raw();
363 (namespace, index)
364 }
365 };
366 (FuncKeyNamespace(namespace), FuncKeyIndex(index))
367 }
368
369 pub fn kind(self) -> FuncKeyKind {
371 self.namespace().kind()
372 }
373
374 pub fn namespace(self) -> FuncKeyNamespace {
376 self.into_parts().0
377 }
378
379 pub fn index(self) -> FuncKeyIndex {
381 self.into_parts().1
382 }
383
384 pub fn abi(self) -> Abi {
386 match self {
387 FuncKey::DefinedWasmFunction(_, _) => Abi::Wasm,
388 FuncKey::ArrayToWasmTrampoline(_, _) => Abi::Array,
389 FuncKey::WasmToArrayTrampoline(_) => Abi::Wasm,
390 FuncKey::WasmToBuiltinTrampoline(_) => Abi::Wasm,
391 FuncKey::PatchableToBuiltinTrampoline(_) => Abi::Patchable,
392 FuncKey::PulleyHostCall(_) => Abi::Wasm,
393 #[cfg(feature = "component-model")]
394 FuncKey::ComponentTrampoline(abi, _) => abi,
395 #[cfg(feature = "component-model")]
396 FuncKey::ResourceDropTrampoline => Abi::Wasm,
397 #[cfg(feature = "component-model")]
398 FuncKey::UnsafeIntrinsic(abi, _) => abi,
399 FuncKey::ModuleStartup(abi, _) => abi,
400 }
401 }
402
403 pub fn into_raw_parts(self) -> (u32, u32) {
413 let (ns, index) = self.into_parts();
414 (ns.into_raw(), index.into_raw())
415 }
416
417 pub fn from_parts(namespace: FuncKeyNamespace, index: FuncKeyIndex) -> Self {
426 Self::from_raw_parts(namespace.into_raw(), index.into_raw())
427 }
428
429 pub fn from_raw_parts(a: u32, b: u32) -> Self {
436 match FuncKeyKind::from_raw(a & Self::KIND_MASK) {
437 FuncKeyKind::DefinedWasmFunction => {
438 let module = StaticModuleIndex::from_u32(a & Self::MODULE_MASK);
439 let def_func = DefinedFuncIndex::from_u32(b);
440 Self::DefinedWasmFunction(module, def_func)
441 }
442 FuncKeyKind::ArrayToWasmTrampoline => {
443 let module = StaticModuleIndex::from_u32(a & Self::MODULE_MASK);
444 let def_func = DefinedFuncIndex::from_u32(b);
445 Self::ArrayToWasmTrampoline(module, def_func)
446 }
447 FuncKeyKind::WasmToArrayTrampoline => {
448 assert_eq!(a & Self::MODULE_MASK, 0);
449 let ty = ModuleInternedTypeIndex::from_u32(b);
450 Self::WasmToArrayTrampoline(ty)
451 }
452 FuncKeyKind::WasmToBuiltinTrampoline => {
453 assert_eq!(a & Self::MODULE_MASK, 0);
454 let builtin = BuiltinFunctionIndex::from_u32(b);
455 Self::WasmToBuiltinTrampoline(builtin)
456 }
457 FuncKeyKind::PatchableToBuiltinTrampoline => {
458 assert_eq!(a & Self::MODULE_MASK, 0);
459 let builtin = BuiltinFunctionIndex::from_u32(b);
460 Self::PatchableToBuiltinTrampoline(builtin)
461 }
462 FuncKeyKind::PulleyHostCall => {
463 assert_eq!(a & Self::MODULE_MASK, 0);
464 let host_call = HostCall::from_index(b);
465 Self::PulleyHostCall(host_call)
466 }
467
468 #[cfg(feature = "component-model")]
469 FuncKeyKind::ComponentTrampoline => {
470 let abi = Abi::from_raw(a & Self::MODULE_MASK);
471 let trampoline = component::TrampolineIndex::from_u32(b);
472 Self::ComponentTrampoline(abi, trampoline)
473 }
474 #[cfg(feature = "component-model")]
475 FuncKeyKind::ResourceDropTrampoline => {
476 assert_eq!(a & Self::MODULE_MASK, 0);
477 assert_eq!(b, 0);
478 Self::ResourceDropTrampoline
479 }
480 #[cfg(feature = "component-model")]
481 FuncKeyKind::UnsafeIntrinsic => {
482 let abi = Abi::from_raw(a & Self::MODULE_MASK);
483 let intrinsic = component::UnsafeIntrinsic::from_u32(b);
484 Self::UnsafeIntrinsic(abi, intrinsic)
485 }
486
487 FuncKeyKind::ModuleStartup => {
488 let module = StaticModuleIndex::from_u32(a & Self::MODULE_MASK);
489 let abi = Abi::from_raw(b);
490 Self::ModuleStartup(abi, module)
491 }
492 }
493 }
494
495 pub fn from_raw_u64(value: u64) -> Self {
501 let hi = u32::try_from(value >> 32).unwrap();
502 let lo = u32::try_from(value & 0xffff_ffff).unwrap();
503 FuncKey::from_raw_parts(hi, lo)
504 }
505
506 pub fn into_raw_u64(&self) -> u64 {
510 let (hi, lo) = self.into_raw_parts();
511 (u64::from(hi) << 32) | u64::from(lo)
512 }
513
514 pub fn unwrap_defined_wasm_function(self) -> (StaticModuleIndex, DefinedFuncIndex) {
516 match self {
517 Self::DefinedWasmFunction(module, def_func) => (module, def_func),
518 _ => panic!("`FuncKey::unwrap_defined_wasm_function` called on {self:?}"),
519 }
520 }
521
522 pub fn unwrap_array_to_wasm_trampoline(self) -> (StaticModuleIndex, DefinedFuncIndex) {
524 match self {
525 Self::ArrayToWasmTrampoline(module, def_func) => (module, def_func),
526 _ => panic!("`FuncKey::unwrap_array_to_wasm_trampoline` called on {self:?}"),
527 }
528 }
529
530 pub fn unwrap_wasm_to_array_trampoline(self) -> ModuleInternedTypeIndex {
532 match self {
533 Self::WasmToArrayTrampoline(ty) => ty,
534 _ => panic!("`FuncKey::unwrap_wasm_to_array_trampoline` called on {self:?}"),
535 }
536 }
537
538 pub fn unwrap_wasm_to_builtin_trampoline(self) -> BuiltinFunctionIndex {
540 match self {
541 Self::WasmToBuiltinTrampoline(builtin) => builtin,
542 _ => panic!("`FuncKey::unwrap_wasm_to_builtin_trampoline` called on {self:?}"),
543 }
544 }
545
546 pub fn unwrap_pulley_host_call(self) -> HostCall {
548 match self {
549 Self::PulleyHostCall(host_call) => host_call,
550 _ => panic!("`FuncKey::unwrap_pulley_host_call` called on {self:?}"),
551 }
552 }
553
554 #[cfg(feature = "component-model")]
556 pub fn unwrap_component_trampoline(self) -> (crate::Abi, component::TrampolineIndex) {
557 match self {
558 Self::ComponentTrampoline(abi, trampoline) => (abi, trampoline),
559 _ => panic!("`FuncKey::unwrap_component_trampoline` called on {self:?}"),
560 }
561 }
562
563 #[cfg(feature = "component-model")]
565 pub fn unwrap_resource_drop_trampoline(self) {
566 match self {
567 Self::ResourceDropTrampoline => {}
568 _ => panic!("`FuncKey::unwrap_resource_drop_trampoline` called on {self:?}"),
569 }
570 }
571
572 pub fn is_store_invariant(&self) -> bool {
585 match self {
586 Self::DefinedWasmFunction(..)
587 | Self::ArrayToWasmTrampoline(..)
588 | Self::ModuleStartup(..) => false,
589 Self::WasmToArrayTrampoline(..)
590 | Self::WasmToBuiltinTrampoline(..)
591 | Self::PatchableToBuiltinTrampoline(..)
592 | Self::PulleyHostCall(..) => true,
593 #[cfg(feature = "component-model")]
594 Self::ComponentTrampoline(..)
595 | Self::ResourceDropTrampoline
596 | Self::UnsafeIntrinsic(..) => true,
597 }
598 }
599}