1 //! Offsets and sizes of various structs in wasmtime-runtime's vmcontext
2 //! module.
3 
4 // Currently the `VMContext` allocation by field looks like this:
5 //
6 // struct VMContext {
7 //      interrupts: *const VMInterrupts,
8 //      signature_ids: [VMSharedSignatureIndex; module.num_signature_ids],
9 //      imported_functions: [VMFunctionImport; module.num_imported_functions],
10 //      imported_tables: [VMTableImport; module.num_imported_tables],
11 //      imported_memories: [VMMemoryImport; module.num_imported_memories],
12 //      imported_globals: [VMGlobalImport; module.num_imported_globals],
13 //      tables: [VMTableDefinition; module.num_defined_tables],
14 //      memories: [VMMemoryDefinition; module.num_defined_memories],
15 //      globals: [VMGlobalDefinition; module.num_defined_globals],
16 //      builtins: VMBuiltinFunctionsArray,
17 // }
18 
19 use crate::module::ModuleLocal;
20 use crate::BuiltinFunctionIndex;
21 use cranelift_codegen::ir;
22 use cranelift_wasm::{
23     DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, FuncIndex, GlobalIndex, MemoryIndex,
24     SignatureIndex, TableIndex,
25 };
26 use more_asserts::assert_lt;
27 use std::convert::TryFrom;
28 
29 /// Sentinel value indicating that wasm has been interrupted.
30 // Note that this has a bit of an odd definition. See the `insert_stack_check`
31 // function in `cranelift/codegen/src/isa/x86/abi.rs` for more information
32 pub const INTERRUPTED: usize = usize::max_value() - 32 * 1024;
33 
34 #[cfg(target_pointer_width = "32")]
cast_to_u32(sz: usize) -> u3235 fn cast_to_u32(sz: usize) -> u32 {
36     u32::try_from(sz).unwrap()
37 }
38 #[cfg(target_pointer_width = "64")]
cast_to_u32(sz: usize) -> u3239 fn cast_to_u32(sz: usize) -> u32 {
40     u32::try_from(sz).expect("overflow in cast from usize to u32")
41 }
42 
43 /// Align an offset used in this module to a specific byte-width by rounding up
align(offset: u32, width: u32) -> u3244 fn align(offset: u32, width: u32) -> u32 {
45     (offset + (width - 1)) / width * width
46 }
47 
48 /// This class computes offsets to fields within `VMContext` and other
49 /// related structs that JIT code accesses directly.
50 pub struct VMOffsets {
51     /// The size in bytes of a pointer on the target.
52     pub pointer_size: u8,
53     /// The number of signature declarations in the module.
54     pub num_signature_ids: u32,
55     /// The number of imported functions in the module.
56     pub num_imported_functions: u32,
57     /// The number of imported tables in the module.
58     pub num_imported_tables: u32,
59     /// The number of imported memories in the module.
60     pub num_imported_memories: u32,
61     /// The number of imported globals in the module.
62     pub num_imported_globals: u32,
63     /// The number of defined tables in the module.
64     pub num_defined_tables: u32,
65     /// The number of defined memories in the module.
66     pub num_defined_memories: u32,
67     /// The number of defined globals in the module.
68     pub num_defined_globals: u32,
69 }
70 
71 impl VMOffsets {
72     /// Return a new `VMOffsets` instance, for a given pointer size.
new(pointer_size: u8, module: &ModuleLocal) -> Self73     pub fn new(pointer_size: u8, module: &ModuleLocal) -> Self {
74         Self {
75             pointer_size,
76             num_signature_ids: cast_to_u32(module.signatures.len()),
77             num_imported_functions: cast_to_u32(module.num_imported_funcs),
78             num_imported_tables: cast_to_u32(module.num_imported_tables),
79             num_imported_memories: cast_to_u32(module.num_imported_memories),
80             num_imported_globals: cast_to_u32(module.num_imported_globals),
81             num_defined_tables: cast_to_u32(module.table_plans.len()),
82             num_defined_memories: cast_to_u32(module.memory_plans.len()),
83             num_defined_globals: cast_to_u32(module.globals.len()),
84         }
85     }
86 }
87 
88 /// Offsets for `VMFunctionImport`.
89 impl VMOffsets {
90     /// The offset of the `body` field.
91     #[allow(clippy::erasing_op)]
vmfunction_import_body(&self) -> u892     pub fn vmfunction_import_body(&self) -> u8 {
93         0 * self.pointer_size
94     }
95 
96     /// The offset of the `vmctx` field.
97     #[allow(clippy::identity_op)]
vmfunction_import_vmctx(&self) -> u898     pub fn vmfunction_import_vmctx(&self) -> u8 {
99         1 * self.pointer_size
100     }
101 
102     /// Return the size of `VMFunctionImport`.
size_of_vmfunction_import(&self) -> u8103     pub fn size_of_vmfunction_import(&self) -> u8 {
104         2 * self.pointer_size
105     }
106 }
107 
108 /// Offsets for `*const VMFunctionBody`.
109 impl VMOffsets {
110     /// The size of the `current_elements` field.
111     #[allow(clippy::identity_op)]
size_of_vmfunction_body_ptr(&self) -> u8112     pub fn size_of_vmfunction_body_ptr(&self) -> u8 {
113         1 * self.pointer_size
114     }
115 }
116 
117 /// Offsets for `VMTableImport`.
118 impl VMOffsets {
119     /// The offset of the `from` field.
120     #[allow(clippy::erasing_op)]
vmtable_import_from(&self) -> u8121     pub fn vmtable_import_from(&self) -> u8 {
122         0 * self.pointer_size
123     }
124 
125     /// The offset of the `vmctx` field.
126     #[allow(clippy::identity_op)]
vmtable_import_vmctx(&self) -> u8127     pub fn vmtable_import_vmctx(&self) -> u8 {
128         1 * self.pointer_size
129     }
130 
131     /// Return the size of `VMTableImport`.
size_of_vmtable_import(&self) -> u8132     pub fn size_of_vmtable_import(&self) -> u8 {
133         2 * self.pointer_size
134     }
135 }
136 
137 /// Offsets for `VMTableDefinition`.
138 impl VMOffsets {
139     /// The offset of the `base` field.
140     #[allow(clippy::erasing_op)]
vmtable_definition_base(&self) -> u8141     pub fn vmtable_definition_base(&self) -> u8 {
142         0 * self.pointer_size
143     }
144 
145     /// The offset of the `current_elements` field.
146     #[allow(clippy::identity_op)]
vmtable_definition_current_elements(&self) -> u8147     pub fn vmtable_definition_current_elements(&self) -> u8 {
148         1 * self.pointer_size
149     }
150 
151     /// The size of the `current_elements` field.
size_of_vmtable_definition_current_elements(&self) -> u8152     pub fn size_of_vmtable_definition_current_elements(&self) -> u8 {
153         4
154     }
155 
156     /// Return the size of `VMTableDefinition`.
size_of_vmtable_definition(&self) -> u8157     pub fn size_of_vmtable_definition(&self) -> u8 {
158         2 * self.pointer_size
159     }
160 
161     /// The type of the `current_elements` field.
type_of_vmtable_definition_current_elements(&self) -> ir::Type162     pub fn type_of_vmtable_definition_current_elements(&self) -> ir::Type {
163         ir::Type::int(u16::from(self.size_of_vmtable_definition_current_elements()) * 8).unwrap()
164     }
165 }
166 
167 /// Offsets for `VMMemoryImport`.
168 impl VMOffsets {
169     /// The offset of the `from` field.
170     #[allow(clippy::erasing_op)]
vmmemory_import_from(&self) -> u8171     pub fn vmmemory_import_from(&self) -> u8 {
172         0 * self.pointer_size
173     }
174 
175     /// The offset of the `vmctx` field.
176     #[allow(clippy::identity_op)]
vmmemory_import_vmctx(&self) -> u8177     pub fn vmmemory_import_vmctx(&self) -> u8 {
178         1 * self.pointer_size
179     }
180 
181     /// Return the size of `VMMemoryImport`.
size_of_vmmemory_import(&self) -> u8182     pub fn size_of_vmmemory_import(&self) -> u8 {
183         2 * self.pointer_size
184     }
185 }
186 
187 /// Offsets for `VMMemoryDefinition`.
188 impl VMOffsets {
189     /// The offset of the `base` field.
190     #[allow(clippy::erasing_op)]
vmmemory_definition_base(&self) -> u8191     pub fn vmmemory_definition_base(&self) -> u8 {
192         0 * self.pointer_size
193     }
194 
195     /// The offset of the `current_length` field.
196     #[allow(clippy::identity_op)]
vmmemory_definition_current_length(&self) -> u8197     pub fn vmmemory_definition_current_length(&self) -> u8 {
198         1 * self.pointer_size
199     }
200 
201     /// The size of the `current_length` field.
size_of_vmmemory_definition_current_length(&self) -> u8202     pub fn size_of_vmmemory_definition_current_length(&self) -> u8 {
203         4
204     }
205 
206     /// Return the size of `VMMemoryDefinition`.
size_of_vmmemory_definition(&self) -> u8207     pub fn size_of_vmmemory_definition(&self) -> u8 {
208         2 * self.pointer_size
209     }
210 
211     /// The type of the `current_length` field.
type_of_vmmemory_definition_current_length(&self) -> ir::Type212     pub fn type_of_vmmemory_definition_current_length(&self) -> ir::Type {
213         ir::Type::int(u16::from(self.size_of_vmmemory_definition_current_length()) * 8).unwrap()
214     }
215 }
216 
217 /// Offsets for `VMGlobalImport`.
218 impl VMOffsets {
219     /// The offset of the `from` field.
220     #[allow(clippy::erasing_op)]
vmglobal_import_from(&self) -> u8221     pub fn vmglobal_import_from(&self) -> u8 {
222         0 * self.pointer_size
223     }
224 
225     /// Return the size of `VMGlobalImport`.
226     #[allow(clippy::identity_op)]
size_of_vmglobal_import(&self) -> u8227     pub fn size_of_vmglobal_import(&self) -> u8 {
228         1 * self.pointer_size
229     }
230 }
231 
232 /// Offsets for `VMGlobalDefinition`.
233 impl VMOffsets {
234     /// Return the size of `VMGlobalDefinition`; this is the size of the largest value type (i.e. a
235     /// V128).
size_of_vmglobal_definition(&self) -> u8236     pub fn size_of_vmglobal_definition(&self) -> u8 {
237         16
238     }
239 }
240 
241 /// Offsets for `VMSharedSignatureIndex`.
242 impl VMOffsets {
243     /// Return the size of `VMSharedSignatureIndex`.
size_of_vmshared_signature_index(&self) -> u8244     pub fn size_of_vmshared_signature_index(&self) -> u8 {
245         4
246     }
247 }
248 
249 /// Offsets for `VMInterrupts`.
250 impl VMOffsets {
251     /// Return the offset of the `stack_limit` field of `VMInterrupts`
vminterrupts_stack_limit(&self) -> u8252     pub fn vminterrupts_stack_limit(&self) -> u8 {
253         0
254     }
255 }
256 
257 /// Offsets for `VMCallerCheckedAnyfunc`.
258 impl VMOffsets {
259     /// The offset of the `func_ptr` field.
260     #[allow(clippy::erasing_op)]
vmcaller_checked_anyfunc_func_ptr(&self) -> u8261     pub fn vmcaller_checked_anyfunc_func_ptr(&self) -> u8 {
262         0 * self.pointer_size
263     }
264 
265     /// The offset of the `type_index` field.
266     #[allow(clippy::identity_op)]
vmcaller_checked_anyfunc_type_index(&self) -> u8267     pub fn vmcaller_checked_anyfunc_type_index(&self) -> u8 {
268         1 * self.pointer_size
269     }
270 
271     /// The offset of the `vmctx` field.
vmcaller_checked_anyfunc_vmctx(&self) -> u8272     pub fn vmcaller_checked_anyfunc_vmctx(&self) -> u8 {
273         2 * self.pointer_size
274     }
275 
276     /// Return the size of `VMCallerCheckedAnyfunc`.
size_of_vmcaller_checked_anyfunc(&self) -> u8277     pub fn size_of_vmcaller_checked_anyfunc(&self) -> u8 {
278         3 * self.pointer_size
279     }
280 }
281 
282 /// Offsets for `VMContext`.
283 impl VMOffsets {
284     /// Return the offset to the `VMInterrupts` structure
vmctx_interrupts(&self) -> u32285     pub fn vmctx_interrupts(&self) -> u32 {
286         0
287     }
288 
289     /// The offset of the `signature_ids` array.
vmctx_signature_ids_begin(&self) -> u32290     pub fn vmctx_signature_ids_begin(&self) -> u32 {
291         self.vmctx_interrupts()
292             .checked_add(u32::from(self.pointer_size))
293             .unwrap()
294     }
295 
296     /// The offset of the `tables` array.
297     #[allow(clippy::erasing_op)]
vmctx_imported_functions_begin(&self) -> u32298     pub fn vmctx_imported_functions_begin(&self) -> u32 {
299         self.vmctx_signature_ids_begin()
300             .checked_add(
301                 self.num_signature_ids
302                     .checked_mul(u32::from(self.size_of_vmshared_signature_index()))
303                     .unwrap(),
304             )
305             .unwrap()
306     }
307 
308     /// The offset of the `tables` array.
309     #[allow(clippy::identity_op)]
vmctx_imported_tables_begin(&self) -> u32310     pub fn vmctx_imported_tables_begin(&self) -> u32 {
311         self.vmctx_imported_functions_begin()
312             .checked_add(
313                 self.num_imported_functions
314                     .checked_mul(u32::from(self.size_of_vmfunction_import()))
315                     .unwrap(),
316             )
317             .unwrap()
318     }
319 
320     /// The offset of the `memories` array.
vmctx_imported_memories_begin(&self) -> u32321     pub fn vmctx_imported_memories_begin(&self) -> u32 {
322         self.vmctx_imported_tables_begin()
323             .checked_add(
324                 self.num_imported_tables
325                     .checked_mul(u32::from(self.size_of_vmtable_import()))
326                     .unwrap(),
327             )
328             .unwrap()
329     }
330 
331     /// The offset of the `globals` array.
vmctx_imported_globals_begin(&self) -> u32332     pub fn vmctx_imported_globals_begin(&self) -> u32 {
333         self.vmctx_imported_memories_begin()
334             .checked_add(
335                 self.num_imported_memories
336                     .checked_mul(u32::from(self.size_of_vmmemory_import()))
337                     .unwrap(),
338             )
339             .unwrap()
340     }
341 
342     /// The offset of the `tables` array.
vmctx_tables_begin(&self) -> u32343     pub fn vmctx_tables_begin(&self) -> u32 {
344         self.vmctx_imported_globals_begin()
345             .checked_add(
346                 self.num_imported_globals
347                     .checked_mul(u32::from(self.size_of_vmglobal_import()))
348                     .unwrap(),
349             )
350             .unwrap()
351     }
352 
353     /// The offset of the `memories` array.
vmctx_memories_begin(&self) -> u32354     pub fn vmctx_memories_begin(&self) -> u32 {
355         self.vmctx_tables_begin()
356             .checked_add(
357                 self.num_defined_tables
358                     .checked_mul(u32::from(self.size_of_vmtable_definition()))
359                     .unwrap(),
360             )
361             .unwrap()
362     }
363 
364     /// The offset of the `globals` array.
vmctx_globals_begin(&self) -> u32365     pub fn vmctx_globals_begin(&self) -> u32 {
366         let offset = self
367             .vmctx_memories_begin()
368             .checked_add(
369                 self.num_defined_memories
370                     .checked_mul(u32::from(self.size_of_vmmemory_definition()))
371                     .unwrap(),
372             )
373             .unwrap();
374         align(offset, 16)
375     }
376 
377     /// The offset of the builtin functions array.
vmctx_builtin_functions_begin(&self) -> u32378     pub fn vmctx_builtin_functions_begin(&self) -> u32 {
379         self.vmctx_globals_begin()
380             .checked_add(
381                 self.num_defined_globals
382                     .checked_mul(u32::from(self.size_of_vmglobal_definition()))
383                     .unwrap(),
384             )
385             .unwrap()
386     }
387 
388     /// Return the size of the `VMContext` allocation.
size_of_vmctx(&self) -> u32389     pub fn size_of_vmctx(&self) -> u32 {
390         self.vmctx_builtin_functions_begin()
391             .checked_add(
392                 BuiltinFunctionIndex::builtin_functions_total_number()
393                     .checked_mul(u32::from(self.pointer_size))
394                     .unwrap(),
395             )
396             .unwrap()
397     }
398 
399     /// Return the offset to `VMSharedSignatureId` index `index`.
vmctx_vmshared_signature_id(&self, index: SignatureIndex) -> u32400     pub fn vmctx_vmshared_signature_id(&self, index: SignatureIndex) -> u32 {
401         assert_lt!(index.as_u32(), self.num_signature_ids);
402         self.vmctx_signature_ids_begin()
403             .checked_add(
404                 index
405                     .as_u32()
406                     .checked_mul(u32::from(self.size_of_vmshared_signature_index()))
407                     .unwrap(),
408             )
409             .unwrap()
410     }
411 
412     /// Return the offset to `VMFunctionImport` index `index`.
vmctx_vmfunction_import(&self, index: FuncIndex) -> u32413     pub fn vmctx_vmfunction_import(&self, index: FuncIndex) -> u32 {
414         assert_lt!(index.as_u32(), self.num_imported_functions);
415         self.vmctx_imported_functions_begin()
416             .checked_add(
417                 index
418                     .as_u32()
419                     .checked_mul(u32::from(self.size_of_vmfunction_import()))
420                     .unwrap(),
421             )
422             .unwrap()
423     }
424 
425     /// Return the offset to `VMTableImport` index `index`.
vmctx_vmtable_import(&self, index: TableIndex) -> u32426     pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {
427         assert_lt!(index.as_u32(), self.num_imported_tables);
428         self.vmctx_imported_tables_begin()
429             .checked_add(
430                 index
431                     .as_u32()
432                     .checked_mul(u32::from(self.size_of_vmtable_import()))
433                     .unwrap(),
434             )
435             .unwrap()
436     }
437 
438     /// Return the offset to `VMMemoryImport` index `index`.
vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32439     pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {
440         assert_lt!(index.as_u32(), self.num_imported_memories);
441         self.vmctx_imported_memories_begin()
442             .checked_add(
443                 index
444                     .as_u32()
445                     .checked_mul(u32::from(self.size_of_vmmemory_import()))
446                     .unwrap(),
447             )
448             .unwrap()
449     }
450 
451     /// Return the offset to `VMGlobalImport` index `index`.
vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32452     pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {
453         assert_lt!(index.as_u32(), self.num_imported_globals);
454         self.vmctx_imported_globals_begin()
455             .checked_add(
456                 index
457                     .as_u32()
458                     .checked_mul(u32::from(self.size_of_vmglobal_import()))
459                     .unwrap(),
460             )
461             .unwrap()
462     }
463 
464     /// Return the offset to `VMTableDefinition` index `index`.
vmctx_vmtable_definition(&self, index: DefinedTableIndex) -> u32465     pub fn vmctx_vmtable_definition(&self, index: DefinedTableIndex) -> u32 {
466         assert_lt!(index.as_u32(), self.num_defined_tables);
467         self.vmctx_tables_begin()
468             .checked_add(
469                 index
470                     .as_u32()
471                     .checked_mul(u32::from(self.size_of_vmtable_definition()))
472                     .unwrap(),
473             )
474             .unwrap()
475     }
476 
477     /// Return the offset to `VMMemoryDefinition` index `index`.
vmctx_vmmemory_definition(&self, index: DefinedMemoryIndex) -> u32478     pub fn vmctx_vmmemory_definition(&self, index: DefinedMemoryIndex) -> u32 {
479         assert_lt!(index.as_u32(), self.num_defined_memories);
480         self.vmctx_memories_begin()
481             .checked_add(
482                 index
483                     .as_u32()
484                     .checked_mul(u32::from(self.size_of_vmmemory_definition()))
485                     .unwrap(),
486             )
487             .unwrap()
488     }
489 
490     /// Return the offset to the `VMGlobalDefinition` index `index`.
vmctx_vmglobal_definition(&self, index: DefinedGlobalIndex) -> u32491     pub fn vmctx_vmglobal_definition(&self, index: DefinedGlobalIndex) -> u32 {
492         assert_lt!(index.as_u32(), self.num_defined_globals);
493         self.vmctx_globals_begin()
494             .checked_add(
495                 index
496                     .as_u32()
497                     .checked_mul(u32::from(self.size_of_vmglobal_definition()))
498                     .unwrap(),
499             )
500             .unwrap()
501     }
502 
503     /// Return the offset to the `body` field in `*const VMFunctionBody` index `index`.
vmctx_vmfunction_import_body(&self, index: FuncIndex) -> u32504     pub fn vmctx_vmfunction_import_body(&self, index: FuncIndex) -> u32 {
505         self.vmctx_vmfunction_import(index)
506             .checked_add(u32::from(self.vmfunction_import_body()))
507             .unwrap()
508     }
509 
510     /// Return the offset to the `vmctx` field in `*const VMFunctionBody` index `index`.
vmctx_vmfunction_import_vmctx(&self, index: FuncIndex) -> u32511     pub fn vmctx_vmfunction_import_vmctx(&self, index: FuncIndex) -> u32 {
512         self.vmctx_vmfunction_import(index)
513             .checked_add(u32::from(self.vmfunction_import_vmctx()))
514             .unwrap()
515     }
516 
517     /// Return the offset to the `from` field in `VMTableImport` index `index`.
vmctx_vmtable_import_from(&self, index: TableIndex) -> u32518     pub fn vmctx_vmtable_import_from(&self, index: TableIndex) -> u32 {
519         self.vmctx_vmtable_import(index)
520             .checked_add(u32::from(self.vmtable_import_from()))
521             .unwrap()
522     }
523 
524     /// Return the offset to the `base` field in `VMTableDefinition` index `index`.
vmctx_vmtable_definition_base(&self, index: DefinedTableIndex) -> u32525     pub fn vmctx_vmtable_definition_base(&self, index: DefinedTableIndex) -> u32 {
526         self.vmctx_vmtable_definition(index)
527             .checked_add(u32::from(self.vmtable_definition_base()))
528             .unwrap()
529     }
530 
531     /// Return the offset to the `current_elements` field in `VMTableDefinition` index `index`.
vmctx_vmtable_definition_current_elements(&self, index: DefinedTableIndex) -> u32532     pub fn vmctx_vmtable_definition_current_elements(&self, index: DefinedTableIndex) -> u32 {
533         self.vmctx_vmtable_definition(index)
534             .checked_add(u32::from(self.vmtable_definition_current_elements()))
535             .unwrap()
536     }
537 
538     /// Return the offset to the `from` field in `VMMemoryImport` index `index`.
vmctx_vmmemory_import_from(&self, index: MemoryIndex) -> u32539     pub fn vmctx_vmmemory_import_from(&self, index: MemoryIndex) -> u32 {
540         self.vmctx_vmmemory_import(index)
541             .checked_add(u32::from(self.vmmemory_import_from()))
542             .unwrap()
543     }
544 
545     /// Return the offset to the `vmctx` field in `VMMemoryImport` index `index`.
vmctx_vmmemory_import_vmctx(&self, index: MemoryIndex) -> u32546     pub fn vmctx_vmmemory_import_vmctx(&self, index: MemoryIndex) -> u32 {
547         self.vmctx_vmmemory_import(index)
548             .checked_add(u32::from(self.vmmemory_import_vmctx()))
549             .unwrap()
550     }
551 
552     /// Return the offset to the `base` field in `VMMemoryDefinition` index `index`.
vmctx_vmmemory_definition_base(&self, index: DefinedMemoryIndex) -> u32553     pub fn vmctx_vmmemory_definition_base(&self, index: DefinedMemoryIndex) -> u32 {
554         self.vmctx_vmmemory_definition(index)
555             .checked_add(u32::from(self.vmmemory_definition_base()))
556             .unwrap()
557     }
558 
559     /// Return the offset to the `current_length` field in `VMMemoryDefinition` index `index`.
vmctx_vmmemory_definition_current_length(&self, index: DefinedMemoryIndex) -> u32560     pub fn vmctx_vmmemory_definition_current_length(&self, index: DefinedMemoryIndex) -> u32 {
561         self.vmctx_vmmemory_definition(index)
562             .checked_add(u32::from(self.vmmemory_definition_current_length()))
563             .unwrap()
564     }
565 
566     /// Return the offset to the `from` field in `VMGlobalImport` index `index`.
vmctx_vmglobal_import_from(&self, index: GlobalIndex) -> u32567     pub fn vmctx_vmglobal_import_from(&self, index: GlobalIndex) -> u32 {
568         self.vmctx_vmglobal_import(index)
569             .checked_add(u32::from(self.vmglobal_import_from()))
570             .unwrap()
571     }
572 
573     /// Return the offset to builtin function in `VMBuiltinFunctionsArray` index `index`.
vmctx_builtin_function(&self, index: BuiltinFunctionIndex) -> u32574     pub fn vmctx_builtin_function(&self, index: BuiltinFunctionIndex) -> u32 {
575         self.vmctx_builtin_functions_begin()
576             .checked_add(
577                 index
578                     .index()
579                     .checked_mul(u32::from(self.pointer_size))
580                     .unwrap(),
581             )
582             .unwrap()
583     }
584 }
585 
586 /// Offsets for `VMExternData`.
587 impl VMOffsets {
588     /// Return the offset for `VMExternData::ref_count`.
vm_extern_data_ref_count() -> u32589     pub fn vm_extern_data_ref_count() -> u32 {
590         0
591     }
592 }
593 
594 /// Target specific type for shared signature index.
595 #[derive(Debug, Copy, Clone)]
596 pub struct TargetSharedSignatureIndex(u32);
597 
598 impl TargetSharedSignatureIndex {
599     /// Constructs `TargetSharedSignatureIndex`.
new(value: u32) -> Self600     pub fn new(value: u32) -> Self {
601         Self(value)
602     }
603 
604     /// Returns index value.
index(self) -> u32605     pub fn index(self) -> u32 {
606         self.0
607     }
608 }
609 
610 #[cfg(test)]
611 mod tests {
612     use crate::vmoffsets::align;
613 
614     #[test]
alignment()615     fn alignment() {
616         fn is_aligned(x: u32) -> bool {
617             x % 16 == 0
618         }
619         assert!(is_aligned(align(0, 16)));
620         assert!(is_aligned(align(32, 16)));
621         assert!(is_aligned(align(33, 16)));
622         assert!(is_aligned(align(31, 16)));
623     }
624 }
625