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