core_wasm_ast/
traverse.rs

1use crate::ast;
2use log::debug;
3use std::collections::HashMap;
4use std::sync::Arc;
5use std::sync::Mutex;
6use threadpool::ThreadPool;
7
8type BoxError = Box<dyn std::error::Error>;
9
10pub struct WasmModule {
11    pub inner: Arc<ast::Module>,
12    types: Mutex<HashMap<u32, ast::Type>>,
13    /// Mapping between funcidx and count of func locals
14    func_locals: HashMap<u32, Vec<ast::CodeLocal>>,
15    func_to_typeidx: Mutex<Vec<u32>>,
16    func_code: HashMap<u32, ast::Code>,
17    pub func_starts: HashMap<u32, usize>,
18    pub func_names: Mutex<HashMap<u32, String>>,
19    global_names: Mutex<HashMap<u32, String>>,
20    imports: Vec<ast::Import>,
21    globals: Vec<ast::Global>,
22    exports: Vec<ast::Export>,
23    custom_sections: Vec<ast::CustomSection>,
24    build_id: Option<Vec<u8>>,
25    imported_func_count: u32,
26}
27impl WasmModule {
28    pub fn new(inner: Arc<ast::Module>) -> Self {
29        let mut types = HashMap::new();
30        let mut func_locals = HashMap::new();
31        let mut func_to_typeidx = Vec::new();
32        let mut imports = Vec::new();
33        let mut globals = Vec::new();
34        let mut exports = Vec::new();
35        let mut custom_sections = Vec::new();
36        let mut func_starts = HashMap::new();
37        let mut func_code = HashMap::new();
38        let mut func_names = HashMap::new();
39        let mut global_names = HashMap::new();
40        let mut build_id = None;
41        let mut imported_func_count = 0;
42
43        let mut funcidx = 0;
44
45        for section in inner.sections.lock().unwrap().iter() {
46            match &section.value {
47                ast::Section::Type((_size, content)) => {
48                    let mut typeidx = 0;
49                    for t in &*content.lock().unwrap() {
50                        types.insert(typeidx, t.to_owned());
51                        typeidx += 1;
52                    }
53                }
54
55                ast::Section::Import((_size, content)) => {
56                    imports = content.lock().unwrap().clone();
57
58                    for import in &imports {
59                        match import.import_type {
60                            ast::ImportType::Func(_) => {
61                                imported_func_count += 1;
62                                funcidx += 1;
63                            }
64                            _ => {}
65                        }
66                    }
67                }
68
69                ast::Section::Global((_size, content)) => {
70                    globals = content.lock().unwrap().clone();
71                }
72
73                ast::Section::Func((_size, content)) => {
74                    func_to_typeidx = content.lock().unwrap().clone();
75                }
76
77                ast::Section::Export((_section_size, content)) => {
78                    exports = content.lock().unwrap().clone();
79                }
80
81                ast::Section::Code((_section_size, content)) => {
82                    for c in &content.lock().unwrap().value {
83                        func_code.insert(funcidx, c.clone());
84
85                        func_starts.insert(funcidx as u32, c.body.lock().unwrap().start_offset);
86                        func_locals.insert(funcidx, c.locals.clone());
87                        funcidx += 1;
88                    }
89                }
90
91                ast::Section::Custom((_size, section)) => {
92                    custom_sections.push(section.lock().unwrap().clone());
93
94                    match &*section.lock().unwrap() {
95                        ast::CustomSection::Name(names) => {
96                            if let Some(v) = &names.func_names {
97                                func_names = v.lock().unwrap().clone();
98                            }
99
100                            global_names = names.global_names.lock().unwrap().clone();
101                        }
102                        ast::CustomSection::BuildId(id) => {
103                            build_id = Some(id.clone());
104                        }
105                        _ => {}
106                    }
107                }
108                _ => {}
109            }
110        }
111
112        Self {
113            inner,
114            imports,
115            globals,
116            exports,
117            func_locals,
118            func_starts,
119            func_code,
120            custom_sections,
121            build_id,
122            imported_func_count,
123            func_names: Mutex::new(func_names),
124            global_names: Mutex::new(global_names),
125            types: Mutex::new(types),
126            func_to_typeidx: Mutex::new(func_to_typeidx),
127        }
128    }
129
130    pub fn into_inner(self) -> ast::Module {
131        Arc::into_inner(self.inner).unwrap()
132    }
133
134    pub fn add_func_name(&self, funcidx: u32, name: &str) {
135        let mut func_names = self.func_names.lock().unwrap();
136        func_names.insert(funcidx, name.to_owned());
137
138        for section in self.inner.sections.lock().unwrap().iter() {
139            match &section.value {
140                ast::Section::Custom((_size, section)) => match &*section.lock().unwrap() {
141                    ast::CustomSection::Name(names) => {
142                        if let Some(names) = &names.func_names {
143                            let mut names = names.lock().unwrap();
144                            names.insert(funcidx, name.to_owned());
145                        }
146                    }
147                    _ => {}
148                },
149                _ => {}
150            }
151        }
152    }
153
154    pub fn add_global_name(&self, globalidx: u32, name: &str) {
155        let mut global_names = self.global_names.lock().unwrap();
156        global_names.insert(globalidx, name.to_owned());
157
158        for section in self.inner.sections.lock().unwrap().iter() {
159            match &section.value {
160                ast::Section::Custom((_size, section)) => match &*section.lock().unwrap() {
161                    ast::CustomSection::Name(section) => {
162                        let mut names = section.global_names.lock().unwrap();
163                        names.insert(globalidx, name.to_owned());
164                    }
165                    _ => {}
166                },
167                _ => {}
168            }
169        }
170    }
171
172    pub fn get_coredump(&self) -> Result<wasm_coredump_types::Coredump, BoxError> {
173        let mut data = vec![];
174        let mut stacks = vec![];
175        let mut process_info = None;
176        let mut memory = vec![];
177
178        for section in self.inner.sections.lock().unwrap().iter() {
179            match &section.value {
180                ast::Section::Data((_section_size, content)) => {
181                    let content = content.lock().unwrap();
182                    let segment = content.first().unwrap();
183                    let offset = segment.compute_offset();
184                    debug!("data offset: {}", offset);
185                    let padding = vec![0u8; offset as usize];
186                    data = [padding, segment.bytes.clone()].concat();
187                }
188
189                ast::Section::Memory((_section_size, content)) => {
190                    for m in content {
191                        memory.push((m.min.value, m.max))
192                    }
193                }
194
195                ast::Section::Custom((_size, section)) => match &*section.lock().unwrap() {
196                    ast::CustomSection::CoredumpCore(info) => process_info = Some(info.clone()),
197                    ast::CustomSection::CoredumpCoreStack(stack) => stacks.push(stack.clone()),
198
199                    _ => {}
200                },
201
202                _ => {}
203            }
204
205            debug!("data size: {:?}", data.len());
206        }
207
208        let process_info = process_info.ok_or("Wasm module is not a coredump")?;
209
210        Ok(wasm_coredump_types::Coredump {
211            data,
212            stacks,
213            process_info,
214            memory,
215        })
216    }
217
218    pub fn add_data(&self, offset: u32, bytes: &[u8]) -> (u32, u32) {
219        for section in self.inner.sections.lock().unwrap().iter() {
220            match &section.value {
221                ast::Section::Data((_section_size, content)) => {
222                    let segment = ast::DataSegment {
223                        offset: Some(ast::Value::new(vec![
224                            ast::Value::new(ast::Instr::i32_const(offset as i64)),
225                            ast::Value::new(ast::Instr::end),
226                        ])),
227                        bytes: bytes.to_vec(),
228                        mode: ast::DataSegmentMode::Active,
229                    };
230                    content.lock().unwrap().push(segment);
231                }
232                _ => {}
233            }
234        }
235
236        (offset, offset + bytes.len() as u32)
237    }
238
239    pub fn is_func_imported(&self, funcidx: u32) -> bool {
240        funcidx <= self.imported_func_count
241    }
242
243    pub fn imports(&self) -> &Vec<ast::Import> {
244        &self.imports
245    }
246
247    pub fn globals(&self) -> &Vec<ast::Global> {
248        &self.globals
249    }
250
251    pub fn func_locals_count(&self, funcidx: u32) -> u32 {
252        let locals = self.func_locals(funcidx);
253        let mut count = 0;
254        for local in locals {
255            count += local.count;
256        }
257
258        count
259    }
260
261    pub fn func_locals(&self, funcidx: u32) -> Vec<ast::CodeLocal> {
262        let locals = self
263            .func_locals
264            .get(&funcidx)
265            .expect(&format!("locals for funcidx {}", funcidx));
266        locals.to_owned()
267    }
268
269    pub fn is_func_exported(&self, funcidx: u32) -> bool {
270        for export in &self.exports {
271            match &export.descr {
272                ast::ExportDescr::Func(f) => {
273                    if *f.lock().unwrap() == funcidx {
274                        return true;
275                    }
276                }
277                _ => {}
278            }
279        }
280
281        false
282    }
283
284    pub fn get_export_func(&self, name: &str) -> Result<(&ast::Code, ast::Type), BoxError> {
285        for export in &self.exports {
286            if export.name == name {
287                match &export.descr {
288                    ast::ExportDescr::Func(f) => {
289                        let funcidx = &*f.lock().unwrap();
290                        let code = self
291                            .func_code
292                            .get(funcidx)
293                            .ok_or("exported function not found")?;
294                        let t = self.get_func_type(*funcidx);
295                        return Ok((code, t.clone()));
296                    }
297                    _ => return Err("export is not a function".into()),
298                }
299            }
300        }
301
302        Err("export not found".into())
303    }
304
305    /// Retrieve the type of a function,
306    /// note that this doesn't work for imported functions as they
307    /// have their type expressed differently.
308    pub fn get_func_type(&self, funcidx: u32) -> ast::Type {
309        let typeidx = self.get_func_typeidx(funcidx);
310        let types = self.types.lock().unwrap();
311        types.get(&typeidx).expect("type not found").clone()
312    }
313
314    pub fn add_func_local(&self, target_funcidx: u32, local: ast::CodeLocal) -> bool {
315        let mut funcidx = self.imported_func_count;
316
317        for section in self.inner.sections.lock().unwrap().iter() {
318            match &section.value {
319                ast::Section::Code((_section_size, content)) => {
320                    for c in &mut content.lock().unwrap().value {
321                        if funcidx == target_funcidx {
322                            c.locals.push(local);
323                            return true;
324                        }
325
326                        funcidx += 1;
327                    }
328                }
329                _ => {}
330            }
331        }
332
333        false
334    }
335
336    pub fn get_type(&self, typeidx: u32) -> Option<ast::Type> {
337        let types = self.types.lock().unwrap();
338        types.get(&typeidx).cloned()
339    }
340
341    pub fn get_func_typeidx(&self, funcidx: u32) -> u32 {
342        let func_to_typeidx = self.func_to_typeidx.lock().unwrap();
343
344        if funcidx < self.imported_func_count {
345            todo!()
346        } else {
347            // Func is an implemented function
348            let funcidx = funcidx - self.imported_func_count;
349
350            *func_to_typeidx
351                .get(funcidx as usize)
352                .expect(&format!("type not found for funcidx: {}", funcidx))
353        }
354    }
355
356    /// Get the start binary offset of a function
357    pub fn get_start_of_func(&self, funcidx: u32) -> Option<usize> {
358        self.func_starts.get(&funcidx).cloned()
359    }
360
361    pub fn get_custom_section(&self, name: &str) -> Option<Vec<u8>> {
362        for section in self.inner.sections.lock().unwrap().iter() {
363            match &section.value {
364                ast::Section::Custom((_size, section)) => match &*section.lock().unwrap() {
365                    ast::CustomSection::Unknown(section_name, bytes) => {
366                        if section_name == name {
367                            return Some(bytes.to_owned());
368                        }
369                    }
370                    _ => {}
371                },
372                _ => {}
373            }
374        }
375
376        None
377    }
378
379    pub fn get_custom_sections(&self) -> &Vec<ast::CustomSection> {
380        &self.custom_sections
381    }
382
383    pub fn remove_custom_section(&self, name: &str) -> Option<()> {
384        let mut idx = None;
385        let mut i = 0;
386
387        for section in self.inner.sections.lock().unwrap().iter() {
388            match &section.value {
389                ast::Section::Custom((_size, section)) => match &*section.lock().unwrap() {
390                    ast::CustomSection::Unknown(section_name, _) => {
391                        if section_name == name {
392                            idx = Some(i)
393                        }
394                    }
395
396                    ast::CustomSection::Name(_) if name == "name" => idx = Some(i),
397                    _ => {}
398                },
399                _ => {}
400            }
401
402            i += 1;
403        }
404
405        if let Some(idx) = idx {
406            let mut sections = self.inner.sections.lock().unwrap();
407            sections.remove(idx);
408
409            Some(())
410        } else {
411            None
412        }
413    }
414
415    pub fn get_func_name(&self, funcidx: u32) -> Option<String> {
416        for section in self.inner.sections.lock().unwrap().iter() {
417            match &section.value {
418                ast::Section::Custom((_size, section)) => match &*section.lock().unwrap() {
419                    ast::CustomSection::Name(names) => {
420                        if let Some(v) = &names.func_names {
421                            if let Some(name) = v.lock().unwrap().get(&funcidx) {
422                                return Some(name.clone());
423                            }
424                        }
425                    }
426                    _ => {}
427                },
428                _ => {}
429            }
430        }
431
432        None
433    }
434
435    pub fn find_import(&self, name: &str) -> u32 {
436        let mut funcidx = 0;
437        for section in self.inner.sections.lock().unwrap().iter() {
438            match &section.value {
439                ast::Section::Import((_section_size, content)) => {
440                    for import in &*content.lock().unwrap() {
441                        if import.name == name {
442                            return funcidx;
443                        }
444                        funcidx += 1;
445                    }
446                }
447                _ => {}
448            }
449        }
450
451        0
452    }
453
454    pub fn add_global_import(&self, module: &str, name: &str, ty: &ast::GlobalType) -> u32 {
455        let import = ast::Import {
456            module: module.to_owned(),
457            name: name.to_owned(),
458            import_type: ast::ImportType::Global(ty.to_owned()),
459        };
460
461        todo!()
462    }
463
464    pub fn add_import(&self, _import: &ast::Import) -> u32 {
465        unimplemented!("Adding an import requires to shifts all references to functions by one, which is unsafe (func tables) or inconvenient (name section).");
466    }
467
468    pub fn add_global(&self, global: &ast::Global) -> Option<u32> {
469        let mut globalidx = 0;
470
471        // FIXME: we should really pre-compute all that
472        for section in self.inner.sections.lock().unwrap().iter() {
473            match &section.value {
474                ast::Section::Import((_section_size, content)) => {
475                    let imports = content.lock().unwrap();
476                    for import in imports.iter() {
477                        match import.import_type {
478                            ast::ImportType::Global(_) => globalidx += 1,
479                            _ => {}
480                        }
481                    }
482                }
483
484                ast::Section::Global((_section_size, content)) => {
485                    globalidx += content.lock().unwrap().len() as u32;
486                    content.lock().unwrap().push(global.to_owned());
487                    return Some(globalidx);
488                }
489                _ => {}
490            }
491        }
492
493        let globals = vec![global.to_owned()];
494        let global_section = ast::Section::Global((
495            ast::Value::new(0), // section size will be set during encoding
496            Arc::new(Mutex::new(globals)),
497        ));
498
499        self.add_section(global_section);
500        return Some(globalidx);
501    }
502
503    pub fn add_export_func(&self, name: &str, funcidx: u32) {
504        for section in self.inner.sections.lock().unwrap().iter() {
505            match &section.value {
506                ast::Section::Export((_section_size, content)) => {
507                    let export = ast::Export {
508                        name: name.to_owned(),
509                        descr: ast::ExportDescr::Func(Arc::new(Mutex::new(funcidx))),
510                    };
511                    content.lock().unwrap().push(export.to_owned());
512                    return;
513                }
514                _ => {}
515            }
516        }
517
518        unimplemented!("no export section")
519    }
520
521    pub fn add_function(&self, func: &ast::Code, typeidx: u32) -> u32 {
522        let mut funcidx = self.imported_func_count;
523
524        for section in self.inner.sections.lock().unwrap().iter() {
525            match &section.value {
526                ast::Section::Code((_section_size, content)) => {
527                    funcidx += content.lock().unwrap().value.len() as u32;
528                    content.lock().unwrap().value.push(func.to_owned());
529                }
530                ast::Section::Func((_section_size, content)) => {
531                    content.lock().unwrap().push(typeidx);
532                }
533                _ => {}
534            }
535        }
536
537        self.func_to_typeidx.lock().unwrap().push(typeidx);
538        funcidx
539    }
540
541    pub fn add_type(&self, t: &ast::Type) -> u32 {
542        let mut typeidx = 0;
543
544        for section in self.inner.sections.lock().unwrap().iter() {
545            match &section.value {
546                ast::Section::Type((_section_size, content)) => {
547                    typeidx = content.lock().unwrap().len() as u32;
548                    content.lock().unwrap().push(t.clone());
549
550                    self.types.lock().unwrap().insert(typeidx, t.to_owned());
551                }
552                _ => {}
553            }
554        }
555
556        typeidx
557    }
558
559    pub fn add_section(&self, s: ast::Section) {
560        let mut sections = self.inner.sections.lock().unwrap();
561        sections.push(ast::Value::new(s));
562        sections.sort_by(|a, b| a.pos().cmp(&b.pos()));
563    }
564
565    pub fn add_custom_section(&self, s: ast::CustomSection) {
566        let section = ast::Section::Custom((ast::Value::new(0), Arc::new(Mutex::new(s))));
567        self.add_section(section);
568    }
569
570    pub fn get_build_id(&self) -> &Option<Vec<u8>> {
571        &self.build_id
572    }
573
574    pub fn set_build_id(&self, build_id: &[u8]) {
575        let section = ast::CustomSection::BuildId(build_id.to_owned());
576        self.add_custom_section(section);
577    }
578}
579
580pub struct VisitorContext<'a, T> {
581    pub module: Arc<WasmModule>,
582    insert_nodes_after: Vec<T>,
583    insert_nodes_before: Vec<T>,
584    replace_node: Option<T>,
585    pub curr_funcidx: Option<u32>,
586    pub node: &'a T,
587    traverse_stop: bool,
588}
589impl<'a, T> VisitorContext<'a, T> {
590    pub fn new(module: Arc<WasmModule>, node: &'a T) -> Self {
591        Self {
592            node,
593            module,
594            insert_nodes_after: vec![],
595            insert_nodes_before: vec![],
596            replace_node: None,
597            curr_funcidx: None,
598            traverse_stop: false,
599        }
600    }
601}
602
603impl<'a, T> VisitorContext<'a, Vec<T>> {
604    pub fn insert_node_after(&mut self, new_node: T) {
605        self.insert_nodes_after.push(vec![new_node]);
606    }
607
608    pub fn insert_node_before(&mut self, new_node: T) {
609        self.insert_nodes_before.push(vec![new_node]);
610    }
611}
612
613impl<'a> VisitorContext<'a, ast::Value<ast::Instr>> {
614    pub fn stop_traversal(&mut self) {
615        self.traverse_stop = true;
616    }
617
618    pub fn insert_node_after(&mut self, new_node: ast::Instr) {
619        self.insert_nodes_after.push(ast::Value::new(new_node));
620    }
621
622    pub fn insert_node_before(&mut self, new_node: ast::Instr) {
623        self.insert_nodes_before.push(ast::Value::new(new_node));
624    }
625
626    pub fn replace_node(&mut self, new_node: ast::Instr) {
627        self.replace_node = Some(ast::Value::new(new_node));
628    }
629}
630
631pub trait Visitor {
632    fn visit_instr<'a>(&self, _ctx: &'_ mut VisitorContext<'a, ast::Value<ast::Instr>>) {}
633    fn visit_type<'a>(&self, _ctx: &'_ mut VisitorContext<'a, ast::Type>, _typeidx: u32) {}
634    fn visit_code_section<'a>(&self, _ctx: &'_ mut VisitorContext<'a, Vec<ast::Code>>) {}
635    fn visit_import_section<'a>(&self, _ctx: &'_ mut VisitorContext<'a, Vec<ast::Import>>) {}
636    fn visit_func_section<'a>(&self, _ctx: &'_ mut VisitorContext<'a, Vec<u32>>) {}
637    fn visit_data_section<'a>(&self, _ctx: &'_ mut VisitorContext<'a, Vec<ast::DataSegment>>) {}
638    fn visit_table<'a>(&self, _ctx: &'_ mut VisitorContext<'a, ast::Table>) {}
639    fn visit_export<'a>(&self, _ctx: &'_ mut VisitorContext<'a, ast::Export>) {}
640    fn visit_element<'a>(&self, _ctx: &'_ mut VisitorContext<'a, ast::Element>) {}
641    fn visit_code<'a>(&self, _ctx: &'_ mut VisitorContext<'a, ast::Code>, _funcidx: u32) {}
642}
643
644pub fn traverse(module: Arc<ast::Module>, visitor: Arc<dyn Visitor + Send + Sync>) {
645    let pool = ThreadPool::new(num_cpus::get());
646
647    let mut curr_funcidx = 0;
648
649    let module_ast = Arc::new(WasmModule::new(Arc::clone(&module)));
650
651    for section in module.sections.lock().unwrap().iter() {
652        match &section.value {
653            ast::Section::Func((_section_size, funcs)) => {
654                let nodes = funcs.lock().unwrap().clone();
655                let mut ctx = VisitorContext::new(Arc::clone(&module_ast), &nodes);
656                Arc::clone(&visitor).visit_func_section(&mut ctx);
657                assert!(ctx.insert_nodes_before.is_empty());
658
659                {
660                    let mut new_nodes = ctx.insert_nodes_after;
661                    new_nodes.reverse();
662
663                    for new_node in new_nodes {
664                        debug!("inject new func: {:?}", new_node);
665                        funcs.lock().unwrap().extend_from_slice(&new_node);
666                    }
667                }
668            }
669            ast::Section::Export((_section_size, exports)) => {
670                for export in exports.lock().unwrap().iter() {
671                    let mut ctx = VisitorContext::new(Arc::clone(&module_ast), export);
672                    visitor.visit_export(&mut ctx);
673                    assert!(ctx.insert_nodes_before.is_empty());
674                    assert!(ctx.insert_nodes_after.is_empty());
675                }
676            }
677            ast::Section::Element((_section_size, elements)) => {
678                for element in elements.lock().unwrap().iter() {
679                    let mut ctx = VisitorContext::new(Arc::clone(&module_ast), element);
680                    visitor.visit_element(&mut ctx);
681                    assert!(ctx.insert_nodes_before.is_empty());
682                    assert!(ctx.insert_nodes_after.is_empty());
683                }
684            }
685            ast::Section::Table((_section_size, tables)) => {
686                let module_ast = Arc::clone(&module_ast);
687                for table in tables.lock().unwrap().iter() {
688                    let mut ctx = VisitorContext::new(Arc::clone(&module_ast), table);
689                    visitor.visit_table(&mut ctx);
690                    assert!(ctx.insert_nodes_before.is_empty());
691                    assert!(ctx.insert_nodes_after.is_empty());
692                }
693            }
694            ast::Section::Type((_section_size, types)) => {
695                let mut typeidx = 0;
696                let types_copy = types.lock().unwrap().clone();
697                for t in types_copy {
698                    let mut ctx = VisitorContext::new(Arc::clone(&module_ast), &t);
699                    visitor.visit_type(&mut ctx, typeidx);
700                    typeidx += 1;
701
702                    assert!(ctx.insert_nodes_before.is_empty());
703                    assert!(ctx.insert_nodes_after.is_empty());
704                }
705            }
706            ast::Section::Import((_section_size, content)) => {
707                let nodes = content.lock().unwrap().clone();
708                let mut ctx = VisitorContext::new(Arc::clone(&module_ast), &nodes);
709                Arc::clone(&visitor).visit_import_section(&mut ctx);
710                assert!(ctx.insert_nodes_before.is_empty());
711
712                {
713                    for new_node in ctx.insert_nodes_after {
714                        debug!("inject new import: {:?}", new_node);
715                        content.lock().unwrap().extend_from_slice(&new_node);
716                    }
717                }
718
719                for import in &nodes {
720                    match import.import_type {
721                        ast::ImportType::Func(_) => {
722                            curr_funcidx += 1;
723                        }
724                        _ => {}
725                    }
726                }
727            }
728            ast::Section::Code((_section_size, codes)) => {
729                {
730                    let nodes = codes.lock().unwrap().clone().value;
731                    let mut ctx = VisitorContext::new(Arc::clone(&module_ast), &nodes);
732                    Arc::clone(&visitor).visit_code_section(&mut ctx);
733                    assert!(ctx.insert_nodes_before.is_empty());
734
735                    let mut new_nodes = ctx.insert_nodes_after;
736                    new_nodes.reverse();
737
738                    for new_node in new_nodes {
739                        debug!("inject new code: {:?}", new_node);
740                        codes.lock().unwrap().value.extend_from_slice(&new_node);
741                    }
742                }
743
744                let codes = codes.lock().unwrap().clone();
745                for code in codes.value {
746                    {
747                        let mut ctx = VisitorContext::new(Arc::clone(&module_ast), &code);
748                        Arc::clone(&visitor).visit_code(&mut ctx, curr_funcidx);
749                    }
750
751                    {
752                        let visitor = Arc::clone(&visitor);
753                        let module_ast = Arc::clone(&module_ast);
754                        pool.execute(move || {
755                            visit_expr(
756                                Arc::clone(&module_ast),
757                                Arc::clone(&code.body),
758                                Arc::clone(&visitor),
759                                curr_funcidx,
760                            );
761                        });
762                    }
763
764                    curr_funcidx += 1;
765                }
766            }
767            ast::Section::Data((_section_size, segments)) => {
768                let nodes = segments.lock().unwrap().clone();
769                let mut ctx = VisitorContext::new(Arc::clone(&module_ast), &nodes);
770                Arc::clone(&visitor).visit_data_section(&mut ctx);
771                assert!(ctx.insert_nodes_before.is_empty());
772
773                let mut new_nodes = ctx.insert_nodes_after;
774                new_nodes.reverse();
775
776                for new_node in new_nodes {
777                    debug!("inject new data: {:?}", new_node);
778                    segments.lock().unwrap().extend_from_slice(&new_node);
779                }
780            }
781            _ => {}
782        }
783    }
784
785    pool.join();
786}
787
788fn visit_expr(
789    module_ast: Arc<WasmModule>,
790    expr: ast::MutableValue<Vec<ast::Value<ast::Instr>>>,
791    visitor: Arc<dyn Visitor + Send + Sync>,
792    curr_funcidx: u32,
793) {
794    let expr_copy = expr.lock().unwrap().clone();
795
796    // Keep track of many nodes we injected since we started iterating, so that
797    // subsequent inserts are at the right place.
798    // The iterator is a copy of the array of nodes.
799    let mut added = 0;
800
801    for i in 0..expr_copy.value.len() {
802        let instr = expr_copy.value[i].clone();
803        if let ast::Instr::Block(_, body) = instr.value {
804            visit_expr(Arc::clone(&module_ast), body, visitor.clone(), curr_funcidx);
805        } else if let ast::Instr::If(_, body) = instr.value {
806            visit_expr(Arc::clone(&module_ast), body, visitor.clone(), curr_funcidx);
807        } else if let ast::Instr::Loop(_, body) = instr.value {
808            visit_expr(Arc::clone(&module_ast), body, visitor.clone(), curr_funcidx);
809        } else {
810            let mut ctx = VisitorContext::new(Arc::clone(&module_ast), &instr);
811            ctx.curr_funcidx = Some(curr_funcidx);
812            visitor.visit_instr(&mut ctx);
813
814            if let Some(replace_node) = ctx.replace_node {
815                debug!("replace instr: {:?}", replace_node);
816                expr.lock().unwrap().value[i + added] = replace_node;
817            }
818
819            if ctx.insert_nodes_after.len() > 0 {
820                debug!("insert instr(s): {:?}", ctx.insert_nodes_after);
821                expr.lock().unwrap().value.splice(
822                    (i + added + 1)..(i + added + 1),
823                    ctx.insert_nodes_after.clone(),
824                );
825                added += ctx.insert_nodes_after.len();
826            }
827
828            if ctx.insert_nodes_before.len() > 0 {
829                debug!("insert instr(s): {:?}", ctx.insert_nodes_before);
830
831                expr.lock()
832                    .unwrap()
833                    .value
834                    .splice((i + added)..(i + added), ctx.insert_nodes_before.clone());
835                added += ctx.insert_nodes_before.len();
836            }
837
838            if ctx.traverse_stop {
839                break;
840            }
841        }
842    }
843}