1use std::mem::{align_of, size_of};
2
3use super::{
4 NativeCall, NativeCancellation, NativeDeoptimization, NativeException, NativeExit, NativeFrame,
5 NativeHostStatus, NativeHostVTable, NativeResumeState, NativeRoot, NativeRootSet,
6 NativeSafepoint, NativeSiteOutcome, NativeSiteOutcomeKind, NativeSitePhase, NativeSiteRequest,
7 NativeSourceLocation, NativeSourceMapEntry, NativeSourceMapView, NativeSuspension, NativeUtf8,
8 NativeValueRef,
9};
10
11pub const NATIVE_ABI_SCHEMA_VERSION: u16 = 4;
12
13#[repr(C)]
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub struct NativeAbiVersion {
16 pub major: u16,
17 pub minor: u16,
18}
19
20impl NativeAbiVersion {
21 pub const fn encoded(self) -> u32 {
22 ((self.major as u32) << 16) | self.minor as u32
23 }
24}
25
26pub const NATIVE_ABI_VERSION: NativeAbiVersion = NativeAbiVersion { major: 1, minor: 3 };
27
28pub fn native_abi_contract_fingerprint() -> runmat_execution::Digest {
30 runmat_execution::Digest::sha256(
31 b"runmat-native-abi-v4\0opaque-values\0generation-roots\0explicit-host-table\0typed-host-status\0out-parameter-exits\0no-cross-boundary-unwind\0exact-site-resume\0transactional-exit\0path-free-sources\0typed-native-site-dispatch\0no-obsolete-slow-call-slot",
32 )
33}
34
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub struct NativeTypeLayout {
37 pub size: usize,
38 pub alignment: usize,
39}
40
41impl NativeTypeLayout {
42 fn of<T>() -> Self {
43 Self {
44 size: size_of::<T>(),
45 alignment: align_of::<T>(),
46 }
47 }
48}
49
50#[derive(Clone, Copy, Debug, Eq, PartialEq)]
54pub struct NativeAbiLayout {
55 pub pointer_width: u16,
56 pub host_status: NativeTypeLayout,
57 pub value: NativeTypeLayout,
58 pub root: NativeTypeLayout,
59 pub root_set: NativeTypeLayout,
60 pub source: NativeTypeLayout,
61 pub utf8: NativeTypeLayout,
62 pub source_map_entry: NativeTypeLayout,
63 pub source_map_view: NativeTypeLayout,
64 pub resume: NativeTypeLayout,
65 pub frame: NativeTypeLayout,
66 pub call: NativeTypeLayout,
67 pub host: NativeTypeLayout,
68 pub exception: NativeTypeLayout,
69 pub cancellation: NativeTypeLayout,
70 pub suspension: NativeTypeLayout,
71 pub deoptimization: NativeTypeLayout,
72 pub exit: NativeTypeLayout,
73 pub safepoint: NativeTypeLayout,
74 pub site_phase: NativeTypeLayout,
75 pub site_request: NativeTypeLayout,
76 pub site_outcome_kind: NativeTypeLayout,
77 pub site_outcome: NativeTypeLayout,
78}
79
80pub fn native_abi_layout() -> NativeAbiLayout {
81 NativeAbiLayout {
82 pointer_width: usize::BITS as u16,
83 host_status: NativeTypeLayout::of::<NativeHostStatus>(),
84 value: NativeTypeLayout::of::<NativeValueRef>(),
85 root: NativeTypeLayout::of::<NativeRoot>(),
86 root_set: NativeTypeLayout::of::<NativeRootSet>(),
87 source: NativeTypeLayout::of::<NativeSourceLocation>(),
88 utf8: NativeTypeLayout::of::<NativeUtf8>(),
89 source_map_entry: NativeTypeLayout::of::<NativeSourceMapEntry>(),
90 source_map_view: NativeTypeLayout::of::<NativeSourceMapView>(),
91 resume: NativeTypeLayout::of::<NativeResumeState>(),
92 frame: NativeTypeLayout::of::<NativeFrame>(),
93 call: NativeTypeLayout::of::<NativeCall>(),
94 host: NativeTypeLayout::of::<NativeHostVTable>(),
95 exception: NativeTypeLayout::of::<NativeException>(),
96 cancellation: NativeTypeLayout::of::<NativeCancellation>(),
97 suspension: NativeTypeLayout::of::<NativeSuspension>(),
98 deoptimization: NativeTypeLayout::of::<NativeDeoptimization>(),
99 exit: NativeTypeLayout::of::<NativeExit>(),
100 safepoint: NativeTypeLayout::of::<NativeSafepoint>(),
101 site_phase: NativeTypeLayout::of::<NativeSitePhase>(),
102 site_request: NativeTypeLayout::of::<NativeSiteRequest>(),
103 site_outcome_kind: NativeTypeLayout::of::<NativeSiteOutcomeKind>(),
104 site_outcome: NativeTypeLayout::of::<NativeSiteOutcome>(),
105 }
106}
107
108pub fn native_abi_layout_fingerprint() -> runmat_execution::Digest {
109 let layout = native_abi_layout();
110 runmat_execution::Digest::sha256(format!(
111 "runmat-native-layout-v1\0{}\0{:?}",
112 std::env::consts::ARCH,
113 layout
114 ))
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
122 #[cfg_attr(not(target_arch = "wasm32"), test)]
123 fn version_and_contract_identity_are_stable() {
124 assert_eq!(NATIVE_ABI_VERSION.encoded(), 0x0001_0003);
125 assert_eq!(
126 native_abi_contract_fingerprint().to_string(),
127 "sha256:f550a4e40b7d2f75c72231767205f88b68c73b1d7ae89b057bbbdcf4de67b225"
128 );
129 }
130
131 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
132 #[cfg_attr(not(target_arch = "wasm32"), test)]
133 fn layouts_are_c_compatible_and_offsets_are_explicit() {
134 let layout = native_abi_layout();
135 assert_eq!(layout.pointer_width, usize::BITS as u16);
136 assert_eq!(
137 layout.host_status,
138 NativeTypeLayout {
139 size: 4,
140 alignment: 4
141 }
142 );
143 assert_eq!(
144 layout.value,
145 NativeTypeLayout {
146 size: 16,
147 alignment: 8
148 }
149 );
150 assert_eq!(
151 layout.root,
152 NativeTypeLayout {
153 size: 24,
154 alignment: 8
155 }
156 );
157 assert_eq!(
158 layout.source,
159 NativeTypeLayout {
160 size: 24,
161 alignment: 8
162 }
163 );
164 assert_eq!(std::mem::offset_of!(NativeFrame, caller), 16);
165 assert_eq!(std::mem::offset_of!(NativeCall, host), 16);
166 assert_eq!(std::mem::offset_of!(NativeExit, exception), 16);
167 assert_eq!(std::mem::offset_of!(NativeResumeState, phase), 12);
168 assert_eq!(std::mem::offset_of!(NativeResumeState, ordinal), 16);
169 assert_eq!(std::mem::offset_of!(NativeResumeState, bytecode_pc), 32);
170 assert_eq!(
171 layout.site_request,
172 NativeTypeLayout {
173 size: 24,
174 alignment: 4
175 }
176 );
177 assert_eq!(
178 layout.site_outcome,
179 NativeTypeLayout {
180 size: 16,
181 alignment: 4
182 }
183 );
184 assert!(
185 std::mem::offset_of!(NativeHostVTable, execute_site)
186 > std::mem::offset_of!(NativeHostVTable, source_lookup)
187 );
188 }
189
190 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
191 #[cfg_attr(not(target_arch = "wasm32"), test)]
192 fn target_layout_fingerprint_is_deterministic() {
193 assert_eq!(
194 native_abi_layout_fingerprint(),
195 native_abi_layout_fingerprint()
196 );
197 assert_ne!(
198 native_abi_layout_fingerprint(),
199 native_abi_contract_fingerprint()
200 );
201 }
202}