Search in sources :

Example 11 with CopyVarStmt

use of org.mapleir.ir.code.stmt.copy.CopyVarStmt in project maple-ir by LLVM-but-worse.

the class SSAGenPass method aggregateInitialisers.

private void aggregateInitialisers() {
    for (BasicBlock b : builder.graph.vertices()) {
        for (Stmt stmt : new ArrayList<>(b)) {
            if (stmt.getOpcode() == Opcode.POP) {
                PopStmt pop = (PopStmt) stmt;
                Expr expr = pop.getExpression();
                if (expr.getOpcode() == Opcode.INVOKE) {
                    InvocationExpr invoke = (InvocationExpr) expr;
                    if (invoke.getCallType() == InvocationExpr.CallType.SPECIAL && invoke.getName().equals("<init>")) {
                        Expr inst = invoke.getPhysicalReceiver();
                        if (inst.getOpcode() == Opcode.LOCAL_LOAD) {
                            VarExpr var = (VarExpr) inst;
                            VersionedLocal local = (VersionedLocal) var.getLocal();
                            AbstractCopyStmt def = pool.defs.get(local);
                            Expr rhs = def.getExpression();
                            if (rhs.getOpcode() == Opcode.ALLOC_OBJ) {
                                // replace pop(x.<init>()) with x := new Klass();
                                // remove x := new Klass;
                                // here we are assuming that the new object
                                // can't be used until it is initialised.
                                Expr[] args = invoke.getParameterExprs();
                                // we want to reuse the exprs, so free it first.
                                pop.deleteAt(0);
                                Expr[] newArgs = Arrays.copyOf(args, args.length);
                                for (int i = args.length - 1; i >= 0; i--) {
                                    args[i].unlink();
                                }
                                // remove the old def
                                def.delete();
                                int index = b.indexOf(pop);
                                // add a copy statement before the pop (x = newExpr)
                                InitialisedObjectExpr newExpr = new InitialisedObjectExpr(invoke.getOwner(), invoke.getDesc(), newArgs);
                                CopyVarStmt newCvs = new CopyVarStmt(var, newExpr);
                                pool.defs.put(local, newCvs);
                                pool.uses.get(local).remove(var);
                                b.add(index, newCvs);
                                // remove the pop statement
                                b.remove(pop);
                                // update the latestval constraints
                                LatestValue lval = latest.get(local);
                                if (lval.hasConstraints()) {
                                    /* need to check this out (shouldn't happen) */
                                    System.out.println("Constraints:");
                                    for (Constraint c : lval.getConstraints()) {
                                        System.out.println("  " + c);
                                    }
                                    throw new IllegalStateException(lval.toString());
                                } else {
                                    lval.makeConstraints(newExpr);
                                }
                            }
                        } else if (inst.getOpcode() == Opcode.ALLOC_OBJ) {
                            // replace pop(new Klass.<init>(args)) with pop(new Klass(args))
                            // UninitialisedObjectExpr obj = (UninitialisedObjectExpr) inst;
                            Expr[] args = invoke.getParameterExprs();
                            // we want to reuse the exprs, so free it first.
                            invoke.unlink();
                            for (Expr e : args) {
                                e.unlink();
                            }
                            Expr[] newArgs = Arrays.copyOf(args, args.length);
                            InitialisedObjectExpr newExpr = new InitialisedObjectExpr(invoke.getOwner(), invoke.getDesc(), newArgs);
                            // replace pop contents
                            // no changes to defs or uses
                            pop.setExpression(newExpr);
                        } else {
                            System.err.println(b);
                            System.err.println("Stmt: " + stmt.getDisplayName() + ". " + stmt);
                            System.err.println("Inst: " + inst);
                            System.err.println(builder.graph);
                            throw new RuntimeException("interesting1 " + inst.getClass());
                        }
                    }
                }
            }
        }
    }
}
Also used : VersionedLocal(org.mapleir.ir.locals.impl.VersionedLocal) Constraint(org.mapleir.ir.cfg.builder.ssaopt.Constraint) CopyVarStmt(org.mapleir.ir.code.stmt.copy.CopyVarStmt) BasicBlock(org.mapleir.ir.cfg.BasicBlock) InitialisedObjectExpr(org.mapleir.ir.code.expr.invoke.InitialisedObjectExpr) Constraint(org.mapleir.ir.cfg.builder.ssaopt.Constraint) SwitchStmt(org.mapleir.ir.code.stmt.SwitchStmt) CopyVarStmt(org.mapleir.ir.code.stmt.copy.CopyVarStmt) PopStmt(org.mapleir.ir.code.stmt.PopStmt) ThrowStmt(org.mapleir.ir.code.stmt.ThrowStmt) UnconditionalJumpStmt(org.mapleir.ir.code.stmt.UnconditionalJumpStmt) Stmt(org.mapleir.ir.code.Stmt) CopyPhiStmt(org.mapleir.ir.code.stmt.copy.CopyPhiStmt) ConditionalJumpStmt(org.mapleir.ir.code.stmt.ConditionalJumpStmt) AbstractCopyStmt(org.mapleir.ir.code.stmt.copy.AbstractCopyStmt) LatestValue(org.mapleir.ir.cfg.builder.ssaopt.LatestValue) ConstantExpr(org.mapleir.ir.code.expr.ConstantExpr) InitialisedObjectExpr(org.mapleir.ir.code.expr.invoke.InitialisedObjectExpr) InvocationExpr(org.mapleir.ir.code.expr.invoke.InvocationExpr) VarExpr(org.mapleir.ir.code.expr.VarExpr) Expr(org.mapleir.ir.code.Expr) PhiExpr(org.mapleir.ir.code.expr.PhiExpr) PopStmt(org.mapleir.ir.code.stmt.PopStmt) VarExpr(org.mapleir.ir.code.expr.VarExpr) AbstractCopyStmt(org.mapleir.ir.code.stmt.copy.AbstractCopyStmt) InvocationExpr(org.mapleir.ir.code.expr.invoke.InvocationExpr)

Example 12 with CopyVarStmt

use of org.mapleir.ir.code.stmt.copy.CopyVarStmt in project maple-ir by LLVM-but-worse.

the class SSAGenPass method splitBlock.

private BasicBlock splitBlock(BasicBlock b, int to) {
    /* eg. split the block as follows:
		 * 
		 *  NAME:
		 *    stmt1
		 *    stmt2
		 *    stmt3
		 *    stmt4
		 *    stmt5
		 *    jump L1, L2
		 *   [jump edge to L1]
		 *   [jump edge to L2]
		 *   [exception edges]
		 * 
		 * split at 3, create a new block (incoming 
		 * immediate), transfer instruction from 0
		 * to index into new block, create immediate
		 * edge to old block, clone exception edges,
		 * redirect pred edges.
		 * 
		 * 1/9/16: we also need to modify the last
		 *         statement of the pred blocks to
		 *         point to NAME'.
		 * 
		 *  NAME':
		 *    stmt1
		 *    stmt2
		 *    stmt3
		 *   [immediate to NAME]
		 *  NAME:
		 *    stmt4
		 *    stmt5
		 *    jump L1, L2
		 *   [jump edge to L1]
		 *   [jump edge to L2]
		 *   [exception edges]
		 */
    // split block
    ControlFlowGraph cfg = builder.graph;
    BasicBlock newBlock = new BasicBlock(cfg, graphSize++, new LabelNode());
    b.transferUp(newBlock, to);
    cfg.addVertex(newBlock);
    // redo ranges
    for (ExceptionRange<BasicBlock> er : cfg.getRanges()) {
        if (er.containsVertex(b))
            er.addVertexBefore(b, newBlock);
    }
    // redirect b preds into newBlock and remove them.
    Set<FlowEdge<BasicBlock>> oldEdges = new HashSet<>(cfg.getReverseEdges(b));
    for (FlowEdge<BasicBlock> e : oldEdges) {
        BasicBlock p = e.src();
        FlowEdge<BasicBlock> c;
        if (e instanceof TryCatchEdge) {
            // b is ehandler
            TryCatchEdge<BasicBlock> tce = (TryCatchEdge<BasicBlock>) e;
            if (tce.dst() != tce.erange.getHandler()) {
                System.err.println(builder.method.owner + "#" + builder.method.name);
                System.err.println(cfg);
                System.err.println("Very odd split case. please investigate");
                System.err.println("Offending postsplit block: " + b);
                System.err.println("Offending newblock: " + newBlock);
                System.err.println("Offending edge: " + tce);
                System.err.println("Offending erange: " + tce.erange);
            }
            if (tce.erange.getHandler() != newBlock) {
                tce.erange.setHandler(newBlock);
                cfg.addEdge(tce.src(), tce.clone(tce.src(), null));
                cfg.removeEdge(tce.src(), tce);
            }
        } else {
            c = e.clone(p, newBlock);
            cfg.addEdge(p, c);
            cfg.removeEdge(p, e);
        }
        // Fix flow instruction targets
        if (!p.isEmpty()) {
            Stmt last = p.get(p.size() - 1);
            int op = last.getOpcode();
            if (e instanceof ConditionalJumpEdge) {
                if (op != Opcode.COND_JUMP)
                    throw new IllegalArgumentException("wrong flow instruction");
                ConditionalJumpStmt j = (ConditionalJumpStmt) last;
                // assertTarget(last, j.getTrueSuccessor(), b);
                if (j.getTrueSuccessor() == b)
                    j.setTrueSuccessor(newBlock);
            } else if (e instanceof UnconditionalJumpEdge) {
                if (op != Opcode.UNCOND_JUMP)
                    throw new IllegalArgumentException("wrong flow instruction");
                UnconditionalJumpStmt j = (UnconditionalJumpStmt) last;
                assertTarget(j, j.getTarget(), b);
                j.setTarget(newBlock);
            } else if (e instanceof SwitchEdge) {
                if (op != Opcode.SWITCH_JUMP)
                    throw new IllegalArgumentException("wrong flow instruction.");
                SwitchStmt s = (SwitchStmt) last;
                for (Entry<Integer, BasicBlock> en : s.getTargets().entrySet()) {
                    BasicBlock t = en.getValue();
                    if (t == b) {
                        en.setValue(newBlock);
                    }
                }
            }
        }
    }
    if (!checkCloneHandler(newBlock)) {
        System.err.println(cfg);
        System.err.println(newBlock.getDisplayName());
        System.err.println(b.getDisplayName());
        throw new IllegalStateException("the new block should always need a handler..?");
    }
    // clone exception edges
    for (FlowEdge<BasicBlock> e : cfg.getEdges(b)) {
        if (e.getType() == FlowEdges.TRYCATCH) {
            // second param is discarded (?)
            TryCatchEdge<BasicBlock> c = ((TryCatchEdge<BasicBlock>) e).clone(newBlock, null);
            cfg.addEdge(newBlock, c);
        }
    }
    // create immediate to newBlock
    cfg.addEdge(newBlock, new ImmediateEdge<>(newBlock, b));
    // update assigns
    Set<Local> assignedLocals = new HashSet<>();
    for (Stmt stmt : b) if (stmt.getOpcode() == Opcode.LOCAL_STORE)
        assignedLocals.add(((CopyVarStmt) stmt).getVariable().getLocal());
    for (Stmt stmt : newBlock) {
        if (stmt.getOpcode() == Opcode.LOCAL_STORE) {
            Local copyLocal = ((CopyVarStmt) stmt).getVariable().getLocal();
            Set<BasicBlock> set = builder.assigns.get(copyLocal);
            set.add(newBlock);
            if (!assignedLocals.contains(copyLocal))
                set.remove(b);
        }
    }
    return newBlock;
}
Also used : LabelNode(org.objectweb.asm.tree.LabelNode) TryCatchEdge(org.mapleir.flowgraph.edges.TryCatchEdge) SwitchStmt(org.mapleir.ir.code.stmt.SwitchStmt) CopyVarStmt(org.mapleir.ir.code.stmt.copy.CopyVarStmt) PopStmt(org.mapleir.ir.code.stmt.PopStmt) ThrowStmt(org.mapleir.ir.code.stmt.ThrowStmt) UnconditionalJumpStmt(org.mapleir.ir.code.stmt.UnconditionalJumpStmt) Stmt(org.mapleir.ir.code.Stmt) CopyPhiStmt(org.mapleir.ir.code.stmt.copy.CopyPhiStmt) ConditionalJumpStmt(org.mapleir.ir.code.stmt.ConditionalJumpStmt) AbstractCopyStmt(org.mapleir.ir.code.stmt.copy.AbstractCopyStmt) UnconditionalJumpEdge(org.mapleir.flowgraph.edges.UnconditionalJumpEdge) FlowEdge(org.mapleir.flowgraph.edges.FlowEdge) SwitchStmt(org.mapleir.ir.code.stmt.SwitchStmt) SwitchEdge(org.mapleir.flowgraph.edges.SwitchEdge) CopyVarStmt(org.mapleir.ir.code.stmt.copy.CopyVarStmt) BasicBlock(org.mapleir.ir.cfg.BasicBlock) BasicLocal(org.mapleir.ir.locals.impl.BasicLocal) Local(org.mapleir.ir.locals.Local) VersionedLocal(org.mapleir.ir.locals.impl.VersionedLocal) Constraint(org.mapleir.ir.cfg.builder.ssaopt.Constraint) UnconditionalJumpStmt(org.mapleir.ir.code.stmt.UnconditionalJumpStmt) ConditionalJumpStmt(org.mapleir.ir.code.stmt.ConditionalJumpStmt) ConditionalJumpEdge(org.mapleir.flowgraph.edges.ConditionalJumpEdge) ControlFlowGraph(org.mapleir.ir.cfg.ControlFlowGraph)

Example 13 with CopyVarStmt

use of org.mapleir.ir.code.stmt.copy.CopyVarStmt in project maple-ir by LLVM-but-worse.

the class SSAGenPass method checkCloneHandler.

private boolean checkCloneHandler(BasicBlock b) {
    if (b.isEmpty())
        throw new IllegalArgumentException("empty block after split?");
    // backwards iteration is faster
    for (ListIterator<Stmt> it = b.listIterator(b.size()); it.hasPrevious(); ) {
        Stmt stmt = it.previous();
        if (stmt instanceof CopyVarStmt) {
            CopyVarStmt copy = (CopyVarStmt) stmt;
            int opc = copy.getExpression().getOpcode();
            if (!copy.isSynthetic() && opc != Opcode.LOCAL_LOAD && opc != Opcode.CATCH)
                return true;
        } else if (stmt.canChangeFlow()) {
            if (stmt instanceof ThrowStmt)
                return true;
        // no need to check child exprs as no complex subexprs can occur before propagation.
        } else {
            return true;
        }
    }
    return false;
}
Also used : CopyVarStmt(org.mapleir.ir.code.stmt.copy.CopyVarStmt) ThrowStmt(org.mapleir.ir.code.stmt.ThrowStmt) Constraint(org.mapleir.ir.cfg.builder.ssaopt.Constraint) SwitchStmt(org.mapleir.ir.code.stmt.SwitchStmt) CopyVarStmt(org.mapleir.ir.code.stmt.copy.CopyVarStmt) PopStmt(org.mapleir.ir.code.stmt.PopStmt) ThrowStmt(org.mapleir.ir.code.stmt.ThrowStmt) UnconditionalJumpStmt(org.mapleir.ir.code.stmt.UnconditionalJumpStmt) Stmt(org.mapleir.ir.code.Stmt) CopyPhiStmt(org.mapleir.ir.code.stmt.copy.CopyPhiStmt) ConditionalJumpStmt(org.mapleir.ir.code.stmt.ConditionalJumpStmt) AbstractCopyStmt(org.mapleir.ir.code.stmt.copy.AbstractCopyStmt)

Example 14 with CopyVarStmt

use of org.mapleir.ir.code.stmt.copy.CopyVarStmt in project maple-ir by LLVM-but-worse.

the class SSAGenPass method splitRanges.

private void splitRanges() {
    // produce cleaner cfg
    List<BasicBlock> order = new ArrayList<>(builder.graph.vertices());
    NullPermeableHashMap<BasicBlock, Set<Local>> splits = new NullPermeableHashMap<>(SetCreator.getInstance());
    for (ExceptionRange<BasicBlock> er : builder.graph.getRanges()) {
        BasicBlock h = er.getHandler();
        handlers.add(h);
        Set<Local> ls = new HashSet<>(liveness.in(h));
        for (BasicBlock b : er.get()) {
            splits.getNonNull(b).addAll(ls);
        }
    }
    for (Entry<BasicBlock, Set<Local>> e : splits.entrySet()) {
        BasicBlock b = e.getKey();
        Set<Local> ls = e.getValue();
        ArrayList<Stmt> stmtsCopy = new ArrayList<>(b);
        int i = 0;
        boolean checkSplit = false;
        for (int i1 = 0; i1 < stmtsCopy.size(); i1++) {
            Stmt stmt = stmtsCopy.get(i1);
            if (b.size() == i)
                throw new IllegalStateException("s");
            if (checkSplit && stmt.getOpcode() == Opcode.LOCAL_STORE) {
                CopyVarStmt copy = (CopyVarStmt) stmt;
                VarExpr v = copy.getVariable();
                if (ls.contains(v.getLocal())) {
                    BasicBlock n = splitBlock(b, i);
                    order.add(order.indexOf(b), n);
                    i = 0;
                    checkSplit = false;
                }
            } else {
                // do not split if we have only seen simple or synthetic copies (catch copy is synthetic)
                if (stmt instanceof CopyVarStmt) {
                    CopyVarStmt copy = (CopyVarStmt) stmt;
                    int opc = copy.getExpression().getOpcode();
                    if (!copy.isSynthetic() && opc != Opcode.LOCAL_LOAD && opc != Opcode.CATCH) {
                        checkSplit = true;
                    }
                } else {
                    checkSplit = true;
                }
            }
            i++;
        }
    }
    builder.graph.naturalise(order);
    int po = 0;
    for (BasicBlock b : SimpleDfs.preorder(builder.graph, builder.graph.getEntries().iterator().next())) {
        insertion.put(b, 0);
        process.put(b, 0);
        preorder.put(b, po++);
    }
}
Also used : CopyVarStmt(org.mapleir.ir.code.stmt.copy.CopyVarStmt) BasicBlock(org.mapleir.ir.cfg.BasicBlock) BasicLocal(org.mapleir.ir.locals.impl.BasicLocal) Local(org.mapleir.ir.locals.Local) VersionedLocal(org.mapleir.ir.locals.impl.VersionedLocal) Constraint(org.mapleir.ir.cfg.builder.ssaopt.Constraint) SwitchStmt(org.mapleir.ir.code.stmt.SwitchStmt) CopyVarStmt(org.mapleir.ir.code.stmt.copy.CopyVarStmt) PopStmt(org.mapleir.ir.code.stmt.PopStmt) ThrowStmt(org.mapleir.ir.code.stmt.ThrowStmt) UnconditionalJumpStmt(org.mapleir.ir.code.stmt.UnconditionalJumpStmt) Stmt(org.mapleir.ir.code.Stmt) CopyPhiStmt(org.mapleir.ir.code.stmt.copy.CopyPhiStmt) ConditionalJumpStmt(org.mapleir.ir.code.stmt.ConditionalJumpStmt) AbstractCopyStmt(org.mapleir.ir.code.stmt.copy.AbstractCopyStmt) NullPermeableHashMap(org.mapleir.stdlib.collections.map.NullPermeableHashMap) VarExpr(org.mapleir.ir.code.expr.VarExpr)

Example 15 with CopyVarStmt

use of org.mapleir.ir.code.stmt.copy.CopyVarStmt in project maple-ir by LLVM-but-worse.

the class SSAGenPass method searchImpl.

private void searchImpl(BasicBlock b) {
    Iterator<Stmt> it = b.iterator();
    while (it.hasNext()) {
        Stmt stmt = it.next();
        int opcode = stmt.getOpcode();
        if (opcode == Opcode.POP) {
            PopStmt pop = (PopStmt) stmt;
            if (!ConstraintUtil.isUncopyable(pop.getExpression())) {
                it.remove();
                continue;
            }
        }
        if (opcode == Opcode.PHI_STORE) {
            /* We can rename these any time as these
				 * are visited before all other statements
				 * in a block (since they are always
				 * the starting statements of a block, if
				 * that block contains phi statements).
				 */
            CopyPhiStmt copy = (CopyPhiStmt) stmt;
            generate(copy);
        } else {
            /* Translates locals into their latest SSA
				 * versioned locals.
				 * 
				 * Do this before a LOCAL_STORE (x = ...)
				 * so that the target local isn't defined
				 * before the use so that copies in the
				 * form x = x; do not get mangled into
				 * x0 = x0 after SSA renaming.
				 * 
				 * We rename phi args later as the source
				 * local can originate from exotic blocks.
				 */
            translate(stmt, true, false);
        }
        if (opcode == Opcode.LOCAL_STORE) {
            /* Generate the target local after
				 * renaming the source pool.uses. 
				 */
            CopyVarStmt copy = (CopyVarStmt) stmt;
            generate(copy);
        }
    }
}
Also used : PopStmt(org.mapleir.ir.code.stmt.PopStmt) CopyVarStmt(org.mapleir.ir.code.stmt.copy.CopyVarStmt) Constraint(org.mapleir.ir.cfg.builder.ssaopt.Constraint) SwitchStmt(org.mapleir.ir.code.stmt.SwitchStmt) CopyVarStmt(org.mapleir.ir.code.stmt.copy.CopyVarStmt) PopStmt(org.mapleir.ir.code.stmt.PopStmt) ThrowStmt(org.mapleir.ir.code.stmt.ThrowStmt) UnconditionalJumpStmt(org.mapleir.ir.code.stmt.UnconditionalJumpStmt) Stmt(org.mapleir.ir.code.Stmt) CopyPhiStmt(org.mapleir.ir.code.stmt.copy.CopyPhiStmt) ConditionalJumpStmt(org.mapleir.ir.code.stmt.ConditionalJumpStmt) AbstractCopyStmt(org.mapleir.ir.code.stmt.copy.AbstractCopyStmt) CopyPhiStmt(org.mapleir.ir.code.stmt.copy.CopyPhiStmt)

Aggregations

CopyVarStmt (org.mapleir.ir.code.stmt.copy.CopyVarStmt)24 Stmt (org.mapleir.ir.code.Stmt)18 BasicBlock (org.mapleir.ir.cfg.BasicBlock)17 VarExpr (org.mapleir.ir.code.expr.VarExpr)17 CopyPhiStmt (org.mapleir.ir.code.stmt.copy.CopyPhiStmt)16 AbstractCopyStmt (org.mapleir.ir.code.stmt.copy.AbstractCopyStmt)14 Local (org.mapleir.ir.locals.Local)13 VersionedLocal (org.mapleir.ir.locals.impl.VersionedLocal)12 Expr (org.mapleir.ir.code.Expr)10 PhiExpr (org.mapleir.ir.code.expr.PhiExpr)8 ConditionalJumpStmt (org.mapleir.ir.code.stmt.ConditionalJumpStmt)6 PopStmt (org.mapleir.ir.code.stmt.PopStmt)6 SwitchStmt (org.mapleir.ir.code.stmt.SwitchStmt)6 ThrowStmt (org.mapleir.ir.code.stmt.ThrowStmt)6 UnconditionalJumpStmt (org.mapleir.ir.code.stmt.UnconditionalJumpStmt)6 Constraint (org.mapleir.ir.cfg.builder.ssaopt.Constraint)5 BasicLocal (org.mapleir.ir.locals.impl.BasicLocal)5 NullPermeableHashMap (org.mapleir.stdlib.collections.map.NullPermeableHashMap)5 ConstantExpr (org.mapleir.ir.code.expr.ConstantExpr)3 Type (org.objectweb.asm.Type)3