lookup_sig.mx raw
1 package iskra
2
3 import "bytes"
4
5 // FindBySignature scans all meta entries at the given stage using the
6 // 24-bit signature hash for fast rejection, then verifying with full
7 // IsIsomorphic on the content. Returns recIdxs of matching entries.
8 func FindBySignature(t *Tree, sig *BindingSignature, stage uint8) []uint32 {
9 targetHash := SignatureHash24(sig)
10 var matches []uint32
11
12 for recIdx := range t.RecMeta {
13 meta := &t.RecMeta[recIdx]
14 if meta.StageTag != stage {
15 continue
16 }
17 if meta.SigHash() != targetHash {
18 continue
19 }
20 content := t.GetContent(uint32(recIdx))
21 if len(content) == 0 {
22 continue
23 }
24 cst := ExtractSymbols(string(content))
25 candidateSig := SignatureWithTypes(cst)
26 if sig.IsIsomorphic(candidateSig) {
27 matches = append(matches, uint32(recIdx))
28 }
29 }
30 return matches
31 }
32
33 // FindBySignatureFromAST extracts symbols from an AST dump and finds
34 // matching entries in the lattice. Convenience wrapper.
35 func FindBySignatureFromAST(t *Tree, astDump string) []uint32 {
36 st := ExtractSymbols(astDump)
37 sig := SignatureWithTypes(st)
38 return FindBySignature(t, sig, StageAST)
39 }
40
41 // FindBySignatureInPkg is like FindBySignature but only considers entries
42 // whose IR representation (at the same name hash, StageIR) contains pkgPrefix.
43 // Cross-stage adjacency is now key-implicit: same hash, different stage prefix.
44 func FindBySignatureInPkg(t *Tree, sig *BindingSignature, stage uint8, pkgPrefix string) []uint32 {
45 targetHash := SignatureHash24(sig)
46 prefix := []byte(pkgPrefix)
47 var matches []uint32
48
49 for recIdx := range t.RecMeta {
50 meta := &t.RecMeta[recIdx]
51 if meta.StageTag != stage {
52 continue
53 }
54 if meta.SigHash() != targetHash {
55 continue
56 }
57 if len(pkgPrefix) > 0 {
58 // Look up IR version of this entry: same name hash, StageIR, same branch.
59 key, ok := t.db.RecKey[uint32(recIdx)]
60 if !ok {
61 continue
62 }
63 branch := KindToBranch(meta.Kind)
64 irKey := MakeCodeKey(StageIR, KeyHash(key))
65 irRecIdx := t.db.LookupRecIdx(branch, irKey)
66 if irRecIdx == NullLatticeRec {
67 continue
68 }
69 ir := t.GetContent(irRecIdx)
70 if !bytes.Contains(ir, prefix) {
71 continue
72 }
73 }
74 content := t.GetContent(uint32(recIdx))
75 if len(content) == 0 {
76 continue
77 }
78 cst := ExtractSymbols(string(content))
79 candidateSig := SignatureWithTypes(cst)
80 if sig.IsIsomorphic(candidateSig) {
81 matches = append(matches, uint32(recIdx))
82 }
83 }
84 return matches
85 }
86
87 func FindBySignatureFromASTInPkg(t *Tree, astDump string, pkgPrefix string) []uint32 {
88 st := ExtractSymbols(astDump)
89 sig := SignatureWithTypes(st)
90 return FindBySignatureInPkg(t, sig, StageAST, pkgPrefix)
91 }
92
93 // RankMatches reorders matches: self first, then name match, then lowest cost.
94 func RankMatches(t *Tree, matches []uint32, selfIdx uint32, queryName string) {
95 if len(matches) < 2 {
96 return
97 }
98 qMethod := unqualifiedName(queryName)
99
100 for j, mi := range matches {
101 if mi == selfIdx && j != 0 {
102 matches[0], matches[j] = matches[j], matches[0]
103 return
104 }
105 }
106 if matches[0] == selfIdx {
107 return
108 }
109
110 for j := 0; j < len(matches); j++ {
111 rec := t.db.GetRecord(matches[j])
112 if rec == nil {
113 continue
114 }
115 mName := FormFromRecord(rec, t.StringPool)
116 if unqualifiedName(mName) == qMethod {
117 if j != 0 {
118 matches[0], matches[j] = matches[j], matches[0]
119 }
120 return
121 }
122 }
123
124 RankByCost(t, matches)
125 }
126
127 // RankByCost sorts matches by ascending CostMap cost.
128 func RankByCost(t *Tree, matches []uint32) {
129 if len(t.CostMap) == 0 || len(matches) < 2 {
130 return
131 }
132 for i := 1; i < len(matches); i++ {
133 key := matches[i]
134 kCost, kHas := t.CostMap[key]
135 j := i - 1
136 for j >= 0 {
137 jCost, jHas := t.CostMap[matches[j]]
138 if !costLess(kCost, kHas, jCost, jHas) {
139 break
140 }
141 matches[j+1] = matches[j]
142 j--
143 }
144 matches[j+1] = key
145 }
146 }
147
148 func costLess(a CostEntry, aHas bool, b CostEntry, bHas bool) bool {
149 if aHas && !bHas {
150 return true
151 }
152 if !aHas {
153 return false
154 }
155 return a.NsOp100 < b.NsOp100
156 }
157
158 func unqualifiedName(name string) string {
159 for i := len(name) - 1; i >= 0; i-- {
160 if name[i] == '.' {
161 return name[i+1:]
162 }
163 }
164 return name
165 }
166