Skip to main content

wasm_smith/core/
encode.rs

1use super::*;
2
3impl Module {
4    /// Encode this Wasm module into bytes.
5    pub fn to_bytes(&self) -> Vec<u8> {
6        self.encoded().finish()
7    }
8
9    fn encoded(&self) -> wasm_encoder::Module {
10        let mut module = wasm_encoder::Module::new();
11
12        self.encode_types(&mut module);
13        self.encode_imports(&mut module);
14        self.encode_funcs(&mut module);
15        self.encode_tables(&mut module);
16        self.encode_memories(&mut module);
17        self.encode_tags(&mut module);
18        self.encode_globals(&mut module);
19        self.encode_exports(&mut module);
20        self.encode_start(&mut module);
21        self.encode_elems(&mut module);
22        self.encode_data_count(&mut module);
23        self.encode_code(&mut module);
24        self.encode_data(&mut module);
25
26        module
27    }
28
29    fn encode_types(&self, module: &mut wasm_encoder::Module) {
30        if !self.should_encode_types {
31            return;
32        }
33
34        let mut section = wasm_encoder::TypeSection::new();
35
36        for group in &self.rec_groups {
37            if group.end - group.start == 1 {
38                let ty = &self.types[group.start];
39                section.ty().subtype(&wasm_encoder::SubType {
40                    is_final: ty.is_final,
41                    supertype_idx: ty.supertype,
42                    composite_type: (&ty.composite_type).into(),
43                });
44            } else {
45                section.ty().rec(self.types[group.clone()].iter().map(|ty| {
46                    wasm_encoder::SubType {
47                        is_final: ty.is_final,
48                        supertype_idx: ty.supertype,
49                        composite_type: (&ty.composite_type).into(),
50                    }
51                }));
52            }
53        }
54
55        module.section(&section);
56    }
57
58    fn encode_imports(&self, module: &mut wasm_encoder::Module) {
59        if !self.should_encode_imports {
60            return;
61        }
62
63        let mut section = wasm_encoder::ImportSection::new();
64        for group in &self.imports {
65            match group {
66                crate::core::Imports::Single(im) => {
67                    section.imports(wasm_encoder::Imports::Single(wasm_encoder::Import {
68                        module: &im.module,
69                        name: &im.name,
70                        ty: translate_entity_type(&im.entity_type),
71                    }));
72                }
73                crate::core::Imports::Compact1 { module, items } => {
74                    section.imports(wasm_encoder::Imports::Compact1 {
75                        module,
76                        items: items
77                            .iter()
78                            .map(|im| wasm_encoder::ImportCompact {
79                                name: &im.name,
80                                ty: translate_entity_type(&im.entity_type),
81                            })
82                            .collect(),
83                    });
84                }
85                crate::core::Imports::Compact2 {
86                    module,
87                    entity_type,
88                    names,
89                } => {
90                    section.imports(wasm_encoder::Imports::Compact2 {
91                        module,
92                        ty: translate_entity_type(entity_type),
93                        names: names.iter().map(String::as_str).collect(),
94                    });
95                }
96            }
97        }
98        module.section(&section);
99    }
100
101    fn encode_tags(&self, module: &mut wasm_encoder::Module) {
102        if self.num_defined_tags == 0 {
103            return;
104        }
105        let mut tags = wasm_encoder::TagSection::new();
106        for tag in self.tags[self.tags.len() - self.num_defined_tags..].iter() {
107            tags.tag(wasm_encoder::TagType {
108                kind: wasm_encoder::TagKind::Exception,
109                func_type_idx: tag.func_type_idx,
110            });
111        }
112        module.section(&tags);
113    }
114
115    fn encode_funcs(&self, module: &mut wasm_encoder::Module) {
116        if self.num_defined_funcs == 0 {
117            return;
118        }
119        let mut funcs = wasm_encoder::FunctionSection::new();
120        for (ty, _) in self.funcs[self.funcs.len() - self.num_defined_funcs..].iter() {
121            funcs.function(*ty);
122        }
123        module.section(&funcs);
124    }
125
126    fn encode_tables(&self, module: &mut wasm_encoder::Module) {
127        if self.defined_tables.is_empty() {
128            return;
129        }
130        let mut tables = wasm_encoder::TableSection::new();
131        for (t, init) in self.tables[self.tables.len() - self.defined_tables.len()..]
132            .iter()
133            .zip(&self.defined_tables)
134        {
135            match init {
136                Some(init) => {
137                    tables.table_with_init(*t, init);
138                }
139                None => {
140                    tables.table(*t);
141                }
142            }
143        }
144        module.section(&tables);
145    }
146
147    fn encode_memories(&self, module: &mut wasm_encoder::Module) {
148        if self.num_defined_memories == 0 {
149            return;
150        }
151        let mut mems = wasm_encoder::MemorySection::new();
152        for m in self.memories[self.memories.len() - self.num_defined_memories..].iter() {
153            mems.memory(*m);
154        }
155        module.section(&mems);
156    }
157
158    fn encode_globals(&self, module: &mut wasm_encoder::Module) {
159        if self.globals.is_empty() {
160            return;
161        }
162        let mut globals = wasm_encoder::GlobalSection::new();
163        for (idx, expr) in &self.defined_globals {
164            let ty = &self.globals[*idx as usize];
165            globals.global(*ty, expr);
166        }
167        module.section(&globals);
168    }
169
170    fn encode_exports(&self, module: &mut wasm_encoder::Module) {
171        if self.exports.is_empty() {
172            return;
173        }
174        let mut exports = wasm_encoder::ExportSection::new();
175        for (name, kind, idx) in &self.exports {
176            exports.export(name, *kind, *idx);
177        }
178        module.section(&exports);
179    }
180
181    fn encode_start(&self, module: &mut wasm_encoder::Module) {
182        if let Some(f) = self.start {
183            module.section(&wasm_encoder::StartSection { function_index: f });
184        }
185    }
186
187    fn encode_elems(&self, module: &mut wasm_encoder::Module) {
188        if self.elems.is_empty() {
189            return;
190        }
191        let mut elems = wasm_encoder::ElementSection::new();
192        for el in &self.elems {
193            let elements = match &el.items {
194                Elements::Expressions(es) => wasm_encoder::Elements::Expressions(el.ty, es.into()),
195                Elements::Functions(fs) => {
196                    assert_eq!(el.ty, RefType::FUNCREF);
197                    wasm_encoder::Elements::Functions(fs.into())
198                }
199            };
200            match &el.kind {
201                ElementKind::Active { table, offset } => {
202                    let offset = match *offset {
203                        Offset::Const32(n) => ConstExpr::i32_const(n),
204                        Offset::Const64(n) => ConstExpr::i64_const(n),
205                        Offset::Global(g) => ConstExpr::global_get(g),
206                    };
207                    elems.active(*table, &offset, elements);
208                }
209                ElementKind::Passive => {
210                    elems.passive(elements);
211                }
212                ElementKind::Declared => {
213                    elems.declared(elements);
214                }
215            }
216        }
217        module.section(&elems);
218    }
219
220    fn encode_data_count(&self, module: &mut wasm_encoder::Module) {
221        // Without bulk memory there's no need for a data count section,
222        if !self.config.bulk_memory_enabled {
223            return;
224        }
225        // ... and also if there's no data no need for a data count section.
226        if self.data.is_empty() {
227            return;
228        }
229        module.section(&wasm_encoder::DataCountSection {
230            count: u32::try_from(self.data.len()).unwrap(),
231        });
232    }
233
234    fn encode_code(&self, module: &mut wasm_encoder::Module) {
235        if self.code.is_empty() {
236            return;
237        }
238        let mut code = wasm_encoder::CodeSection::new();
239        for c in &self.code {
240            // Skip the run-length encoding because it is a little
241            // annoying to compute; use a length of one for every local.
242            let mut func = wasm_encoder::Function::new(c.locals.iter().map(|l| (1, *l)));
243            match &c.instructions {
244                Instructions::Generated(instrs) => {
245                    for instr in instrs {
246                        func.instruction(instr);
247                    }
248                    func.instructions().end();
249                }
250                Instructions::Arbitrary(body) => {
251                    func.raw(body.iter().copied());
252                }
253            }
254            code.function(&func);
255        }
256        module.section(&code);
257    }
258
259    fn encode_data(&self, module: &mut wasm_encoder::Module) {
260        if self.data.is_empty() {
261            return;
262        }
263        let mut data = wasm_encoder::DataSection::new();
264        for seg in &self.data {
265            match &seg.kind {
266                DataSegmentKind::Active {
267                    memory_index,
268                    offset,
269                } => {
270                    let offset = match *offset {
271                        Offset::Const32(n) => ConstExpr::i32_const(n),
272                        Offset::Const64(n) => ConstExpr::i64_const(n),
273                        Offset::Global(g) => ConstExpr::global_get(g),
274                    };
275                    data.active(*memory_index, &offset, seg.init.iter().copied());
276                }
277                DataSegmentKind::Passive => {
278                    data.passive(seg.init.iter().copied());
279                }
280            }
281        }
282        module.section(&data);
283    }
284}
285
286pub(crate) fn translate_entity_type(ty: &EntityType) -> wasm_encoder::EntityType {
287    match ty {
288        EntityType::Tag(t) => wasm_encoder::EntityType::Tag(wasm_encoder::TagType {
289            kind: wasm_encoder::TagKind::Exception,
290            func_type_idx: t.func_type_idx,
291        }),
292        EntityType::Func(f, _) => wasm_encoder::EntityType::Function(*f),
293        EntityType::Table(ty) => (*ty).into(),
294        EntityType::Memory(m) => (*m).into(),
295        EntityType::Global(g) => (*g).into(),
296    }
297}