1use crate::core::*;
2use crate::gensym;
3use crate::token::{Id, Index, Span};
4use std::mem;
5
6pub fn run(fields: &mut Vec<ModuleField>) {
7 for mut item in mem::take(fields) {
8 match &mut item {
9 ModuleField::Func(f) => {
10 for name in f.exports.names.drain(..) {
11 fields.push(export(f.span, name, ExportKind::Func, &mut f.id));
12 }
13 match f.kind {
14 FuncKind::Import(import) => {
15 item = ModuleField::Import(Import {
16 span: f.span,
17 module: import.module,
18 field: import.field,
19 item: ItemSig {
20 span: f.span,
21 id: f.id,
22 name: f.name,
23 kind: ItemKind::Func(f.ty.clone()),
24 },
25 });
26 }
27 FuncKind::Inline { .. } => {}
28 }
29 }
30
31 ModuleField::Memory(m) => {
32 for name in m.exports.names.drain(..) {
33 fields.push(export(m.span, name, ExportKind::Memory, &mut m.id));
34 }
35 match m.kind {
36 MemoryKind::Import { import, ty } => {
37 item = ModuleField::Import(Import {
38 span: m.span,
39 module: import.module,
40 field: import.field,
41 item: ItemSig {
42 span: m.span,
43 id: m.id,
44 name: None,
45 kind: ItemKind::Memory(ty),
46 },
47 });
48 }
49 // If data is defined inline insert an explicit `data` module
50 // field here instead, switching this to a `Normal` memory.
51 MemoryKind::Inline {
52 is64,
53 ref data,
54 page_size_log2,
55 } => {
56 let len = data.iter().map(|l| l.len()).sum::<usize>() as u64;
57 let pages = (len + default_page_size() - 1) / default_page_size();
58 let kind = MemoryKind::Normal(MemoryType {
59 limits: Limits {
60 is64,
61 min: pages,
62 max: Some(pages),
63 },
64 shared: false,
65 page_size_log2,
66 });
67 let data = match mem::replace(&mut m.kind, kind) {
68 MemoryKind::Inline { data, .. } => data,
69 _ => unreachable!(),
70 };
71 let id = gensym::fill(m.span, &mut m.id);
72 fields.push(ModuleField::Data(Data {
73 span: m.span,
74 id: None,
75 name: None,
76 kind: DataKind::Active {
77 memory: Index::Id(id),
78 offset: Expression::one(if is64 {
79 Instruction::I64Const(0)
80 } else {
81 Instruction::I32Const(0)
82 }),
83 },
84 data,
85 }));
86 }
87
88 MemoryKind::Normal(_) => {}
89 }
90 }
91
92 ModuleField::Table(t) => {
93 for name in t.exports.names.drain(..) {
94 fields.push(export(t.span, name, ExportKind::Table, &mut t.id));
95 }
96 match &mut t.kind {
97 TableKind::Import { import, ty } => {
98 item = ModuleField::Import(Import {
99 span: t.span,
100 module: import.module,
101 field: import.field,
102 item: ItemSig {
103 span: t.span,
104 id: t.id,
105 name: None,
106 kind: ItemKind::Table(*ty),
107 },
108 });
109 }
110 // If data is defined inline insert an explicit `data`
111 // module field here instead, switching this to a `Normal`
112 // memory.
113 TableKind::Inline {
114 payload,
115 elem,
116 shared,
117 is64,
118 } => {
119 let is64 = *is64;
120 let len = match payload {
121 ElemPayload::Indices(v) => v.len(),
122 ElemPayload::Exprs { exprs, .. } => exprs.len(),
123 };
124 let kind = TableKind::Normal {
125 ty: TableType {
126 limits: Limits {
127 min: len as u64,
128 max: Some(len as u64),
129 is64,
130 },
131 elem: *elem,
132 shared: *shared,
133 },
134 init_expr: None,
135 };
136 let payload = match mem::replace(&mut t.kind, kind) {
137 TableKind::Inline { payload, .. } => payload,
138 _ => unreachable!(),
139 };
140 let id = gensym::fill(t.span, &mut t.id);
141 fields.push(ModuleField::Elem(Elem {
142 span: t.span,
143 id: None,
144 name: None,
145 kind: ElemKind::Active {
146 table: Some(Index::Id(id)),
147 offset: Expression::one(if is64 {
148 Instruction::I64Const(0)
149 } else {
150 Instruction::I32Const(0)
151 }),
152 },
153 payload,
154 }));
155 }
156
157 TableKind::Normal { .. } => {}
158 }
159 }
160
161 ModuleField::Global(g) => {
162 for name in g.exports.names.drain(..) {
163 fields.push(export(g.span, name, ExportKind::Global, &mut g.id));
164 }
165 match g.kind {
166 GlobalKind::Import(import) => {
167 item = ModuleField::Import(Import {
168 span: g.span,
169 module: import.module,
170 field: import.field,
171 item: ItemSig {
172 span: g.span,
173 id: g.id,
174 name: None,
175 kind: ItemKind::Global(g.ty),
176 },
177 });
178 }
179 GlobalKind::Inline { .. } => {}
180 }
181 }
182
183 ModuleField::Tag(e) => {
184 for name in e.exports.names.drain(..) {
185 fields.push(export(e.span, name, ExportKind::Tag, &mut e.id));
186 }
187 match e.kind {
188 TagKind::Import(import) => {
189 item = ModuleField::Import(Import {
190 span: e.span,
191 module: import.module,
192 field: import.field,
193 item: ItemSig {
194 span: e.span,
195 id: e.id,
196 name: None,
197 kind: ItemKind::Tag(e.ty.clone()),
198 },
199 });
200 }
201 TagKind::Inline { .. } => {}
202 }
203 }
204
205 ModuleField::Import(_)
206 | ModuleField::Type(_)
207 | ModuleField::Rec(_)
208 | ModuleField::Export(_)
209 | ModuleField::Start(_)
210 | ModuleField::Elem(_)
211 | ModuleField::Data(_)
212 | ModuleField::Custom(_) => {}
213 }
214
215 fields.push(item);
216 }
217
218 fn default_page_size() -> u64 {
219 1 << 16
220 }
221}
222
223fn export<'a>(
224 span: Span,
225 name: &'a str,
226 kind: ExportKind,
227 id: &mut Option<Id<'a>>,
228) -> ModuleField<'a> {
229 let id: Id<'_> = gensym::fill(span, slot:id);
230 ModuleField::Export(Export {
231 span,
232 name,
233 kind,
234 item: Index::Id(id),
235 })
236}
237