pwasm_utils/
export_globals.rs1use parity_wasm::elements;
2
3use crate::optimizer::{export_section, global_section};
4
5pub fn export_mutable_globals(module: &mut elements::Module, prefix: impl Into<String>) {
11 let exports = global_section(module)
12 .map(|section| {
13 section
14 .entries()
15 .iter()
16 .enumerate()
17 .filter_map(
18 |(index, global)| {
19 if global.global_type().is_mutable() {
20 Some(index)
21 } else {
22 None
23 }
24 },
25 )
26 .collect::<Vec<_>>()
27 })
28 .unwrap_or_default();
29
30 if module.export_section().is_none() {
31 module
32 .sections_mut()
33 .push(elements::Section::Export(elements::ExportSection::default()));
34 }
35
36 let prefix: String = prefix.into();
37 for (symbol_index, export) in exports.into_iter().enumerate() {
38 let new_entry = elements::ExportEntry::new(
39 format!("{}_{}", prefix, symbol_index),
40 elements::Internal::Global(
41 (module.import_count(elements::ImportCountType::Global) + export) as _,
42 ),
43 );
44 export_section(module)
45 .expect("added above if does not exists")
46 .entries_mut()
47 .push(new_entry);
48 }
49}
50
51#[cfg(test)]
52mod tests {
53
54 use super::export_mutable_globals;
55 use parity_wasm::elements;
56
57 fn parse_wat(source: &str) -> elements::Module {
58 let module_bytes = wabt::Wat2Wasm::new()
59 .validate(true)
60 .convert(source)
61 .expect("failed to parse module");
62 elements::deserialize_buffer(module_bytes.as_ref()).expect("failed to parse module")
63 }
64
65 macro_rules! test_export_global {
66 (name = $name:ident; input = $input:expr; expected = $expected:expr) => {
67 #[test]
68 fn $name() {
69 let mut input_module = parse_wat($input);
70 let expected_module = parse_wat($expected);
71
72 export_mutable_globals(&mut input_module, "exported_internal_global");
73
74 let actual_bytes = elements::serialize(input_module)
75 .expect("injected module must have a function body");
76
77 let expected_bytes = elements::serialize(expected_module)
78 .expect("injected module must have a function body");
79
80 assert_eq!(actual_bytes, expected_bytes);
81 }
82 };
83 }
84
85 test_export_global! {
86 name = simple;
87 input = r#"
88 (module
89 (global (;0;) (mut i32) (i32.const 1))
90 (global (;1;) (mut i32) (i32.const 0)))
91 "#;
92 expected = r#"
93 (module
94 (global (;0;) (mut i32) (i32.const 1))
95 (global (;1;) (mut i32) (i32.const 0))
96 (export "exported_internal_global_0" (global 0))
97 (export "exported_internal_global_1" (global 1)))
98 "#
99 }
100
101 test_export_global! {
102 name = with_import;
103 input = r#"
104 (module
105 (import "env" "global" (global $global i64))
106 (global (;0;) (mut i32) (i32.const 1))
107 (global (;1;) (mut i32) (i32.const 0)))
108 "#;
109 expected = r#"
110 (module
111 (import "env" "global" (global $global i64))
112 (global (;0;) (mut i32) (i32.const 1))
113 (global (;1;) (mut i32) (i32.const 0))
114 (export "exported_internal_global_0" (global 1))
115 (export "exported_internal_global_1" (global 2)))
116 "#
117 }
118
119 test_export_global! {
120 name = with_import_and_some_are_immutable;
121 input = r#"
122 (module
123 (import "env" "global" (global $global i64))
124 (global (;0;) i32 (i32.const 1))
125 (global (;1;) (mut i32) (i32.const 0)))
126 "#;
127 expected = r#"
128 (module
129 (import "env" "global" (global $global i64))
130 (global (;0;) i32 (i32.const 1))
131 (global (;1;) (mut i32) (i32.const 0))
132 (export "exported_internal_global_0" (global 2)))
133 "#
134 }
135}