1use crate::prelude::*;
5use crate::{FilePos, FuncIndex, FuncKey, FuncKeyIndex, FuncKeyKind, FuncKeyNamespace, Module};
6use core::ops::Range;
7use core::{fmt, u32};
8use core::{iter, str};
9use cranelift_entity::{EntityRef, PrimaryMap};
10use serde_derive::{Deserialize, Serialize};
11
12#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
15pub struct FunctionLoc {
16 pub start: u32,
19 pub length: u32,
21}
22
23impl FunctionLoc {
24 #[inline]
26 pub fn is_empty(&self) -> bool {
27 self.length == 0
28 }
29}
30
31pub struct CompiledFunctionsTableBuilder {
33 inner: CompiledFunctionsTable,
34}
35
36impl CompiledFunctionsTableBuilder {
37 pub fn new() -> Self {
39 Self {
40 inner: CompiledFunctionsTable {
41 namespaces: PrimaryMap::new(),
42 func_loc_starts: PrimaryMap::new(),
43 sparse_starts: PrimaryMap::new(),
44 src_loc_starts: PrimaryMap::new(),
45 sparse_indices: PrimaryMap::new(),
46 func_locs: PrimaryMap::new(),
47 src_locs: PrimaryMap::new(),
48 },
49 }
50 }
51
52 fn last_namespace(&self) -> Option<FuncKeyNamespace> {
53 let (_, &ns) = self.inner.namespaces.last()?;
54 Some(ns)
55 }
56
57 fn last_key_index(&self) -> Option<FuncKeyIndex> {
58 let (ns_idx, ns) = self.inner.namespaces.last()?;
59 let start = self.inner.func_loc_starts[ns_idx];
60 if CompiledFunctionsTable::is_dense(ns.kind()) {
61 let len = self.inner.func_locs.len();
62 let len = u32::try_from(len).unwrap();
63 let key_index = len - start.as_u32();
64 let key_index = FuncKeyIndex::from_raw(key_index);
65 Some(key_index)
66 } else {
67 let sparse_start = self.inner.sparse_starts[ns_idx];
68 if self.inner.sparse_indices.len() > sparse_start.index() {
69 let (_, &key_index) = self.inner.sparse_indices.last().unwrap();
70 Some(key_index)
71 } else {
72 None
73 }
74 }
75 }
76
77 fn last_func_loc(&self) -> Option<FunctionLoc> {
78 let (_, &loc) = self.inner.func_locs.last()?;
79 Some(loc)
80 }
81
82 pub fn push_func(
86 &mut self,
87 key: FuncKey,
88 func_loc: FunctionLoc,
89 src_loc: FilePos,
90 ) -> &mut Self {
91 let (key_ns, key_index) = key.into_parts();
92
93 assert!(
94 self.last_namespace().is_none_or(|ns| ns <= key_ns),
95 "`FuncKey`s pushed out of order"
96 );
97 assert!(
98 self.last_key_index().is_none_or(
99 |i| i <= key_index || self.last_namespace().is_some_and(|ns| ns != key_ns)
100 ),
101 "`FuncKey`s pushed out of order"
102 );
103 assert!(
104 self.last_func_loc()
105 .is_none_or(|l| l.start + l.length <= func_loc.start),
106 "`FunctionLoc`s pushed out of order"
107 );
108
109 let kind_start_index = self
111 .inner
112 .namespaces
113 .last()
114 .and_then(|(ns_idx, ns)| {
115 if *ns == key_ns {
116 Some(self.inner.func_loc_starts[ns_idx])
117 } else {
118 None
119 }
120 })
121 .unwrap_or_else(|| {
122 let start = self.inner.func_locs.next_key();
123 let ns_idx = self.inner.namespaces.push(key_ns);
124 let ns_idx2 = self.inner.func_loc_starts.push(start);
125 let ns_idx3 = self
126 .inner
127 .sparse_starts
128 .push(self.inner.sparse_indices.next_key());
129 let ns_idx4 = self
130 .inner
131 .src_loc_starts
132 .push(self.inner.src_locs.next_key());
133 debug_assert_eq!(ns_idx, ns_idx2);
134 debug_assert_eq!(ns_idx, ns_idx3);
135 debug_assert_eq!(ns_idx, ns_idx4);
136 start
137 });
138
139 if CompiledFunctionsTable::is_dense(key.kind()) {
140 let index = kind_start_index.as_u32() + key_index.into_raw();
142 let index = FuncLocIndex::from_u32(index);
143 debug_assert!(self.inner.func_locs.get(index).is_none());
144
145 let null_func_loc = FunctionLoc {
153 start: self
154 .last_func_loc()
155 .map(|l| l.start + l.length)
156 .unwrap_or_default(),
157 length: 0,
158 };
159 let gap = index.index() - self.inner.func_locs.len();
160 self.inner
161 .func_locs
162 .extend(iter::repeat(null_func_loc).take(gap));
163 debug_assert_eq!(index, self.inner.func_locs.next_key());
164
165 if CompiledFunctionsTable::has_src_locs(key_ns.kind()) {
166 self.inner
167 .src_locs
168 .extend(iter::repeat(FilePos::none()).take(gap));
169 }
170 } else {
171 debug_assert!(
172 src_loc.is_none(),
173 "sparse keys do not have source locations"
174 );
175 self.inner.sparse_indices.push(key_index);
176 }
177
178 self.inner.func_locs.push(func_loc);
180 if CompiledFunctionsTable::has_src_locs(key_ns.kind()) {
181 self.inner.src_locs.push(src_loc);
182 } else {
183 debug_assert!(src_loc.is_none());
184 }
185
186 self
187 }
188
189 pub fn finish(self) -> CompiledFunctionsTable {
191 self.inner
192 }
193}
194
195#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
196struct NamespaceIndex(u32);
197cranelift_entity::entity_impl!(NamespaceIndex);
198
199#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
200struct FuncLocIndex(u32);
201cranelift_entity::entity_impl!(FuncLocIndex);
202
203#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
204struct SparseIndex(u32);
205cranelift_entity::entity_impl!(SparseIndex);
206
207#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
208struct SrcLocIndex(u32);
209cranelift_entity::entity_impl!(SrcLocIndex);
210
211#[derive(Debug, Serialize, Deserialize)]
243pub struct CompiledFunctionsTable {
244 namespaces: PrimaryMap<NamespaceIndex, FuncKeyNamespace>,
249
250 func_loc_starts: PrimaryMap<NamespaceIndex, FuncLocIndex>,
257
258 sparse_starts: PrimaryMap<NamespaceIndex, SparseIndex>,
267
268 src_loc_starts: PrimaryMap<NamespaceIndex, SrcLocIndex>,
278
279 sparse_indices: PrimaryMap<SparseIndex, FuncKeyIndex>,
287
288 func_locs: PrimaryMap<FuncLocIndex, FunctionLoc>,
298
299 src_locs: PrimaryMap<SrcLocIndex, FilePos>,
305}
306
307impl CompiledFunctionsTable {
308 #[inline]
309 fn namespace_index(&self, namespace: FuncKeyNamespace) -> Option<NamespaceIndex> {
310 const LINEAR_SEARCH_LIMIT: usize = 32;
311 if self.namespaces.len() <= LINEAR_SEARCH_LIMIT {
312 self.namespaces
313 .iter()
314 .find_map(|(idx, ns)| if *ns == namespace { Some(idx) } else { None })
315 } else {
316 self.namespaces
317 .binary_search_values_by_key(&namespace, |ns| *ns)
318 .ok()
319 }
320 }
321
322 #[inline]
323 fn func_loc_range(&self, ns_idx: NamespaceIndex) -> Range<FuncLocIndex> {
324 let start = self.func_loc_starts[ns_idx];
325 let next_ns_idx = NamespaceIndex::from_u32(ns_idx.as_u32() + 1);
326 let end = self
327 .func_loc_starts
328 .get(next_ns_idx)
329 .copied()
330 .unwrap_or_else(|| self.func_locs.next_key());
331 start..end
332 }
333
334 fn sparse_range(&self, ns_idx: NamespaceIndex) -> Range<SparseIndex> {
335 debug_assert!(!Self::is_dense(self.namespaces[ns_idx].kind()));
336 let start = self.sparse_starts[ns_idx];
337 let next_ns_idx = NamespaceIndex::from_u32(ns_idx.as_u32() + 1);
338 let end = self
339 .sparse_starts
340 .get(next_ns_idx)
341 .copied()
342 .unwrap_or_else(|| self.sparse_indices.next_key());
343 start..end
344 }
345
346 fn src_loc_range(&self, ns_idx: NamespaceIndex) -> Range<SrcLocIndex> {
347 debug_assert!(Self::has_src_locs(self.namespaces[ns_idx].kind()));
348 let start = self.src_loc_starts[ns_idx];
349 let next_ns_idx = NamespaceIndex::from_u32(ns_idx.as_u32() + 1);
350 let end = self
351 .src_loc_starts
352 .get(next_ns_idx)
353 .copied()
354 .unwrap_or_else(|| self.src_locs.next_key());
355 start..end
356 }
357
358 #[inline]
361 fn func_loc_index(&self, key: FuncKey) -> Option<FuncLocIndex> {
362 let (key_ns, key_index) = key.into_parts();
363 let ns_idx = self.namespace_index(key_ns)?;
364 let Range { start, end } = self.func_loc_range(ns_idx);
365
366 let index = if Self::is_dense(key.kind()) {
367 let index = start.as_u32().checked_add(key_index.into_raw())?;
368 FuncLocIndex::from_u32(index)
369 } else {
370 let sparse_range = self.sparse_range(ns_idx);
371 let sparse_subslice = self.sparse_indices.get_range(sparse_range).unwrap();
372 match sparse_subslice.binary_search(&key_index) {
373 Ok(i) => FuncLocIndex::new(start.index() + i),
374 Err(_) => return None,
375 }
376 };
377
378 if index < end { Some(index) } else { None }
379 }
380
381 #[inline]
384 pub fn func_loc(&self, key: FuncKey) -> Option<&FunctionLoc> {
385 let index = self.func_loc_index(key)?;
386 let loc = &self.func_locs[index];
387 if loc.is_empty() { None } else { Some(loc) }
388 }
389
390 fn src_loc_index(&self, key: FuncKey) -> Option<SrcLocIndex> {
391 let (key_ns, key_index) = key.into_parts();
392 if !Self::has_src_locs(key_ns.kind()) {
393 return None;
394 }
395
396 let ns_idx = self.namespace_index(key_ns)?;
397 let Range { start, end } = self.src_loc_range(ns_idx);
398
399 debug_assert!(Self::is_dense(key_ns.kind()));
400 let index = start.as_u32().checked_add(key_index.into_raw())?;
401 let index = SrcLocIndex::from_u32(index);
402 if index >= end {
403 return None;
404 }
405
406 Some(index)
407 }
408
409 pub fn src_loc(&self, key: FuncKey) -> Option<FilePos> {
412 let index = self.src_loc_index(key)?;
413 let loc = self.src_locs[index];
414 if loc.is_none() { None } else { Some(loc) }
415 }
416
417 pub fn func_by_text_offset(&self, text_offset: u32) -> Option<FuncKey> {
420 let index = match self.func_locs.as_values_slice().binary_search_by(|loc| {
421 if loc.is_empty() {
422 loc.start
423 .cmp(&text_offset)
424 .then_with(|| core::cmp::Ordering::Less)
425 } else {
426 if loc.start > text_offset {
427 core::cmp::Ordering::Greater
428 } else if loc.start + loc.length <= text_offset {
429 core::cmp::Ordering::Less
430 } else {
431 debug_assert!(loc.start <= text_offset);
432 debug_assert!(text_offset < loc.start + loc.length);
433 core::cmp::Ordering::Equal
434 }
435 }
436 }) {
437 Ok(k) => k,
439 Err(k) => k,
444 };
445 let index = FuncLocIndex::new(index);
446
447 let loc = self.func_locs.get(index)?;
453 let start = loc.start;
454 let end = start + loc.length;
455 if text_offset < start || end < text_offset {
456 return None;
457 }
458
459 let ns_idx = match self
460 .func_loc_starts
461 .binary_search_values_by_key(&index, |s| *s)
462 {
463 Ok(i) => i,
465 Err(i) => {
469 let i = i.as_u32();
470 assert_ne!(i, 0);
471 NamespaceIndex::from_u32(i - 1)
472 }
473 };
474 let key_ns = self.namespaces[ns_idx];
475 let start = self.func_loc_starts[ns_idx];
476
477 let key_index = if Self::is_dense(key_ns.kind()) {
478 let key_index = index.as_u32() - start.as_u32();
479 FuncKeyIndex::from_raw(key_index)
480 } else {
481 let sparse_index = index.as_u32() - start.as_u32();
482 let sparse_index = SparseIndex::from_u32(sparse_index);
483 self.sparse_indices[sparse_index]
484 };
485 let key = FuncKey::from_parts(key_ns, key_index);
486
487 Some(key)
488 }
489
490 fn is_dense(kind: FuncKeyKind) -> bool {
495 match kind {
496 FuncKeyKind::DefinedWasmFunction
497 | FuncKeyKind::WasmToArrayTrampoline
498 | FuncKeyKind::PulleyHostCall => true,
499
500 FuncKeyKind::ArrayToWasmTrampoline | FuncKeyKind::WasmToBuiltinTrampoline => false,
501
502 #[cfg(feature = "component-model")]
503 FuncKeyKind::ComponentTrampoline | FuncKeyKind::ResourceDropTrampoline => true,
504 }
505 }
506
507 fn has_src_locs(kind: FuncKeyKind) -> bool {
509 match kind {
510 FuncKeyKind::DefinedWasmFunction => true,
511 FuncKeyKind::ArrayToWasmTrampoline
512 | FuncKeyKind::WasmToArrayTrampoline
513 | FuncKeyKind::WasmToBuiltinTrampoline
514 | FuncKeyKind::PulleyHostCall => false,
515 #[cfg(feature = "component-model")]
516 FuncKeyKind::ComponentTrampoline | FuncKeyKind::ResourceDropTrampoline => false,
517 }
518 }
519}
520
521#[derive(Serialize, Deserialize)]
526pub struct CompiledModuleInfo {
527 pub module: Module,
529
530 pub meta: Metadata,
532
533 pub func_names: Vec<FunctionName>,
535}
536
537#[derive(Serialize, Deserialize)]
540pub struct FunctionName {
541 pub idx: FuncIndex,
543 pub offset: u32,
546 pub len: u32,
548}
549
550#[derive(Serialize, Deserialize)]
552pub struct Metadata {
553 pub has_unparsed_debuginfo: bool,
556
557 pub code_section_offset: u64,
559
560 pub has_wasm_debuginfo: bool,
566
567 pub dwarf: Vec<(u8, Range<u64>)>,
570}
571
572#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
574pub enum FlagValue<'a> {
575 Enum(&'a str),
577 Num(u8),
579 Bool(bool),
581}
582
583impl fmt::Display for FlagValue<'_> {
584 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
585 match self {
586 Self::Enum(v) => v.fmt(f),
587 Self::Num(v) => v.fmt(f),
588 Self::Bool(v) => v.fmt(f),
589 }
590 }
591}
592
593pub enum ObjectKind {
595 Module,
597 Component,
599}
600
601#[cfg(test)]
602mod tests {
603 use super::*;
604 use crate::{DefinedFuncIndex, StaticModuleIndex};
605
606 fn func_loc(range: Range<u32>) -> FunctionLoc {
607 FunctionLoc {
608 start: range.start,
609 length: range.end - range.start,
610 }
611 }
612
613 fn def_func_key(m: u32, f: u32) -> FuncKey {
614 FuncKey::DefinedWasmFunction(
615 StaticModuleIndex::from_u32(m),
616 DefinedFuncIndex::from_u32(f),
617 )
618 }
619
620 fn array_to_wasm_tramp_key(m: u32, f: u32) -> FuncKey {
621 FuncKey::ArrayToWasmTrampoline(
622 StaticModuleIndex::from_u32(m),
623 DefinedFuncIndex::from_u32(f),
624 )
625 }
626
627 fn make_test_table() -> CompiledFunctionsTable {
628 let mut builder = CompiledFunctionsTableBuilder::new();
629
630 builder
631 .push_func(def_func_key(0, 0), func_loc(0..10), FilePos::new(111))
633 .push_func(def_func_key(0, 1), func_loc(10..20), FilePos::new(222))
634 .push_func(def_func_key(0, 2), func_loc(20..30), FilePos::none())
635 .push_func(def_func_key(0, 5), func_loc(30..40), FilePos::new(333))
637 .push_func(
639 array_to_wasm_tramp_key(0, 1),
640 func_loc(100..110),
641 FilePos::none(),
642 )
643 .push_func(
644 array_to_wasm_tramp_key(0, 2),
645 func_loc(110..120),
646 FilePos::none(),
647 )
648 .push_func(
649 array_to_wasm_tramp_key(0, 5),
650 func_loc(120..130),
651 FilePos::none(),
652 );
653
654 builder.finish()
655 }
656
657 #[test]
658 fn src_locs() {
659 let table = make_test_table();
660
661 for (key, expected) in [
662 (def_func_key(0, 0), Some(FilePos::new(111))),
663 (def_func_key(0, 1), Some(FilePos::new(222))),
664 (def_func_key(0, 2), None),
665 (def_func_key(0, 3), None),
666 (def_func_key(0, 4), None),
667 (def_func_key(0, 5), Some(FilePos::new(333))),
668 (array_to_wasm_tramp_key(0, 0), None),
669 (array_to_wasm_tramp_key(0, 1), None),
670 (array_to_wasm_tramp_key(0, 2), None),
671 (array_to_wasm_tramp_key(0, 3), None),
672 (array_to_wasm_tramp_key(0, 4), None),
673 (array_to_wasm_tramp_key(0, 5), None),
674 ] {
675 eprintln!("Checking key {key:?}");
676 let actual = table.src_loc(key);
677 assert_eq!(expected, actual);
678 }
679 }
680
681 #[test]
682 fn func_locs() {
683 let table = make_test_table();
684
685 for (key, expected) in [
686 (def_func_key(0, 0), Some(0)),
687 (def_func_key(0, 1), Some(10)),
688 (def_func_key(0, 2), Some(20)),
689 (def_func_key(0, 3), None),
690 (def_func_key(0, 4), None),
691 (def_func_key(0, 5), Some(30)),
692 (array_to_wasm_tramp_key(0, 0), None),
693 (array_to_wasm_tramp_key(0, 1), Some(100)),
694 (array_to_wasm_tramp_key(0, 2), Some(110)),
695 (array_to_wasm_tramp_key(0, 3), None),
696 (array_to_wasm_tramp_key(0, 4), None),
697 (array_to_wasm_tramp_key(0, 5), Some(120)),
698 ] {
699 let actual = table.func_loc(key);
700 match (expected, actual) {
701 (None, None) => {}
702 (Some(expected), Some(actual)) => assert_eq!(expected, actual.start),
703 (None, Some(actual)) => {
704 panic!("expected no function location for {key:?}, got {actual:?}")
705 }
706 (Some(_), None) => {
707 panic!("expected a function location for {key:?}, but got nothing")
708 }
709 }
710 }
711 }
712
713 #[test]
714 fn reverse_func_locs() {
715 let table = make_test_table();
716
717 for (range, expected) in [
718 (0..10, Some(def_func_key(0, 0))),
719 (10..20, Some(def_func_key(0, 1))),
720 (20..30, Some(def_func_key(0, 2))),
721 (30..40, Some(def_func_key(0, 5))),
722 (40..100, None),
723 (100..110, Some(array_to_wasm_tramp_key(0, 1))),
724 (110..120, Some(array_to_wasm_tramp_key(0, 2))),
725 (120..130, Some(array_to_wasm_tramp_key(0, 5))),
726 (140..150, None),
727 ] {
728 for i in range {
729 eprintln!("Checking offset {i}");
730 let actual = table.func_by_text_offset(i);
731 assert_eq!(expected, actual);
732 }
733 }
734 }
735}