Search in sources :

Example 1 with LocalBitSetPacker

use of soot.util.LocalBitSetPacker in project soot by Sable.

the class LocalSplitter method internalTransform.

@Override
protected void internalTransform(Body body, String phaseName, Map<String, String> options) {
    if (Options.v().verbose())
        logger.debug("[" + body.getMethod().getName() + "] Splitting locals...");
    if (Options.v().time())
        Timers.v().splitTimer.start();
    if (Options.v().time())
        Timers.v().splitPhase1Timer.start();
    if (throwAnalysis == null)
        throwAnalysis = Scene.v().getDefaultThrowAnalysis();
    if (omitExceptingUnitEdges == false)
        omitExceptingUnitEdges = Options.v().omit_excepting_unit_edges();
    // Pack the locals for efficiency
    final LocalBitSetPacker localPacker = new LocalBitSetPacker(body);
    localPacker.pack();
    // Go through the definitions, building the webs
    ExceptionalUnitGraph graph = new ExceptionalUnitGraph(body, throwAnalysis, omitExceptingUnitEdges);
    // run in panic mode on first split (maybe change this depending on the input
    // source)
    final LocalDefs defs = LocalDefs.Factory.newLocalDefs(graph, true);
    final LocalUses uses = LocalUses.Factory.newLocalUses(graph, defs);
    if (Options.v().time())
        Timers.v().splitPhase1Timer.end();
    if (Options.v().time())
        Timers.v().splitPhase2Timer.start();
    Set<Unit> visited = new HashSet<Unit>();
    // Collect the set of locals that we need to split^
    BitSet localsToSplit = new BitSet(localPacker.getLocalCount());
    {
        BitSet localsVisited = new BitSet(localPacker.getLocalCount());
        for (Unit s : body.getUnits()) {
            if (s.getDefBoxes().isEmpty())
                continue;
            if (!(s.getDefBoxes().get(0).getValue() instanceof Local))
                continue;
            // If we see a local the second time, we know that we must split it
            Local l = (Local) s.getDefBoxes().get(0).getValue();
            if (localsVisited.get(l.getNumber()))
                localsToSplit.set(l.getNumber());
            localsVisited.set(l.getNumber());
        }
    }
    int w = 0;
    for (Unit s : body.getUnits()) {
        if (s.getDefBoxes().isEmpty())
            continue;
        if (s.getDefBoxes().size() > 1)
            throw new RuntimeException("stmt with more than 1 defbox!");
        if (!(s.getDefBoxes().get(0).getValue() instanceof Local))
            continue;
        // we don't want to visit a node twice
        if (visited.remove(s))
            continue;
        // always reassign locals to avoid "use before definition" bugs!
        // unfortunately this creates a lot of new locals, so it's important
        // to remove them afterwards
        Local oldLocal = (Local) s.getDefBoxes().get(0).getValue();
        if (!localsToSplit.get(oldLocal.getNumber()))
            continue;
        Local newLocal = (Local) oldLocal.clone();
        // renaming should not be done here
        newLocal.setName(newLocal.getName() + '#' + ++w);
        body.getLocals().add(newLocal);
        Deque<Unit> queue = new ArrayDeque<Unit>();
        queue.addFirst(s);
        do {
            final Unit head = queue.removeFirst();
            if (visited.add(head)) {
                for (UnitValueBoxPair use : uses.getUsesOf(head)) {
                    ValueBox vb = use.valueBox;
                    Value v = vb.getValue();
                    if (v == newLocal)
                        continue;
                    // should always be true - but who knows ...
                    if (v instanceof Local) {
                        Local l = (Local) v;
                        queue.addAll(defs.getDefsOfAt(l, use.unit));
                        vb.setValue(newLocal);
                    }
                }
                for (ValueBox vb : head.getDefBoxes()) {
                    Value v = vb.getValue();
                    if (v instanceof Local) {
                        vb.setValue(newLocal);
                    }
                }
            }
        } while (!queue.isEmpty());
        // keep the set small
        visited.remove(s);
    }
    // Restore the original local numbering
    localPacker.unpack();
    if (Options.v().time())
        Timers.v().splitPhase2Timer.end();
    if (Options.v().time())
        Timers.v().splitTimer.end();
}
Also used : BitSet(java.util.BitSet) Local(soot.Local) Unit(soot.Unit) ArrayDeque(java.util.ArrayDeque) ExceptionalUnitGraph(soot.toolkits.graph.ExceptionalUnitGraph) ValueBox(soot.ValueBox) Value(soot.Value) LocalBitSetPacker(soot.util.LocalBitSetPacker) HashSet(java.util.HashSet)

Aggregations

ArrayDeque (java.util.ArrayDeque)1 BitSet (java.util.BitSet)1 HashSet (java.util.HashSet)1 Local (soot.Local)1 Unit (soot.Unit)1 Value (soot.Value)1 ValueBox (soot.ValueBox)1 ExceptionalUnitGraph (soot.toolkits.graph.ExceptionalUnitGraph)1 LocalBitSetPacker (soot.util.LocalBitSetPacker)1