Search in sources :

Example 6 with VersionedLocal

use of org.mapleir.ir.locals.impl.VersionedLocal 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 7 with VersionedLocal

use of org.mapleir.ir.locals.impl.VersionedLocal in project maple-ir by LLVM-but-worse.

the class SSAGenPass method removeSimpleCopy.

private void removeSimpleCopy(AbstractCopyStmt copy) {
    VarExpr v = (VarExpr) copy.getExpression();
    VersionedLocal vl = (VersionedLocal) v.getLocal();
    copy.delete();
    pool.uses.get(vl).remove(v);
}
Also used : VersionedLocal(org.mapleir.ir.locals.impl.VersionedLocal) VarExpr(org.mapleir.ir.code.expr.VarExpr)

Example 8 with VersionedLocal

use of org.mapleir.ir.locals.impl.VersionedLocal in project maple-ir by LLVM-but-worse.

the class SSAGenPass method merge.

private void merge(VersionedLocal vla, VersionedLocal vlb) {
    Set<VersionedLocal> cca = shadowed.getNonNull(vla);
    Set<VersionedLocal> ccb = shadowed.getNonNull(vlb);
    cca.add(vlb);
    ccb.add(vla);
    cca.addAll(ccb);
    for (VersionedLocal l : cca) {
        shadowed.put(l, cca);
    }
}
Also used : VersionedLocal(org.mapleir.ir.locals.impl.VersionedLocal)

Example 9 with VersionedLocal

use of org.mapleir.ir.locals.impl.VersionedLocal in project maple-ir by LLVM-but-worse.

the class SSAGenPass method reduceClass.

private void reduceClass(Set<CopyPhiStmt> cc, CopyPhiStmt preferred) {
    Set<CopyPhiStmt> useless = new HashSet<>(cc);
    useless.remove(preferred);
    VersionedLocal phiLocal = (VersionedLocal) preferred.getVariable().getLocal();
    /* all the *dead* phi class locals */
    Set<VersionedLocal> deadLocals = new HashSet<>();
    for (CopyPhiStmt def : useless) {
        VersionedLocal local = (VersionedLocal) def.getVariable().getLocal();
        deadLocals.add(local);
        for (Expr e : def.enumerateOnlyChildren()) {
            if (e.getOpcode() == Opcode.LOCAL_LOAD) {
                VarExpr v = (VarExpr) e;
                VersionedLocal vl = (VersionedLocal) v.getLocal();
                pool.uses.get(vl).remove(v);
            }
        }
        // System.out.println(" killing " + def);
        def.delete();
    }
    for (VersionedLocal vl : deadLocals) {
        Set<VarExpr> deadVExprs = pool.uses.get(vl);
        for (VarExpr v : deadVExprs) {
            /* v.getLocal() == vl, i.e. dead phi local.
				 * Replace each dead var with the real one. */
            v.setLocal(phiLocal);
            pool.uses.get(phiLocal).add(v);
        }
        /* all dead. */
        /*pool.uses.get(vl)*/
        deadVExprs.clear();
        pool.defs.remove(vl);
    }
}
Also used : VersionedLocal(org.mapleir.ir.locals.impl.VersionedLocal) 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) VarExpr(org.mapleir.ir.code.expr.VarExpr) CopyPhiStmt(org.mapleir.ir.code.stmt.copy.CopyPhiStmt)

Example 10 with VersionedLocal

use of org.mapleir.ir.locals.impl.VersionedLocal 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

VersionedLocal (org.mapleir.ir.locals.impl.VersionedLocal)21 VarExpr (org.mapleir.ir.code.expr.VarExpr)18 Expr (org.mapleir.ir.code.Expr)12 PhiExpr (org.mapleir.ir.code.expr.PhiExpr)12 AbstractCopyStmt (org.mapleir.ir.code.stmt.copy.AbstractCopyStmt)11 ConstantExpr (org.mapleir.ir.code.expr.ConstantExpr)9 InitialisedObjectExpr (org.mapleir.ir.code.expr.invoke.InitialisedObjectExpr)8 InvocationExpr (org.mapleir.ir.code.expr.invoke.InvocationExpr)8 Stmt (org.mapleir.ir.code.Stmt)6 CopyPhiStmt (org.mapleir.ir.code.stmt.copy.CopyPhiStmt)6 BasicBlock (org.mapleir.ir.cfg.BasicBlock)5 Constraint (org.mapleir.ir.cfg.builder.ssaopt.Constraint)5 CopyVarStmt (org.mapleir.ir.code.stmt.copy.CopyVarStmt)5 Local (org.mapleir.ir.locals.Local)5 LocalsPool (org.mapleir.ir.locals.LocalsPool)5 LatestValue (org.mapleir.ir.cfg.builder.ssaopt.LatestValue)4 CodeUnit (org.mapleir.ir.code.CodeUnit)3 BasicLocal (org.mapleir.ir.locals.impl.BasicLocal)3 HashSet (java.util.HashSet)2 Entry (java.util.Map.Entry)2