1use crate::emit::{Emit, EmitContext};
3use crate::parse::IndicesToIds;
4use crate::tombstone_arena::{Id, Tombstone, TombstoneArena};
5use crate::{ConstExpr, ImportId, Module, Result, ValType};
6
7pub type GlobalId = Id<Global>;
9
10#[derive(Debug)]
12pub struct Global {
13 id: GlobalId,
16 pub ty: ValType,
18 pub mutable: bool,
20 pub shared: bool,
22 pub kind: GlobalKind,
24 pub name: Option<String>,
27}
28
29impl Tombstone for Global {}
30
31#[derive(Debug)]
33pub enum GlobalKind {
34 Import(ImportId),
36 Local(ConstExpr),
38}
39
40impl Global {
41 pub fn id(&self) -> GlobalId {
43 self.id
44 }
45}
46
47#[derive(Debug, Default)]
49pub struct ModuleGlobals {
50 arena: TombstoneArena<Global>,
52}
53
54impl ModuleGlobals {
55 pub fn add_import(
57 &mut self,
58 ty: ValType,
59 mutable: bool,
60 shared: bool,
61 import_id: ImportId,
62 ) -> GlobalId {
63 self.arena.alloc_with_id(|id| Global {
64 id,
65 ty,
66 mutable,
67 shared,
68 kind: GlobalKind::Import(import_id),
69 name: None,
70 })
71 }
72
73 pub fn add_local(
76 &mut self,
77 ty: ValType,
78 mutable: bool,
79 shared: bool,
80 init: ConstExpr,
81 ) -> GlobalId {
82 self.arena.alloc_with_id(|id| Global {
83 id,
84 ty,
85 mutable,
86 shared,
87 kind: GlobalKind::Local(init),
88 name: None,
89 })
90 }
91
92 pub fn get(&self, id: GlobalId) -> &Global {
94 &self.arena[id]
95 }
96
97 pub fn get_mut(&mut self, id: GlobalId) -> &mut Global {
99 &mut self.arena[id]
100 }
101
102 pub fn delete(&mut self, id: GlobalId) {
107 self.arena.delete(id);
108 }
109
110 pub fn iter(&self) -> impl Iterator<Item = &Global> {
112 self.arena.iter().map(|(_, f)| f)
113 }
114}
115
116impl Module {
117 pub(crate) fn parse_globals(
119 &mut self,
120 section: wasmparser::GlobalSectionReader,
121 ids: &mut IndicesToIds,
122 ) -> Result<()> {
123 log::debug!("parse global section");
124 for g in section {
125 let g = g?;
126 let init_expr = ConstExpr::eval(&g.init_expr, ids)?;
127 let id = self.globals.add_local(
128 ValType::parse(&g.ty.content_type)?,
129 g.ty.mutable,
130 g.ty.shared,
131 init_expr,
132 );
133 ids.push_global(id);
134 }
135 Ok(())
136 }
137}
138
139impl Emit for ModuleGlobals {
140 fn emit(&self, cx: &mut EmitContext) {
141 log::debug!("emit global section");
142 let mut wasm_global_section = wasm_encoder::GlobalSection::new();
143
144 fn get_local(global: &Global) -> Option<(&Global, &ConstExpr)> {
145 match &global.kind {
146 GlobalKind::Import(_) => None,
147 GlobalKind::Local(local) => Some((global, local)),
148 }
149 }
150
151 let globals = self.iter().filter_map(get_local).count();
154 if globals == 0 {
155 return;
156 }
157
158 for (global, local) in self.iter().filter_map(get_local) {
159 cx.indices.push_global(global.id());
160
161 wasm_global_section.global(
162 wasm_encoder::GlobalType {
163 val_type: global.ty.to_wasmencoder_type(),
164 mutable: global.mutable,
165 shared: global.shared,
166 },
167 &local.to_wasmencoder_type(cx),
168 );
169 }
170
171 cx.wasm_module.section(&wasm_global_section);
172 }
173}