1use std::{
5 collections::{hash_map::Entry, HashMap},
6 sync::RwLock,
7};
8use std::{convert::TryFrom, sync::Arc};
9use wasmtime_environ::{ModuleTypes, PrimaryMap, SignatureIndex, WasmFuncType};
10use wasmtime_runtime::{VMSharedSignatureIndex, VMTrampoline};
11
12#[derive(Debug)]
19pub struct SignatureCollection {
20 registry: Arc<RwLock<SignatureRegistryInner>>,
21 signatures: PrimaryMap<SignatureIndex, VMSharedSignatureIndex>,
22 trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
23}
24
25impl SignatureCollection {
26 pub fn new_for_module(
29 registry: &SignatureRegistry,
30 types: &ModuleTypes,
31 trampolines: impl Iterator<Item = (SignatureIndex, VMTrampoline)>,
32 ) -> Self {
33 let (signatures, trampolines) = registry
34 .0
35 .write()
36 .unwrap()
37 .register_for_module(types, trampolines);
38
39 Self {
40 registry: registry.0.clone(),
41 signatures,
42 trampolines,
43 }
44 }
45
46 pub fn as_module_map(&self) -> &PrimaryMap<SignatureIndex, VMSharedSignatureIndex> {
52 &self.signatures
53 }
54
55 pub fn shared_signature(&self, index: SignatureIndex) -> Option<VMSharedSignatureIndex> {
57 self.signatures.get(index).copied()
58 }
59
60 pub fn trampoline(&self, index: VMSharedSignatureIndex) -> Option<VMTrampoline> {
62 self.trampolines.get(&index).copied()
63 }
64}
65
66impl Drop for SignatureCollection {
67 fn drop(&mut self) {
68 if !self.signatures.is_empty() || !self.trampolines.is_empty() {
69 self.registry.write().unwrap().unregister_signatures(self);
70 }
71 }
72}
73
74#[derive(Debug)]
75struct RegistryEntry {
76 references: usize,
77 ty: WasmFuncType,
78}
79
80#[derive(Debug, Default)]
81struct SignatureRegistryInner {
82 map: HashMap<WasmFuncType, VMSharedSignatureIndex>,
83 entries: Vec<Option<RegistryEntry>>,
84 free: Vec<VMSharedSignatureIndex>,
85}
86
87impl SignatureRegistryInner {
88 fn register_for_module(
89 &mut self,
90 types: &ModuleTypes,
91 trampolines: impl Iterator<Item = (SignatureIndex, VMTrampoline)>,
92 ) -> (
93 PrimaryMap<SignatureIndex, VMSharedSignatureIndex>,
94 HashMap<VMSharedSignatureIndex, VMTrampoline>,
95 ) {
96 let mut sigs = PrimaryMap::default();
97 let mut map = HashMap::default();
98
99 for (idx, ty) in types.wasm_signatures() {
100 let b = sigs.push(self.register(ty));
101 assert_eq!(idx, b);
102 }
103
104 for (index, trampoline) in trampolines {
105 map.insert(sigs[index], trampoline);
106 }
107
108 (sigs, map)
109 }
110
111 fn register(&mut self, ty: &WasmFuncType) -> VMSharedSignatureIndex {
112 let len = self.map.len();
113
114 let index = match self.map.entry(ty.clone()) {
115 Entry::Occupied(e) => *e.get(),
116 Entry::Vacant(e) => {
117 let (index, entry) = match self.free.pop() {
118 Some(index) => (index, &mut self.entries[index.bits() as usize]),
119 None => {
120 assert!(
123 len < std::u32::MAX as usize,
124 "Invariant check: index_map.len() < std::u32::MAX"
125 );
126 debug_assert_eq!(len, self.entries.len());
127
128 let index = VMSharedSignatureIndex::new(u32::try_from(len).unwrap());
129 self.entries.push(None);
130
131 (index, self.entries.last_mut().unwrap())
132 }
133 };
134
135 assert!(entry.is_none());
138
139 *entry = Some(RegistryEntry {
140 references: 0,
141 ty: ty.clone(),
142 });
143
144 *e.insert(index)
145 }
146 };
147
148 self.entries[index.bits() as usize]
149 .as_mut()
150 .unwrap()
151 .references += 1;
152
153 index
154 }
155
156 fn unregister_signatures(&mut self, collection: &SignatureCollection) {
157 if !collection.signatures.is_empty() {
160 for (_, index) in collection.signatures.iter() {
161 self.unregister_entry(*index, 1);
162 }
163 } else {
164 for (index, _) in collection.trampolines.iter() {
167 self.unregister_entry(*index, 1);
168 }
169 }
170 }
171
172 fn unregister_entry(&mut self, index: VMSharedSignatureIndex, count: usize) {
173 let removed = {
174 let entry = self.entries[index.bits() as usize].as_mut().unwrap();
175
176 debug_assert!(entry.references >= count);
177 entry.references -= count;
178
179 if entry.references == 0 {
180 self.map.remove(&entry.ty);
181 self.free.push(index);
182 true
183 } else {
184 false
185 }
186 };
187
188 if removed {
189 self.entries[index.bits() as usize] = None;
190 }
191 }
192}
193
194#[cfg(debug_assertions)]
197impl Drop for SignatureRegistryInner {
198 fn drop(&mut self) {
199 assert!(
200 self.map.is_empty() && self.free.len() == self.entries.len(),
201 "signature registry not empty"
202 );
203 }
204}
205
206#[derive(Debug)]
213pub struct SignatureRegistry(Arc<RwLock<SignatureRegistryInner>>);
214
215impl SignatureRegistry {
216 pub fn new() -> Self {
218 Self(Arc::new(RwLock::new(SignatureRegistryInner::default())))
219 }
220
221 pub fn lookup_type(&self, index: VMSharedSignatureIndex) -> Option<WasmFuncType> {
223 self.0
224 .read()
225 .unwrap()
226 .entries
227 .get(index.bits() as usize)
228 .and_then(|e| e.as_ref().map(|e| &e.ty).cloned())
229 }
230
231 pub fn register(&self, ty: &WasmFuncType) -> VMSharedSignatureIndex {
235 self.0.write().unwrap().register(ty)
236 }
237
238 pub unsafe fn unregister(&self, sig: VMSharedSignatureIndex) {
242 self.0.write().unwrap().unregister_entry(sig, 1)
243 }
244}