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.peel() {
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.peel() {
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.peel()
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.peel();
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(_) | Type::GenericParam { .. } | Type::Unknown | Type::Void => {
1050 let object_idx = self
1053 .intrinsic_type_indices()
1054 .ok_or_else(|| {
1055 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1056 })?
1057 .object;
1058 ValType::Ref(RefType {
1059 nullable: true,
1060 heap_type: HeapType::Concrete(object_idx),
1061 })
1062 }
1063 Type::Function { .. } => {
1064 let sig = crate::codegen::closures::classify(ty)?;
1065 let idx = self.closure_struct_type_idx(sig).ok_or_else(|| {
1066 crate::codegen::internal_failure(format!(
1067 "closure signature {sig:?} is not registered"
1068 ))
1069 })?;
1070 ValType::Ref(RefType {
1071 nullable: false,
1072 heap_type: HeapType::Concrete(idx),
1073 })
1074 }
1075 Type::Null => {
1076 let object_idx = self
1077 .intrinsic_type_indices()
1078 .ok_or_else(|| {
1079 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1080 })?
1081 .object;
1082 ValType::Ref(RefType {
1083 nullable: true,
1084 heap_type: HeapType::Concrete(object_idx),
1085 })
1086 }
1087 Type::Undefined => {
1088 let intrinsic = self.intrinsic_type_indices().ok_or_else(|| {
1089 crate::codegen::internal_failure("undefined intrinsic is not declared")
1090 })?;
1091 ValType::Ref(RefType {
1092 nullable: false,
1093 heap_type: HeapType::Concrete(intrinsic.undefined),
1094 })
1095 }
1096 Type::Error => {
1097 return Err(crate::codegen::internal_failure(
1099 "error cannot occupy a value slot",
1100 ));
1101 }
1102 Type::Never => {
1103 let object_idx = self
1108 .intrinsic_type_indices()
1109 .ok_or_else(|| {
1110 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1111 })?
1112 .object;
1113 ValType::Ref(RefType {
1114 nullable: true,
1115 heap_type: HeapType::Concrete(object_idx),
1116 })
1117 }
1118 Type::Union(members) => {
1119 let lowered: Vec<ValType> = members
1120 .iter()
1121 .map(|m| self.value_type(m))
1122 .collect::<Result<_, _>>()?;
1123 let first_lowering = *lowered.first().ok_or_else(|| {
1124 crate::codegen::internal_failure("Type::Union holds ≥2 members")
1125 })?;
1126 if lowered.iter().all(|&lowering| lowering == first_lowering) {
1127 return Ok(first_lowering);
1128 }
1129 let all_object_or_null = members
1131 .iter()
1132 .all(|m| matches!(m.peel(), Type::Object { .. } | Type::Null));
1133 let heap_idx = if all_object_or_null {
1134 self.intrinsic_type_indices()
1135 .ok_or_else(|| {
1136 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1137 })?
1138 .object_shape
1139 } else {
1140 self.intrinsic_type_indices()
1141 .ok_or_else(|| {
1142 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1143 })?
1144 .object
1145 };
1146 let nullable = lowered.iter().copied().any(is_nullable_ref)
1151 || members
1152 .iter()
1153 .any(|member| matches!(member.peel(), Type::Undefined));
1154 ValType::Ref(RefType {
1155 nullable,
1156 heap_type: HeapType::Concrete(heap_idx),
1157 })
1158 }
1159 Type::ClassRef { mangled, .. } => match self.class_struct_type_idx(mangled) {
1167 Some(idx) => ValType::Ref(RefType {
1168 nullable: false,
1169 heap_type: HeapType::Concrete(idx),
1170 }),
1171 None => ValType::Ref(RefType {
1172 nullable: true,
1173 heap_type: HeapType::Concrete(
1174 self.intrinsic_type_indices()
1175 .ok_or_else(|| {
1176 crate::codegen::internal_failure(
1177 "intrinsics declared by codegen entry",
1178 )
1179 })?
1180 .object,
1181 ),
1182 }),
1183 },
1184 Type::InterfaceRef { .. } => {
1185 let object_idx = self
1186 .intrinsic_type_indices()
1187 .ok_or_else(|| {
1188 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1189 })?
1190 .object;
1191 ValType::Ref(RefType {
1192 nullable: true,
1193 heap_type: HeapType::Concrete(object_idx),
1194 })
1195 }
1196 Type::AliasRef { .. } => {
1197 let object_idx = self
1203 .intrinsic_type_indices()
1204 .ok_or_else(|| {
1205 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1206 })?
1207 .object;
1208 ValType::Ref(RefType {
1209 nullable: true,
1210 heap_type: HeapType::Concrete(object_idx),
1211 })
1212 }
1213 Type::NumberEnum { .. } => {
1214 let idx = self.boxed_number_type_idx().ok_or_else(|| {
1215 crate::codegen::internal_failure(
1216 "Type::NumberEnum requires the intrinsic types to be declared",
1217 )
1218 })?;
1219 ValType::Ref(RefType {
1220 nullable: false,
1221 heap_type: HeapType::Concrete(idx),
1222 })
1223 }
1224 Type::StringEnum { .. } => {
1225 let idx = self.string_type_idx().ok_or_else(|| {
1226 crate::codegen::internal_failure(
1227 "Type::StringEnum requires the intrinsic types to be declared",
1228 )
1229 })?;
1230 ValType::Ref(RefType {
1231 nullable: false,
1232 heap_type: HeapType::Concrete(idx),
1233 })
1234 }
1235 Type::Alias { .. } | Type::Refined { .. } | Type::Readonly(_) => {
1236 return Err(crate::codegen::internal_failure(
1237 "unpeeled alias in value type lowering",
1238 ));
1239 }
1240 })
1241 }
1242
1243 pub fn wasm_result(
1244 &self,
1245 ty: &Type,
1246 ) -> Result<Vec<ValType>, crate::compiler_error::CompilerFailure> {
1247 Ok(vec![self.value_type(ty)?])
1248 }
1249
1250 pub fn slot_value_type(
1264 &self,
1265 ty: &Type,
1266 ) -> Result<ValType, crate::compiler_error::CompilerFailure> {
1267 if is_erased(ty) {
1268 let object = self
1269 .intrinsic_type_indices()
1270 .ok_or_else(|| {
1271 crate::codegen::internal_failure(
1272 "intrinsics declared before class slot signatures",
1273 )
1274 })?
1275 .object;
1276 return Ok(ValType::Ref(RefType {
1277 nullable: true,
1278 heap_type: HeapType::Concrete(object),
1279 }));
1280 }
1281 self.value_type(ty)
1282 }
1283
1284 pub fn slot_wasm_result(
1285 &self,
1286 ty: &Type,
1287 ) -> Result<Vec<ValType>, crate::compiler_error::CompilerFailure> {
1288 Ok(vec![self.slot_value_type(ty)?])
1289 }
1290
1291 pub fn host_value_type(
1292 &self,
1293 ty: &Type,
1294 ) -> Result<ValType, crate::compiler_error::CompilerFailure> {
1295 if matches!(ty, Type::String | Type::StringLiteral(_)) {
1296 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)"))?;
1297 return Ok(ValType::Ref(RefType {
1298 nullable: false,
1299 heap_type: HeapType::Concrete(idx),
1300 }));
1301 }
1302 if matches!(ty, Type::Uint8Array) {
1303 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)"))?;
1304 return Ok(ValType::Ref(RefType {
1305 nullable: false,
1306 heap_type: HeapType::Concrete(idx),
1307 }));
1308 }
1309 self.value_type(ty)
1310 }
1311}
1312
1313fn generic_parameter_names(args: &[Type]) -> Option<Vec<String>> {
1316 if args.is_empty() {
1317 return None;
1318 }
1319 args.iter()
1320 .map(|arg| match arg {
1321 Type::TypeVar(name) => Some(name.clone()),
1322 _ => None,
1323 })
1324 .collect()
1325}
1326
1327#[cfg(test)]
1328mod tests {
1329 use super::*;
1330
1331 #[test]
1332 fn func_idx_round_trip_across_name_shapes() {
1333 let mut map = SymbolTable::default();
1334 map.record_local_fn(
1335 crate::mangle::package_symbol("main", "main"),
1336 10,
1337 Vec::new(),
1338 Type::Void,
1339 )
1340 .unwrap();
1341 let unmangled: MangledName = serde_json::from_str("\"main\"").unwrap();
1342 assert!(
1343 map.record_local_fn(unmangled.clone(), 13, Vec::new(), Type::Void)
1344 .is_err()
1345 );
1346 assert_eq!(map.func_idx(&unmangled), None);
1347 map.record_imported_fn(
1348 crate::mangle::prelude("string_concat"),
1349 11,
1350 vec![Type::String, Type::String],
1351 Type::String,
1352 false,
1353 );
1354 map.record_func(
1355 crate::mangle::extend(&crate::mangle::prelude("Number"), "toString"),
1356 12,
1357 );
1358
1359 assert_eq!(
1360 map.func_idx(&crate::mangle::package_symbol("main", "main")),
1361 Some(10)
1362 );
1363 assert_eq!(map.prelude_func_idx("string_concat"), Some(11));
1364 assert_eq!(
1365 map.func_idx(&crate::mangle::extend(
1366 &crate::mangle::prelude("Number"),
1367 "toString",
1368 )),
1369 Some(12),
1370 );
1371
1372 assert_eq!(
1373 map.func_idx(&crate::mangle::package_symbol("main", "string_concat")),
1374 None,
1375 );
1376 assert_eq!(map.prelude_func_idx("toString"), None);
1377 }
1378}