1use std::collections::HashSet;
4
5use wasm_encoder::{
6 CompositeInnerType, CompositeType, FieldType, StorageType, StructType, SubType, TypeSection,
7 ValType,
8};
9
10use crate::codegen::symbol_table::SymbolTable;
11use crate::{
12 ClosureBody, ExprId, StmtId, Type, TypedAst, TypedExprKind, TypedParam, TypedStmtKind,
13};
14
15pub fn collect(
16 ta: &TypedAst,
17 symbols: &SymbolTable,
18) -> Result<Vec<ValType>, crate::compiler_error::CompilerFailure> {
19 let mut state = Collector {
20 ta,
21 symbols,
22 seen: HashSet::new(),
23 order: Vec::new(),
24 };
25 let function_bodies: Vec<(Vec<TypedParam>, StmtId)> = ta
26 .functions
27 .iter()
28 .map(|f| (f.params.clone(), f.body))
29 .collect();
30 for (params, body) in function_bodies {
31 for p in ¶ms {
32 if p.boxed {
33 state.note(&p.ty)?;
34 }
35 }
36 state.walk_stmt(body)?;
37 }
38 let stmt_ids: Vec<StmtId> = ta.top_level_statements.clone();
39 for sid in stmt_ids {
40 state.walk_stmt(sid)?;
41 }
42 for member in class_member_params(ta) {
46 for p in member {
47 if p.boxed {
48 state.note(&p.ty)?;
49 }
50 }
51 }
52 for body in ta.class_body_roots() {
53 state.walk_stmt(body)?;
54 }
55 for init in ta.class_field_initializers() {
56 state.walk_expr(init)?;
57 }
58 Ok(state.order)
59}
60
61fn class_member_params(ta: &TypedAst) -> Vec<Vec<TypedParam>> {
64 let mut out = Vec::new();
65 for ty_decl in &ta.types {
66 let crate::TypedTypeDecl::Class(c) = ty_decl else {
67 continue;
68 };
69 if let Some(ctor) = &c.constructor {
70 out.push(ctor.params.clone());
71 }
72 out.extend(c.methods.iter().map(|m| m.params.clone()));
73 for a in &c.accessors {
74 if let crate::TypedClassAccessor::Setter { param, .. } = a {
75 out.push(vec![param.clone()]);
76 }
77 }
78 }
79 out
80}
81
82struct Collector<'a> {
83 ta: &'a TypedAst,
84 symbols: &'a SymbolTable,
85 seen: HashSet<ValType>,
86 order: Vec<ValType>,
87}
88
89impl Collector<'_> {
90 fn note(&mut self, ty: &Type) -> Result<(), crate::compiler_error::CompilerFailure> {
92 let valtype = self.symbols.slot_value_type(ty)?;
93 if self.seen.insert(valtype) {
94 self.order.push(valtype);
95 };
96 Ok(())
97 }
98
99 fn walk_stmt(&mut self, id: StmtId) -> Result<(), crate::compiler_error::CompilerFailure> {
100 let _: () = match &self
101 .ta
102 .try_stmt(id)
103 .map_err(crate::codegen::arena_failure)?
104 .kind
105 {
106 TypedStmtKind::Block(stmts) => {
107 for &s in stmts {
108 self.walk_stmt(s)?;
109 }
110 }
111 TypedStmtKind::Let {
112 ty, value, boxed, ..
113 } => {
114 if *boxed {
115 self.note(ty)?;
116 }
117 self.walk_expr(*value)?;
118 }
119 TypedStmtKind::Const { value, .. } => self.walk_expr(*value)?,
120 TypedStmtKind::If {
121 condition,
122 then_block,
123 else_block,
124 } => {
125 self.walk_expr(*condition)?;
126 self.walk_stmt(*then_block)?;
127 if let Some(eb) = else_block {
128 self.walk_stmt(*eb)?;
129 }
130 }
131 TypedStmtKind::While { condition, body } => {
132 self.walk_expr(*condition)?;
133 self.walk_stmt(*body)?;
134 }
135 TypedStmtKind::For {
136 init,
137 condition,
138 update,
139 body,
140 } => {
141 for i in init {
142 self.walk_stmt(*i)?;
143 }
144 if let Some(c) = condition {
145 self.walk_expr(*c)?;
146 }
147 if let Some(u) = update {
148 self.walk_stmt(*u)?;
149 }
150 self.walk_stmt(*body)?;
151 }
152 TypedStmtKind::ForOf { iter, body, .. } => {
153 self.walk_expr(*iter)?;
154 self.walk_stmt(*body)?;
155 }
156 TypedStmtKind::DoWhile { body, condition } => {
157 self.walk_stmt(*body)?;
158 self.walk_expr(*condition)?;
159 }
160 TypedStmtKind::Switch {
161 discriminant,
162 cases,
163 default,
164 ..
165 } => {
166 self.walk_expr(*discriminant)?;
167 for comparison in cases
168 .iter()
169 .flat_map(crate::TypedSwitchCase::label_comparisons)
170 {
171 self.walk_expr(comparison)?;
172 }
173 for case in cases {
174 self.walk_stmt(case.body)?;
175 }
176 if let Some(d) = default {
177 self.walk_stmt(*d)?;
178 }
179 }
180 TypedStmtKind::Break | TypedStmtKind::Continue | TypedStmtKind::ReboxLocal { .. } => {}
181 TypedStmtKind::Return(value) => {
182 if let Some(v) = value {
183 self.walk_expr(*v)?;
184 }
185 }
186 TypedStmtKind::Expr(e) => self.walk_expr(*e)?,
187 TypedStmtKind::AssignLocal { value, .. }
188 | TypedStmtKind::AssignGlobal { value, .. } => self.walk_expr(*value)?,
189 TypedStmtKind::AssignField {
190 receiver, value, ..
191 } => {
192 self.walk_expr(*receiver)?;
193 self.walk_expr(*value)?;
194 }
195 TypedStmtKind::AssignIndex {
196 receiver,
197 index,
198 value,
199 ..
200 } => {
201 self.walk_expr(*receiver)?;
202 self.walk_expr(*index)?;
203 self.walk_expr(*value)?;
204 }
205 TypedStmtKind::NarrowRegion { source, body, .. } => {
206 self.walk_expr(*source)?;
207 self.walk_stmt(*body)?;
208 }
209 TypedStmtKind::Throw { value } => self.walk_expr(*value)?,
210 TypedStmtKind::Try {
211 body,
212 catches,
213 finally,
214 } => {
215 self.walk_stmt(*body)?;
216 for c in catches {
217 if c.boxed {
218 self.note(&c.ty)?;
219 }
220 self.walk_stmt(c.body)?;
221 }
222 if let Some(f) = finally {
223 self.walk_stmt(*f)?;
224 }
225 }
226 };
227 Ok(())
228 }
229
230 fn walk_expr(&mut self, id: ExprId) -> Result<(), crate::compiler_error::CompilerFailure> {
231 let _: () = match &self
232 .ta
233 .try_expr(id)
234 .map_err(crate::codegen::arena_failure)?
235 .kind
236 {
237 TypedExprKind::Closure {
238 params,
239 captured,
240 body,
241 ..
242 } => {
243 for p in params {
244 if p.boxed {
245 self.note(&p.ty)?;
246 }
247 }
248 for c in captured {
249 if c.boxed {
250 self.note(&c.ty)?;
251 }
252 }
253 match *body {
254 ClosureBody::Expr(e) => self.walk_expr(e)?,
255 ClosureBody::Block(b) => self.walk_stmt(b)?,
256 }
257 }
258 TypedExprKind::Binary { lhs, rhs, .. } => {
259 self.walk_expr(*lhs)?;
260 self.walk_expr(*rhs)?;
261 }
262 TypedExprKind::EffectThen { effect, result } => {
263 self.walk_expr(*effect)?;
264 self.walk_expr(*result)?;
265 }
266 TypedExprKind::Sequence { stmts, result } => {
267 for &stmt in stmts {
268 self.walk_stmt(stmt)?;
269 }
270 self.walk_expr(*result)?;
271 }
272 TypedExprKind::Unary { operand, .. } => self.walk_expr(*operand)?,
273 TypedExprKind::TypeofTag { value, .. } | TypedExprKind::InstanceOf { value, .. } => {
274 self.walk_expr(*value)?;
275 }
276 TypedExprKind::Call { args, .. }
277 | TypedExprKind::VirtualCall { args, .. }
278 | TypedExprKind::SuperCtorCall { args, .. }
279 | TypedExprKind::SuperMethodCall { args, .. } => {
280 for &a in args {
281 self.walk_expr(a)?;
282 }
283 }
284 TypedExprKind::CallClosure { callee, args } => {
285 self.walk_expr(*callee)?;
286 for &a in args {
287 self.walk_expr(a)?;
288 }
289 }
290 TypedExprKind::GenericCall { args, .. } => {
291 for a in args {
292 self.walk_expr(a.expr)?;
293 }
294 }
295 TypedExprKind::MethodCall { receiver, args, .. } => {
296 self.walk_expr(*receiver)?;
297 for &a in args {
298 self.walk_expr(a)?;
299 }
300 }
301 TypedExprKind::GenericMethodCall { receiver, args, .. } => {
302 self.walk_expr(*receiver)?;
303 for a in args {
304 self.walk_expr(a.expr)?;
305 }
306 }
307 TypedExprKind::IntrinsicCall { args, .. } => {
308 for &a in args {
309 self.walk_expr(a)?;
310 }
311 }
312 TypedExprKind::ObjectLiteral { members, .. } => {
313 for member in members {
314 for expression in member.expressions() {
315 self.walk_expr(expression)?;
316 }
317 }
318 }
319 TypedExprKind::ArrayLiteral { elements, .. } => {
320 for e in elements {
321 self.walk_expr(e.expr_id())?;
322 }
323 }
324 TypedExprKind::TupleLiteral { elements, .. } => {
325 for &e in elements {
326 self.walk_expr(e)?;
327 }
328 }
329 TypedExprKind::FieldAccess { receiver, .. }
330 | TypedExprKind::InterfacePropertyAccess { receiver, .. } => {
331 self.walk_expr(*receiver)?;
332 }
333 TypedExprKind::IndexAccess { receiver, index } => {
334 self.walk_expr(*receiver)?;
335 self.walk_expr(*index)?;
336 }
337 TypedExprKind::Narrowed { source, inner, .. } => {
338 self.walk_expr(*source)?;
339 self.walk_expr(*inner)?;
340 }
341 TypedExprKind::Ternary { cond, then_, else_ } => {
342 self.walk_expr(*cond)?;
343 self.walk_expr(*then_)?;
344 self.walk_expr(*else_)?;
345 }
346 TypedExprKind::NullishCoalesce { lhs, rhs } => {
347 self.walk_expr(*lhs)?;
348 self.walk_expr(*rhs)?;
349 }
350 TypedExprKind::OptionalChain { base, parts } => {
351 self.walk_expr(*base)?;
352 for part in parts {
353 match part {
354 crate::TypedChainPart::Index { idx, .. } => self.walk_expr(*idx)?,
355 crate::TypedChainPart::Call { args, .. }
356 | crate::TypedChainPart::MethodCall { args, .. } => {
357 for a in args {
358 self.walk_expr(*a)?;
359 }
360 }
361 crate::TypedChainPart::Field { .. }
362 | crate::TypedChainPart::InterfaceProperty { .. }
363 | crate::TypedChainPart::NonNull { .. }
364 | crate::TypedChainPart::Constraint { .. } => {}
365 }
366 }
367 }
368 TypedExprKind::PostfixUnary { target, .. } => match target {
369 crate::PostfixTarget::Local {
370 boxed, target_ty, ..
371 } => {
372 if *boxed {
373 self.note(target_ty)?;
374 }
375 }
376 crate::PostfixTarget::Global { .. } => {}
377 crate::PostfixTarget::Field { receiver, .. } => self.walk_expr(*receiver)?,
378 crate::PostfixTarget::Index {
379 receiver, index, ..
380 } => {
381 self.walk_expr(*receiver)?;
382 self.walk_expr(*index)?;
383 }
384 },
385 TypedExprKind::NonNullAssert { value } | TypedExprKind::Cast { value, .. } => {
386 self.walk_expr(*value)?;
387 }
388 TypedExprKind::Number(_)
389 | TypedExprKind::BigInt(_)
390 | TypedExprKind::String(_)
391 | TypedExprKind::Boolean(_)
392 | TypedExprKind::Null
393 | TypedExprKind::Undefined
394 | TypedExprKind::This
395 | TypedExprKind::Regex { .. }
396 | TypedExprKind::LocalRef { .. }
397 | TypedExprKind::LocalNarrowRef { .. }
398 | TypedExprKind::GlobalRef { .. }
399 | TypedExprKind::FunctionRef { .. }
400 | TypedExprKind::NumberEnumMember { .. }
401 | TypedExprKind::StringEnumMember { .. } => {}
402 };
403 Ok(())
404 }
405}
406
407pub fn emit(
409 value_types_to_emit: &[ValType],
410 types: &mut TypeSection,
411 symbols: &mut SymbolTable,
412 next_type_idx: &mut u32,
413) {
414 for val in value_types_to_emit {
415 let field = FieldType {
416 element_type: StorageType::Val(match *val {
417 ValType::Ref(mut reference) => {
418 reference.nullable = true;
419 ValType::Ref(reference)
420 }
421 value => value,
422 }),
423 mutable: true,
424 };
425 types.ty().subtype(&SubType {
426 is_final: false,
427 supertype_idx: None,
428 composite_type: CompositeType {
429 inner: CompositeInnerType::Struct(StructType {
430 fields: vec![
431 field,
432 FieldType {
433 element_type: StorageType::Val(ValType::I32),
434 mutable: true,
435 },
436 ]
437 .into_boxed_slice(),
438 }),
439 shared: false,
440 descriptor: None,
441 describes: None,
442 },
443 });
444 symbols.record_box_type(*val, *next_type_idx);
445 *next_type_idx += 1;
446 }
447}