1use std::collections::{BTreeMap, BTreeSet, HashMap};
5
6use wasm_encoder::{HeapType, RefType, ValType};
7
8use crate::codegen::closures::ClosureSig;
9use crate::codegen::internal_failure;
10use crate::codegen::intrinsics::{IntrinsicTypeIndices, intrinsic_supertypes};
11use crate::compiler_error::CompilerFailure;
12use crate::{Dispatch, ExprId, MangledName, Type};
13
14#[derive(Clone, Debug)]
18pub enum FieldSetup {
19 Init { field: String, value: ExprId },
21 ParamCopy {
23 field: String,
24 param: Box<crate::TypedParam>,
25 },
26 Reset { field: String },
30}
31
32#[derive(Default, Clone, Copy, Debug)]
33pub struct ClassGuardLayout {
34 pub inheritance_depth: u32,
35 pub named_payload_len: u32,
36 pub has_instance_guards: bool,
37}
38
39#[derive(Default, Clone, Debug)]
40pub struct SymbolTable {
41 pub(crate) field_lookup_function: Option<u32>,
42 pub(crate) resultless_functions: BTreeSet<u32>,
43 host_parameter_defaults: BTreeMap<u32, Vec<Option<crate::DefaultValue>>>,
45 pub class_type_parameters: BTreeMap<MangledName, Vec<String>>,
46 pub runtime_generic_functions: BTreeSet<MangledName>,
47 pub field_guard_targets: BTreeMap<u32, Type>,
48 pub type_descriptor_functions: BTreeMap<Type, u32>,
49 pub type_descriptor_globals: BTreeMap<Type, u32>,
50 types: BTreeMap<MangledName, u32>,
51 funcs: BTreeMap<MangledName, u32>,
52 globals: BTreeMap<MangledName, u32>,
53 global_types: BTreeMap<MangledName, Type>,
54 init_guards: BTreeMap<MangledName, crate::codegen::init_guard::InitFlag>,
55 class_declaration_flags: BTreeMap<usize, Vec<u32>>,
58 intrinsic_type_indices: Option<IntrinsicTypeIndices>,
59 pub(crate) this_environment_type: Option<u32>,
60 pub(crate) call_metadata_type: Option<u32>,
61 pub(crate) function_argument_metadata: BTreeMap<MangledName, String>,
62 class_struct_type_idx: BTreeMap<MangledName, u32>,
65 class_vtable_type_idx: BTreeMap<MangledName, u32>,
66 class_vtable_global_idx: BTreeMap<MangledName, u32>,
67 class_getter_global_idx: BTreeMap<MangledName, u32>,
68 class_setter_global_idx: BTreeMap<MangledName, u32>,
69 class_method_func_idx: BTreeMap<(MangledName, String), u32>,
70 class_ctor_init_func_idx: BTreeMap<MangledName, u32>,
74 class_method_adapter_func_idx: BTreeMap<(MangledName, String), u32>,
77 class_method_slot: BTreeMap<(MangledName, String), u32>,
80 class_payload_methods: BTreeSet<(MangledName, String)>,
82 rewritable_members: crate::codegen::classes::RewritableMembers,
84 class_method_sig: BTreeMap<(MangledName, String), u32>,
86 class_method_abi: BTreeMap<(MangledName, String), MethodSlotAbi>,
89 class_ctor_abi: BTreeMap<MangledName, Vec<ValType>>,
92 class_field_slot: BTreeMap<(MangledName, String), u32>,
95 class_field_narrowing_check: BTreeMap<(MangledName, String), crate::FieldNarrowingCheck>,
97 class_field_setup: BTreeMap<MangledName, Vec<FieldSetup>>,
100 vtable_global_idx: BTreeMap<Type, u32>,
101 field_names_global_idx: BTreeMap<Vec<super::field_names::FieldName>, u32>,
102 optional_field_name_type: Option<u32>,
103 field_name_string_global_idx: BTreeMap<String, u32>,
104 box_type_idx: HashMap<ValType, u32>,
106 struct_supertype: BTreeMap<u32, u32>,
109 closure_func_type_idx: BTreeMap<ClosureSig, u32>,
110 closure_struct_type_idx: BTreeMap<ClosureSig, u32>,
111 closure_coercions: BTreeMap<ClosureSig, u32>,
112 closure_coercion_vtable_type: Option<u32>,
113 env_type_idx: BTreeMap<ExprId, u32>,
114 closure_func_idx: BTreeMap<ExprId, u32>,
115 closure_vtable_global_idx: Option<u32>,
116 error_tag_idx: Option<u32>,
118 adapter_func_idx: BTreeMap<MangledName, u32>,
119 adapter_closure_global_idx: BTreeMap<MangledName, u32>,
120 shared_closure_globals: BTreeSet<MangledName>,
123 runtime_validator_idx: BTreeMap<Type, u32>,
125 generic_runtime_validators: BTreeMap<MangledName, (Vec<String>, u32)>,
126 instance_field_guards: BTreeMap<(Type, MangledName, String), u32>,
127 class_guard_layout: BTreeMap<MangledName, ClassGuardLayout>,
128 top_level_fns: BTreeMap<MangledName, TopLevelFn>,
130 iface_dispatch: BTreeMap<MangledName, Dispatch>,
131 static_value_tags: BTreeMap<MangledName, String>,
134 iface_method_abi: BTreeMap<MangledName, MethodSlotAbi>,
137 intrinsic_members: BTreeSet<MangledName>,
139}
140
141#[derive(Clone, Debug)]
142pub struct TopLevelFn {
143 pub wasm_idx: u32,
144 pub params: Vec<Type>,
145 pub ret: Type,
146 pub is_host: bool,
149}
150
151#[derive(Clone, Debug, Default, PartialEq)]
164pub struct MethodSlotAbi {
165 pub params: Vec<ValType>,
167 pub ret: Option<ValType>,
169}
170
171pub fn is_erased(ty: &Type) -> bool {
179 match ty.lowered() {
180 Type::TypeVar(_) | Type::GenericParam { .. } | Type::ClassRef { .. } => true,
181 Type::Union(members) => members.iter().any(is_erased),
182 _ => false,
183 }
184}
185
186pub(crate) fn is_nullable_ref(val: ValType) -> bool {
189 matches!(val, ValType::Ref(RefType { nullable: true, .. }))
190}
191
192pub(crate) fn may_hold_null(ty: &Type) -> bool {
201 match ty.lowered() {
202 Type::Null
205 | Type::Void
206 | Type::Unknown
207 | Type::TypeVar(_)
208 | Type::GenericParam { .. }
209 | Type::AliasRef { .. } => true,
210 Type::Union(members) => members.iter().any(may_hold_null),
211 _ => false,
212 }
213}
214
215impl SymbolTable {
216 pub fn new() -> Self {
217 Self::default()
218 }
219
220 pub fn type_idx(&self, mangled: &MangledName) -> Option<u32> {
221 self.types.get(mangled).copied()
222 }
223
224 pub fn func_idx(&self, mangled: &MangledName) -> Option<u32> {
225 self.funcs.get(mangled).copied()
226 }
227
228 pub fn global_idx(&self, mangled: &MangledName) -> Option<u32> {
229 self.globals.get(mangled).copied()
230 }
231
232 pub fn global_type(&self, mangled: &MangledName) -> Option<&Type> {
233 self.global_types.get(mangled)
234 }
235
236 pub fn init_guard(
237 &self,
238 global: &MangledName,
239 ) -> Option<&crate::codegen::init_guard::InitFlag> {
240 self.init_guards.get(global)
241 }
242
243 pub fn class_declaration_flags(&self, index: usize) -> &[u32] {
244 self.class_declaration_flags
245 .get(&index)
246 .map_or(&[], Vec::as_slice)
247 }
248
249 pub fn prelude_func_idx(&self, symbol: &str) -> Option<u32> {
250 self.func_idx(&crate::mangle::prelude(symbol))
251 }
252
253 pub fn prelude_global_idx(&self, symbol: &str) -> Option<u32> {
254 self.global_idx(&crate::mangle::prelude(symbol))
255 }
256
257 pub fn string_type_idx(&self) -> Option<u32> {
258 self.intrinsic_type_indices.map(|i| i.string)
259 }
260
261 pub fn raw_string_type_idx(&self) -> Option<u32> {
262 self.intrinsic_type_indices.map(|i| i.raw_string)
263 }
264
265 pub fn bigint_type_idx(&self) -> Option<u32> {
266 self.intrinsic_type_indices.map(|i| i.bigint)
267 }
268
269 pub fn raw_bigint_type_idx(&self) -> Option<u32> {
270 self.intrinsic_type_indices.map(|i| i.raw_bigint)
271 }
272
273 pub fn regex_type_idx(&self) -> Option<u32> {
274 self.intrinsic_type_indices.map(|i| i.regex)
275 }
276
277 pub fn regex_match_type_idx(&self) -> Option<u32> {
278 self.intrinsic_type_indices.map(|i| i.regex_match)
279 }
280
281 pub fn regex_capture_array_type_idx(&self) -> Option<u32> {
282 self.intrinsic_type_indices.map(|i| i.regex_capture_array)
283 }
284
285 pub fn regex_match_box_type_idx(&self) -> Option<u32> {
286 self.intrinsic_type_indices.map(|i| i.regex_match_box)
287 }
288
289 pub fn boxed_number_type_idx(&self) -> Option<u32> {
290 self.intrinsic_type_indices.map(|i| i.boxed_number)
291 }
292
293 pub fn boxed_boolean_type_idx(&self) -> Option<u32> {
294 self.intrinsic_type_indices.map(|i| i.boxed_boolean)
295 }
296
297 pub fn raw_array_type_idx(&self) -> Option<u32> {
298 self.intrinsic_type_indices.map(|i| i.raw_array)
299 }
300
301 pub fn field_names_type_idx(&self) -> Option<u32> {
302 self.intrinsic_type_indices.map(|i| i.field_names)
303 }
304
305 pub fn object_shape_type_idx(&self) -> Option<u32> {
306 self.intrinsic_type_indices.map(|i| i.object_shape)
307 }
308
309 pub fn array_type_idx(&self) -> Option<u32> {
310 self.intrinsic_type_indices.map(|i| i.array)
311 }
312
313 pub fn raw_uint8_array_type_idx(&self) -> Option<u32> {
314 self.intrinsic_type_indices.map(|i| i.raw_uint8_array)
315 }
316
317 pub fn uint8_array_type_idx(&self) -> Option<u32> {
318 self.intrinsic_type_indices.map(|i| i.uint8_array)
319 }
320
321 pub fn closure_type_idx(&self) -> Option<u32> {
322 self.intrinsic_type_indices.map(|i| i.closure)
323 }
324
325 pub fn intrinsic_type_indices(&self) -> Option<IntrinsicTypeIndices> {
326 self.intrinsic_type_indices
327 }
328
329 pub fn object_subtype_idx(&self, ty: &Type) -> Option<u32> {
330 match ty {
331 Type::Object { .. } => self.object_shape_type_idx(),
332 _ => None,
333 }
334 }
335
336 pub fn class_struct_type_idx(&self, mangled: &MangledName) -> Option<u32> {
337 self.class_struct_type_idx.get(mangled).copied()
338 }
339
340 pub fn class_vtable_type_idx(&self, mangled: &MangledName) -> Option<u32> {
341 self.class_vtable_type_idx.get(mangled).copied()
342 }
343
344 pub fn class_vtable_global_idx(&self, mangled: &MangledName) -> Option<u32> {
345 self.class_vtable_global_idx.get(mangled).copied()
346 }
347
348 pub fn class_getter_global_idx(&self, mangled: &MangledName) -> Option<u32> {
349 self.class_getter_global_idx.get(mangled).copied()
350 }
351
352 pub fn class_setter_global_idx(&self, mangled: &MangledName) -> Option<u32> {
353 self.class_setter_global_idx.get(mangled).copied()
354 }
355
356 pub fn class_method_func_idx(&self, class: &MangledName, method: &str) -> Option<u32> {
357 self.class_method_func_idx
358 .get(&(class.clone(), method.to_string()))
359 .copied()
360 }
361
362 pub fn class_ctor_init_func_idx(&self, class: &MangledName) -> Option<u32> {
363 self.class_ctor_init_func_idx.get(class).copied()
364 }
365
366 pub fn class_method_adapter_func_idx(&self, class: &MangledName, method: &str) -> Option<u32> {
367 self.class_method_adapter_func_idx
368 .get(&(class.clone(), method.to_string()))
369 .copied()
370 }
371
372 pub fn class_method_slot(&self, class: &MangledName, method: &str) -> Option<u32> {
373 self.class_method_slot
374 .get(&(class.clone(), method.to_string()))
375 .copied()
376 }
377
378 pub fn is_class_payload_method(&self, class: &MangledName, method: &str) -> bool {
379 self.class_payload_methods
380 .contains(&(class.clone(), method.to_string()))
381 }
382
383 pub fn class_method_sig(&self, class: &MangledName, method: &str) -> Option<u32> {
384 self.class_method_sig
385 .get(&(class.clone(), method.to_string()))
386 .copied()
387 }
388
389 pub fn class_method_abi(&self, class: &MangledName, method: &str) -> Option<&MethodSlotAbi> {
390 self.class_method_abi
391 .get(&(class.clone(), method.to_string()))
392 }
393
394 pub fn class_ctor_abi(&self, class: &MangledName) -> Option<&[ValType]> {
395 self.class_ctor_abi.get(class).map(Vec::as_slice)
396 }
397
398 pub fn class_field_slot(&self, class: &MangledName, field: &str) -> Option<u32> {
399 self.class_field_slot
400 .get(&(class.clone(), field.to_string()))
401 .copied()
402 }
403
404 pub fn class_field_narrowing_check(
406 &self,
407 class: &MangledName,
408 field: &str,
409 ) -> Option<&crate::FieldNarrowingCheck> {
410 self.class_field_narrowing_check
411 .get(&(class.clone(), field.to_string()))
412 }
413
414 pub fn class_field_narrowing_checks<'a>(
415 &'a self,
416 field: &'a str,
417 ) -> impl Iterator<Item = (&'a MangledName, &'a crate::FieldNarrowingCheck)> + 'a {
418 self.class_field_narrowing_check
419 .iter()
420 .filter(move |((_, name), _)| name == field)
421 .map(|((class, _), check)| (class, check))
422 }
423
424 pub fn class_field_setup(&self, class: &MangledName) -> Option<&[FieldSetup]> {
425 self.class_field_setup.get(class).map(Vec::as_slice)
426 }
427
428 pub fn vtable_global_idx(&self, ty: &Type) -> Option<u32> {
429 self.vtable_global_idx.get(ty).copied()
430 }
431
432 pub fn record_optional_field_name_type(&mut self, index: u32) {
433 self.optional_field_name_type = Some(index);
434 }
435
436 pub fn optional_field_name_type(&self) -> Result<u32, CompilerFailure> {
437 self.optional_field_name_type
438 .ok_or_else(|| internal_failure("optional field-name type was not declared"))
439 }
440
441 pub fn field_names_global_idx(
442 &self,
443 field_names: &[super::field_names::FieldName],
444 ) -> Option<u32> {
445 self.field_names_global_idx.get(field_names).copied()
446 }
447
448 pub fn field_name_string_global_idx(&self, name: &str) -> Option<u32> {
449 self.field_name_string_global_idx.get(name).copied()
450 }
451
452 pub fn box_type_idx(
457 &self,
458 ty: &Type,
459 ) -> Result<Option<u32>, crate::compiler_error::CompilerFailure> {
460 Ok(self.box_type_idx.get(&self.slot_value_type(ty)?).copied())
461 }
462
463 pub fn box_payload_type(&self, idx: u32) -> Option<ValType> {
471 self.box_type_idx
472 .iter()
473 .find(|&(_, &v)| v == idx)
474 .map(|(payload, _)| *payload)
475 }
476
477 pub fn closure_func_type_idx(&self, sig: ClosureSig) -> Option<u32> {
478 self.closure_func_type_idx.get(&sig).copied()
479 }
480
481 pub fn record_closure_coercion_vtable_type(&mut self, index: u32) {
482 self.closure_coercion_vtable_type = Some(index);
483 }
484
485 pub fn closure_coercion_vtable_type(
486 &self,
487 ) -> Result<u32, crate::compiler_error::CompilerFailure> {
488 self.closure_coercion_vtable_type.ok_or_else(|| {
489 crate::codegen::internal_failure("closure coercion vtable is not registered")
490 })
491 }
492
493 pub fn closure_signatures(&self) -> impl Iterator<Item = ClosureSig> + '_ {
494 self.closure_struct_type_idx.keys().copied()
495 }
496
497 pub fn record_closure_coercion(&mut self, target: ClosureSig, index: u32) {
498 self.closure_coercions.insert(target, index);
499 }
500
501 pub fn closure_coercion(&self, target: ClosureSig) -> Option<u32> {
502 self.closure_coercions.get(&target).copied()
503 }
504
505 pub fn closure_struct_type_idx(&self, sig: ClosureSig) -> Option<u32> {
506 self.closure_struct_type_idx.get(&sig).copied()
507 }
508
509 pub fn env_type_idx(&self, expr_id: ExprId) -> Option<u32> {
510 self.env_type_idx.get(&expr_id).copied()
511 }
512
513 pub fn closure_func_idx(&self, expr_id: ExprId) -> Option<u32> {
514 self.closure_func_idx.get(&expr_id).copied()
515 }
516
517 pub fn closure_vtable_global_idx(&self) -> Option<u32> {
518 self.closure_vtable_global_idx
519 }
520
521 pub fn adapter_func_idx(&self, mangled: &MangledName) -> Option<u32> {
522 self.adapter_func_idx.get(mangled).copied()
523 }
524
525 pub fn adapter_closure_global_idx(&self, mangled: &MangledName) -> Option<u32> {
526 self.adapter_closure_global_idx.get(mangled).copied()
527 }
528
529 pub fn is_shared_closure_global(&self, mangled: &MangledName) -> bool {
530 self.shared_closure_globals.contains(mangled)
531 }
532
533 pub fn ref_fits_slot(&self, value: RefType, slot: RefType) -> bool {
542 if value.nullable && !slot.nullable {
543 return false;
544 }
545 let (HeapType::Concrete(value_idx), HeapType::Concrete(slot_idx)) =
546 (value.heap_type, slot.heap_type)
547 else {
548 return value.heap_type == slot.heap_type;
549 };
550 let mut current = value_idx;
551 while current != slot_idx {
552 match self.struct_supertype.get(¤t) {
555 Some(&parent) if parent < current => current = parent,
556 _ => return false,
557 }
558 }
559 true
560 }
561
562 pub fn record_type(&mut self, mangled: MangledName, idx: u32) {
563 self.types.insert(mangled, idx);
564 }
565
566 pub fn set_intrinsic_type_indices(&mut self, indices: IntrinsicTypeIndices) {
569 self.intrinsic_type_indices = Some(indices);
570 for (child, parent) in intrinsic_supertypes(indices) {
571 self.record_struct_supertype(child, parent);
572 }
573 }
574
575 pub fn record_struct_supertype(&mut self, child: u32, parent: u32) {
576 self.struct_supertype.insert(child, parent);
577 }
578
579 pub fn record_class_struct_type(&mut self, mangled: MangledName, idx: u32) {
580 self.class_struct_type_idx.insert(mangled, idx);
581 }
582
583 pub fn record_class_vtable_type(&mut self, mangled: MangledName, idx: u32) {
584 self.class_vtable_type_idx.insert(mangled, idx);
585 }
586
587 pub fn record_class_vtable_global(&mut self, mangled: MangledName, idx: u32) {
588 self.class_vtable_global_idx.insert(mangled, idx);
589 }
590
591 pub fn record_class_getter_global(&mut self, mangled: MangledName, idx: u32) {
592 self.class_getter_global_idx.insert(mangled, idx);
593 }
594
595 pub fn record_class_setter_global(&mut self, mangled: MangledName, idx: u32) {
596 self.class_setter_global_idx.insert(mangled, idx);
597 }
598
599 pub fn record_class_method_func(&mut self, class: MangledName, method: String, idx: u32) {
600 self.class_method_func_idx.insert((class, method), idx);
601 }
602
603 pub fn record_class_ctor_init_func(&mut self, class: MangledName, idx: u32) {
604 self.class_ctor_init_func_idx.insert(class, idx);
605 }
606
607 pub fn record_class_method_adapter_func(
608 &mut self,
609 class: MangledName,
610 method: String,
611 idx: u32,
612 ) {
613 self.class_method_adapter_func_idx
614 .insert((class, method), idx);
615 }
616
617 pub fn record_class_method_slot(&mut self, class: MangledName, method: String, slot: u32) {
618 self.class_method_slot.insert((class, method), slot);
619 }
620
621 pub(crate) fn record_host_parameter_defaults(
622 &mut self,
623 func_idx: u32,
624 defaults: Vec<Option<crate::DefaultValue>>,
625 ) {
626 self.host_parameter_defaults.insert(func_idx, defaults);
627 }
628
629 pub(crate) fn host_call_defaults(
636 &self,
637 func_idx: u32,
638 arg_count: usize,
639 ) -> &[Option<crate::DefaultValue>] {
640 let defaults = self
641 .host_parameter_defaults
642 .get(&func_idx)
643 .map_or(&[][..], Vec::as_slice);
644 let receivers = defaults.len().saturating_sub(arg_count);
645 defaults.get(receivers..).unwrap_or_default()
646 }
647
648 pub fn record_class_payload_method(&mut self, class: MangledName, method: String) {
649 self.class_payload_methods.insert((class, method));
650 }
651
652 pub(crate) fn record_rewritable_members(
653 &mut self,
654 members: crate::codegen::classes::RewritableMembers,
655 ) {
656 self.rewritable_members = members;
657 }
658
659 pub fn is_rewritable_class_method(&self, class: &MangledName, method: &str) -> bool {
663 self.rewritable_members.includes(method) && self.is_class_payload_method(class, method)
664 }
665
666 pub fn record_class_method_sig(&mut self, class: MangledName, method: String, sig: u32) {
667 self.class_method_sig.insert((class, method), sig);
668 }
669
670 pub fn record_class_method_abi(
671 &mut self,
672 class: MangledName,
673 method: String,
674 abi: MethodSlotAbi,
675 ) {
676 self.class_method_abi.insert((class, method), abi);
677 }
678
679 pub fn record_class_ctor_abi(&mut self, class: MangledName, params: Vec<ValType>) {
680 self.class_ctor_abi.insert(class, params);
681 }
682
683 pub fn record_class_field_narrowing_check(
684 &mut self,
685 class: MangledName,
686 field: String,
687 check: crate::FieldNarrowingCheck,
688 ) {
689 self.class_field_narrowing_check
690 .insert((class, field), check);
691 }
692
693 pub fn record_class_field_slot(&mut self, class: MangledName, field: String, slot: u32) {
694 self.class_field_slot.insert((class, field), slot);
695 }
696
697 pub fn record_class_field_setup(&mut self, class: MangledName, setup: Vec<FieldSetup>) {
698 self.class_field_setup.insert(class, setup);
699 }
700
701 pub fn record_vtable_global(&mut self, ty: Type, idx: u32) {
702 self.vtable_global_idx.insert(ty, idx);
703 }
704
705 pub fn record_field_names_global(
706 &mut self,
707 field_names: Vec<super::field_names::FieldName>,
708 idx: u32,
709 ) {
710 self.field_names_global_idx.insert(field_names, idx);
711 }
712
713 pub fn record_field_name_string_global(&mut self, name: String, idx: u32) {
714 self.field_name_string_global_idx.insert(name, idx);
715 }
716
717 pub fn record_box_type(&mut self, value_type: ValType, idx: u32) {
718 self.box_type_idx.insert(value_type, idx);
719 }
720
721 pub fn record_closure_func_type(&mut self, sig: ClosureSig, idx: u32) {
722 self.closure_func_type_idx.insert(sig, idx);
723 }
724
725 pub fn record_closure_struct_type(&mut self, sig: ClosureSig, idx: u32) {
726 self.closure_struct_type_idx.insert(sig, idx);
727 }
728
729 pub fn record_env_type(&mut self, expr_id: ExprId, idx: u32) {
730 self.env_type_idx.insert(expr_id, idx);
731 }
732
733 pub fn record_closure_func_idx(&mut self, expr_id: ExprId, idx: u32) {
734 self.closure_func_idx.insert(expr_id, idx);
735 }
736
737 pub fn set_closure_vtable_global(&mut self, idx: u32) {
738 self.closure_vtable_global_idx = Some(idx);
739 }
740
741 pub fn error_tag_idx(&self) -> Option<u32> {
743 self.error_tag_idx
744 }
745
746 pub fn set_error_tag_idx(&mut self, idx: u32) {
747 self.error_tag_idx = Some(idx);
748 }
749
750 pub fn record_adapter_func_idx(&mut self, mangled: MangledName, idx: u32) {
751 self.adapter_func_idx.insert(mangled, idx);
752 }
753
754 pub fn record_adapter_closure_global_idx(&mut self, mangled: MangledName, idx: u32) {
755 self.adapter_closure_global_idx.insert(mangled, idx);
756 }
757
758 pub fn record_shared_closure_global_idx(&mut self, mangled: MangledName, idx: u32) {
759 self.shared_closure_globals.insert(mangled.clone());
760 self.adapter_closure_global_idx.insert(mangled, idx);
761 }
762
763 pub fn record_class_guard_layout(
764 &mut self,
765 class: MangledName,
766 parent: Option<&MangledName>,
767 named_len: u32,
768 guarded: bool,
769 ) -> Result<(), CompilerFailure> {
770 let depth = match parent {
771 Some(parent) => self
772 .recorded_class_guard_layout(parent)?
773 .inheritance_depth
774 .checked_add(1)
775 .ok_or_else(|| internal_failure("class inheritance depth overflowed"))?,
776 None => 0,
777 };
778 self.class_guard_layout.insert(
779 class,
780 ClassGuardLayout {
781 inheritance_depth: depth,
782 named_payload_len: named_len,
783 has_instance_guards: guarded,
784 },
785 );
786 Ok(())
787 }
788
789 pub fn class_guard_layout(&self, class: &MangledName) -> ClassGuardLayout {
793 self.class_guard_layout
794 .get(class)
795 .copied()
796 .unwrap_or_default()
797 }
798
799 pub fn recorded_class_guard_layout(
802 &self,
803 class: &MangledName,
804 ) -> Result<ClassGuardLayout, CompilerFailure> {
805 self.class_guard_layout.get(class).copied().ok_or_else(|| {
806 internal_failure(format!(
807 "class `{}` has no recorded guard layout",
808 class.as_str()
809 ))
810 })
811 }
812
813 pub fn record_instance_field_guard(
814 &mut self,
815 class: Type,
816 declaration: MangledName,
817 field: String,
818 function: u32,
819 ) {
820 self.instance_field_guards
821 .insert((class, declaration, field), function);
822 }
823
824 pub fn instance_field_guards<'a>(
825 &'a self,
826 class: &'a Type,
827 ) -> impl Iterator<Item = (&'a MangledName, &'a str, u32)> + 'a {
828 self.instance_field_guards
829 .iter()
830 .filter(move |((ty, _, _), _)| ty == class)
831 .map(|((_, declaration, field), function)| (declaration, field.as_str(), *function))
832 }
833
834 pub fn record_runtime_validator(&mut self, key: Type, idx: u32) {
835 if let Type::AliasRef { mangled, args, .. } | Type::InterfaceRef { mangled, args, .. } =
836 &key
837 && let Some(names) = generic_parameter_names(args)
838 {
839 self.generic_runtime_validators
840 .insert(mangled.clone(), (names, idx));
841 }
842 self.runtime_validator_idx.insert(key, idx);
843 }
844
845 pub fn runtime_validator_idx(&self, key: &Type) -> Option<u32> {
848 self.runtime_validator_idx
849 .get(key)
850 .copied()
851 .or_else(|| self.generic_runtime_validator(key).map(|(_, idx)| idx))
852 }
853
854 pub fn generic_runtime_validator(&self, key: &Type) -> Option<(&[String], u32)> {
855 let (Type::AliasRef {
856 mangled: identity, ..
857 }
858 | Type::InterfaceRef {
859 mangled: identity, ..
860 }) = key.lowered()
861 else {
862 return None;
863 };
864 let (names, index) = self.generic_runtime_validators.get(identity)?;
865 if self
866 .runtime_validator_idx
867 .get(key)
868 .is_some_and(|exact| exact != index)
869 {
870 return None;
871 }
872 Some((names.as_slice(), *index))
873 }
874
875 pub fn record_func(&mut self, mangled: MangledName, idx: u32) {
876 self.funcs.insert(mangled, idx);
877 }
878
879 pub fn record_global(&mut self, mangled: MangledName, idx: u32) {
880 self.globals.insert(mangled, idx);
881 }
882
883 pub fn record_init_guard(
885 &mut self,
886 global: MangledName,
887 flag: crate::codegen::init_guard::InitFlag,
888 ) {
889 self.init_guards.insert(global, flag);
890 }
891
892 pub fn record_class_declaration_flag(&mut self, index: usize, flag_idx: u32) {
893 self.class_declaration_flags
894 .entry(index)
895 .or_default()
896 .push(flag_idx);
897 }
898
899 pub fn record_typed_global(&mut self, mangled: MangledName, idx: u32, ty: Type) {
902 self.global_types.insert(mangled.clone(), ty);
903 self.record_global(mangled, idx);
904 }
905
906 pub fn record_imported_fn(
909 &mut self,
910 mangled: MangledName,
911 idx: u32,
912 params: Vec<Type>,
913 ret: Type,
914 is_host: bool,
915 ) {
916 self.funcs.insert(mangled.clone(), idx);
917 self.top_level_fns.insert(
918 mangled,
919 TopLevelFn {
920 wasm_idx: idx,
921 params,
922 ret,
923 is_host,
924 },
925 );
926 }
927
928 pub fn record_local_fn(
929 &mut self,
930 mangled: MangledName,
931 idx: u32,
932 params: Vec<Type>,
933 ret: Type,
934 ) -> Result<(), CompilerFailure> {
935 if !mangled.as_str().contains(crate::mangle::SEP) {
937 return Err(internal_failure(format!(
938 "local function `{}` has no mangled package prefix",
939 mangled.as_str()
940 )));
941 }
942 self.funcs.insert(mangled.clone(), idx);
943 self.top_level_fns.insert(
944 mangled,
945 TopLevelFn {
946 wasm_idx: idx,
947 params,
948 ret,
949 is_host: false,
950 },
951 );
952 Ok(())
953 }
954
955 pub fn top_level_fn(&self, mangled: &MangledName) -> Option<&TopLevelFn> {
956 self.top_level_fns.get(mangled)
957 }
958
959 pub fn record_iface_dispatch(&mut self, iface: MangledName, dispatch: Dispatch) {
960 self.iface_dispatch.insert(iface, dispatch);
961 }
962
963 pub fn record_static_value_tag(&mut self, iface: MangledName, tag: String) {
964 self.static_value_tags.insert(iface, tag);
965 }
966
967 pub fn static_value_tag(&self, iface: &MangledName) -> Option<&str> {
968 self.static_value_tags.get(iface).map(String::as_str)
969 }
970
971 pub fn iface_dispatch(&self, iface: &MangledName) -> Option<Dispatch> {
972 self.iface_dispatch.get(iface).copied()
973 }
974
975 pub fn record_iface_method_abi(&mut self, method_key: MangledName, abi: MethodSlotAbi) {
976 self.iface_method_abi.insert(method_key, abi);
977 }
978
979 pub fn iface_method_abi(&self, method_key: &MangledName) -> Option<&MethodSlotAbi> {
980 self.iface_method_abi.get(method_key)
981 }
982
983 pub fn record_intrinsic_member(&mut self, mangled: MangledName) {
984 self.intrinsic_members.insert(mangled);
985 }
986
987 pub fn is_intrinsic_member(&self, mangled: &MangledName) -> bool {
988 self.intrinsic_members.contains(mangled)
989 }
990
991 pub fn value_type(&self, ty: &Type) -> Result<ValType, crate::compiler_error::CompilerFailure> {
992 let ty = ty.lowered();
993 Ok(match ty {
994 Type::Number | Type::NumberLiteral(_) => ValType::F64,
995 Type::Boolean | Type::BooleanLiteral(_) => ValType::I32,
996 Type::String | Type::StringLiteral(_) => {
997 let idx = self.string_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::String requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
998 ValType::Ref(RefType {
999 nullable: false,
1000 heap_type: HeapType::Concrete(idx),
1001 })
1002 }
1003 Type::BigInt | Type::BigIntLiteral(_) => {
1004 let idx = self.bigint_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::BigInt requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1005 ValType::Ref(RefType {
1006 nullable: false,
1007 heap_type: HeapType::Concrete(idx),
1008 })
1009 }
1010 Type::Object { .. } => {
1011 let idx = self
1016 .intrinsic_type_indices()
1017 .ok_or_else(|| {
1018 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1019 })?
1020 .object_shape;
1021 ValType::Ref(RefType {
1022 nullable: false,
1023 heap_type: HeapType::Concrete(idx),
1024 })
1025 }
1026 Type::Array(_) => {
1027 let idx = self.array_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::Array requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1028 ValType::Ref(RefType {
1029 nullable: false,
1030 heap_type: HeapType::Concrete(idx),
1031 })
1032 }
1033 Type::Tuple(_) => {
1034 let idx = self.array_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::Tuple requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1037 ValType::Ref(RefType {
1038 nullable: false,
1039 heap_type: HeapType::Concrete(idx),
1040 })
1041 }
1042 Type::Uint8Array => {
1043 let idx = self.uint8_array_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::Uint8Array requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1044 ValType::Ref(RefType {
1045 nullable: false,
1046 heap_type: HeapType::Concrete(idx),
1047 })
1048 }
1049 Type::TypeVar(_)
1050 | Type::GenericParam { .. }
1051 | Type::Unknown
1052 | Type::NonPrimitive
1053 | Type::Void => {
1054 let object_idx = self
1057 .intrinsic_type_indices()
1058 .ok_or_else(|| {
1059 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1060 })?
1061 .object;
1062 ValType::Ref(RefType {
1063 nullable: true,
1064 heap_type: HeapType::Concrete(object_idx),
1065 })
1066 }
1067 Type::Function { .. } => {
1068 let sig = crate::codegen::closures::classify(ty)?;
1069 let idx = self.closure_struct_type_idx(sig).ok_or_else(|| {
1070 crate::codegen::internal_failure(format!(
1071 "closure signature {sig:?} is not registered"
1072 ))
1073 })?;
1074 ValType::Ref(RefType {
1075 nullable: false,
1076 heap_type: HeapType::Concrete(idx),
1077 })
1078 }
1079 Type::Null => {
1080 let object_idx = self
1081 .intrinsic_type_indices()
1082 .ok_or_else(|| {
1083 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1084 })?
1085 .object;
1086 ValType::Ref(RefType {
1087 nullable: true,
1088 heap_type: HeapType::Concrete(object_idx),
1089 })
1090 }
1091 Type::Undefined => {
1092 let intrinsic = self.intrinsic_type_indices().ok_or_else(|| {
1093 crate::codegen::internal_failure("undefined intrinsic is not declared")
1094 })?;
1095 ValType::Ref(RefType {
1096 nullable: false,
1097 heap_type: HeapType::Concrete(intrinsic.undefined),
1098 })
1099 }
1100 Type::Error => {
1101 return Err(crate::codegen::internal_failure(
1103 "error cannot occupy a value slot",
1104 ));
1105 }
1106 Type::Never => {
1107 let object_idx = self
1112 .intrinsic_type_indices()
1113 .ok_or_else(|| {
1114 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1115 })?
1116 .object;
1117 ValType::Ref(RefType {
1118 nullable: true,
1119 heap_type: HeapType::Concrete(object_idx),
1120 })
1121 }
1122 Type::Union(members) => {
1123 let lowered: Vec<ValType> = members
1124 .iter()
1125 .map(|m| self.value_type(m))
1126 .collect::<Result<_, _>>()?;
1127 let first_lowering = *lowered.first().ok_or_else(|| {
1128 crate::codegen::internal_failure("Type::Union holds ≥2 members")
1129 })?;
1130 if lowered.iter().all(|&lowering| lowering == first_lowering) {
1131 return Ok(first_lowering);
1132 }
1133 let all_object_or_null = members
1135 .iter()
1136 .all(|m| matches!(m.lowered(), Type::Object { .. } | Type::Null));
1137 let heap_idx = if all_object_or_null {
1138 self.intrinsic_type_indices()
1139 .ok_or_else(|| {
1140 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1141 })?
1142 .object_shape
1143 } else {
1144 self.intrinsic_type_indices()
1145 .ok_or_else(|| {
1146 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1147 })?
1148 .object
1149 };
1150 let nullable = lowered.iter().copied().any(is_nullable_ref)
1155 || members
1156 .iter()
1157 .any(|member| matches!(member.lowered(), Type::Undefined));
1158 ValType::Ref(RefType {
1159 nullable,
1160 heap_type: HeapType::Concrete(heap_idx),
1161 })
1162 }
1163 Type::ClassRef { mangled, .. } => match self.class_struct_type_idx(mangled) {
1171 Some(idx) => ValType::Ref(RefType {
1172 nullable: false,
1173 heap_type: HeapType::Concrete(idx),
1174 }),
1175 None => ValType::Ref(RefType {
1176 nullable: true,
1177 heap_type: HeapType::Concrete(
1178 self.intrinsic_type_indices()
1179 .ok_or_else(|| {
1180 crate::codegen::internal_failure(
1181 "intrinsics declared by codegen entry",
1182 )
1183 })?
1184 .object,
1185 ),
1186 }),
1187 },
1188 Type::InterfaceRef { .. } => {
1189 let object_idx = self
1190 .intrinsic_type_indices()
1191 .ok_or_else(|| {
1192 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1193 })?
1194 .object;
1195 ValType::Ref(RefType {
1196 nullable: true,
1197 heap_type: HeapType::Concrete(object_idx),
1198 })
1199 }
1200 Type::AliasRef { .. } => {
1201 let object_idx = self
1207 .intrinsic_type_indices()
1208 .ok_or_else(|| {
1209 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1210 })?
1211 .object;
1212 ValType::Ref(RefType {
1213 nullable: true,
1214 heap_type: HeapType::Concrete(object_idx),
1215 })
1216 }
1217 Type::NumberEnum { .. } => {
1218 let idx = self.boxed_number_type_idx().ok_or_else(|| {
1219 crate::codegen::internal_failure(
1220 "Type::NumberEnum requires the intrinsic types to be declared",
1221 )
1222 })?;
1223 ValType::Ref(RefType {
1224 nullable: false,
1225 heap_type: HeapType::Concrete(idx),
1226 })
1227 }
1228 Type::StringEnum { .. } => {
1229 let idx = self.string_type_idx().ok_or_else(|| {
1230 crate::codegen::internal_failure(
1231 "Type::StringEnum requires the intrinsic types to be declared",
1232 )
1233 })?;
1234 ValType::Ref(RefType {
1235 nullable: false,
1236 heap_type: HeapType::Concrete(idx),
1237 })
1238 }
1239 Type::Alias { .. } | Type::Refined { .. } | Type::Readonly(_) => {
1240 return Err(crate::codegen::internal_failure(
1241 "unpeeled alias in value type lowering",
1242 ));
1243 }
1244 })
1245 }
1246
1247 pub fn wasm_result(
1248 &self,
1249 ty: &Type,
1250 ) -> Result<Vec<ValType>, crate::compiler_error::CompilerFailure> {
1251 Ok(vec![self.value_type(ty)?])
1252 }
1253
1254 pub fn slot_value_type(
1268 &self,
1269 ty: &Type,
1270 ) -> Result<ValType, crate::compiler_error::CompilerFailure> {
1271 if is_erased(ty) {
1272 let object = self
1273 .intrinsic_type_indices()
1274 .ok_or_else(|| {
1275 crate::codegen::internal_failure(
1276 "intrinsics declared before class slot signatures",
1277 )
1278 })?
1279 .object;
1280 return Ok(ValType::Ref(RefType {
1281 nullable: true,
1282 heap_type: HeapType::Concrete(object),
1283 }));
1284 }
1285 self.value_type(ty)
1286 }
1287
1288 pub fn slot_wasm_result(
1289 &self,
1290 ty: &Type,
1291 ) -> Result<Vec<ValType>, crate::compiler_error::CompilerFailure> {
1292 Ok(vec![self.slot_value_type(ty)?])
1293 }
1294
1295 pub fn host_value_type(
1296 &self,
1297 ty: &Type,
1298 ) -> Result<ValType, crate::compiler_error::CompilerFailure> {
1299 if matches!(ty, Type::String | Type::StringLiteral(_)) {
1300 let idx = self.raw_string_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::String requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1301 return Ok(ValType::Ref(RefType {
1302 nullable: false,
1303 heap_type: HeapType::Concrete(idx),
1304 }));
1305 }
1306 if matches!(ty, Type::Uint8Array) {
1307 let idx = self.raw_uint8_array_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::Uint8Array requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1308 return Ok(ValType::Ref(RefType {
1309 nullable: false,
1310 heap_type: HeapType::Concrete(idx),
1311 }));
1312 }
1313 self.value_type(ty)
1314 }
1315}
1316
1317fn generic_parameter_names(args: &[Type]) -> Option<Vec<String>> {
1320 if args.is_empty() {
1321 return None;
1322 }
1323 args.iter()
1324 .map(|arg| match arg {
1325 Type::TypeVar(name) => Some(name.clone()),
1326 _ => None,
1327 })
1328 .collect()
1329}
1330
1331#[cfg(test)]
1332mod tests {
1333 use super::*;
1334
1335 #[test]
1336 fn func_idx_round_trip_across_name_shapes() {
1337 let mut map = SymbolTable::default();
1338 map.record_local_fn(
1339 crate::mangle::package_symbol("main", "main"),
1340 10,
1341 Vec::new(),
1342 Type::Void,
1343 )
1344 .unwrap();
1345 let unmangled: MangledName = serde_json::from_str("\"main\"").unwrap();
1346 assert!(
1347 map.record_local_fn(unmangled.clone(), 13, Vec::new(), Type::Void)
1348 .is_err()
1349 );
1350 assert_eq!(map.func_idx(&unmangled), None);
1351 map.record_imported_fn(
1352 crate::mangle::prelude("string_concat"),
1353 11,
1354 vec![Type::String, Type::String],
1355 Type::String,
1356 false,
1357 );
1358 map.record_func(
1359 crate::mangle::extend(&crate::mangle::prelude("Number"), "toString"),
1360 12,
1361 );
1362
1363 assert_eq!(
1364 map.func_idx(&crate::mangle::package_symbol("main", "main")),
1365 Some(10)
1366 );
1367 assert_eq!(map.prelude_func_idx("string_concat"), Some(11));
1368 assert_eq!(
1369 map.func_idx(&crate::mangle::extend(
1370 &crate::mangle::prelude("Number"),
1371 "toString",
1372 )),
1373 Some(12),
1374 );
1375
1376 assert_eq!(
1377 map.func_idx(&crate::mangle::package_symbol("main", "string_concat")),
1378 None,
1379 );
1380 assert_eq!(map.prelude_func_idx("toString"), None);
1381 }
1382}