Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/component-util/src/lib.rs
1692 views
1
//! > **⚠️ Warning ⚠️**: this crate is an internal-only crate for the Wasmtime
2
//! > project and is not intended for general use. APIs are not strictly
3
//! > reviewed for safety and usage outside of Wasmtime may have bugs. If
4
//! > you're interested in using this feel free to file an issue on the
5
//! > Wasmtime repository to start a discussion about doing so, but otherwise
6
//! > be aware that your usage of this crate is not supported.
7
8
#![no_std]
9
10
/// Represents the possible sizes in bytes of the discriminant of a variant type in the component model
11
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
12
pub enum DiscriminantSize {
13
/// 8-bit discriminant
14
Size1,
15
/// 16-bit discriminant
16
Size2,
17
/// 32-bit discriminant
18
Size4,
19
}
20
21
impl DiscriminantSize {
22
/// Calculate the size of discriminant needed to represent a variant with the specified number of cases.
23
pub const fn from_count(count: usize) -> Option<Self> {
24
if count <= 0xFF {
25
Some(Self::Size1)
26
} else if count <= 0xFFFF {
27
Some(Self::Size2)
28
} else if count <= 0xFFFF_FFFF {
29
Some(Self::Size4)
30
} else {
31
None
32
}
33
}
34
35
/// Returns the size, in bytes, of this discriminant
36
pub const fn byte_size(&self) -> u32 {
37
match self {
38
DiscriminantSize::Size1 => 1,
39
DiscriminantSize::Size2 => 2,
40
DiscriminantSize::Size4 => 4,
41
}
42
}
43
}
44
45
impl From<DiscriminantSize> for u32 {
46
/// Size of the discriminant as a `u32`
47
fn from(size: DiscriminantSize) -> u32 {
48
size.byte_size()
49
}
50
}
51
52
impl From<DiscriminantSize> for usize {
53
/// Size of the discriminant as a `usize`
54
fn from(size: DiscriminantSize) -> usize {
55
match size {
56
DiscriminantSize::Size1 => 1,
57
DiscriminantSize::Size2 => 2,
58
DiscriminantSize::Size4 => 4,
59
}
60
}
61
}
62
63
/// Represents the number of bytes required to store a flags value in the component model
64
pub enum FlagsSize {
65
/// There are no flags
66
Size0,
67
/// Flags can fit in a u8
68
Size1,
69
/// Flags can fit in a u16
70
Size2,
71
/// Flags can fit in a specified number of u32 fields
72
Size4Plus(u8),
73
}
74
75
impl FlagsSize {
76
/// Calculate the size needed to represent a value with the specified number of flags.
77
pub const fn from_count(count: usize) -> FlagsSize {
78
if count == 0 {
79
FlagsSize::Size0
80
} else if count <= 8 {
81
FlagsSize::Size1
82
} else if count <= 16 {
83
FlagsSize::Size2
84
} else {
85
let amt = count.div_ceil(32);
86
if amt > (u8::MAX as usize) {
87
panic!("too many flags");
88
}
89
FlagsSize::Size4Plus(amt as u8)
90
}
91
}
92
}
93
94
/// A simple bump allocator which can be used with modules
95
pub const REALLOC_AND_FREE: &str = r#"
96
(global $last (mut i32) (i32.const 8))
97
(func $realloc (export "realloc")
98
(param $old_ptr i32)
99
(param $old_size i32)
100
(param $align i32)
101
(param $new_size i32)
102
(result i32)
103
104
(local $ret i32)
105
106
;; Test if the old pointer is non-null
107
local.get $old_ptr
108
if
109
;; If the old size is bigger than the new size then
110
;; this is a shrink and transparently allow it
111
local.get $old_size
112
local.get $new_size
113
i32.gt_u
114
if
115
local.get $old_ptr
116
return
117
end
118
119
;; otherwise fall through to allocate a new chunk which will later
120
;; copy data over
121
end
122
123
;; align up `$last`
124
(global.set $last
125
(i32.and
126
(i32.add
127
(global.get $last)
128
(i32.add
129
(local.get $align)
130
(i32.const -1)))
131
(i32.xor
132
(i32.add
133
(local.get $align)
134
(i32.const -1))
135
(i32.const -1))))
136
137
;; save the current value of `$last` as the return value
138
global.get $last
139
local.set $ret
140
141
;; bump our pointer
142
(global.set $last
143
(i32.add
144
(global.get $last)
145
(local.get $new_size)))
146
147
;; while `memory.size` is less than `$last`, grow memory
148
;; by one page
149
(loop $loop
150
(if
151
(i32.lt_u
152
(i32.mul (memory.size) (i32.const 65536))
153
(global.get $last))
154
(then
155
i32.const 1
156
memory.grow
157
;; test to make sure growth succeeded
158
i32.const -1
159
i32.eq
160
if unreachable end
161
162
br $loop)))
163
164
165
;; ensure anything necessary is set to valid data by spraying a bit
166
;; pattern that is invalid
167
local.get $ret
168
i32.const 0xde
169
local.get $new_size
170
memory.fill
171
172
;; If the old pointer is present then that means this was a reallocation
173
;; of an existing chunk which means the existing data must be copied.
174
local.get $old_ptr
175
if
176
local.get $ret ;; destination
177
local.get $old_ptr ;; source
178
local.get $old_size ;; size
179
memory.copy
180
end
181
182
local.get $ret
183
)
184
"#;
185
186