Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/environ/src/vmoffsets.rs
3076 views
1
//! Offsets and sizes of various structs in `wasmtime::runtime::vm::*` that are
2
//! accessed directly by compiled Wasm code.
3
4
// Currently the `VMContext` allocation by field looks like this:
5
//
6
// struct VMContext {
7
// // Fixed-width data comes first so the calculation of the offset of
8
// // these fields is a compile-time constant when using `HostPtr`.
9
// magic: u32,
10
// _padding: u32, // (On 64-bit systems)
11
// vm_store_context: *const VMStoreContext,
12
// builtin_functions: *mut VMBuiltinFunctionsArray,
13
// epoch_ptr: *mut AtomicU64,
14
// gc_heap_data: *mut T, // Collector-specific pointer
15
// type_ids: *const VMSharedTypeIndex,
16
//
17
// // Variable-width fields come after the fixed-width fields above. Place
18
// // memory-related items first as they're some of the most frequently
19
// // accessed items and minimizing their offset in this structure can
20
// // shrink the size of load/store instruction offset immediates on
21
// // platforms like x64 and Pulley (e.g. fit in an 8-bit offset instead
22
// // of needing a 32-bit offset)
23
// imported_memories: [VMMemoryImport; module.num_imported_memories],
24
// memories: [*mut VMMemoryDefinition; module.num_defined_memories],
25
// owned_memories: [VMMemoryDefinition; module.num_owned_memories],
26
// imported_functions: [VMFunctionImport; module.num_imported_functions],
27
// imported_tables: [VMTableImport; module.num_imported_tables],
28
// imported_globals: [VMGlobalImport; module.num_imported_globals],
29
// imported_tags: [VMTagImport; module.num_imported_tags],
30
// tables: [VMTableDefinition; module.num_defined_tables],
31
// globals: [VMGlobalDefinition; module.num_defined_globals],
32
// tags: [VMTagDefinition; module.num_defined_tags],
33
// func_refs: [VMFuncRef; module.num_escaped_funcs],
34
// }
35
36
use crate::{
37
DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, DefinedTagIndex, FuncIndex,
38
FuncRefIndex, GlobalIndex, MemoryIndex, Module, OwnedMemoryIndex, TableIndex, TagIndex,
39
};
40
use cranelift_entity::packed_option::ReservedValue;
41
42
#[cfg(target_pointer_width = "32")]
43
fn cast_to_u32(sz: usize) -> u32 {
44
u32::try_from(sz).unwrap()
45
}
46
#[cfg(target_pointer_width = "64")]
47
fn cast_to_u32(sz: usize) -> u32 {
48
u32::try_from(sz).expect("overflow in cast from usize to u32")
49
}
50
51
/// Align an offset used in this module to a specific byte-width by rounding up
52
#[inline]
53
fn align(offset: u32, width: u32) -> u32 {
54
(offset + (width - 1)) / width * width
55
}
56
57
/// This class computes offsets to fields within `VMContext` and other
58
/// related structs that JIT code accesses directly.
59
#[derive(Debug, Clone, Copy)]
60
pub struct VMOffsets<P> {
61
/// The size in bytes of a pointer on the target.
62
pub ptr: P,
63
/// The number of imported functions in the module.
64
pub num_imported_functions: u32,
65
/// The number of imported tables in the module.
66
pub num_imported_tables: u32,
67
/// The number of imported memories in the module.
68
pub num_imported_memories: u32,
69
/// The number of imported globals in the module.
70
pub num_imported_globals: u32,
71
/// The number of imported tags in the module.
72
pub num_imported_tags: u32,
73
/// The number of defined tables in the module.
74
pub num_defined_tables: u32,
75
/// The number of defined memories in the module.
76
pub num_defined_memories: u32,
77
/// The number of memories owned by the module instance.
78
pub num_owned_memories: u32,
79
/// The number of defined globals in the module.
80
pub num_defined_globals: u32,
81
/// The number of defined tags in the module.
82
pub num_defined_tags: u32,
83
/// The number of escaped functions in the module, the size of the func_refs
84
/// array.
85
pub num_escaped_funcs: u32,
86
87
// precalculated offsets of various member fields
88
imported_functions: u32,
89
imported_tables: u32,
90
imported_memories: u32,
91
imported_globals: u32,
92
imported_tags: u32,
93
defined_tables: u32,
94
defined_memories: u32,
95
owned_memories: u32,
96
defined_globals: u32,
97
defined_tags: u32,
98
defined_func_refs: u32,
99
size: u32,
100
}
101
102
/// Trait used for the `ptr` representation of the field of `VMOffsets`
103
pub trait PtrSize {
104
/// Returns the pointer size, in bytes, for the target.
105
fn size(&self) -> u8;
106
107
/// The offset of the `VMContext::store_context` field
108
fn vmcontext_store_context(&self) -> u8 {
109
u8::try_from(align(
110
u32::try_from(core::mem::size_of::<u32>()).unwrap(),
111
u32::from(self.size()),
112
))
113
.unwrap()
114
}
115
116
/// The offset of the `VMContext::builtin_functions` field
117
fn vmcontext_builtin_functions(&self) -> u8 {
118
self.vmcontext_store_context() + self.size()
119
}
120
121
/// The offset of the `array_call` field.
122
#[inline]
123
fn vm_func_ref_array_call(&self) -> u8 {
124
0 * self.size()
125
}
126
127
/// The offset of the `wasm_call` field.
128
#[inline]
129
fn vm_func_ref_wasm_call(&self) -> u8 {
130
1 * self.size()
131
}
132
133
/// The offset of the `type_index` field.
134
#[inline]
135
fn vm_func_ref_type_index(&self) -> u8 {
136
2 * self.size()
137
}
138
139
/// The offset of the `vmctx` field.
140
#[inline]
141
fn vm_func_ref_vmctx(&self) -> u8 {
142
3 * self.size()
143
}
144
145
/// Return the size of `VMFuncRef`.
146
#[inline]
147
fn size_of_vm_func_ref(&self) -> u8 {
148
4 * self.size()
149
}
150
151
/// Return the size of `VMGlobalDefinition`; this is the size of the largest value type (i.e. a
152
/// V128).
153
#[inline]
154
fn size_of_vmglobal_definition(&self) -> u8 {
155
16
156
}
157
158
/// Return the size of `VMTagDefinition`.
159
#[inline]
160
fn size_of_vmtag_definition(&self) -> u8 {
161
4
162
}
163
164
/// This is the size of the largest value type (i.e. a V128).
165
#[inline]
166
fn maximum_value_size(&self) -> u8 {
167
self.size_of_vmglobal_definition()
168
}
169
170
// Offsets within `VMStoreContext`
171
172
/// Return the offset of the `fuel_consumed` field of `VMStoreContext`
173
#[inline]
174
fn vmstore_context_fuel_consumed(&self) -> u8 {
175
0
176
}
177
178
/// Return the offset of the `epoch_deadline` field of `VMStoreContext`
179
#[inline]
180
fn vmstore_context_epoch_deadline(&self) -> u8 {
181
self.vmstore_context_fuel_consumed() + 8
182
}
183
184
/// Return the offset of the `stack_limit` field of `VMStoreContext`
185
#[inline]
186
fn vmstore_context_stack_limit(&self) -> u8 {
187
self.vmstore_context_epoch_deadline() + 8
188
}
189
190
/// Return the offset of the `gc_heap` field of `VMStoreContext`.
191
#[inline]
192
fn vmstore_context_gc_heap(&self) -> u8 {
193
self.vmstore_context_stack_limit() + self.size()
194
}
195
196
/// Return the offset of the `gc_heap.base` field within a `VMStoreContext`.
197
fn vmstore_context_gc_heap_base(&self) -> u8 {
198
let offset = self.vmstore_context_gc_heap() + self.vmmemory_definition_base();
199
debug_assert!(offset < self.vmstore_context_last_wasm_exit_trampoline_fp());
200
offset
201
}
202
203
/// Return the offset of the `gc_heap.current_length` field within a `VMStoreContext`.
204
fn vmstore_context_gc_heap_current_length(&self) -> u8 {
205
let offset = self.vmstore_context_gc_heap() + self.vmmemory_definition_current_length();
206
debug_assert!(offset < self.vmstore_context_last_wasm_exit_trampoline_fp());
207
offset
208
}
209
210
/// Return the offset of the `last_wasm_exit_trampoline_fp` field
211
/// of `VMStoreContext`.
212
fn vmstore_context_last_wasm_exit_trampoline_fp(&self) -> u8 {
213
self.vmstore_context_gc_heap() + self.size_of_vmmemory_definition()
214
}
215
216
/// Return the offset of the `last_wasm_exit_pc` field of `VMStoreContext`.
217
fn vmstore_context_last_wasm_exit_pc(&self) -> u8 {
218
self.vmstore_context_last_wasm_exit_trampoline_fp() + self.size()
219
}
220
221
/// Return the offset of the `last_wasm_entry_sp` field of `VMStoreContext`.
222
fn vmstore_context_last_wasm_entry_sp(&self) -> u8 {
223
self.vmstore_context_last_wasm_exit_pc() + self.size()
224
}
225
226
/// Return the offset of the `last_wasm_entry_fp` field of `VMStoreContext`.
227
fn vmstore_context_last_wasm_entry_fp(&self) -> u8 {
228
self.vmstore_context_last_wasm_entry_sp() + self.size()
229
}
230
231
/// Return the offset of the `last_wasm_entry_trap_handler` field of `VMStoreContext`.
232
fn vmstore_context_last_wasm_entry_trap_handler(&self) -> u8 {
233
self.vmstore_context_last_wasm_entry_fp() + self.size()
234
}
235
236
/// Return the offset of the `stack_chain` field of `VMStoreContext`.
237
fn vmstore_context_stack_chain(&self) -> u8 {
238
self.vmstore_context_last_wasm_entry_trap_handler() + self.size()
239
}
240
241
/// Return the offset of the `stack_chain` field of `VMStoreContext`.
242
fn vmstore_context_store_data(&self) -> u8 {
243
self.vmstore_context_stack_chain() + self.size_of_vmstack_chain()
244
}
245
246
// Offsets within `VMMemoryDefinition`
247
248
/// The offset of the `base` field.
249
#[inline]
250
fn vmmemory_definition_base(&self) -> u8 {
251
0 * self.size()
252
}
253
254
/// The offset of the `current_length` field.
255
#[inline]
256
fn vmmemory_definition_current_length(&self) -> u8 {
257
1 * self.size()
258
}
259
260
/// Return the size of `VMMemoryDefinition`.
261
#[inline]
262
fn size_of_vmmemory_definition(&self) -> u8 {
263
2 * self.size()
264
}
265
266
/// Return the size of `*mut VMMemoryDefinition`.
267
#[inline]
268
fn size_of_vmmemory_pointer(&self) -> u8 {
269
self.size()
270
}
271
272
// Offsets within `VMArrayCallHostFuncContext`.
273
274
/// Return the offset of `VMArrayCallHostFuncContext::func_ref`.
275
fn vmarray_call_host_func_context_func_ref(&self) -> u8 {
276
u8::try_from(align(
277
u32::try_from(core::mem::size_of::<u32>()).unwrap(),
278
u32::from(self.size()),
279
))
280
.unwrap()
281
}
282
283
/// Return the size of `VMStackChain`.
284
fn size_of_vmstack_chain(&self) -> u8 {
285
2 * self.size()
286
}
287
288
// Offsets within `VMStackLimits`
289
290
/// Return the offset of `VMStackLimits::stack_limit`.
291
fn vmstack_limits_stack_limit(&self) -> u8 {
292
0
293
}
294
295
/// Return the offset of `VMStackLimits::last_wasm_entry_fp`.
296
fn vmstack_limits_last_wasm_entry_fp(&self) -> u8 {
297
self.size()
298
}
299
300
// Offsets within `VMHostArray`
301
302
/// Return the offset of `VMHostArray::length`.
303
fn vmhostarray_length(&self) -> u8 {
304
0
305
}
306
307
/// Return the offset of `VMHostArray::capacity`.
308
fn vmhostarray_capacity(&self) -> u8 {
309
4
310
}
311
312
/// Return the offset of `VMHostArray::data`.
313
fn vmhostarray_data(&self) -> u8 {
314
8
315
}
316
317
/// Return the size of `VMHostArray`.
318
fn size_of_vmhostarray(&self) -> u8 {
319
8 + self.size()
320
}
321
322
// Offsets within `VMCommonStackInformation`
323
324
/// Return the offset of `VMCommonStackInformation::limits`.
325
fn vmcommon_stack_information_limits(&self) -> u8 {
326
0 * self.size()
327
}
328
329
/// Return the offset of `VMCommonStackInformation::state`.
330
fn vmcommon_stack_information_state(&self) -> u8 {
331
2 * self.size()
332
}
333
334
/// Return the offset of `VMCommonStackInformation::handlers`.
335
fn vmcommon_stack_information_handlers(&self) -> u8 {
336
u8::try_from(align(
337
self.vmcommon_stack_information_state() as u32 + 4,
338
u32::from(self.size()),
339
))
340
.unwrap()
341
}
342
343
/// Return the offset of `VMCommonStackInformation::first_switch_handler_index`.
344
fn vmcommon_stack_information_first_switch_handler_index(&self) -> u8 {
345
self.vmcommon_stack_information_handlers() + self.size_of_vmhostarray()
346
}
347
348
/// Return the size of `VMCommonStackInformation`.
349
fn size_of_vmcommon_stack_information(&self) -> u8 {
350
u8::try_from(align(
351
self.vmcommon_stack_information_first_switch_handler_index() as u32 + 4,
352
u32::from(self.size()),
353
))
354
.unwrap()
355
}
356
357
// Offsets within `VMContObj`
358
359
/// Return the offset of `VMContObj::contref`
360
fn vmcontobj_contref(&self) -> u8 {
361
0
362
}
363
364
/// Return the offset of `VMContObj::revision`
365
fn vmcontobj_revision(&self) -> u8 {
366
self.size()
367
}
368
369
/// Return the size of `VMContObj`.
370
fn size_of_vmcontobj(&self) -> u8 {
371
u8::try_from(align(
372
u32::from(self.vmcontobj_revision())
373
+ u32::try_from(core::mem::size_of::<usize>()).unwrap(),
374
u32::from(self.size()),
375
))
376
.unwrap()
377
}
378
379
// Offsets within `VMContRef`
380
381
/// Return the offset of `VMContRef::common_stack_information`.
382
fn vmcontref_common_stack_information(&self) -> u8 {
383
0 * self.size()
384
}
385
386
/// Return the offset of `VMContRef::parent_chain`.
387
fn vmcontref_parent_chain(&self) -> u8 {
388
u8::try_from(align(
389
(self.vmcontref_common_stack_information() + self.size_of_vmcommon_stack_information())
390
as u32,
391
u32::from(self.size()),
392
))
393
.unwrap()
394
}
395
396
/// Return the offset of `VMContRef::last_ancestor`.
397
fn vmcontref_last_ancestor(&self) -> u8 {
398
self.vmcontref_parent_chain() + 2 * self.size()
399
}
400
401
/// Return the offset of `VMContRef::revision`.
402
fn vmcontref_revision(&self) -> u8 {
403
self.vmcontref_last_ancestor() + self.size()
404
}
405
406
/// Return the offset of `VMContRef::stack`.
407
fn vmcontref_stack(&self) -> u8 {
408
self.vmcontref_revision() + self.size()
409
}
410
411
/// Return the offset of `VMContRef::args`.
412
fn vmcontref_args(&self) -> u8 {
413
self.vmcontref_stack() + 3 * self.size()
414
}
415
416
/// Return the offset of `VMContRef::values`.
417
fn vmcontref_values(&self) -> u8 {
418
self.vmcontref_args() + self.size_of_vmhostarray()
419
}
420
421
/// Return the offset to the `magic` value in this `VMContext`.
422
#[inline]
423
fn vmctx_magic(&self) -> u8 {
424
// This is required by the implementation of `VMContext::instance` and
425
// `VMContext::instance_mut`. If this value changes then those locations
426
// need to be updated.
427
0
428
}
429
430
/// Return the offset to the `VMStoreContext` structure
431
#[inline]
432
fn vmctx_store_context(&self) -> u8 {
433
self.vmctx_magic() + self.size()
434
}
435
436
/// Return the offset to the `VMBuiltinFunctionsArray` structure
437
#[inline]
438
fn vmctx_builtin_functions(&self) -> u8 {
439
self.vmctx_store_context() + self.size()
440
}
441
442
/// Return the offset to the `*const AtomicU64` epoch-counter
443
/// pointer.
444
#[inline]
445
fn vmctx_epoch_ptr(&self) -> u8 {
446
self.vmctx_builtin_functions() + self.size()
447
}
448
449
/// Return the offset to the `*mut T` collector-specific data.
450
///
451
/// This is a pointer that different collectors can use however they see
452
/// fit.
453
#[inline]
454
fn vmctx_gc_heap_data(&self) -> u8 {
455
self.vmctx_epoch_ptr() + self.size()
456
}
457
458
/// The offset of the `type_ids` array pointer.
459
#[inline]
460
fn vmctx_type_ids_array(&self) -> u8 {
461
self.vmctx_gc_heap_data() + self.size()
462
}
463
464
/// The end of statically known offsets in `VMContext`.
465
///
466
/// Data after this is dynamically sized.
467
#[inline]
468
fn vmctx_dynamic_data_start(&self) -> u8 {
469
self.vmctx_type_ids_array() + self.size()
470
}
471
}
472
473
/// Type representing the size of a pointer for the current compilation host
474
#[derive(Clone, Copy)]
475
pub struct HostPtr;
476
477
impl PtrSize for HostPtr {
478
#[inline]
479
fn size(&self) -> u8 {
480
core::mem::size_of::<usize>() as u8
481
}
482
}
483
484
impl PtrSize for u8 {
485
#[inline]
486
fn size(&self) -> u8 {
487
*self
488
}
489
}
490
491
/// Used to construct a `VMOffsets`
492
#[derive(Debug, Clone, Copy)]
493
pub struct VMOffsetsFields<P> {
494
/// The size in bytes of a pointer on the target.
495
pub ptr: P,
496
/// The number of imported functions in the module.
497
pub num_imported_functions: u32,
498
/// The number of imported tables in the module.
499
pub num_imported_tables: u32,
500
/// The number of imported memories in the module.
501
pub num_imported_memories: u32,
502
/// The number of imported globals in the module.
503
pub num_imported_globals: u32,
504
/// The number of imported tags in the module.
505
pub num_imported_tags: u32,
506
/// The number of defined tables in the module.
507
pub num_defined_tables: u32,
508
/// The number of defined memories in the module.
509
pub num_defined_memories: u32,
510
/// The number of memories owned by the module instance.
511
pub num_owned_memories: u32,
512
/// The number of defined globals in the module.
513
pub num_defined_globals: u32,
514
/// The number of defined tags in the module.
515
pub num_defined_tags: u32,
516
/// The number of escaped functions in the module, the size of the function
517
/// references array.
518
pub num_escaped_funcs: u32,
519
}
520
521
impl<P: PtrSize> VMOffsets<P> {
522
/// Return a new `VMOffsets` instance, for a given pointer size.
523
pub fn new(ptr: P, module: &Module) -> Self {
524
let num_owned_memories = module
525
.memories
526
.iter()
527
.skip(module.num_imported_memories)
528
.filter(|p| !p.1.shared)
529
.count()
530
.try_into()
531
.unwrap();
532
VMOffsets::from(VMOffsetsFields {
533
ptr,
534
num_imported_functions: cast_to_u32(module.num_imported_funcs),
535
num_imported_tables: cast_to_u32(module.num_imported_tables),
536
num_imported_memories: cast_to_u32(module.num_imported_memories),
537
num_imported_globals: cast_to_u32(module.num_imported_globals),
538
num_imported_tags: cast_to_u32(module.num_imported_tags),
539
num_defined_tables: cast_to_u32(module.num_defined_tables()),
540
num_defined_memories: cast_to_u32(module.num_defined_memories()),
541
num_owned_memories,
542
num_defined_globals: cast_to_u32(module.globals.len() - module.num_imported_globals),
543
num_defined_tags: cast_to_u32(module.tags.len() - module.num_imported_tags),
544
num_escaped_funcs: cast_to_u32(module.num_escaped_funcs),
545
})
546
}
547
548
/// Returns the size, in bytes, of the target
549
#[inline]
550
pub fn pointer_size(&self) -> u8 {
551
self.ptr.size()
552
}
553
554
/// Returns an iterator which provides a human readable description and a
555
/// byte size. The iterator returned will iterate over the bytes allocated
556
/// to the entire `VMOffsets` structure to explain where each byte size is
557
/// coming from.
558
pub fn region_sizes(&self) -> impl Iterator<Item = (&str, u32)> {
559
macro_rules! calculate_sizes {
560
($($name:ident: $desc:tt,)*) => {{
561
let VMOffsets {
562
// These fields are metadata not talking about specific
563
// offsets of specific fields.
564
ptr: _,
565
num_imported_functions: _,
566
num_imported_tables: _,
567
num_imported_memories: _,
568
num_imported_globals: _,
569
num_imported_tags: _,
570
num_defined_tables: _,
571
num_defined_globals: _,
572
num_defined_memories: _,
573
num_defined_tags: _,
574
num_owned_memories: _,
575
num_escaped_funcs: _,
576
577
// used as the initial size below
578
size,
579
580
// exhaustively match the rest of the fields with input from
581
// the macro
582
$($name,)*
583
} = *self;
584
585
// calculate the size of each field by relying on the inputs to
586
// the macro being in reverse order and determining the size of
587
// the field as the offset from the field to the last field.
588
let mut last = size;
589
$(
590
assert!($name <= last);
591
let tmp = $name;
592
let $name = last - $name;
593
last = tmp;
594
)*
595
assert_ne!(last, 0);
596
IntoIterator::into_iter([
597
$(($desc, $name),)*
598
("static vmctx data", last),
599
])
600
}};
601
}
602
603
calculate_sizes! {
604
defined_func_refs: "module functions",
605
defined_tags: "defined tags",
606
defined_globals: "defined globals",
607
defined_tables: "defined tables",
608
imported_tags: "imported tags",
609
imported_globals: "imported globals",
610
imported_tables: "imported tables",
611
imported_functions: "imported functions",
612
owned_memories: "owned memories",
613
defined_memories: "defined memories",
614
imported_memories: "imported memories",
615
}
616
}
617
}
618
619
impl<P: PtrSize> From<VMOffsetsFields<P>> for VMOffsets<P> {
620
fn from(fields: VMOffsetsFields<P>) -> VMOffsets<P> {
621
let mut ret = Self {
622
ptr: fields.ptr,
623
num_imported_functions: fields.num_imported_functions,
624
num_imported_tables: fields.num_imported_tables,
625
num_imported_memories: fields.num_imported_memories,
626
num_imported_globals: fields.num_imported_globals,
627
num_imported_tags: fields.num_imported_tags,
628
num_defined_tables: fields.num_defined_tables,
629
num_defined_memories: fields.num_defined_memories,
630
num_owned_memories: fields.num_owned_memories,
631
num_defined_globals: fields.num_defined_globals,
632
num_defined_tags: fields.num_defined_tags,
633
num_escaped_funcs: fields.num_escaped_funcs,
634
imported_functions: 0,
635
imported_tables: 0,
636
imported_memories: 0,
637
imported_globals: 0,
638
imported_tags: 0,
639
defined_tables: 0,
640
defined_memories: 0,
641
owned_memories: 0,
642
defined_globals: 0,
643
defined_tags: 0,
644
defined_func_refs: 0,
645
size: 0,
646
};
647
648
// Convenience functions for checked addition and multiplication.
649
// As side effect this reduces binary size by using only a single
650
// `#[track_caller]` location for each function instead of one for
651
// each individual invocation.
652
#[inline]
653
fn cadd(count: u32, size: u32) -> u32 {
654
count.checked_add(size).unwrap()
655
}
656
657
#[inline]
658
fn cmul(count: u32, size: u8) -> u32 {
659
count.checked_mul(u32::from(size)).unwrap()
660
}
661
662
let mut next_field_offset = u32::from(ret.ptr.vmctx_dynamic_data_start());
663
664
macro_rules! fields {
665
(size($field:ident) = $size:expr, $($rest:tt)*) => {
666
ret.$field = next_field_offset;
667
next_field_offset = cadd(next_field_offset, u32::from($size));
668
fields!($($rest)*);
669
};
670
(align($align:expr), $($rest:tt)*) => {
671
next_field_offset = align(next_field_offset, $align);
672
fields!($($rest)*);
673
};
674
() => {};
675
}
676
677
fields! {
678
size(imported_memories)
679
= cmul(ret.num_imported_memories, ret.size_of_vmmemory_import()),
680
size(defined_memories)
681
= cmul(ret.num_defined_memories, ret.ptr.size_of_vmmemory_pointer()),
682
size(owned_memories)
683
= cmul(ret.num_owned_memories, ret.ptr.size_of_vmmemory_definition()),
684
size(imported_functions)
685
= cmul(ret.num_imported_functions, ret.size_of_vmfunction_import()),
686
size(imported_tables)
687
= cmul(ret.num_imported_tables, ret.size_of_vmtable_import()),
688
size(imported_globals)
689
= cmul(ret.num_imported_globals, ret.size_of_vmglobal_import()),
690
size(imported_tags)
691
= cmul(ret.num_imported_tags, ret.size_of_vmtag_import()),
692
size(defined_tables)
693
= cmul(ret.num_defined_tables, ret.size_of_vmtable_definition()),
694
align(16),
695
size(defined_globals)
696
= cmul(ret.num_defined_globals, ret.ptr.size_of_vmglobal_definition()),
697
size(defined_tags)
698
= cmul(ret.num_defined_tags, ret.ptr.size_of_vmtag_definition()),
699
size(defined_func_refs) = cmul(
700
ret.num_escaped_funcs,
701
ret.ptr.size_of_vm_func_ref(),
702
),
703
}
704
705
ret.size = next_field_offset;
706
707
return ret;
708
}
709
}
710
711
impl<P: PtrSize> VMOffsets<P> {
712
/// The offset of the `wasm_call` field.
713
#[inline]
714
pub fn vmfunction_import_wasm_call(&self) -> u8 {
715
0 * self.pointer_size()
716
}
717
718
/// The offset of the `array_call` field.
719
#[inline]
720
pub fn vmfunction_import_array_call(&self) -> u8 {
721
1 * self.pointer_size()
722
}
723
724
/// The offset of the `vmctx` field.
725
#[inline]
726
pub fn vmfunction_import_vmctx(&self) -> u8 {
727
2 * self.pointer_size()
728
}
729
730
/// Return the size of `VMFunctionImport`.
731
#[inline]
732
pub fn size_of_vmfunction_import(&self) -> u8 {
733
3 * self.pointer_size()
734
}
735
}
736
737
/// Offsets for `*const VMFunctionBody`.
738
impl<P: PtrSize> VMOffsets<P> {
739
/// The size of the `current_elements` field.
740
pub fn size_of_vmfunction_body_ptr(&self) -> u8 {
741
1 * self.pointer_size()
742
}
743
}
744
745
/// Offsets for `VMTableImport`.
746
impl<P: PtrSize> VMOffsets<P> {
747
/// The offset of the `from` field.
748
#[inline]
749
pub fn vmtable_import_from(&self) -> u8 {
750
0 * self.pointer_size()
751
}
752
753
/// The offset of the `vmctx` field.
754
#[inline]
755
pub fn vmtable_import_vmctx(&self) -> u8 {
756
1 * self.pointer_size()
757
}
758
759
/// The offset of the `index` field.
760
#[inline]
761
pub fn vmtable_import_index(&self) -> u8 {
762
2 * self.pointer_size()
763
}
764
765
/// Return the size of `VMTableImport`.
766
#[inline]
767
pub fn size_of_vmtable_import(&self) -> u8 {
768
3 * self.pointer_size()
769
}
770
}
771
772
/// Offsets for `VMTableDefinition`.
773
impl<P: PtrSize> VMOffsets<P> {
774
/// The offset of the `base` field.
775
#[inline]
776
pub fn vmtable_definition_base(&self) -> u8 {
777
0 * self.pointer_size()
778
}
779
780
/// The offset of the `current_elements` field.
781
pub fn vmtable_definition_current_elements(&self) -> u8 {
782
1 * self.pointer_size()
783
}
784
785
/// The size of the `current_elements` field.
786
#[inline]
787
pub fn size_of_vmtable_definition_current_elements(&self) -> u8 {
788
self.pointer_size()
789
}
790
791
/// Return the size of `VMTableDefinition`.
792
#[inline]
793
pub fn size_of_vmtable_definition(&self) -> u8 {
794
2 * self.pointer_size()
795
}
796
}
797
798
/// Offsets for `VMMemoryImport`.
799
impl<P: PtrSize> VMOffsets<P> {
800
/// The offset of the `from` field.
801
#[inline]
802
pub fn vmmemory_import_from(&self) -> u8 {
803
0 * self.pointer_size()
804
}
805
806
/// The offset of the `vmctx` field.
807
#[inline]
808
pub fn vmmemory_import_vmctx(&self) -> u8 {
809
1 * self.pointer_size()
810
}
811
812
/// The offset of the `index` field.
813
#[inline]
814
pub fn vmmemory_import_index(&self) -> u8 {
815
2 * self.pointer_size()
816
}
817
818
/// Return the size of `VMMemoryImport`.
819
#[inline]
820
pub fn size_of_vmmemory_import(&self) -> u8 {
821
3 * self.pointer_size()
822
}
823
}
824
825
/// Offsets for `VMGlobalImport`.
826
impl<P: PtrSize> VMOffsets<P> {
827
/// The offset of the `from` field.
828
#[inline]
829
pub fn vmglobal_import_from(&self) -> u8 {
830
0 * self.pointer_size()
831
}
832
833
/// Return the size of `VMGlobalImport`.
834
#[inline]
835
pub fn size_of_vmglobal_import(&self) -> u8 {
836
// `VMGlobalImport` has two pointers plus 8 bytes for `VMGlobalKind`
837
2 * self.pointer_size() + 8
838
}
839
}
840
841
/// Offsets for `VMSharedTypeIndex`.
842
impl<P: PtrSize> VMOffsets<P> {
843
/// Return the size of `VMSharedTypeIndex`.
844
#[inline]
845
pub fn size_of_vmshared_type_index(&self) -> u8 {
846
4
847
}
848
}
849
850
/// Offsets for `VMTagImport`.
851
impl<P: PtrSize> VMOffsets<P> {
852
/// The offset of the `from` field.
853
#[inline]
854
pub fn vmtag_import_from(&self) -> u8 {
855
0 * self.pointer_size()
856
}
857
858
/// The offset of the `vmctx` field.
859
#[inline]
860
pub fn vmtag_import_vmctx(&self) -> u8 {
861
1 * self.pointer_size()
862
}
863
864
/// The offset of the `index` field.
865
#[inline]
866
pub fn vmtag_import_index(&self) -> u8 {
867
2 * self.pointer_size()
868
}
869
870
/// Return the size of `VMTagImport`.
871
#[inline]
872
pub fn size_of_vmtag_import(&self) -> u8 {
873
3 * self.pointer_size()
874
}
875
}
876
877
/// Offsets for `VMContext`.
878
impl<P: PtrSize> VMOffsets<P> {
879
/// The offset of the `tables` array.
880
#[inline]
881
pub fn vmctx_imported_functions_begin(&self) -> u32 {
882
self.imported_functions
883
}
884
885
/// The offset of the `tables` array.
886
#[inline]
887
pub fn vmctx_imported_tables_begin(&self) -> u32 {
888
self.imported_tables
889
}
890
891
/// The offset of the `memories` array.
892
#[inline]
893
pub fn vmctx_imported_memories_begin(&self) -> u32 {
894
self.imported_memories
895
}
896
897
/// The offset of the `globals` array.
898
#[inline]
899
pub fn vmctx_imported_globals_begin(&self) -> u32 {
900
self.imported_globals
901
}
902
903
/// The offset of the `tags` array.
904
#[inline]
905
pub fn vmctx_imported_tags_begin(&self) -> u32 {
906
self.imported_tags
907
}
908
909
/// The offset of the `tables` array.
910
#[inline]
911
pub fn vmctx_tables_begin(&self) -> u32 {
912
self.defined_tables
913
}
914
915
/// The offset of the `memories` array.
916
#[inline]
917
pub fn vmctx_memories_begin(&self) -> u32 {
918
self.defined_memories
919
}
920
921
/// The offset of the `owned_memories` array.
922
#[inline]
923
pub fn vmctx_owned_memories_begin(&self) -> u32 {
924
self.owned_memories
925
}
926
927
/// The offset of the `globals` array.
928
#[inline]
929
pub fn vmctx_globals_begin(&self) -> u32 {
930
self.defined_globals
931
}
932
933
/// The offset of the `tags` array.
934
#[inline]
935
pub fn vmctx_tags_begin(&self) -> u32 {
936
self.defined_tags
937
}
938
939
/// The offset of the `func_refs` array.
940
#[inline]
941
pub fn vmctx_func_refs_begin(&self) -> u32 {
942
self.defined_func_refs
943
}
944
945
/// Return the size of the `VMContext` allocation.
946
#[inline]
947
pub fn size_of_vmctx(&self) -> u32 {
948
self.size
949
}
950
951
/// Return the offset to `VMFunctionImport` index `index`.
952
#[inline]
953
pub fn vmctx_vmfunction_import(&self, index: FuncIndex) -> u32 {
954
assert!(index.as_u32() < self.num_imported_functions);
955
self.vmctx_imported_functions_begin()
956
+ index.as_u32() * u32::from(self.size_of_vmfunction_import())
957
}
958
959
/// Return the offset to `VMTable` index `index`.
960
#[inline]
961
pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {
962
assert!(index.as_u32() < self.num_imported_tables);
963
self.vmctx_imported_tables_begin()
964
+ index.as_u32() * u32::from(self.size_of_vmtable_import())
965
}
966
967
/// Return the offset to `VMMemoryImport` index `index`.
968
#[inline]
969
pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {
970
assert!(index.as_u32() < self.num_imported_memories);
971
self.vmctx_imported_memories_begin()
972
+ index.as_u32() * u32::from(self.size_of_vmmemory_import())
973
}
974
975
/// Return the offset to `VMGlobalImport` index `index`.
976
#[inline]
977
pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {
978
assert!(index.as_u32() < self.num_imported_globals);
979
self.vmctx_imported_globals_begin()
980
+ index.as_u32() * u32::from(self.size_of_vmglobal_import())
981
}
982
983
/// Return the offset to `VMTagImport` index `index`.
984
#[inline]
985
pub fn vmctx_vmtag_import(&self, index: TagIndex) -> u32 {
986
assert!(index.as_u32() < self.num_imported_tags);
987
self.vmctx_imported_tags_begin() + index.as_u32() * u32::from(self.size_of_vmtag_import())
988
}
989
990
/// Return the offset to `VMTableDefinition` index `index`.
991
#[inline]
992
pub fn vmctx_vmtable_definition(&self, index: DefinedTableIndex) -> u32 {
993
assert!(index.as_u32() < self.num_defined_tables);
994
self.vmctx_tables_begin() + index.as_u32() * u32::from(self.size_of_vmtable_definition())
995
}
996
997
/// Return the offset to the `*mut VMMemoryDefinition` at index `index`.
998
#[inline]
999
pub fn vmctx_vmmemory_pointer(&self, index: DefinedMemoryIndex) -> u32 {
1000
assert!(index.as_u32() < self.num_defined_memories);
1001
self.vmctx_memories_begin()
1002
+ index.as_u32() * u32::from(self.ptr.size_of_vmmemory_pointer())
1003
}
1004
1005
/// Return the offset to the owned `VMMemoryDefinition` at index `index`.
1006
#[inline]
1007
pub fn vmctx_vmmemory_definition(&self, index: OwnedMemoryIndex) -> u32 {
1008
assert!(index.as_u32() < self.num_owned_memories);
1009
self.vmctx_owned_memories_begin()
1010
+ index.as_u32() * u32::from(self.ptr.size_of_vmmemory_definition())
1011
}
1012
1013
/// Return the offset to the `VMGlobalDefinition` index `index`.
1014
#[inline]
1015
pub fn vmctx_vmglobal_definition(&self, index: DefinedGlobalIndex) -> u32 {
1016
assert!(index.as_u32() < self.num_defined_globals);
1017
self.vmctx_globals_begin()
1018
+ index.as_u32() * u32::from(self.ptr.size_of_vmglobal_definition())
1019
}
1020
1021
/// Return the offset to the `VMTagDefinition` index `index`.
1022
#[inline]
1023
pub fn vmctx_vmtag_definition(&self, index: DefinedTagIndex) -> u32 {
1024
assert!(index.as_u32() < self.num_defined_tags);
1025
self.vmctx_tags_begin() + index.as_u32() * u32::from(self.ptr.size_of_vmtag_definition())
1026
}
1027
1028
/// Return the offset to the `VMFuncRef` for the given function
1029
/// index (either imported or defined).
1030
#[inline]
1031
pub fn vmctx_func_ref(&self, index: FuncRefIndex) -> u32 {
1032
assert!(!index.is_reserved_value());
1033
assert!(index.as_u32() < self.num_escaped_funcs);
1034
self.vmctx_func_refs_begin() + index.as_u32() * u32::from(self.ptr.size_of_vm_func_ref())
1035
}
1036
1037
/// Return the offset to the `wasm_call` field in `*const VMFunctionBody` index `index`.
1038
#[inline]
1039
pub fn vmctx_vmfunction_import_wasm_call(&self, index: FuncIndex) -> u32 {
1040
self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_wasm_call())
1041
}
1042
1043
/// Return the offset to the `array_call` field in `*const VMFunctionBody` index `index`.
1044
#[inline]
1045
pub fn vmctx_vmfunction_import_array_call(&self, index: FuncIndex) -> u32 {
1046
self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_array_call())
1047
}
1048
1049
/// Return the offset to the `vmctx` field in `*const VMFunctionBody` index `index`.
1050
#[inline]
1051
pub fn vmctx_vmfunction_import_vmctx(&self, index: FuncIndex) -> u32 {
1052
self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx())
1053
}
1054
1055
/// Return the offset to the `from` field in the imported `VMTable` at index
1056
/// `index`.
1057
#[inline]
1058
pub fn vmctx_vmtable_from(&self, index: TableIndex) -> u32 {
1059
self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_from())
1060
}
1061
1062
/// Return the offset to the `base` field in `VMTableDefinition` index `index`.
1063
#[inline]
1064
pub fn vmctx_vmtable_definition_base(&self, index: DefinedTableIndex) -> u32 {
1065
self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base())
1066
}
1067
1068
/// Return the offset to the `current_elements` field in `VMTableDefinition` index `index`.
1069
#[inline]
1070
pub fn vmctx_vmtable_definition_current_elements(&self, index: DefinedTableIndex) -> u32 {
1071
self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements())
1072
}
1073
1074
/// Return the offset to the `from` field in `VMMemoryImport` index `index`.
1075
#[inline]
1076
pub fn vmctx_vmmemory_import_from(&self, index: MemoryIndex) -> u32 {
1077
self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_from())
1078
}
1079
1080
/// Return the offset to the `base` field in `VMMemoryDefinition` index `index`.
1081
#[inline]
1082
pub fn vmctx_vmmemory_definition_base(&self, index: OwnedMemoryIndex) -> u32 {
1083
self.vmctx_vmmemory_definition(index) + u32::from(self.ptr.vmmemory_definition_base())
1084
}
1085
1086
/// Return the offset to the `current_length` field in `VMMemoryDefinition` index `index`.
1087
#[inline]
1088
pub fn vmctx_vmmemory_definition_current_length(&self, index: OwnedMemoryIndex) -> u32 {
1089
self.vmctx_vmmemory_definition(index)
1090
+ u32::from(self.ptr.vmmemory_definition_current_length())
1091
}
1092
1093
/// Return the offset to the `from` field in `VMGlobalImport` index `index`.
1094
#[inline]
1095
pub fn vmctx_vmglobal_import_from(&self, index: GlobalIndex) -> u32 {
1096
self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_from())
1097
}
1098
1099
/// Return the offset to the `from` field in `VMTagImport` index `index`.
1100
#[inline]
1101
pub fn vmctx_vmtag_import_from(&self, index: TagIndex) -> u32 {
1102
self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_from())
1103
}
1104
1105
/// Return the offset to the `vmctx` field in `VMTagImport` index `index`.
1106
#[inline]
1107
pub fn vmctx_vmtag_import_vmctx(&self, index: TagIndex) -> u32 {
1108
self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_vmctx())
1109
}
1110
1111
/// Return the offset to the `index` field in `VMTagImport` index `index`.
1112
#[inline]
1113
pub fn vmctx_vmtag_import_index(&self, index: TagIndex) -> u32 {
1114
self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_index())
1115
}
1116
}
1117
1118
/// Offsets for `VMGcHeader`.
1119
impl<P: PtrSize> VMOffsets<P> {
1120
/// Return the offset for the `VMGcHeader::kind` field.
1121
#[inline]
1122
pub fn vm_gc_header_kind(&self) -> u32 {
1123
0
1124
}
1125
1126
/// Return the offset for the `VMGcHeader`'s reserved bits.
1127
#[inline]
1128
pub fn vm_gc_header_reserved_bits(&self) -> u32 {
1129
// NB: The reserved bits are the unused `VMGcKind` bits.
1130
self.vm_gc_header_kind()
1131
}
1132
1133
/// Return the offset for the `VMGcHeader::ty` field.
1134
#[inline]
1135
pub fn vm_gc_header_ty(&self) -> u32 {
1136
self.vm_gc_header_kind() + 4
1137
}
1138
}
1139
1140
/// Offsets for `VMDrcHeader`.
1141
///
1142
/// Should only be used when the DRC collector is enabled.
1143
impl<P: PtrSize> VMOffsets<P> {
1144
/// Return the offset for `VMDrcHeader::ref_count`.
1145
#[inline]
1146
pub fn vm_drc_header_ref_count(&self) -> u32 {
1147
8
1148
}
1149
1150
/// Return the offset for `VMDrcHeader::next_over_approximated_stack_root`.
1151
#[inline]
1152
pub fn vm_drc_header_next_over_approximated_stack_root(&self) -> u32 {
1153
self.vm_drc_header_ref_count() + 8
1154
}
1155
}
1156
1157
/// Magic value for core Wasm VM contexts.
1158
///
1159
/// This is stored at the start of all `VMContext` structures.
1160
pub const VMCONTEXT_MAGIC: u32 = u32::from_le_bytes(*b"core");
1161
1162
/// Equivalent of `VMCONTEXT_MAGIC` except for array-call host functions.
1163
///
1164
/// This is stored at the start of all `VMArrayCallHostFuncContext` structures
1165
/// and double-checked on `VMArrayCallHostFuncContext::from_opaque`.
1166
pub const VM_ARRAY_CALL_HOST_FUNC_MAGIC: u32 = u32::from_le_bytes(*b"ACHF");
1167
1168
#[cfg(test)]
1169
mod tests {
1170
use crate::vmoffsets::align;
1171
1172
#[test]
1173
fn alignment() {
1174
fn is_aligned(x: u32) -> bool {
1175
x % 16 == 0
1176
}
1177
assert!(is_aligned(align(0, 16)));
1178
assert!(is_aligned(align(32, 16)));
1179
assert!(is_aligned(align(33, 16)));
1180
assert!(is_aligned(align(31, 16)));
1181
}
1182
}
1183
1184