Search in sources :

Example 1 with ArraySet

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

the class OutFlow method jimplify.

/**
 * Main.v() entry point for converting list of Instructions to Jimple statements;
 * performs flow analysis, constructs Jimple statements, and fixes jumps.
 * @param constant_pool constant pool of ClassFile.
 * @param this_class constant pool index of the CONSTANT_Class_info object for
 * this' class.
 * @param clearStacks if <i>true</i> semantic stacks will be deleted after
 * the process is complete.
 * @return <i>true</i> if all ok, <i>false</i> if there was an error.
 * @see CFG#jimplify(cp_info[], int)
 * @see Stmt
 */
void jimplify(cp_info[] constant_pool, int this_class) {
    Code_attribute codeAttribute = method.locate_code_attribute();
    Set<Instruction> handlerInstructions = new ArraySet<Instruction>();
    Map<Instruction, SootClass> handlerInstructionToException = new HashMap<Instruction, SootClass>();
    Map<Instruction, TypeStack> instructionToTypeStack;
    Map<Instruction, TypeStack> instructionToPostTypeStack;
    {
        // build graph in
        buildInsnCFGfromBBCFG();
        // Put in successors due to exception handlers
        {
            for (int i = 0; i < codeAttribute.exception_table_length; i++) {
                Instruction startIns = codeAttribute.exception_table[i].start_inst;
                Instruction endIns = codeAttribute.exception_table[i].end_inst;
                Instruction handlerIns = codeAttribute.exception_table[i].handler_inst;
                handlerInstructions.add(handlerIns);
                // Determine exception to catch
                {
                    int catchType = codeAttribute.exception_table[i].catch_type;
                    SootClass exception;
                    if (catchType != 0) {
                        CONSTANT_Class_info classinfo = (CONSTANT_Class_info) constant_pool[catchType];
                        String name = ((CONSTANT_Utf8_info) (constant_pool[classinfo.name_index])).convert();
                        name = name.replace('/', '.');
                        exception = cm.getSootClass(name);
                    } else
                        exception = cm.getSootClass("java.lang.Throwable");
                    handlerInstructionToException.put(handlerIns, exception);
                }
                if (startIns == endIns)
                    throw new RuntimeException("Empty catch range for exception handler");
                Instruction ins = startIns;
                for (; ; ) {
                    Instruction[] succs = ins.succs;
                    Instruction[] newsuccs = new Instruction[succs.length + 1];
                    System.arraycopy(succs, 0, newsuccs, 0, succs.length);
                    newsuccs[succs.length] = handlerIns;
                    ins.succs = newsuccs;
                    ins = ins.next;
                    if (ins == endIns || ins == null)
                        break;
                }
            }
        }
    }
    Set<Instruction> reachableInstructions = new HashSet<Instruction>();
    // Mark all the reachable instructions
    {
        LinkedList<Instruction> instructionsToVisit = new LinkedList<Instruction>();
        reachableInstructions.add(firstInstruction);
        instructionsToVisit.addLast(firstInstruction);
        while (!instructionsToVisit.isEmpty()) {
            Instruction ins = instructionsToVisit.removeFirst();
            Instruction[] succs = ins.succs;
            for (Instruction succ : succs) {
                if (!reachableInstructions.contains(succ)) {
                    reachableInstructions.add(succ);
                    instructionsToVisit.addLast(succ);
                }
            }
        }
    }
    /*
        // Check to see if any instruction is unmarked.
        {
            BasicBlock b = cfg;

             while(b != null)
            {
                Instruction ins = b.head;

                 while(ins != null)
                {
                    if(!reachableInstructions.contains(ins))
                        throw new RuntimeException("Method to jimplify contains unreachable code!  (not handled for now)");

                     ins = ins.next;
                }

                 b = b.next;
            }
        }
        */
    // Perform the flow analysis, and build up instructionToTypeStack and instructionToLocalArray
    {
        instructionToTypeStack = new HashMap<Instruction, TypeStack>();
        instructionToPostTypeStack = new HashMap<Instruction, TypeStack>();
        Set<Instruction> visitedInstructions = new HashSet<Instruction>();
        List<Instruction> changedInstructions = new ArrayList<Instruction>();
        TypeStack initialTypeStack;
        // Build up initial type stack and initial local array (for the first instruction)
        {
            initialTypeStack = TypeStack.v();
        // the empty stack with nothing on it.
        }
        // Get the loop cranked up.
        {
            instructionToTypeStack.put(firstInstruction, initialTypeStack);
            visitedInstructions.add(firstInstruction);
            changedInstructions.add(firstInstruction);
        }
        {
            while (!changedInstructions.isEmpty()) {
                Instruction ins = changedInstructions.get(0);
                changedInstructions.remove(0);
                OutFlow ret = processFlow(ins, instructionToTypeStack.get(ins), constant_pool);
                instructionToPostTypeStack.put(ins, ret.typeStack);
                Instruction[] successors = ins.succs;
                for (Instruction s : successors) {
                    if (!visitedInstructions.contains(s)) {
                        if (handlerInstructions.contains(s)) {
                            TypeStack exceptionTypeStack = (TypeStack.v()).push(RefType.v(handlerInstructionToException.get(s).getName()));
                            instructionToTypeStack.put(s, exceptionTypeStack);
                        } else {
                            instructionToTypeStack.put(s, ret.typeStack);
                        }
                        visitedInstructions.add(s);
                        changedInstructions.add(s);
                    // logger.debug("adding successor: " + s);
                    } else {
                        // logger.debug("considering successor: " + s);
                        TypeStack newTypeStack, oldTypeStack = instructionToTypeStack.get(s);
                        if (handlerInstructions.contains(s)) {
                            // The type stack for an instruction handler should always be that of
                            // single object on the stack.
                            TypeStack exceptionTypeStack = (TypeStack.v()).push(RefType.v(handlerInstructionToException.get(s).getName()));
                            newTypeStack = exceptionTypeStack;
                        } else {
                            try {
                                newTypeStack = ret.typeStack.merge(oldTypeStack);
                            } catch (RuntimeException re) {
                                logger.debug("Considering " + s);
                                throw re;
                            }
                        }
                        if (!newTypeStack.equals(oldTypeStack)) {
                            changedInstructions.add(s);
                        // logger.debug("requires a revisit: " + s);
                        }
                        instructionToTypeStack.put(s, newTypeStack);
                    }
                }
            }
        }
    }
    // logger.debug("Producing Jimple code...");
    // Jimplify each statement
    {
        BasicBlock b = cfg;
        while (b != null) {
            Instruction ins = b.head;
            b.statements = new ArrayList<Stmt>();
            List<Stmt> blockStatements = b.statements;
            for (; ; ) {
                List<Stmt> statementsForIns = new ArrayList<Stmt>();
                if (reachableInstructions.contains(ins))
                    generateJimple(ins, instructionToTypeStack.get(ins), instructionToPostTypeStack.get(ins), constant_pool, statementsForIns, b);
                else
                    statementsForIns.add(Jimple.v().newNopStmt());
                if (!statementsForIns.isEmpty()) {
                    for (int i = 0; i < statementsForIns.size(); i++) {
                        units.add(statementsForIns.get(i));
                        blockStatements.add(statementsForIns.get(i));
                    }
                    instructionToFirstStmt.put(ins, statementsForIns.get(0));
                    instructionToLastStmt.put(ins, statementsForIns.get(statementsForIns.size() - 1));
                }
                if (ins == b.tail)
                    break;
                ins = ins.next;
            }
            b = b.next;
        }
    }
    // fix up jump targets
    jimpleTargetFixup();
    /*
        // Print out basic blocks
        {
            BasicBlock b = cfg;

            logger.debug("Basic blocks for: " + jmethod.getName());

            while(b != null)
            {
                Instruction ins = b.head;

                

                while(ins != null)
                {
                    logger.debug(""+ins.toString());
                    ins = ins.next;
                }

                b = b.next;
            }
        }
        */
    // Insert beginCatch/endCatch statements for exception handling
    {
        Map<Stmt, Stmt> targetToHandler = new HashMap<Stmt, Stmt>();
        for (int i = 0; i < codeAttribute.exception_table_length; i++) {
            Instruction startIns = codeAttribute.exception_table[i].start_inst;
            Instruction endIns = codeAttribute.exception_table[i].end_inst;
            Instruction targetIns = codeAttribute.exception_table[i].handler_inst;
            if (!instructionToFirstStmt.containsKey(startIns) || (endIns != null && (!instructionToLastStmt.containsKey(endIns)))) {
                throw new RuntimeException("Exception range does not coincide with jimple instructions");
            }
            if (!instructionToFirstStmt.containsKey(targetIns)) {
                throw new RuntimeException("Exception handler does not coincide with jimple instruction");
            }
            SootClass exception;
            // Determine exception to catch
            {
                int catchType = codeAttribute.exception_table[i].catch_type;
                if (catchType != 0) {
                    CONSTANT_Class_info classinfo = (CONSTANT_Class_info) constant_pool[catchType];
                    String name = ((CONSTANT_Utf8_info) (constant_pool[classinfo.name_index])).convert();
                    name = name.replace('/', '.');
                    exception = cm.getSootClass(name);
                } else
                    exception = cm.getSootClass("java.lang.Throwable");
            }
            Stmt newTarget;
            // Insert assignment of exception
            {
                Stmt firstTargetStmt = instructionToFirstStmt.get(targetIns);
                if (targetToHandler.containsKey(firstTargetStmt))
                    newTarget = targetToHandler.get(firstTargetStmt);
                else {
                    Local local = Util.v().getLocalCreatingIfNecessary(listBody, "$stack0", UnknownType.v());
                    newTarget = Jimple.v().newIdentityStmt(local, Jimple.v().newCaughtExceptionRef());
                    // changed to account for catch blocks which are also part of normal control flow
                    // units.insertBefore(newTarget, firstTargetStmt);
                    ((PatchingChain<Unit>) units).insertBeforeNoRedirect(newTarget, firstTargetStmt);
                    targetToHandler.put(firstTargetStmt, newTarget);
                    if (units.getFirst() != newTarget) {
                        Unit prev = (Unit) units.getPredOf(newTarget);
                        if (prev != null && prev.fallsThrough())
                            units.insertAfter(Jimple.v().newGotoStmt(firstTargetStmt), prev);
                    }
                }
            }
            // Insert trap
            {
                Stmt firstStmt = instructionToFirstStmt.get(startIns);
                Stmt afterEndStmt;
                if (endIns == null) {
                    // A kludge which isn't really correct, but
                    // gets us closer to correctness (until we
                    // clean up the rest of Soot to properly
                    // represent Traps which extend to the end
                    // of a method): if the protected code extends
                    // to the end of the method, use the last Stmt
                    // as the endUnit of the Trap, even though
                    // that will leave the last unit outside
                    // the protected area.
                    afterEndStmt = (Stmt) units.getLast();
                } else {
                    afterEndStmt = instructionToLastStmt.get(endIns);
                    IdentityStmt catchStart = (IdentityStmt) targetToHandler.get(afterEndStmt);
                    // (Cast to IdentityStmt as an assertion check.)
                    if (catchStart != null) {
                        // before the old afterEndStmt.
                        if (catchStart != units.getPredOf(afterEndStmt)) {
                            throw new IllegalStateException("Assertion failure: catchStart != pred of afterEndStmt");
                        }
                        afterEndStmt = catchStart;
                    }
                }
                Trap trap = Jimple.v().newTrap(exception, firstStmt, afterEndStmt, newTarget);
                listBody.getTraps().add(trap);
            }
        }
    }
    /* convert line number table to tags attached to statements */
    if (Options.v().keep_line_number()) {
        HashMap<Stmt, Tag> stmtstags = new HashMap<Stmt, Tag>();
        LinkedList<Stmt> startstmts = new LinkedList<Stmt>();
        attribute_info[] attrs = codeAttribute.attributes;
        for (attribute_info element : attrs) {
            if (element instanceof LineNumberTable_attribute) {
                LineNumberTable_attribute lntattr = (LineNumberTable_attribute) element;
                for (line_number_table_entry element0 : lntattr.line_number_table) {
                    Stmt start_stmt = instructionToFirstStmt.get(element0.start_inst);
                    if (start_stmt != null) {
                        LineNumberTag lntag = new LineNumberTag(element0.line_number);
                        stmtstags.put(start_stmt, lntag);
                        startstmts.add(start_stmt);
                    }
                }
            }
        }
        /* if the predecessor of a statement is a caughtexcetionref,
             * give it the tag of its successor */
        for (Iterator<Stmt> stmtIt = new ArrayList<Stmt>(stmtstags.keySet()).iterator(); stmtIt.hasNext(); ) {
            final Stmt stmt = stmtIt.next();
            Stmt pred = stmt;
            Tag tag = stmtstags.get(stmt);
            while (true) {
                pred = (Stmt) units.getPredOf(pred);
                if (pred == null)
                    break;
                if (!(pred instanceof IdentityStmt))
                    break;
                stmtstags.put(pred, tag);
                pred.addTag(tag);
            }
        }
        /* attach line number tag to each statement. */
        for (int i = 0; i < startstmts.size(); i++) {
            Stmt stmt = startstmts.get(i);
            Tag tag = stmtstags.get(stmt);
            stmt.addTag(tag);
            stmt = (Stmt) units.getSuccOf(stmt);
            while (stmt != null && !stmtstags.containsKey(stmt)) {
                stmt.addTag(tag);
                stmt = (Stmt) units.getSuccOf(stmt);
            }
        }
    }
}
Also used : ArraySet(soot.util.ArraySet) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Unit(soot.Unit) GotoStmt(soot.jimple.GotoStmt) IfStmt(soot.jimple.IfStmt) IdentityStmt(soot.jimple.IdentityStmt) TableSwitchStmt(soot.jimple.TableSwitchStmt) LookupSwitchStmt(soot.jimple.LookupSwitchStmt) Stmt(soot.jimple.Stmt) LineNumberTag(soot.tagkit.LineNumberTag) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) IdentityStmt(soot.jimple.IdentityStmt) HashSet(java.util.HashSet) ArraySet(soot.util.ArraySet) PatchingChain(soot.PatchingChain) Local(soot.Local) Trap(soot.Trap) SootClass(soot.SootClass) LinkedList(java.util.LinkedList) Tag(soot.tagkit.Tag) LineNumberTag(soot.tagkit.LineNumberTag) BytecodeOffsetTag(soot.tagkit.BytecodeOffsetTag) Map(java.util.Map) HashMap(java.util.HashMap)

Example 2 with ArraySet

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

the class ExceptionalUnitGraph method buildExceptionalEdges.

/**
 * Method to compute the edges corresponding to exceptional control flow.
 *
 * @param throwAnalysis
 *            the source of information about the exceptions which each
 *            {@link Unit} may throw.
 *
 * @param unitToExceptionDests
 *            A <code>Map</code> from {@link Unit}s to {@link Collection}s
 *            of {@link ExceptionalUnitGraph.ExceptionDest ExceptionDest}s
 *            which represent the handlers that might catch exceptions
 *            thrown by the <code>Unit</code>. This is an ``in parameter''.
 *
 * @param unitToSuccs
 *            A <code>Map</code> from <code>Unit</code>s to {@link List}s of
 *            <code>Unit</code>s. This is an ``out parameter'';
 *            <code>buildExceptionalEdges</code> will add a mapping from
 *            every <code>Unit</code> in the body that may throw an
 *            exception that could be caught by a {@link Trap} in the body
 *            to a list of its exceptional successors.
 *
 * @param unitToPreds
 *            A <code>Map</code> from <code>Unit</code>s to
 *            <code>List</code>s of <code>Unit</code>s. This is an ``out
 *            parameter''; <code>buildExceptionalEdges</code> will add a
 *            mapping from each handler unit that may catch an exception to
 *            the list of <code>Unit</code>s whose exceptions it may catch.
 * @param omitExceptingUnitEdges
 *            Indicates whether to omit exceptional edges from excepting
 *            units which lack side effects
 *
 * @return a {@link Set} of trap <code>Unit</code>s that might catch
 *         exceptions thrown by the first <code>Unit</code> in the
 *         {@link Body} associated with the graph being constructed. Such
 *         trap <code>Unit</code>s may need to be added to the list of heads
 *         (depending on your definition of heads), since they can be the
 *         first <code>Unit</code> in the <code>Body</code> which actually
 *         completes execution.
 */
protected Set<Unit> buildExceptionalEdges(ThrowAnalysis throwAnalysis, Map<Unit, Collection<ExceptionDest>> unitToExceptionDests, Map<Unit, List<Unit>> unitToSuccs, Map<Unit, List<Unit>> unitToPreds, boolean omitExceptingUnitEdges) {
    Set<Unit> trapsThatAreHeads = new ArraySet<Unit>();
    Unit entryPoint = unitChain.getFirst();
    for (Entry<Unit, Collection<ExceptionDest>> entry : unitToExceptionDests.entrySet()) {
        Unit thrower = entry.getKey();
        List<Unit> throwersPreds = getUnexceptionalPredsOf(thrower);
        Collection<ExceptionDest> dests = entry.getValue();
        // We need to recognize:
        // - caught exceptions for which we must add edges from the
        // thrower's predecessors to the catcher:
        // - all exceptions of non-throw instructions;
        // - implicit exceptions of throw instructions.
        // 
        // - caught exceptions where we must add edges from the
        // thrower itself to the catcher:
        // - any exception of non-throw instructions if
        // omitExceptingUnitEdges is not set.
        // - any exception of non-throw instructions with side effects.
        // - explicit exceptions of throw instructions
        // - implicit exceptions of throw instructions if
        // omitExceptingUnitEdges is not set.
        // - implicit exceptions of throw instructions with possible
        // side effects (this is only possible for the grimp
        // IR, where the throw's argument may be an
        // expression---probably a NewInvokeExpr---which
        // might have executed partially before the
        // exception arose).
        // 
        // Note that a throw instruction may be capable of throwing a given
        // Throwable type both implicitly and explicitly.
        // 
        // We track these situations using predThrowables and
        // selfThrowables. Essentially predThrowables is the set
        // of Throwable types to whose catchers there should be
        // edges from predecessors of the thrower, while
        // selfThrowables is the set of Throwable types to whose
        // catchers there should be edges from the thrower itself,
        // but we we take some short cuts to avoid calling
        // ThrowableSet.catchableAs() when we can avoid it.
        boolean alwaysAddSelfEdges = ((!omitExceptingUnitEdges) || mightHaveSideEffects(thrower));
        ThrowableSet predThrowables = null;
        ThrowableSet selfThrowables = null;
        if (thrower instanceof ThrowInst) {
            ThrowInst throwInst = (ThrowInst) thrower;
            predThrowables = throwAnalysis.mightThrowImplicitly(throwInst);
            selfThrowables = throwAnalysis.mightThrowExplicitly(throwInst);
        } else if (thrower instanceof ThrowStmt) {
            ThrowStmt throwStmt = (ThrowStmt) thrower;
            predThrowables = throwAnalysis.mightThrowImplicitly(throwStmt);
            selfThrowables = throwAnalysis.mightThrowExplicitly(throwStmt);
        }
        for (ExceptionDest dest : dests) {
            if (dest.getTrap() != null) {
                Unit catcher = dest.getTrap().getHandlerUnit();
                RefType trapsType = dest.getTrap().getException().getType();
                if (predThrowables == null || predThrowables.catchableAs(trapsType)) {
                    // catcher.
                    if (thrower == entryPoint) {
                        trapsThatAreHeads.add(catcher);
                    }
                    for (Unit pred : throwersPreds) {
                        addEdge(unitToSuccs, unitToPreds, pred, catcher);
                    }
                }
                if (alwaysAddSelfEdges || (selfThrowables != null && selfThrowables.catchableAs(trapsType))) {
                    addEdge(unitToSuccs, unitToPreds, thrower, catcher);
                }
            }
        }
    }
    // worklist containing CFG edges that lead to such a handler.
    class CFGEdge {

        // If null, represents an edge to the handler
        Unit head;

        // from the fictitious "predecessor" of the
        // very first unit in the chain. I.e., tail
        // is a handler which might be reached as a
        // result of an exception thrown by the
        // first Unit in the Body.
        Unit tail;

        CFGEdge(Unit head, Unit tail) {
            if (tail == null)
                throw new RuntimeException("invalid CFGEdge(" + (head == null ? "null" : head.toString()) + ',' + "null" + ')');
            this.head = head;
            this.tail = tail;
        }

        @Override
        public boolean equals(Object rhs) {
            if (rhs == this) {
                return true;
            }
            if (!(rhs instanceof CFGEdge)) {
                return false;
            }
            CFGEdge rhsEdge = (CFGEdge) rhs;
            return ((this.head == rhsEdge.head) && (this.tail == rhsEdge.tail));
        }

        @Override
        public int hashCode() {
            // Following Joshua Bloch's recipe in "Effective Java", Item 8:
            int result = 17;
            result = 37 * result + this.head.hashCode();
            result = 37 * result + this.tail.hashCode();
            return result;
        }
    }
    LinkedList<CFGEdge> workList = new LinkedList<CFGEdge>();
    for (Trap trap : body.getTraps()) {
        Unit handlerStart = trap.getHandlerUnit();
        if (mightThrowToIntraproceduralCatcher(handlerStart)) {
            List<Unit> handlerPreds = getUnexceptionalPredsOf(handlerStart);
            for (Unit pred : handlerPreds) {
                workList.addLast(new CFGEdge(pred, handlerStart));
            }
            handlerPreds = getExceptionalPredsOf(handlerStart);
            for (Unit pred : handlerPreds) {
                workList.addLast(new CFGEdge(pred, handlerStart));
            }
            if (trapsThatAreHeads.contains(handlerStart)) {
                workList.addLast(new CFGEdge(null, handlerStart));
            }
        }
    }
    // the handler's exception.
    while (workList.size() > 0) {
        CFGEdge edgeToThrower = workList.removeFirst();
        Unit pred = edgeToThrower.head;
        Unit thrower = edgeToThrower.tail;
        Collection<ExceptionDest> throwerDests = getExceptionDests(thrower);
        for (ExceptionDest dest : throwerDests) {
            if (dest.getTrap() != null) {
                Unit handlerStart = dest.getTrap().getHandlerUnit();
                boolean edgeAdded = false;
                if (pred == null) {
                    if (!trapsThatAreHeads.contains(handlerStart)) {
                        trapsThatAreHeads.add(handlerStart);
                        edgeAdded = true;
                    }
                } else {
                    if (!getExceptionalSuccsOf(pred).contains(handlerStart)) {
                        addEdge(unitToSuccs, unitToPreds, pred, handlerStart);
                        edgeAdded = true;
                    }
                }
                if (edgeAdded && mightThrowToIntraproceduralCatcher(handlerStart)) {
                    workList.addLast(new CFGEdge(pred, handlerStart));
                }
            }
        }
    }
    return trapsThatAreHeads;
}
Also used : ThrowInst(soot.baf.ThrowInst) ArraySet(soot.util.ArraySet) Trap(soot.Trap) Unit(soot.Unit) LinkedList(java.util.LinkedList) RefType(soot.RefType) ThrowableSet(soot.toolkits.exceptions.ThrowableSet) Collection(java.util.Collection) ThrowStmt(soot.jimple.ThrowStmt)

Example 3 with ArraySet

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

the class OutFlow method jimplify.

/**
 * Main.v() entry point for converting list of Instructions to Jimple statements;
 * performs flow analysis, constructs Jimple statements, and fixes jumps.
 * @param constant_pool constant pool of ClassFile.
 * @param this_class constant pool index of the CONSTANT_Class_info object for
 * this' class.
 * @param bootstrap_methods_attribute
 * @return <i>true</i> if all ok, <i>false</i> if there was an error.
 * @see Stmt
 */
public boolean jimplify(cp_info[] constant_pool, int this_class, BootstrapMethods_attribute bootstrap_methods_attribute, JimpleBody listBody) {
    this.bootstrap_methods_attribute = bootstrap_methods_attribute;
    Chain<Unit> units = listBody.getUnits();
    this.listBody = listBody;
    this.units = units;
    instructionToFirstStmt = new HashMap<Instruction, Stmt>();
    instructionToLastStmt = new HashMap<Instruction, Stmt>();
    jmethod = listBody.getMethod();
    cm = Scene.v();
    // TypeArray.setClassManager(cm);
    // TypeStack.setClassManager(cm);
    Set<Local> initialLocals = new ArraySet<Local>();
    List<Type> parameterTypes = jmethod.getParameterTypes();
    // Initialize nameToLocal which is an index*Type->Local map, which is used
    // to determine local in bytecode references.
    {
        Code_attribute ca = method.locate_code_attribute();
        LocalVariableTable_attribute la = ca.findLocalVariableTable();
        LocalVariableTypeTable_attribute lt = ca.findLocalVariableTypeTable();
        Util.v().bodySetup(la, lt, constant_pool);
        boolean isStatic = Modifier.isStatic(jmethod.getModifiers());
        int currentLocalIndex = 0;
        // Initialize the 'this' variable
        {
            if (!isStatic) {
                Local local = Util.v().getLocalForParameter(listBody, currentLocalIndex);
                currentLocalIndex++;
                units.add(Jimple.v().newIdentityStmt(local, Jimple.v().newThisRef(jmethod.getDeclaringClass().getType())));
            }
        }
        // Initialize parameters
        {
            Iterator<Type> typeIt = parameterTypes.iterator();
            int argCount = 0;
            while (typeIt.hasNext()) {
                Local local = Util.v().getLocalForParameter(listBody, currentLocalIndex);
                Type type = typeIt.next();
                initialLocals.add(local);
                units.add(Jimple.v().newIdentityStmt(local, Jimple.v().newParameterRef(type, argCount)));
                if (type.equals(DoubleType.v()) || type.equals(LongType.v())) {
                    currentLocalIndex += 2;
                } else {
                    currentLocalIndex += 1;
                }
                argCount++;
            }
        }
        Util.v().resetEasyNames();
    }
    jimplify(constant_pool, this_class);
    return true;
}
Also used : ArraySet(soot.util.ArraySet) Local(soot.Local) Unit(soot.Unit) GotoStmt(soot.jimple.GotoStmt) IfStmt(soot.jimple.IfStmt) IdentityStmt(soot.jimple.IdentityStmt) TableSwitchStmt(soot.jimple.TableSwitchStmt) LookupSwitchStmt(soot.jimple.LookupSwitchStmt) Stmt(soot.jimple.Stmt) RefType(soot.RefType) ShortType(soot.ShortType) BooleanType(soot.BooleanType) ByteType(soot.ByteType) Type(soot.Type) UnknownType(soot.UnknownType) DoubleType(soot.DoubleType) FloatType(soot.FloatType) IntType(soot.IntType) CharType(soot.CharType) LongType(soot.LongType) StmtAddressType(soot.StmtAddressType) ArrayType(soot.ArrayType) VoidType(soot.VoidType)

Example 4 with ArraySet

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

the class GroupIntPair method emitMethodBody.

@Override
protected void emitMethodBody(SootMethod method) {
    if (Options.v().time())
        Timers.v().buildJasminTimer.end();
    Body activeBody = method.getActiveBody();
    if (!(activeBody instanceof BafBody)) {
        if (activeBody instanceof JimpleBody) {
            if (Options.v().verbose()) {
                logger.debug("Was expecting Baf body for " + method + " but found a Jimple body. Will convert body to Baf on the fly.");
            }
            activeBody = PackManager.v().convertJimpleBodyToBaf(method);
        } else
            throw new RuntimeException("method: " + method.getName() + " has an invalid active body!");
    }
    BafBody body = (BafBody) activeBody;
    if (body == null)
        throw new RuntimeException("method: " + method.getName() + " has no active body!");
    if (Options.v().time())
        Timers.v().buildJasminTimer.start();
    Chain<Unit> instList = body.getUnits();
    int stackLimitIndex = -1;
    subroutineToReturnAddressSlot = new HashMap<Unit, Integer>(10, 0.7f);
    // Determine the unitToLabel map
    {
        unitToLabel = new HashMap<Unit, String>(instList.size() * 2 + 1, 0.7f);
        labelCount = 0;
        for (UnitBox uBox : body.getUnitBoxes(true)) {
            // Assign a label for each statement reference
            {
                InstBox box = (InstBox) uBox;
                if (!unitToLabel.containsKey(box.getUnit()))
                    unitToLabel.put(box.getUnit(), "label" + labelCount++);
            }
        }
    }
    // Emit the exceptions, recording the Units at the beginning
    // of handlers so that later on we can recognize blocks that
    // begin with an exception on the stack.
    Set<Unit> handlerUnits = new ArraySet<Unit>(body.getTraps().size());
    {
        for (Trap trap : body.getTraps()) {
            handlerUnits.add(trap.getHandlerUnit());
            if (trap.getBeginUnit() != trap.getEndUnit()) {
                emit(".catch " + slashify(trap.getException().getName()) + " from " + unitToLabel.get(trap.getBeginUnit()) + " to " + unitToLabel.get(trap.getEndUnit()) + " using " + unitToLabel.get(trap.getHandlerUnit()));
            }
        }
    }
    // Determine where the locals go
    {
        int localCount = 0;
        int[] paramSlots = new int[method.getParameterCount()];
        int thisSlot = 0;
        Set<Local> assignedLocals = new HashSet<Local>();
        localToSlot = new HashMap<Local, Integer>(body.getLocalCount() * 2 + 1, 0.7f);
        // assignColorsToLocals(body);
        // Determine slots for 'this' and parameters
        {
            if (!method.isStatic()) {
                thisSlot = 0;
                localCount++;
            }
            for (int i = 0; i < method.getParameterCount(); i++) {
                paramSlots[i] = localCount;
                localCount += sizeOfType(method.getParameterType(i));
            }
        }
        // Handle identity statements
        {
            for (Unit u : instList) {
                Inst s = (Inst) u;
                if (s instanceof IdentityInst && ((IdentityInst) s).getLeftOp() instanceof Local) {
                    Local l = (Local) ((IdentityInst) s).getLeftOp();
                    IdentityRef identity = (IdentityRef) ((IdentityInst) s).getRightOp();
                    int slot = 0;
                    if (identity instanceof ThisRef) {
                        if (method.isStatic())
                            throw new RuntimeException("Attempting to use 'this' in static method");
                        slot = thisSlot;
                    } else if (identity instanceof ParameterRef)
                        slot = paramSlots[((ParameterRef) identity).getIndex()];
                    else {
                        // Exception ref. Skip over this
                        continue;
                    }
                    localToSlot.put(l, new Integer(slot));
                    assignedLocals.add(l);
                }
            }
        }
        // Assign the rest of the locals
        {
            for (Local local : body.getLocals()) {
                if (assignedLocals.add(local)) {
                    localToSlot.put(local, new Integer(localCount));
                    localCount += sizeOfType(local.getType());
                }
            }
            if (!Modifier.isNative(method.getModifiers()) && !Modifier.isAbstract(method.getModifiers())) {
                emit("    .limit stack ?");
                stackLimitIndex = code.size() - 1;
                emit("    .limit locals " + localCount);
            }
        }
    }
    // Emit code in one pass
    {
        isEmittingMethodCode = true;
        maxStackHeight = 0;
        isNextGotoAJsr = false;
        for (Unit u : instList) {
            Inst s = (Inst) u;
            if (unitToLabel.containsKey(s))
                emit(unitToLabel.get(s) + ":");
            // emit this statement
            {
                emitInst(s);
            }
        }
        isEmittingMethodCode = false;
        // calculate max stack height
        {
            maxStackHeight = 0;
            if (activeBody.getUnits().size() != 0) {
                BlockGraph blockGraph = new BriefBlockGraph(activeBody);
                List<Block> blocks = blockGraph.getBlocks();
                if (blocks.size() != 0) {
                    // set the stack height of the entry points
                    List<Block> entryPoints = ((DirectedGraph<Block>) blockGraph).getHeads();
                    for (Block entryBlock : entryPoints) {
                        Integer initialHeight;
                        if (handlerUnits.contains(entryBlock.getHead())) {
                            initialHeight = new Integer(1);
                        } else {
                            initialHeight = new Integer(0);
                        }
                        if (blockToStackHeight == null) {
                            blockToStackHeight = new HashMap<Block, Integer>();
                        }
                        blockToStackHeight.put(entryBlock, initialHeight);
                        if (blockToLogicalStackHeight == null) {
                            blockToLogicalStackHeight = new HashMap<Block, Integer>();
                        }
                        blockToLogicalStackHeight.put(entryBlock, initialHeight);
                    }
                    // entryPoints list as roots
                    for (Block nextBlock : entryPoints) {
                        calculateStackHeight(nextBlock);
                        calculateLogicalStackHeightCheck(nextBlock);
                    }
                }
            }
        }
        if (!Modifier.isNative(method.getModifiers()) && !Modifier.isAbstract(method.getModifiers()))
            code.set(stackLimitIndex, "    .limit stack " + maxStackHeight);
    }
    // emit code attributes
    {
        for (Tag t : body.getTags()) {
            if (t instanceof JasminAttribute) {
                emit(".code_attribute " + t.getName() + " \"" + ((JasminAttribute) t).getJasminValue(unitToLabel) + "\"");
            }
        }
    }
}
Also used : HashSet(java.util.HashSet) ArraySet(soot.util.ArraySet) Set(java.util.Set) HashMap(java.util.HashMap) Unit(soot.Unit) BriefBlockGraph(soot.toolkits.graph.BriefBlockGraph) BlockGraph(soot.toolkits.graph.BlockGraph) BriefBlockGraph(soot.toolkits.graph.BriefBlockGraph) DirectedGraph(soot.toolkits.graph.DirectedGraph) Body(soot.Body) UnitBox(soot.UnitBox) ArraySet(soot.util.ArraySet) Local(soot.Local) Trap(soot.Trap) JasminAttribute(soot.tagkit.JasminAttribute) Block(soot.toolkits.graph.Block) Tag(soot.tagkit.Tag) LineNumberTag(soot.tagkit.LineNumberTag)

Aggregations

Unit (soot.Unit)4 ArraySet (soot.util.ArraySet)4 Local (soot.Local)3 Trap (soot.Trap)3 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 LinkedList (java.util.LinkedList)2 Set (java.util.Set)2 RefType (soot.RefType)2 GotoStmt (soot.jimple.GotoStmt)2 IdentityStmt (soot.jimple.IdentityStmt)2 IfStmt (soot.jimple.IfStmt)2 LookupSwitchStmt (soot.jimple.LookupSwitchStmt)2 Stmt (soot.jimple.Stmt)2 TableSwitchStmt (soot.jimple.TableSwitchStmt)2 LineNumberTag (soot.tagkit.LineNumberTag)2 Tag (soot.tagkit.Tag)2 ArrayList (java.util.ArrayList)1 Collection (java.util.Collection)1 List (java.util.List)1