src/third_party/mozjs/extract/js/src/devtools/rootAnalysis/loadCallgraph.js
// and will still be set to LIMIT_UNVISITED. Scan through and gather them.
and will still be set to LIMIT_UNVISITED. Scan through and gather them.
and will still be set to LIMIT_UNVISITED . Scan through and gather them .
function gather_recursive_roots(functionLimits, callersOf) {
    const roots = [];
     Consider:
       A <--> B --> C <-- D <--> E
                    C --> F
                    C --> G
     So there are two root cycles AB and DE, both calling C that in turn
     calls F and G. If we start at F and scan up through callers, we will
     keep going until A loops back to B and E loops back to D, and will add B
     and D as roots. Then if we scan from G, we encounter C and see that it
     was already been seen on an earlier pass. So C and everything reachable
     from it is already reachable by some root. (We need to label nodes with
     their pass because otherwise we couldn't distinguish "already seen C,
     done" from "already seen B, must be a root".)
    const seen = new Map();
    for (var func in functionLimits) {
        if (functionLimits[func] != LIMIT_UNVISITED)
            continue;
         We should only be looking at nodes with callers, since otherwise
         they would have been handled in the previous pass!
        assert(callersOf[func].length > 0);
        const work = [func];
        while (work.length > 0) {
            const f = work.pop();
            if (seen.has(f)) {
                if (seen.get(f) == func) {
                     We have traversed a cycle and reached an already-seen
                     node. Treat it as a root.
                    roots.push([f, LIMIT_NONE, 'root']);
                    print(`recursive root? ${f} = ${functionNames[f]}`);
                } else {
                     Otherwise we hit the portion of the graph that is
                     reachable from a past root.
                    seen.set(f, func);
                }
            } else {
                print(`retained by recursive root? ${f} = ${functionNames[f]}`);
                work.push(...callersOf[f]);
                seen.set(f, func);
            }
        }
    }
    return roots;
}
function gather_recursive_roots ( functionLimits , callersOf ) { const roots = [ ] ; const seen = new Map ( ) ; for ( var func in functionLimits ) { if ( functionLimits [ func ] != LIMIT_UNVISITED ) continue ; assert ( callersOf [ func ] . length > 0 ) ; const work = [ func ] ; while ( work . length > 0 ) { const f = work . pop ( ) ; if ( seen . has ( f ) ) { if ( seen . get ( f ) == func ) { roots . push ( [ f , LIMIT_NONE , 'root' ] ) ; print ( ` ${ f } ${ functionNames [ f ] } ` ) ; } else { seen . set ( f , func ) ; } } else { print ( ` ${ f } ${ functionNames [ f ] } ` ) ; work . push ( ... callersOf [ f ] ) ; seen . set ( f , func ) ; } } } return roots ; }
and will still be set to LIMIT_UNVISITED.
and will still be set to LIMIT_UNVISITED .
// 'seen' maps functions to the most recent starting function that each was // first reachable from, to distinguish between the current pass and passes // for preceding functions. // // Consider: // //   A <--> B --> C <-- D <--> E //                C --> F //                C --> G // // So there are two root cycles AB and DE, both calling C that in turn // calls F and G. If we start at F and scan up through callers, we will // keep going until A loops back to B and E loops back to D, and will add B // and D as roots. Then if we scan from G, we encounter C and see that it // was already been seen on an earlier pass. So C and everything reachable // from it is already reachable by some root. (We need to label nodes with // their pass because otherwise we couldn't distinguish "already seen C, // done" from "already seen B, must be a root".) // // We should only be looking at nodes with callers, since otherwise // they would have been handled in the previous pass! // We have traversed a cycle and reached an already-seen // node. Treat it as a root. // Otherwise we hit the portion of the graph that is // reachable from a past root.