Search in sources :

Example 1 with LatestValue

use of org.mapleir.ir.cfg.builder.ssaopt.LatestValue 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 2 with LatestValue

use of org.mapleir.ir.cfg.builder.ssaopt.LatestValue 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)

Example 3 with LatestValue

use of org.mapleir.ir.cfg.builder.ssaopt.LatestValue in project maple-ir by LLVM-but-worse.

the class SSAGenPass method processDeferredTranslations.

private int processDeferredTranslations() {
    int i = 0;
    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 (deferred.contains(vl) || vl.isStack()) {
            Set<VarExpr> useSet = e.getValue();
            AbstractCopyStmt def = pool.defs.get(vl);
            if (def != null && useSet.size() == 1) {
                /* In this case, the only place that the value
					 * of this assignment will be used is at the use site.
					 * Since that value can not be spread until this one
					 * is, we can propagate it.*/
                if (def.getOpcode() != Opcode.PHI_STORE) {
                    VarExpr use = useSet.iterator().next();
                    LatestValue val = latest.get(vl);
                    // System.out.println();
                    // System.out.println();
                    // System.out.println(def);
                    // System.out.println(use);
                    /* phi var*/
                    Expr rhs = def.getExpression();
                    if (use.getParent() != null) {
                        if (canTransferHandlers(def.getBlock(), use.getBlock()) && val.canPropagate(def, use.getRootParent(), use, false)) {
                            CodeUnit parent = use.getParent();
                            if (rhs.getOpcode() == Opcode.CATCH) {
                                // CodeUnit rp = use.getRootParent();
                                // System.out.println("DENIED NIGGA");
                                // System.out.println("replace " + vl + " with " + rhs);
                                // System.out.println(" in " + parent);
                                // System.out.println(" kill def: " + def);
                                // System.out.println();
                                deferred.remove(vl);
                                continue;
                            // check to see if we're moving it to the
                            // first expression in the block, if we aren't
                            // then deny, otherwise we can get rid of the local.
                            // if(rp.getBlock().indexOf(rp) != 1 || rp.enumerateExecutionOrder().indexOf(use) != 0) {
                            // 
                            // }
                            }
                            rhs.unlink();
                            def.delete();
                            pool.defs.remove(vl);
                            useSet.clear();
                            parent.overwrite(rhs, parent.indexOf(use));
                            i++;
                            it.remove();
                        }
                    }
                }
            }
        }
    }
    return i;
}
Also used : VersionedLocal(org.mapleir.ir.locals.impl.VersionedLocal) LatestValue(org.mapleir.ir.cfg.builder.ssaopt.LatestValue) Entry(java.util.Map.Entry) 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) AbstractCopyStmt(org.mapleir.ir.code.stmt.copy.AbstractCopyStmt) Constraint(org.mapleir.ir.cfg.builder.ssaopt.Constraint) CodeUnit(org.mapleir.ir.code.CodeUnit)

Example 4 with LatestValue

use of org.mapleir.ir.cfg.builder.ssaopt.LatestValue in project maple-ir by LLVM-but-worse.

the class SSAGenPass method makeValue.

private void makeValue(AbstractCopyStmt copy, VersionedLocal ssaL) {
    /* Attempts to find the 'value' of a local.
		 * The value can be the following types:
		 *   param - assigned by caller method
		 *   phi - set by a phi node
		 *   const - compiletime constant
		 *   var - runtime computed
		 *   
		 * when a copy x = y, is visited,
		 * if y is a var, x inherits
		 * the value and value type.
		 * */
    Expr e = copy.getExpression();
    int opcode = e.getOpcode();
    if (opcode == Opcode.LOCAL_LOAD) {
        if (copy.isSynthetic()) {
            /* equals itself (pure value).*/
            LatestValue value = new LatestValue(builder.graph, LatestValue.PARAM, ssaL, null);
            latest.put(ssaL, value);
        } else {
            /* i.e. x = y, where x and y are both variables.
				 * 
				 * It is expected that the local uses of the copy 
				 * (rhs) are visited before the target is.
				 */
            VarExpr rhs = (VarExpr) e;
            VersionedLocal rhsL = (VersionedLocal) rhs.getLocal();
            /* the rhsL must have been visited already
				 * and the lhsL must not have been.*/
            if (!latest.containsKey(ssaL)) {
                if (latest.containsKey(rhsL)) {
                    LatestValue anc = latest.get(rhsL);
                    // TODO: maybe advance the src local if we
                    // can validate an expr propagation to the
                    // new copy dst.
                    LatestValue value = new LatestValue(builder.graph, anc.getType(), rhsL, anc.getSuggestedValue(), anc.getSource());
                    value.importConstraints(anc);
                    latest.put(ssaL, value);
                } else {
                    throw new IllegalStateException("Non anc parent: " + ssaL + " = " + rhsL + " (def: " + pool.defs.get(rhsL) + ")");
                }
            } else {
                throw new IllegalStateException("Revisit def " + ssaL + " ( = " + rhsL + ")");
            }
        }
    } else {
        LatestValue value;
        if (opcode == Opcode.CONST_LOAD) {
            ConstantExpr ce = (ConstantExpr) e;
            value = new LatestValue(builder.graph, LatestValue.CONST, ce, null);
        } else if ((opcode & Opcode.CLASS_PHI) == Opcode.CLASS_PHI) {
            value = new LatestValue(builder.graph, LatestValue.PHI, ssaL, null);
        } else {
            if (e.getOpcode() == Opcode.LOCAL_LOAD) {
                throw new RuntimeException(copy + "    " + e);
            }
            value = new LatestValue(builder.graph, LatestValue.VAR, e, ssaL);
            value.makeConstraints(e);
        }
        latest.put(ssaL, value);
    }
// System.out.println("made val " + ssaL + " -> " + latest.get(ssaL));
}
Also used : LatestValue(org.mapleir.ir.cfg.builder.ssaopt.LatestValue) 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) ConstantExpr(org.mapleir.ir.code.expr.ConstantExpr) VarExpr(org.mapleir.ir.code.expr.VarExpr) Constraint(org.mapleir.ir.cfg.builder.ssaopt.Constraint)

Aggregations

LatestValue (org.mapleir.ir.cfg.builder.ssaopt.LatestValue)4 Expr (org.mapleir.ir.code.Expr)4 ConstantExpr (org.mapleir.ir.code.expr.ConstantExpr)4 PhiExpr (org.mapleir.ir.code.expr.PhiExpr)4 VarExpr (org.mapleir.ir.code.expr.VarExpr)4 InitialisedObjectExpr (org.mapleir.ir.code.expr.invoke.InitialisedObjectExpr)4 InvocationExpr (org.mapleir.ir.code.expr.invoke.InvocationExpr)4 VersionedLocal (org.mapleir.ir.locals.impl.VersionedLocal)4 Constraint (org.mapleir.ir.cfg.builder.ssaopt.Constraint)3 AbstractCopyStmt (org.mapleir.ir.code.stmt.copy.AbstractCopyStmt)3 CodeUnit (org.mapleir.ir.code.CodeUnit)2 Entry (java.util.Map.Entry)1 BasicBlock (org.mapleir.ir.cfg.BasicBlock)1 Stmt (org.mapleir.ir.code.Stmt)1 ConditionalJumpStmt (org.mapleir.ir.code.stmt.ConditionalJumpStmt)1 PopStmt (org.mapleir.ir.code.stmt.PopStmt)1 SwitchStmt (org.mapleir.ir.code.stmt.SwitchStmt)1 ThrowStmt (org.mapleir.ir.code.stmt.ThrowStmt)1 UnconditionalJumpStmt (org.mapleir.ir.code.stmt.UnconditionalJumpStmt)1 CopyPhiStmt (org.mapleir.ir.code.stmt.copy.CopyPhiStmt)1