1use crate::transform::{InnerTransform, Transformed, Transformer};
2use crate::visit::{InnerVisit, Visitor};
3use crate::{
4 AttrSet, Const, Context, DataInstForm, DeclDef, ExportKey, Exportee, Func, FxIndexSet,
5 GlobalVar, Import, Module, Type,
6};
7use rustc_hash::{FxHashMap, FxHashSet};
8use std::collections::VecDeque;
9
10pub fn minimize_exports(module: &mut Module, is_root: impl Fn(&ExportKey) -> bool) {
28 let mut collector = LiveExportCollector {
29 cx: module.cx_ref(),
30 module,
31
32 live_exports: FxIndexSet::default(),
33
34 seen_types: FxHashSet::default(),
35 seen_consts: FxHashSet::default(),
36 seen_data_inst_forms: FxHashSet::default(),
37 seen_global_vars: FxHashSet::default(),
38 seen_funcs: FxHashSet::default(),
39 };
40 for (export_key, &exportee) in &module.exports {
41 if is_root(export_key) && collector.live_exports.insert(export_key.clone()) {
42 exportee.inner_visit_with(&mut collector);
43 }
44 }
45 module.exports = collector
46 .live_exports
47 .into_iter()
48 .map(|export_key| {
49 let exportee = module.exports[&export_key];
50 (export_key, exportee)
51 })
52 .collect();
53}
54
55struct LiveExportCollector<'a> {
56 cx: &'a Context,
57 module: &'a Module,
58
59 live_exports: FxIndexSet<ExportKey>,
60
61 seen_types: FxHashSet<Type>,
63 seen_consts: FxHashSet<Const>,
64 seen_data_inst_forms: FxHashSet<DataInstForm>,
65 seen_global_vars: FxHashSet<GlobalVar>,
66 seen_funcs: FxHashSet<Func>,
67}
68
69impl Visitor<'_> for LiveExportCollector<'_> {
70 fn visit_attr_set_use(&mut self, _attrs: AttrSet) {
72 }
74 fn visit_type_use(&mut self, ty: Type) {
75 if self.seen_types.insert(ty) {
76 self.visit_type_def(&self.cx[ty]);
77 }
78 }
79 fn visit_const_use(&mut self, ct: Const) {
80 if self.seen_consts.insert(ct) {
81 self.visit_const_def(&self.cx[ct]);
82 }
83 }
84 fn visit_data_inst_form_use(&mut self, data_inst_form: DataInstForm) {
85 if self.seen_data_inst_forms.insert(data_inst_form) {
86 self.visit_data_inst_form_def(&self.cx[data_inst_form]);
87 }
88 }
89
90 fn visit_global_var_use(&mut self, gv: GlobalVar) {
91 if self.seen_global_vars.insert(gv) {
92 self.visit_global_var_decl(&self.module.global_vars[gv]);
93 }
94 }
95 fn visit_func_use(&mut self, func: Func) {
96 if self.seen_funcs.insert(func) {
97 self.visit_func_decl(&self.module.funcs[func]);
98 }
99 }
100
101 fn visit_import(&mut self, import: &Import) {
102 match *import {
103 Import::LinkName(name) => {
104 let export_key = ExportKey::LinkName(name);
105 if let Some(&exportee) = self.module.exports.get(&export_key) {
106 if self.live_exports.insert(export_key) {
107 exportee.inner_visit_with(self);
108 }
109 }
110 }
111 }
112 }
113}
114
115pub fn resolve_imports(module: &mut Module) {
121 let (resolved_global_vars, resolved_funcs) = {
122 let mut collector = ImportResolutionCollector {
123 cx: module.cx_ref(),
124 module,
125
126 resolved_global_vars: FxHashMap::default(),
127 resolved_funcs: FxHashMap::default(),
128
129 seen_types: FxHashSet::default(),
130 seen_consts: FxHashSet::default(),
131 seen_data_inst_forms: FxHashSet::default(),
132 seen_global_vars: FxHashSet::default(),
133 seen_funcs: FxHashSet::default(),
134 };
135 collector.visit_module(module);
136 (collector.resolved_global_vars, collector.resolved_funcs)
137 };
138
139 let mut resolver = ImportResolver {
140 cx: &module.cx(),
141
142 resolved_global_vars: &resolved_global_vars,
143 resolved_funcs: &resolved_funcs,
144
145 transformed_types: FxHashMap::default(),
146 transformed_consts: FxHashMap::default(),
147 transformed_data_inst_forms: FxHashMap::default(),
148 transformed_global_vars: FxHashMap::default(),
149 global_var_queue: VecDeque::new(),
150 transformed_funcs: FxHashMap::default(),
151 func_queue: VecDeque::new(),
152 };
153
154 for exportee in module.exports.values_mut() {
156 exportee.inner_transform_with(&mut resolver).apply_to(exportee);
157 }
158
159 while !resolver.global_var_queue.is_empty() || !resolver.func_queue.is_empty() {
161 while let Some(gv) = resolver.global_var_queue.pop_front() {
162 resolver.in_place_transform_global_var_decl(&mut module.global_vars[gv]);
163 }
164 while let Some(func) = resolver.func_queue.pop_front() {
165 resolver.in_place_transform_func_decl(&mut module.funcs[func]);
166 }
167 }
168}
169
170struct ImportResolutionCollector<'a> {
173 cx: &'a Context,
174 module: &'a Module,
175
176 resolved_global_vars: FxHashMap<GlobalVar, GlobalVar>,
177 resolved_funcs: FxHashMap<Func, Func>,
178
179 seen_types: FxHashSet<Type>,
181 seen_consts: FxHashSet<Const>,
182 seen_data_inst_forms: FxHashSet<DataInstForm>,
183 seen_global_vars: FxHashSet<GlobalVar>,
184 seen_funcs: FxHashSet<Func>,
185}
186
187impl Visitor<'_> for ImportResolutionCollector<'_> {
188 fn visit_attr_set_use(&mut self, _attrs: AttrSet) {
190 }
192 fn visit_type_use(&mut self, ty: Type) {
193 if self.seen_types.insert(ty) {
194 self.visit_type_def(&self.cx[ty]);
195 }
196 }
197 fn visit_const_use(&mut self, ct: Const) {
198 if self.seen_consts.insert(ct) {
199 self.visit_const_def(&self.cx[ct]);
200 }
201 }
202 fn visit_data_inst_form_use(&mut self, data_inst_form: DataInstForm) {
203 if self.seen_data_inst_forms.insert(data_inst_form) {
204 self.visit_data_inst_form_def(&self.cx[data_inst_form]);
205 }
206 }
207
208 fn visit_global_var_use(&mut self, gv: GlobalVar) {
209 if self.seen_global_vars.insert(gv) {
210 let gv_decl = &self.module.global_vars[gv];
211 self.visit_global_var_decl(gv_decl);
212
213 if let DeclDef::Imported(Import::LinkName(name)) = gv_decl.def {
217 if let Some(&Exportee::GlobalVar(def_gv)) =
218 self.module.exports.get(&ExportKey::LinkName(name))
219 {
220 self.resolved_global_vars.insert(gv, def_gv);
221 }
222 }
223 }
224 }
225 fn visit_func_use(&mut self, func: Func) {
226 if self.seen_funcs.insert(func) {
227 let func_decl = &self.module.funcs[func];
228 self.visit_func_decl(func_decl);
229
230 if let DeclDef::Imported(Import::LinkName(name)) = func_decl.def {
234 if let Some(&Exportee::Func(def_func)) =
235 self.module.exports.get(&ExportKey::LinkName(name))
236 {
237 self.resolved_funcs.insert(func, def_func);
238 }
239 }
240 }
241 }
242}
243
244struct ImportResolver<'a> {
245 cx: &'a Context,
246
247 resolved_global_vars: &'a FxHashMap<GlobalVar, GlobalVar>,
248 resolved_funcs: &'a FxHashMap<Func, Func>,
249
250 transformed_types: FxHashMap<Type, Transformed<Type>>,
252 transformed_consts: FxHashMap<Const, Transformed<Const>>,
253 transformed_data_inst_forms: FxHashMap<DataInstForm, Transformed<DataInstForm>>,
254 transformed_global_vars: FxHashMap<GlobalVar, Transformed<GlobalVar>>,
255 global_var_queue: VecDeque<GlobalVar>,
256 transformed_funcs: FxHashMap<Func, Transformed<Func>>,
257 func_queue: VecDeque<Func>,
258}
259
260impl Transformer for ImportResolver<'_> {
261 fn transform_type_use(&mut self, ty: Type) -> Transformed<Type> {
263 if let Some(&cached) = self.transformed_types.get(&ty) {
264 return cached;
265 }
266 let transformed =
267 self.transform_type_def(&self.cx[ty]).map(|ty_def| self.cx.intern(ty_def));
268 self.transformed_types.insert(ty, transformed);
269 transformed
270 }
271 fn transform_const_use(&mut self, ct: Const) -> Transformed<Const> {
272 if let Some(&cached) = self.transformed_consts.get(&ct) {
273 return cached;
274 }
275 let transformed =
276 self.transform_const_def(&self.cx[ct]).map(|ct_def| self.cx.intern(ct_def));
277 self.transformed_consts.insert(ct, transformed);
278 transformed
279 }
280 fn transform_data_inst_form_use(
281 &mut self,
282 data_inst_form: DataInstForm,
283 ) -> Transformed<DataInstForm> {
284 if let Some(&cached) = self.transformed_data_inst_forms.get(&data_inst_form) {
285 return cached;
286 }
287 let transformed = self
288 .transform_data_inst_form_def(&self.cx[data_inst_form])
289 .map(|data_inst_form_def| self.cx.intern(data_inst_form_def));
290 self.transformed_data_inst_forms.insert(data_inst_form, transformed);
291 transformed
292 }
293
294 fn transform_global_var_use(&mut self, gv: GlobalVar) -> Transformed<GlobalVar> {
295 if let Some(&cached) = self.transformed_global_vars.get(&gv) {
296 return cached;
297 }
298 let transformed = match self.resolved_global_vars.get(&gv).copied() {
299 Some(mut new_gv) => {
300 self.transform_global_var_use(new_gv).apply_to(&mut new_gv);
301 Transformed::Changed(new_gv)
302 }
303 None => {
304 self.global_var_queue.push_back(gv);
305 Transformed::Unchanged
306 }
307 };
308 self.transformed_global_vars.insert(gv, transformed);
309 transformed
310 }
311 fn transform_func_use(&mut self, func: Func) -> Transformed<Func> {
312 if let Some(&cached) = self.transformed_funcs.get(&func) {
313 return cached;
314 }
315 let transformed = match self.resolved_funcs.get(&func).copied() {
316 Some(mut new_func) => {
317 self.transform_func_use(new_func).apply_to(&mut new_func);
318 Transformed::Changed(new_func)
319 }
320 None => {
321 self.func_queue.push_back(func);
322 Transformed::Unchanged
323 }
324 };
325 self.transformed_funcs.insert(func, transformed);
326 transformed
327 }
328}