@@ -608,10 +608,23 @@ export interface CallNodeInfoInverted extends CallNodeInfo {
608608 nodeHandle : IndexIntoCallNodeTable
609609 ) : [ SuffixOrderIndex , SuffixOrderIndex ] ;
610610
611- // The number of functions. There is one root in the inverted tree per func,
612- // and the inverted root's call node handle equals the func index.
611+ // The number of functions in the func table this CNI was built from.
612+ // (Sizes per-func scratch buffers in callers; not directly tied to the
613+ // number of inverted-tree roots — see getRootCount.)
613614 getFuncCount ( ) : number ;
614615
616+ // The number of roots in the inverted tree. Root call node handles are
617+ // 0..getRootCount()-1. For the full inverted tree this equals funcCount
618+ // (one root per func); for a lower-wing CNI it is 1.
619+ getRootCount ( ) : number ;
620+
621+ // Returns the inverted root call node handle for `funcIndex`, or -1 if no
622+ // root in this CNI corresponds to that function (e.g. a lower-wing CNI only
623+ // has a root for its selected func).
624+ getRootNodeForFunc (
625+ funcIndex : IndexIntoFuncTable
626+ ) : IndexIntoCallNodeTable | - 1 ;
627+
615628 // True if the given node is a root of the inverted tree.
616629 isRoot ( nodeHandle : IndexIntoCallNodeTable ) : boolean ;
617630
@@ -1059,13 +1072,23 @@ export class LazyInvertedCallNodeInfo implements CallNodeInfoInverted {
10591072 return this . _suffixOrderIndexes ;
10601073 }
10611074
1062- // Get the number of functions. There is one root per function.
1063- // So this is also the number of roots at the same time .
1064- // The inverted call node index for a root is the same as the function index.
1075+ // Get the number of functions. There is one root per function in this
1076+ // (full inverted) CNI, so it also equals getRootCount() .
1077+ // For roots, the inverted call node handle equals the function index.
10651078 getFuncCount ( ) : number {
10661079 return this . _rootCount ;
10671080 }
10681081
1082+ getRootCount ( ) : number {
1083+ return this . _rootCount ;
1084+ }
1085+
1086+ // For the full inverted tree, each func has its own root and the root
1087+ // handle equals the func index.
1088+ getRootNodeForFunc ( funcIndex : IndexIntoFuncTable ) : InvertedCallNodeHandle {
1089+ return funcIndex ;
1090+ }
1091+
10691092 // Returns whether the given node is a root node.
10701093 isRoot ( nodeHandle : InvertedCallNodeHandle ) : boolean {
10711094 return nodeHandle < this . _rootCount ;
@@ -1757,9 +1780,9 @@ export class LazyInvertedCallNodeInfo implements CallNodeInfoInverted {
17571780}
17581781
17591782// The lower wing's inverted call node table. Index 0 is the selected-func
1760- // root; indices 1..length-1 are non-root nodes. The public handle scheme
1761- // (rootHandle === funcIndex, non-root handles start at funcCount) is preserved
1762- // by the accessors, which translate handle ↔ table index .
1783+ // root; indices 1..length-1 are non-root nodes. The public InvertedCallNodeHandle
1784+ // IS the table index (no translation): handle 0 is the root, handles
1785+ // 1..length-1 are non-roots .
17631786//
17641787// Layout note: rows are appended in BFS-by-inverted-depth order, with each
17651788// parent's children emitted contiguously, sorted by func index. Index 0 is the
@@ -1801,19 +1824,23 @@ export type LowerWingTable = {
18011824 * only renders the rows currently in the viewport, so building deeper than
18021825 * necessary is wasted work.
18031826 *
1804- * Conventions kept from LazyInvertedCallNodeInfo so consumers (especially
1805- * CallTreeInternalInverted and computeCallTreeTimingsInverted) work unchanged:
1806- * - There are funcCount logical roots, with rootHandle === funcIndex.
1807- * Only the root at selectedFuncIndex has non-empty data.
1808- * - Non-root handles start at funcCount.
1827+ * Handle scheme:
1828+ * - There is exactly one root, with handle === 0. Its func is `selectedFuncIndex`
1829+ * (or 0 when no selection — the row is then a placeholder with no children).
1830+ * - Non-root handles are 1..length-1 and equal their table index. Handles
1831+ * other than 0 only exist after the BFS has expanded to materialize them.
1832+ * - `getRootNodeForFunc(f)` returns 0 iff f === selectedFuncIndex, else -1.
18091833 * - `getSuffixOrderedCallNodes()` and `getSuffixOrderIndexes()` are kept in
18101834 * sync as the BFS refines partitions.
18111835 */
18121836export class LowerWingCallNodeInfo implements CallNodeInfoInverted {
18131837 _callNodeTable : CallNodeTable ;
18141838 _stackIndexToNonInvertedCallNodeIndex : Int32Array ;
18151839 _defaultCategory : IndexIntoCategoryList ;
1816- _rootCount : number ;
1840+ // Number of functions in the originating func table. Used to size per-func
1841+ // scratch buffers in `_extendToDepth`; unrelated to the number of roots
1842+ // (which is always 1 — see getRootCount).
1843+ _funcCount : number ;
18171844 _selectedFuncIndex : IndexIntoFuncTable | null ;
18181845
18191846 // Suffix-ordered entry points: maps suffix order index -> non-inverted call
@@ -1884,7 +1911,7 @@ export class LowerWingCallNodeInfo implements CallNodeInfoInverted {
18841911 this . _stackIndexToNonInvertedCallNodeIndex =
18851912 stackIndexToNonInvertedCallNodeIndex ;
18861913 this . _defaultCategory = defaultCategory ;
1887- this . _rootCount = funcCount ;
1914+ this . _funcCount = funcCount ;
18881915 this . _selectedFuncIndex = selectedFuncIndex ;
18891916
18901917 // Pass 1: collect root-most non-inverted nodes whose func is the selected
@@ -2007,38 +2034,35 @@ export class LowerWingCallNodeInfo implements CallNodeInfoInverted {
20072034 }
20082035
20092036 getFuncCount ( ) : number {
2010- return this . _rootCount ;
2037+ return this . _funcCount ;
2038+ }
2039+
2040+ getRootCount ( ) : number {
2041+ return 1 ;
2042+ }
2043+
2044+ // Only the selected func has a root in this CNI. Other funcs return -1.
2045+ getRootNodeForFunc (
2046+ funcIndex : IndexIntoFuncTable
2047+ ) : InvertedCallNodeHandle | - 1 {
2048+ return funcIndex === this . _selectedFuncIndex ? 0 : - 1 ;
20112049 }
20122050
20132051 isRoot ( nodeHandle : InvertedCallNodeHandle ) : boolean {
2014- return nodeHandle < this . _rootCount ;
2052+ return nodeHandle === 0 ;
20152053 }
20162054
20172055 getSuffixOrderIndexRangeForCallNode (
20182056 nodeHandle : InvertedCallNodeHandle
20192057 ) : [ SuffixOrderIndex , SuffixOrderIndex ] {
2020- if ( nodeHandle < this . _rootCount ) {
2021- if ( nodeHandle === this . _selectedFuncIndex ) {
2022- return [ this . _tSoStart [ 0 ] , this . _tSoEnd [ 0 ] ] ;
2023- }
2024- return [ 0 , 0 ] ;
2025- }
2026- const idx = nodeHandle - this . _rootCount + 1 ;
2027- return [ this . _tSoStart [ idx ] , this . _tSoEnd [ idx ] ] ;
2058+ return [ this . _tSoStart [ nodeHandle ] , this . _tSoEnd [ nodeHandle ] ] ;
20282059 }
20292060
20302061 getChildren ( nodeIndex : InvertedCallNodeHandle ) : InvertedCallNodeHandle [ ] {
2031- if ( nodeIndex < this . _rootCount ) {
2032- if ( nodeIndex !== this . _selectedFuncIndex ) {
2033- return EMPTY_LOWER_WING_CHILDREN ;
2034- }
2035- // Root: depth 0 — process it (if needed) so children are populated.
2036- this . _extendToDepth ( 0 ) ;
2037- return this . _tChildren [ 0 ] ;
2038- }
2039- const idx = nodeIndex - this . _rootCount + 1 ;
2040- this . _extendToDepth ( this . _tDepth [ idx ] ) ;
2041- return this . _tChildren [ idx ] ;
2062+ // Extend the BFS far enough for this node to have its children
2063+ // materialized (depth 0 for the root, depth d for a node at depth d).
2064+ this . _extendToDepth ( this . _tDepth [ nodeIndex ] ) ;
2065+ return this . _tChildren [ nodeIndex ] ;
20422066 }
20432067
20442068 getCallNodePathFromIndex (
@@ -2049,12 +2073,11 @@ export class LowerWingCallNodeInfo implements CallNodeInfoInverted {
20492073 }
20502074 const callNodePath : number [ ] = [ ] ;
20512075 let current = callNodeHandle ;
2052- while ( current >= this . _rootCount ) {
2053- const idx = current - this . _rootCount + 1 ;
2054- callNodePath . push ( this . _tFunc [ idx ] ) ;
2055- current = this . _tPrefix [ idx ] ;
2076+ while ( current !== 0 ) {
2077+ callNodePath . push ( this . _tFunc [ current ] ) ;
2078+ current = this . _tPrefix [ current ] ;
20562079 }
2057- callNodePath . push ( current ) ; // root: handle === func
2080+ callNodePath . push ( this . _tFunc [ 0 ] ) ;
20582081 callNodePath . reverse ( ) ;
20592082 return callNodePath ;
20602083 }
@@ -2065,14 +2088,12 @@ export class LowerWingCallNodeInfo implements CallNodeInfoInverted {
20652088 if ( callNodePath . length === 0 ) {
20662089 return null ;
20672090 }
2068- // Reject paths that don't start at the selected func — only that root has
2069- // any descendants .
2091+ // The only root in this CNI is for the selected func. Any path that doesn't
2092+ // start there has no match .
20702093 if ( callNodePath [ 0 ] !== this . _selectedFuncIndex ) {
2071- // The first func is also a valid root handle (handle === func), but only
2072- // the selected func's path can be reached beyond depth 0.
2073- return callNodePath . length === 1 ? callNodePath [ 0 ] : null ;
2094+ return null ;
20742095 }
2075- let handle : InvertedCallNodeHandle = callNodePath [ 0 ] ;
2096+ let handle : InvertedCallNodeHandle = 0 ;
20762097 for ( let i = 1 ; i < callNodePath . length ; i ++ ) {
20772098 const next = this . getCallNodeIndexFromParentAndFunc (
20782099 handle ,
@@ -2091,7 +2112,7 @@ export class LowerWingCallNodeInfo implements CallNodeInfoInverted {
20912112 func : IndexIntoFuncTable
20922113 ) : InvertedCallNodeHandle | null {
20932114 if ( parent === - 1 ) {
2094- return func ; // For roots, handle === func.
2115+ return this . getRootNodeForFunc ( func ) === - 1 ? null : 0 ;
20952116 }
20962117 const children = this . getChildren ( parent ) ;
20972118 // Children are sorted by func; bisect to find a match.
@@ -2108,68 +2129,39 @@ export class LowerWingCallNodeInfo implements CallNodeInfoInverted {
21082129 prefixForNode (
21092130 callNodeHandle : InvertedCallNodeHandle
21102131 ) : InvertedCallNodeHandle | - 1 {
2111- if ( callNodeHandle < this . _rootCount ) {
2112- return - 1 ;
2113- }
2114- return this . _tPrefix [ callNodeHandle - this . _rootCount + 1 ] ;
2132+ return this . _tPrefix [ callNodeHandle ] ;
21152133 }
21162134
21172135 funcForNode ( callNodeHandle : InvertedCallNodeHandle ) : IndexIntoFuncTable {
2118- if ( callNodeHandle < this . _rootCount ) {
2119- return callNodeHandle ; // root handle === func index
2120- }
2121- return this . _tFunc [ callNodeHandle - this . _rootCount + 1 ] ;
2136+ return this . _tFunc [ callNodeHandle ] ;
21222137 }
21232138
21242139 categoryForNode (
21252140 callNodeHandle : InvertedCallNodeHandle
21262141 ) : IndexIntoCategoryList {
2127- if ( callNodeHandle < this . _rootCount ) {
2128- return callNodeHandle === this . _selectedFuncIndex
2129- ? this . _tCategory [ 0 ]
2130- : this . _defaultCategory ;
2131- }
2132- return this . _tCategory [ callNodeHandle - this . _rootCount + 1 ] ;
2142+ return this . _tCategory [ callNodeHandle ] ;
21332143 }
21342144
21352145 subcategoryForNode (
21362146 callNodeHandle : InvertedCallNodeHandle
21372147 ) : IndexIntoSubcategoryListForCategory {
2138- if ( callNodeHandle < this . _rootCount ) {
2139- return callNodeHandle === this . _selectedFuncIndex
2140- ? this . _tSubcategory [ 0 ]
2141- : 0 ;
2142- }
2143- return this . _tSubcategory [ callNodeHandle - this . _rootCount + 1 ] ;
2148+ return this . _tSubcategory [ callNodeHandle ] ;
21442149 }
21452150
21462151 innerWindowIDForNode (
21472152 callNodeHandle : InvertedCallNodeHandle
21482153 ) : IndexIntoCategoryList {
2149- if ( callNodeHandle < this . _rootCount ) {
2150- return callNodeHandle === this . _selectedFuncIndex
2151- ? this . _tInnerWindowID [ 0 ]
2152- : 0 ;
2153- }
2154- return this . _tInnerWindowID [ callNodeHandle - this . _rootCount + 1 ] ;
2154+ return this . _tInnerWindowID [ callNodeHandle ] ;
21552155 }
21562156
21572157 depthForNode ( callNodeHandle : InvertedCallNodeHandle ) : number {
2158- if ( callNodeHandle < this . _rootCount ) {
2159- return 0 ;
2160- }
2161- return this . _tDepth [ callNodeHandle - this . _rootCount + 1 ] ;
2158+ return this . _tDepth [ callNodeHandle ] ;
21622159 }
21632160
21642161 sourceFramesInlinedIntoSymbolForNode (
21652162 callNodeHandle : InvertedCallNodeHandle
21662163 ) : IndexIntoNativeSymbolTable | - 1 | - 2 {
2167- if ( callNodeHandle < this . _rootCount ) {
2168- return callNodeHandle === this . _selectedFuncIndex
2169- ? ( this . _tInlinedInto [ 0 ] as IndexIntoNativeSymbolTable | - 1 | - 2 )
2170- : - 2 ;
2171- }
2172- return this . _tInlinedInto [ callNodeHandle - this . _rootCount + 1 ] as
2164+ return this . _tInlinedInto [ callNodeHandle ] as
21732165 | IndexIntoNativeSymbolTable
21742166 | - 1
21752167 | - 2 ;
@@ -2242,7 +2234,6 @@ export class LowerWingCallNodeInfo implements CallNodeInfoInverted {
22422234 const scratchSelf = this . _scratchSelf ;
22432235 const scratchDeep = this . _scratchDeep ;
22442236 const defaultCategory = this . _defaultCategory ;
2245- const funcCount = this . _rootCount ;
22462237
22472238 // Scratch list of distinct funcs seen in Pass 1 of the current node.
22482239 // Cleared at the top of each iteration.
@@ -2257,7 +2248,8 @@ export class LowerWingCallNodeInfo implements CallNodeInfoInverted {
22572248 const parentSuffixStart = tSoStart [ k ] ;
22582249 const parentSuffixEnd = tSoEnd [ k ] ;
22592250 const parentDepth = tDepth [ k ] ;
2260- const parentHandle = k === 0 ? tFunc [ 0 ] : funcCount + k - 1 ;
2251+ // Public handle === table index.
2252+ const parentHandle = k ;
22612253
22622254 // Pass 1: walk each entry's deepNode one step up, bucket-counting by
22632255 // the new deepNode's func. Entries whose chain bottoms out are tallied
@@ -2359,7 +2351,9 @@ export class LowerWingCallNodeInfo implements CallNodeInfoInverted {
23592351 }
23602352 }
23612353
2362- const newHandle = funcCount + tPrefix . length - 1 ;
2354+ // Public handle === table index, which is the slot the child row is
2355+ // about to be pushed into.
2356+ const newHandle = tPrefix . length ;
23632357 tPrefix . push ( parentHandle ) ;
23642358 tFunc . push ( f ) ;
23652359 tCategory . push ( category ) ;
0 commit comments