@@ -3,7 +3,7 @@ use crate::descriptor::{Descriptor, Function};
3
3
use crate :: descriptors:: WasmBindgenDescriptorsSection ;
4
4
use crate :: intrinsic:: Intrinsic ;
5
5
use anyhow:: { anyhow, bail, Error } ;
6
- use std:: collections:: HashMap ;
6
+ use std:: collections:: { HashMap , HashSet } ;
7
7
use std:: str;
8
8
use walrus:: MemoryId ;
9
9
use walrus:: { ExportId , FunctionId , ImportId , Module } ;
@@ -107,21 +107,47 @@ impl<'a> Context<'a> {
107
107
// placeholder module name which we'll want to be sure that we've got a
108
108
// location listed of what to import there for each item.
109
109
let mut intrinsics = Vec :: new ( ) ;
110
+ let mut duplicate_import_map = HashMap :: new ( ) ;
111
+ let mut imports_to_delete = HashSet :: new ( ) ;
110
112
for import in self . module . imports . iter ( ) {
111
113
if import. module != PLACEHOLDER_MODULE {
112
114
continue ;
113
115
}
114
- if let walrus:: ImportKind :: Function ( f) = import. kind {
115
- self . function_imports
116
- . insert ( import. name . clone ( ) , ( import. id ( ) , f) ) ;
117
- if let Some ( intrinsic) = Intrinsic :: from_symbol ( & import. name ) {
118
- intrinsics. push ( ( import. id ( ) , intrinsic) ) ;
116
+ let f = match import. kind {
117
+ walrus:: ImportKind :: Function ( f) => f,
118
+ _ => continue ,
119
+ } ;
120
+
121
+ match self . function_imports . get ( & import. name ) {
122
+ // If this `import.name` already exists in our import map, then
123
+ // we need to delete `import`. We also need to replace any
124
+ // references to it with `prev_func`, so register that here to
125
+ // happen later.
126
+ Some ( ( _, prev_func) ) => {
127
+ imports_to_delete. insert ( import. id ( ) ) ;
128
+ duplicate_import_map. insert ( f, * prev_func) ;
129
+ }
130
+
131
+ // Otherwise this is brand new, so insert it into the map.
132
+ None => {
133
+ self . function_imports
134
+ . insert ( import. name . clone ( ) , ( import. id ( ) , f) ) ;
119
135
}
120
136
}
137
+
138
+ // Test to see if this is an intrinsic symbol, in which case we'll
139
+ // process this later.
140
+ if let Some ( intrinsic) = Intrinsic :: from_symbol ( & import. name ) {
141
+ intrinsics. push ( ( import. id ( ) , intrinsic) ) ;
142
+ }
121
143
}
122
144
for ( id, intrinsic) in intrinsics {
123
145
self . bind_intrinsic ( id, intrinsic) ?;
124
146
}
147
+ for import in imports_to_delete {
148
+ self . module . imports . delete ( import) ;
149
+ }
150
+ self . handle_duplicate_imports ( & duplicate_import_map) ;
125
151
126
152
self . inject_anyref_initialization ( ) ?;
127
153
@@ -182,6 +208,38 @@ impl<'a> Context<'a> {
182
208
Ok ( ( ) )
183
209
}
184
210
211
+ /// The same name function from the same module may be imported at different
212
+ /// points in a program. The compiler may synthesize two `import`
213
+ /// statements, both with the same module/name, to match these two function
214
+ /// imports. This is handled here.
215
+ ///
216
+ /// Almost all of our handling of directives and such is string-based (eew)
217
+ /// instead of ID based due to the way the macro works right now. This means
218
+ /// that we don't work well with these duplicate imports. As a result when
219
+ /// we see these duplicate imports we fixup the module to ensure that only
220
+ /// one import is used, deleting all the other imports. This is what's
221
+ /// wanted anyway in terms of semantics.
222
+ ///
223
+ /// The map provided here is a map where the key is a function id to replace
224
+ /// and the value is what to replace it with.
225
+ fn handle_duplicate_imports ( & mut self , map : & HashMap < FunctionId , FunctionId > ) {
226
+ struct Replace < ' a > {
227
+ map : & ' a HashMap < FunctionId , FunctionId > ,
228
+ }
229
+ impl walrus:: ir:: VisitorMut for Replace < ' _ > {
230
+ fn visit_function_id_mut ( & mut self , function : & mut FunctionId ) {
231
+ if let Some ( replacement) = self . map . get ( function) {
232
+ * function = * replacement;
233
+ }
234
+ }
235
+ }
236
+ let mut replace = Replace { map } ;
237
+ for ( _id, func) in self . module . funcs . iter_local_mut ( ) {
238
+ let entry = func. entry_block ( ) ;
239
+ walrus:: ir:: dfs_pre_order_mut ( & mut replace, func, entry) ;
240
+ }
241
+ }
242
+
185
243
// Discover a function `main(i32, i32) -> i32` and, if it exists, make that function run at module start.
186
244
fn discover_main ( & mut self ) -> Result < ( ) , Error > {
187
245
// find a `main(i32, i32) -> i32`
0 commit comments