wasmtime_environ/component/vmcomponent_offsets.rs
1//! Offsets of the fields within a `VMComponentContext`.
2//!
3//! The layout itself is not defined here: it is defined once, alongside
4//! `VMContext`'s, in `for_each_vmctx_type!`. Everything in this module is either
5//! generated from that definition or is an offset that is not simply the offset
6//! of one of the layout's fields.
7
8use crate::GetPtrSize;
9use crate::PtrSize;
10use crate::component::*;
11
12/// Equivalent of `VMCONTEXT_MAGIC` except for components.
13///
14/// This is stored at the start of all `VMComponentContext` structures and
15/// double-checked on `VMComponentContext::from_opaque`.
16pub const VMCOMPONENT_MAGIC: u32 = u32::from_le_bytes(*b"comp");
17
18/// Runtime offsets within a `VMComponentContext` for a specific component.
19#[derive(Debug, Clone, Copy)]
20pub struct VMComponentOffsets<P> {
21 /// The host pointer size
22 pub ptr: P,
23
24 /// The number of lowered functions this component will be creating.
25 pub num_lowerings: u32,
26 /// The number of memories which are recorded in this component for options.
27 pub num_runtime_memories: u32,
28 /// The number of tables which are recorded in this component for options.
29 pub num_runtime_tables: u32,
30 /// The number of reallocs which are recorded in this component for options.
31 pub num_runtime_reallocs: u32,
32 /// The number of callbacks which are recorded in this component for options.
33 pub num_runtime_callbacks: u32,
34 /// The number of post-returns which are recorded in this component for options.
35 pub num_runtime_post_returns: u32,
36 /// Number of component instances internally in the component (always at
37 /// least 1).
38 pub num_runtime_component_instances: u32,
39 /// Number of cranelift-compiled trampolines required for this component.
40 pub num_trampolines: u32,
41 /// Number of `VMFuncRef`s for unsafe intrinsics within this component's
42 /// context.
43 pub num_unsafe_intrinsics: u32,
44 /// Number of resources within a component which need destructors stored.
45 pub num_resources: u32,
46
47 // Precalculated offsets of the dynamically-positioned fields, one per entry
48 // in `VMComponentContext`'s `dynamic` section in `for_each_vmctx_type!`,
49 // plus this `VMComponentContext`'s total size. These are all computed by the
50 // generated `compute_field_offsets` and read by the generated accessors of
51 // the same names.
52 may_leave: u32,
53 task_may_block: u32,
54 trampoline_func_refs: u32,
55 intrinsic_func_refs: u32,
56 lowerings: u32,
57 memories: u32,
58 tables: u32,
59 reallocs: u32,
60 callbacks: u32,
61 post_returns: u32,
62 resource_destructors: u32,
63 size: u32,
64}
65
66impl<P: PtrSize> GetPtrSize for VMComponentOffsets<P> {
67 type Ptr = P;
68
69 #[inline]
70 fn get_ptr_size(&self) -> &Self::Ptr {
71 &self.ptr
72 }
73}
74
75impl_vmctx_array_index! {
76 RuntimeComponentInstanceIndex,
77 TrampolineIndex,
78 LoweredIndex,
79 RuntimeMemoryIndex,
80 RuntimeTableIndex,
81 RuntimeReallocIndex,
82 RuntimeCallbackIndex,
83 RuntimePostReturnIndex,
84 ResourceIndex,
85}
86
87impl crate::VmctxArrayIndex for UnsafeIntrinsic {
88 #[inline]
89 fn vmctx_array_index(self) -> u32 {
90 self.index()
91 }
92}
93
94/// Generate the offsets of `VMComponentContext`'s dynamically-positioned fields,
95/// ignoring every other vmctx type.
96macro_rules! define_vmcomponent_offsets_dynamic_offsets {
97 (@one VMComponentContext $snake:ident { $($dyn:tt)* }) => {
98 /// Offsets of the dynamically-positioned fields of `VMComponentContext`.
99 impl<P: PtrSize> VMComponentOffsets<P> {
100 define_vmctx_dynamic_offsets!(@accessors (self) [ $($dyn)* ]);
101
102 define_vmctx_dynamic_offsets!(@compute_fn (self, next) $snake [ $($dyn)* ]);
103
104 /// Return the size of the `VMComponentContext` allocation.
105 #[inline]
106 pub fn size_of_vmctx(&self) -> u32 {
107 self.size
108 }
109 }
110 };
111 (@one $other:ident $snake:ident { $($dyn:tt)* }) => {};
112
113 ( $(
114 {
115 $Name:ident $snake:ident
116 static { $($stat:tt)* }
117 dynamic { $($dyn:tt)* }
118 }
119 )* ) => {
120 $( define_vmcomponent_offsets_dynamic_offsets!(@one $Name $snake { $($dyn)* }); )*
121 };
122}
123
124for_each_vmctx_type!(define_vmcomponent_offsets_dynamic_offsets);
125
126impl<P: PtrSize> VMComponentOffsets<P> {
127 /// Creates a new set of offsets for the `component` specified configured
128 /// additionally for the `ptr` size specified.
129 pub fn new(ptr: P, component: &Component) -> Self {
130 // This is required by the implementation of
131 // `VMComponentContext::from_opaque`. If this value changes then this
132 // location needs to be updated.
133 assert_eq!(ptr.vmcomponent().magic(), 0);
134
135 let mut ret = Self {
136 ptr,
137 num_lowerings: component.num_lowerings,
138 num_runtime_memories: component.num_runtime_memories,
139 num_runtime_tables: component.num_runtime_tables,
140 num_runtime_reallocs: component.num_runtime_reallocs,
141 num_runtime_callbacks: component.num_runtime_callbacks,
142 num_runtime_post_returns: component.num_runtime_post_returns,
143 num_runtime_component_instances: component.num_runtime_component_instances,
144 num_trampolines: component.trampolines.len().try_into().unwrap(),
145 num_unsafe_intrinsics: if let Some(i) = component
146 .unsafe_intrinsics
147 .iter()
148 .rposition(|x| x.is_some())
149 {
150 // Note: We do not currently have an indirection between "the
151 // `i`th unsafe intrinsic in the vmctx" and
152 // `UnsafeIntrinsic::from_u32(i)`, so therefore if we are
153 // compiling in *any* intrinsics, we need to include space for
154 // all of them up to the max `i` that is used.
155 //
156 // We _could_ introduce such an indirection via a map in
157 // `Component` like `PrimaryMap<UnsafeIntrinsicIndex,
158 // UnsafeIntrinsic>`, and that would allow us to densely pack
159 // intrinsics in the vmctx. However we do not do that today
160 // because there are very few unsafe intrinsics, and we do not
161 // see that changing anytime soon, so we aren't wasting much
162 // space.
163 u32::try_from(i + 1).unwrap()
164 } else {
165 0
166 },
167 num_resources: component.num_resources,
168 may_leave: 0,
169 task_may_block: 0,
170 trampoline_func_refs: 0,
171 intrinsic_func_refs: 0,
172 lowerings: 0,
173 memories: 0,
174 tables: 0,
175 reallocs: 0,
176 callbacks: 0,
177 post_returns: 0,
178 resource_destructors: 0,
179 size: 0,
180 };
181
182 ret.compute_field_offsets();
183
184 ret
185 }
186
187 /// The size, in bytes, of the host pointer.
188 #[inline]
189 pub fn pointer_size(&self) -> u8 {
190 self.ptr.size()
191 }
192
193 /// The offset of the `callee` for the `index` specified.
194 #[inline]
195 pub fn lowering_callee(&self, index: LoweredIndex) -> u32 {
196 self.lowerings().at(index) + self.lowering_callee_offset()
197 }
198
199 /// The offset of the `data` for the `index` specified.
200 #[inline]
201 pub fn lowering_data(&self, index: LoweredIndex) -> u32 {
202 self.lowerings().at(index) + self.lowering_data_offset()
203 }
204
205 /// The size of the `VMLowering` type
206 #[inline]
207 pub fn lowering_size(&self) -> u8 {
208 2 * self.ptr.size()
209 }
210
211 /// The offset of the `callee` field within the `VMLowering` type.
212 #[inline]
213 pub fn lowering_callee_offset(&self) -> u32 {
214 0
215 }
216
217 /// The offset of the `data` field within the `VMLowering` type.
218 #[inline]
219 pub fn lowering_data_offset(&self) -> u32 {
220 u32::from(self.ptr.size())
221 }
222}