Search in sources :

Example 1 with AbstractCopyStmt

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

the class BoissinotDestructor method applyRemapping.

// Flatten ccs so that each local in each cc is replaced with a new representative local.
private void applyRemapping() {
    GenericBitSet<BasicBlock> processed = cfg.createBitSet();
    GenericBitSet<BasicBlock> processed2 = cfg.createBitSet();
    for (Local e : remap.keySet()) {
        for (BasicBlock used : defuse.uses.getNonNull(e)) {
            if (processed.contains(used))
                continue;
            processed.add(used);
            for (Stmt stmt : used) {
                for (Expr s : stmt.enumerateOnlyChildren()) {
                    if (s.getOpcode() == Opcode.LOCAL_LOAD) {
                        VarExpr v = (VarExpr) s;
                        v.setLocal(remap.getOrDefault(v.getLocal(), v.getLocal()));
                    }
                }
            }
        }
        BasicBlock b = defuse.defs.get(e);
        if (processed2.contains(b))
            continue;
        processed2.add(b);
        for (Iterator<Stmt> it = b.iterator(); it.hasNext(); ) {
            Stmt stmt = it.next();
            if (stmt instanceof ParallelCopyVarStmt) {
                ParallelCopyVarStmt copy = (ParallelCopyVarStmt) stmt;
                for (Iterator<CopyPair> it2 = copy.pairs.iterator(); it2.hasNext(); ) {
                    CopyPair p = it2.next();
                    p.source = remap.getOrDefault(p.source, p.source);
                    p.targ = remap.getOrDefault(p.targ, p.targ);
                    if (p.source == p.targ)
                        it2.remove();
                }
                if (copy.pairs.isEmpty())
                    it.remove();
            } else if (stmt instanceof CopyVarStmt) {
                AbstractCopyStmt copy = (AbstractCopyStmt) stmt;
                VarExpr v = copy.getVariable();
                v.setLocal(remap.getOrDefault(v.getLocal(), v.getLocal()));
                if (!copy.isSynthetic() && copy.getExpression().getOpcode() == Opcode.LOCAL_LOAD)
                    if (((VarExpr) copy.getExpression()).getLocal() == v.getLocal())
                        it.remove();
            } else if (stmt instanceof CopyPhiStmt) {
                throw new IllegalArgumentException("Phi copy still in block?");
            }
        }
    }
    for (Local e : remap.keySet()) {
        defuse.defs.remove(e);
        defuse.uses.remove(e);
    }
}
Also used : CopyVarStmt(org.mapleir.ir.code.stmt.copy.CopyVarStmt) BasicBlock(org.mapleir.ir.cfg.BasicBlock) Local(org.mapleir.ir.locals.Local) VersionedLocal(org.mapleir.ir.locals.impl.VersionedLocal) CopyVarStmt(org.mapleir.ir.code.stmt.copy.CopyVarStmt) Stmt(org.mapleir.ir.code.Stmt) CopyPhiStmt(org.mapleir.ir.code.stmt.copy.CopyPhiStmt) AbstractCopyStmt(org.mapleir.ir.code.stmt.copy.AbstractCopyStmt) CopyPhiStmt(org.mapleir.ir.code.stmt.copy.CopyPhiStmt) VarExpr(org.mapleir.ir.code.expr.VarExpr) Expr(org.mapleir.ir.code.Expr) PhiExpr(org.mapleir.ir.code.expr.PhiExpr) VarExpr(org.mapleir.ir.code.expr.VarExpr) AbstractCopyStmt(org.mapleir.ir.code.stmt.copy.AbstractCopyStmt)

Example 2 with AbstractCopyStmt

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

the class SSADefUseMap method build.

protected void build(BasicBlock b, Stmt stmt, Set<Local> usedLocals) {
    if (stmt instanceof AbstractCopyStmt) {
        AbstractCopyStmt copy = (AbstractCopyStmt) stmt;
        Local l = copy.getVariable().getLocal();
        defs.put(l, b);
        if (copy instanceof CopyPhiStmt) {
            phiDefs.put(l, (CopyPhiStmt) copy);
            PhiExpr phi = (PhiExpr) copy.getExpression();
            for (Entry<BasicBlock, Expr> en : phi.getArguments().entrySet()) {
                Local ul = ((VarExpr) en.getValue()).getLocal();
                uses.getNonNull(ul).add(en.getKey());
                phiUses.get(b).add(ul);
            }
            return;
        }
    }
    for (Local usedLocal : usedLocals) uses.getNonNull(usedLocal).add(b);
}
Also used : VarExpr(org.mapleir.ir.code.expr.VarExpr) Expr(org.mapleir.ir.code.Expr) PhiExpr(org.mapleir.ir.code.expr.PhiExpr) PhiExpr(org.mapleir.ir.code.expr.PhiExpr) BasicBlock(org.mapleir.ir.cfg.BasicBlock) AbstractCopyStmt(org.mapleir.ir.code.stmt.copy.AbstractCopyStmt) Local(org.mapleir.ir.locals.Local) VarExpr(org.mapleir.ir.code.expr.VarExpr) CopyPhiStmt(org.mapleir.ir.code.stmt.copy.CopyPhiStmt)

Example 3 with AbstractCopyStmt

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

the class SSAGenPass method pruneStatements.

private int pruneStatements() {
    int s = pool.uses.size();
    Iterator<Entry<VersionedLocal, Set<VarExpr>>> it = pool.uses.entrySet().iterator();
    while (it.hasNext()) {
        Entry<VersionedLocal, Set<VarExpr>> e = it.next();
        VersionedLocal vl = e.getKey();
        if (e.getValue().size() == 0) {
            AbstractCopyStmt def = pool.defs.get(vl);
            /* i.e. it has not been shadowed. */
            if (def != null && def.getBlock() != null && prune(def)) {
                if (vl != def.getVariable().getLocal()) {
                    throw new RuntimeException(vl + ", " + def);
                }
                /* use pool remove */
                it.remove();
                pool.defs.remove(vl);
            }
        }
    }
    return s - pool.uses.size();
}
Also used : VersionedLocal(org.mapleir.ir.locals.impl.VersionedLocal) Entry(java.util.Map.Entry) VarExpr(org.mapleir.ir.code.expr.VarExpr) AbstractCopyStmt(org.mapleir.ir.code.stmt.copy.AbstractCopyStmt) Constraint(org.mapleir.ir.cfg.builder.ssaopt.Constraint)

Example 4 with AbstractCopyStmt

use of org.mapleir.ir.code.stmt.copy.AbstractCopyStmt 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 5 with AbstractCopyStmt

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

the class SSAGenPass method translateStmt.

private void translateStmt(VarExpr var, boolean resolve, boolean isPhi) {
    /* Here we only remap local variable loads
		 * on the right hand side of a statement or
		 * expression. This means that if we are able
		 * to simply replace a local load which has
		 * a constant or deferred local value.
		 * 
		 * However, if the value of the local is
		 * a complex expression we need to check that
		 * we can propagate it before we do.
		 * 
		 * Since we will only replace a single
		 * local load in the original expression,
		 * only 1 variable is killed. However, there
		 * may be local load expressions in the
		 * propagated expression. To account for this,
		 * these local loads must be counted as new
		 * uses (except for when an expression is
		 * moved instead of copied to a use site).*/
    Local l = var.getLocal();
    VersionedLocal ssaL;
    if (resolve) {
        ssaL = latest(l.getIndex(), l.isStack());
    } else {
        ssaL = (VersionedLocal) l;
    }
    pool.uses.get(ssaL).add(var);
    VersionedLocal newL = ssaL;
    boolean exists = true;
    if (OPTIMISE) {
        if (latest.containsKey(ssaL)) {
            /* Try to propagate a simple copy local
				 * to its use site. It is possible that
				 * a non simple copy (including phis)
				 * will not have a mapping. In this case
				 * they will not have an updated target.*/
            LatestValue value = latest.get(ssaL);
            boolean unpredictable = value.getType() == LatestValue.PARAM || value.getType() == LatestValue.PHI;
            if (unpredictable && ssaL != value.getSuggestedValue()) {
                VersionedLocal vl = (VersionedLocal) value.getSuggestedValue();
                if (shouldPropagate(ssaL, vl)) {
                    newL = vl;
                }
            } else if (!isPhi && !unpredictable) {
                Expr e = null;
                AbstractCopyStmt def = pool.defs.get(ssaL);
                Expr rval = (Expr) value.getSuggestedValue();
                if (ConstraintUtil.isUncopyable(rval)) {
                    /* A variable might have a value
						 * that is uncopyable such as an
						 * invoke or allocation call.
						 * 
						 * There are two ways this may happen:
						 *   x = call();
						 *  or
						 *   x = call();
						 *   y = x;
						 *   
						 * we defer optimising the first
						 * case till the end.
						 * 
						 * in the second case, we can
						 * propagate the source var (x)
						 * in place of the target (y). */
                    newL = tryDefer(value, ssaL);
                } else {
                    AbstractCopyStmt from = def;
                    if (value.getSource() != null) {
                        from = pool.defs.get(value.getSource());
                    }
                    if (!value.hasConstraints() || (canTransferHandlers(def.getBlock(), var.getBlock()) && value.canPropagate(from, var.getRootParent(), var, false))) {
                        if (shouldCopy(rval)) {
                            e = rval;
                        } else {
                            newL = tryDefer(value, ssaL);
                        }
                    } else if (value.getRealValue() instanceof VersionedLocal) {
                        VersionedLocal realVal = (VersionedLocal) value.getRealValue();
                        if (shouldPropagate(ssaL, realVal)) {
                            newL = realVal;
                        } else {
                            shadowed.getNonNull(ssaL).add(realVal);
                            shadowed.getNonNull(realVal).add(ssaL);
                        }
                    }
                }
                if (e != null) {
                    // System.out.println("=====");
                    // System.out.println("   ssaL: " + ssaL);
                    // System.out.println("   bpar: " + var.getParent());
                    CodeUnit parent = var.getParent();
                    int idx = parent.indexOf(var);
                    parent.overwrite(e = e.copy(), idx);
                    // System.out.println("    def: " + def);
                    // System.out.println("    idx: " + idx);
                    // System.out.println("    val: " + value);
                    // System.out.println("   apar: " + parent);
                    // System.out.println("      e: " + e);
                    /* Remove the use of the var before
						 * we translate the children of the 
						 * newly propagated expression.*/
                    pool.uses.get(ssaL).remove(var);
                    // System.out.println("   uses: " + pool.uses.get(ssaL));
                    /* Account for the new pool.uses.*/
                    collectUses(e);
                    /* Finally see if we can reduce
						 * this statement further.*/
                    translate(e, false, isPhi);
                    exists = false;
                }
            } else {
                newL = ssaL;
            }
        } else {
            throw new IllegalStateException("No (self) ancestors: " + l + " -> " + ssaL);
        }
    }
    if (exists) {
        if (OPTIMISE) {
            // System.out.println("replace: " + ssaL + " with " + newL);
            if (ssaL != newL) {
                // System.out.println(ssaL + "  -->  " + newL);
                pool.uses.get(ssaL).remove(var);
                pool.uses.get(newL).add(var);
            }
        }
        /* If the expression still exists, update
			 * or set both variable and type information.*/
        var.setLocal(newL);
        Type type = types.get(ssaL);
        if (type == null) {
            throw new IllegalStateException(var + ", " + ssaL + ", t=null");
        } else {
            var.setType(type);
        }
    }
}
Also used : VersionedLocal(org.mapleir.ir.locals.impl.VersionedLocal) LatestValue(org.mapleir.ir.cfg.builder.ssaopt.LatestValue) Type(org.objectweb.asm.Type) 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) BasicLocal(org.mapleir.ir.locals.impl.BasicLocal) Local(org.mapleir.ir.locals.Local) VersionedLocal(org.mapleir.ir.locals.impl.VersionedLocal) AbstractCopyStmt(org.mapleir.ir.code.stmt.copy.AbstractCopyStmt) CodeUnit(org.mapleir.ir.code.CodeUnit)

Aggregations

AbstractCopyStmt (org.mapleir.ir.code.stmt.copy.AbstractCopyStmt)20 VarExpr (org.mapleir.ir.code.expr.VarExpr)17 Expr (org.mapleir.ir.code.Expr)15 VersionedLocal (org.mapleir.ir.locals.impl.VersionedLocal)12 PhiExpr (org.mapleir.ir.code.expr.PhiExpr)11 Local (org.mapleir.ir.locals.Local)11 BasicBlock (org.mapleir.ir.cfg.BasicBlock)9 Stmt (org.mapleir.ir.code.Stmt)8 ConstantExpr (org.mapleir.ir.code.expr.ConstantExpr)8 InitialisedObjectExpr (org.mapleir.ir.code.expr.invoke.InitialisedObjectExpr)7 InvocationExpr (org.mapleir.ir.code.expr.invoke.InvocationExpr)7 CopyPhiStmt (org.mapleir.ir.code.stmt.copy.CopyPhiStmt)6 CopyVarStmt (org.mapleir.ir.code.stmt.copy.CopyVarStmt)5 HashSet (java.util.HashSet)4 CodeUnit (org.mapleir.ir.code.CodeUnit)4 LocalsPool (org.mapleir.ir.locals.LocalsPool)4 Constraint (org.mapleir.ir.cfg.builder.ssaopt.Constraint)3 LatestValue (org.mapleir.ir.cfg.builder.ssaopt.LatestValue)3 ConditionalJumpStmt (org.mapleir.ir.code.stmt.ConditionalJumpStmt)3 PopStmt (org.mapleir.ir.code.stmt.PopStmt)3