1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
use crate::ast::*;
use crate::resolve::gensym;
use std::mem;

pub fn run(fields: &mut Vec<ModuleField>) {
    let mut cur = 0;
    let mut to_append = Vec::new();
    while cur < fields.len() {
        let item = &mut fields[cur];
        match item {
            ModuleField::Func(f) => {
                for name in f.exports.names.drain(..) {
                    let id = gensym::fill(f.span, &mut f.id);
                    to_append.push(ModuleField::Export(Export {
                        span: f.span,
                        name,
                        kind: ExportKind::Func(Index::Id(id)),
                    }));
                }
                match f.kind {
                    FuncKind::Import(import) => {
                        *item = ModuleField::Import(Import {
                            span: f.span,
                            module: import.module,
                            field: import.field,
                            item: ItemSig {
                                span: f.span,
                                id: f.id,
                                name: f.name,
                                kind: ItemKind::Func(f.ty.clone()),
                            },
                        });
                    }
                    FuncKind::Inline { .. } => {}
                }
            }

            ModuleField::Memory(m) => {
                for name in m.exports.names.drain(..) {
                    let id = gensym::fill(m.span, &mut m.id);
                    to_append.push(ModuleField::Export(Export {
                        span: m.span,
                        name,
                        kind: ExportKind::Memory(Index::Id(id)),
                    }));
                }
                match m.kind {
                    MemoryKind::Import { import, ty } => {
                        *item = ModuleField::Import(Import {
                            span: m.span,
                            module: import.module,
                            field: import.field,
                            item: ItemSig {
                                span: m.span,
                                id: m.id,
                                name: None,
                                kind: ItemKind::Memory(ty),
                            },
                        });
                    }
                    // If data is defined inline insert an explicit `data` module
                    // field here instead, switching this to a `Normal` memory.
                    MemoryKind::Inline { is_32, ref data } => {
                        let len = data.iter().map(|l| l.len()).sum::<usize>() as u32;
                        let pages = (len + page_size() - 1) / page_size();
                        let kind = MemoryKind::Normal(if is_32 {
                            MemoryType::B32 {
                                limits: Limits {
                                    min: pages,
                                    max: Some(pages),
                                },
                                shared: false,
                            }
                        } else {
                            MemoryType::B64 {
                                limits: Limits64 {
                                    min: u64::from(pages),
                                    max: Some(u64::from(pages)),
                                },
                            }
                        });
                        let data = match mem::replace(&mut m.kind, kind) {
                            MemoryKind::Inline { data, .. } => data,
                            _ => unreachable!(),
                        };
                        let id = gensym::fill(m.span, &mut m.id);
                        to_append.push(ModuleField::Data(Data {
                            span: m.span,
                            id: None,
                            kind: DataKind::Active {
                                memory: Index::Id(id),
                                offset: Expression {
                                    instrs: Box::new([if is_32 {
                                        Instruction::I32Const(0)
                                    } else {
                                        Instruction::I64Const(0)
                                    }]),
                                },
                            },
                            data,
                        }));
                    }

                    MemoryKind::Normal(_) => {}
                }
            }

            ModuleField::Table(t) => {
                for name in t.exports.names.drain(..) {
                    let id = gensym::fill(t.span, &mut t.id);
                    to_append.push(ModuleField::Export(Export {
                        span: t.span,
                        name,
                        kind: ExportKind::Table(Index::Id(id)),
                    }));
                }
                match &mut t.kind {
                    TableKind::Import { import, ty } => {
                        *item = ModuleField::Import(Import {
                            span: t.span,
                            module: import.module,
                            field: import.field,
                            item: ItemSig {
                                span: t.span,
                                id: t.id,
                                name: None,
                                kind: ItemKind::Table(*ty),
                            },
                        });
                    }
                    // If data is defined inline insert an explicit `data` module
                    // field here instead, switching this to a `Normal` memory.
                    TableKind::Inline { payload, elem } => {
                        let len = match payload {
                            ElemPayload::Indices(v) => v.len(),
                            ElemPayload::Exprs { exprs, .. } => exprs.len(),
                        };
                        let kind = TableKind::Normal(TableType {
                            limits: Limits {
                                min: len as u32,
                                max: Some(len as u32),
                            },
                            elem: *elem,
                        });
                        let payload = match mem::replace(&mut t.kind, kind) {
                            TableKind::Inline { payload, .. } => payload,
                            _ => unreachable!(),
                        };
                        let id = gensym::fill(t.span, &mut t.id);
                        to_append.push(ModuleField::Elem(Elem {
                            span: t.span,
                            id: None,
                            kind: ElemKind::Active {
                                table: Index::Id(id),
                                offset: Expression {
                                    instrs: Box::new([Instruction::I32Const(0)]),
                                },
                            },
                            payload,
                        }));
                    }

                    TableKind::Normal(_) => {}
                }
            }

            ModuleField::Global(g) => {
                for name in g.exports.names.drain(..) {
                    let id = gensym::fill(g.span, &mut g.id);
                    to_append.push(ModuleField::Export(Export {
                        span: g.span,
                        name,
                        kind: ExportKind::Global(Index::Id(id)),
                    }));
                }
                match g.kind {
                    GlobalKind::Import(import) => {
                        *item = ModuleField::Import(Import {
                            span: g.span,
                            module: import.module,
                            field: import.field,
                            item: ItemSig {
                                span: g.span,
                                id: g.id,
                                name: None,
                                kind: ItemKind::Global(g.ty),
                            },
                        });
                    }
                    GlobalKind::Inline { .. } => {}
                }
            }

            ModuleField::Event(e) => {
                for name in e.exports.names.drain(..) {
                    let id = gensym::fill(e.span, &mut e.id);
                    to_append.push(ModuleField::Export(Export {
                        span: e.span,
                        name,
                        kind: ExportKind::Event(Index::Id(id)),
                    }));
                }
            }

            ModuleField::Instance(i) => {
                for name in i.exports.names.drain(..) {
                    let id = gensym::fill(i.span, &mut i.id);
                    to_append.push(ModuleField::Export(Export {
                        span: i.span,
                        name,
                        kind: ExportKind::Instance(Index::Id(id)),
                    }));
                }
                match &mut i.kind {
                    InstanceKind::Import { import, ty } => {
                        *item = ModuleField::Import(Import {
                            span: i.span,
                            module: import.module,
                            field: import.field,
                            item: ItemSig {
                                span: i.span,
                                id: i.id,
                                name: None,
                                kind: ItemKind::Instance(mem::replace(
                                    ty,
                                    TypeUse::new_with_index(Index::Num(0, Span::from_offset(0))),
                                )),
                            },
                        });
                    }
                    InstanceKind::Inline { .. } => {}
                }
            }

            ModuleField::NestedModule(m) => {
                for name in m.exports.names.drain(..) {
                    let id = gensym::fill(m.span, &mut m.id);
                    to_append.push(ModuleField::Export(Export {
                        span: m.span,
                        name,
                        kind: ExportKind::Module(Index::Id(id)),
                    }));
                }
                match &mut m.kind {
                    NestedModuleKind::Import { import, ty } => {
                        *item = ModuleField::Import(Import {
                            span: m.span,
                            module: import.module,
                            field: import.field,
                            item: ItemSig {
                                span: m.span,
                                id: m.id,
                                name: m.name,
                                kind: ItemKind::Module(mem::replace(
                                    ty,
                                    TypeUse::new_with_index(Index::Num(0, Span::from_offset(0))),
                                )),
                            },
                        });
                    }
                    NestedModuleKind::Inline { fields, .. } => {
                        run(fields);
                    }
                };
            }

            ModuleField::ExportAll(..)
            | ModuleField::Import(_)
            | ModuleField::Type(_)
            | ModuleField::Export(_)
            | ModuleField::Alias(_)
            | ModuleField::Start(_)
            | ModuleField::Elem(_)
            | ModuleField::Data(_)
            | ModuleField::Custom(_) => {}
        }

        fields.splice(cur..cur, to_append.drain(..));
        cur += 1;
    }

    assert!(to_append.is_empty());

    fn page_size() -> u32 {
        1 << 16
    }
}