diff options
Diffstat (limited to 'src/de/fernflower/modules/decompiler/exps/FunctionExprent.java')
-rw-r--r-- | src/de/fernflower/modules/decompiler/exps/FunctionExprent.java | 586 |
1 files changed, 586 insertions, 0 deletions
diff --git a/src/de/fernflower/modules/decompiler/exps/FunctionExprent.java b/src/de/fernflower/modules/decompiler/exps/FunctionExprent.java new file mode 100644 index 0000000..230fc5b --- /dev/null +++ b/src/de/fernflower/modules/decompiler/exps/FunctionExprent.java @@ -0,0 +1,586 @@ +/* + * Fernflower - The Analytical Java Decompiler + * http://www.reversed-java.com + * + * (C) 2008 - 2010, Stiver + * + * This software is NEITHER public domain NOR free software + * as per GNU License. See license.txt for more details. + * + * This software is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. + */ + +package de.fernflower.modules.decompiler.exps; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +import de.fernflower.code.CodeConstants; +import de.fernflower.modules.decompiler.ExprProcessor; +import de.fernflower.modules.decompiler.vars.CheckTypesResult; +import de.fernflower.struct.gen.VarType; +import de.fernflower.util.InterpreterUtil; +import de.fernflower.util.ListStack; + + + +public class FunctionExprent extends Exprent { + + public static final int FUNCTION_ADD = 0; + public static final int FUNCTION_SUB = 1; + public static final int FUNCTION_MUL = 2; + public static final int FUNCTION_DIV = 3; + + public static final int FUNCTION_AND = 4; + public static final int FUNCTION_OR = 5; + public static final int FUNCTION_XOR = 6; + + public static final int FUNCTION_REM = 7; + + public static final int FUNCTION_SHL = 8; + public static final int FUNCTION_SHR = 9; + public static final int FUNCTION_USHR = 10; + + public static final int FUNCTION_BITNOT = 11; + public static final int FUNCTION_BOOLNOT = 12; + public static final int FUNCTION_NEG = 13; + + public final static int FUNCTION_I2L = 14; + public final static int FUNCTION_I2F = 15; + public final static int FUNCTION_I2D = 16; + public final static int FUNCTION_L2I = 17; + public final static int FUNCTION_L2F = 18; + public final static int FUNCTION_L2D = 19; + public final static int FUNCTION_F2I = 20; + public final static int FUNCTION_F2L = 21; + public final static int FUNCTION_F2D = 22; + public final static int FUNCTION_D2I = 23; + public final static int FUNCTION_D2L = 24; + public final static int FUNCTION_D2F = 25; + public final static int FUNCTION_I2B = 26; + public final static int FUNCTION_I2C = 27; + public final static int FUNCTION_I2S = 28; + + public final static int FUNCTION_CAST = 29; + public final static int FUNCTION_INSTANCEOF = 30; + + public final static int FUNCTION_ARRAYLENGTH = 31; + + public final static int FUNCTION_IMM = 32; + public final static int FUNCTION_MMI = 33; + + public final static int FUNCTION_IPP = 34; + public final static int FUNCTION_PPI = 35; + + public final static int FUNCTION_IIF = 36; + + public final static int FUNCTION_LCMP = 37; + public final static int FUNCTION_FCMPL = 38; + public final static int FUNCTION_FCMPG = 39; + public final static int FUNCTION_DCMPL = 40; + public final static int FUNCTION_DCMPG = 41; + + public static final int FUNCTION_EQ = 42; + public static final int FUNCTION_NE = 43; + public static final int FUNCTION_LT = 44; + public static final int FUNCTION_GE = 45; + public static final int FUNCTION_GT = 46; + public static final int FUNCTION_LE = 47; + + public static final int FUNCTION_CADD = 48; + public static final int FUNCTION_COR = 49; + + public static final int FUNCTION_STRCONCAT = 50; + + private static final VarType[] types = new VarType[] { + VarType.VARTYPE_LONG, + VarType.VARTYPE_FLOAT, + VarType.VARTYPE_DOUBLE, + VarType.VARTYPE_INT, + VarType.VARTYPE_FLOAT, + VarType.VARTYPE_DOUBLE, + VarType.VARTYPE_INT, + VarType.VARTYPE_LONG, + VarType.VARTYPE_DOUBLE, + VarType.VARTYPE_INT, + VarType.VARTYPE_LONG, + VarType.VARTYPE_FLOAT, + VarType.VARTYPE_BYTE, + VarType.VARTYPE_CHAR, + VarType.VARTYPE_SHORT + }; + + private static final String[] operators = new String[] { + " + ", + " - ", + " * ", + " / ", + " & ", + " | ", + " ^ ", + " % ", + " << ", + " >> ", + " >>> ", + " == ", + " != ", + " < ", + " >= ", + " > ", + " <= ", + " && ", + " || ", + " + " + }; + + private static final int[] precedence = new int[] { + 3, // FUNCTION_ADD + 3, // FUNCTION_SUB + 2, // FUNCTION_MUL + 2, // FUNCTION_DIV + 7, // FUNCTION_AND + 9, // FUNCTION_OR + 8, // FUNCTION_XOR + 2, // FUNCTION_REM + 4, // FUNCTION_SHL + 4, // FUNCTION_SHR + 4, // FUNCTION_USHR + 1, // FUNCTION_BITNOT + 1, // FUNCTION_BOOLNOT + 1, // FUNCTION_NEG + 1, // FUNCTION_I2L + 1, // FUNCTION_I2F + 1, // FUNCTION_I2D + 1, // FUNCTION_L2I + 1, // FUNCTION_L2F + 1, // FUNCTION_L2D + 1, // FUNCTION_F2I + 1, // FUNCTION_F2L + 1, // FUNCTION_F2D + 1, // FUNCTION_D2I + 1, // FUNCTION_D2L + 1, // FUNCTION_D2F + 1, // FUNCTION_I2B + 1, // FUNCTION_I2C + 1, // FUNCTION_I2S + 1, // FUNCTION_CAST + 6, // FUNCTION_INSTANCEOF + 0, // FUNCTION_ARRAYLENGTH + 1, // FUNCTION_IMM + 1, // FUNCTION_MMI + 1, // FUNCTION_IPP + 1, // FUNCTION_PPI + 12, // FUNCTION_IFF + -1, // FUNCTION_LCMP + -1, // FUNCTION_FCMPL + -1, // FUNCTION_FCMPG + -1, // FUNCTION_DCMPL + -1, // FUNCTION_DCMPG + 6, // FUNCTION_EQ = 41; + 6, // FUNCTION_NE = 42; + 5, // FUNCTION_LT = 43; + 5, // FUNCTION_GE = 44; + 5, // FUNCTION_GT = 45; + 5, // FUNCTION_LE = 46; + 10, // FUNCTION_CADD = 47; + 11, // FUNCTION_COR = 48; + 3 // FUNCTION_STRCONCAT = 49; + }; + + private static final HashSet<Integer> associativity = new HashSet<Integer>(Arrays.asList(new Integer[]{FUNCTION_ADD, FUNCTION_MUL, FUNCTION_AND, + FUNCTION_OR, FUNCTION_XOR, FUNCTION_CADD, FUNCTION_COR, FUNCTION_STRCONCAT})); + + private int functype; + + private VarType implicitType; + + private List<Exprent> lstOperands = new ArrayList<Exprent>(); + + { + this.type = EXPRENT_FUNCTION; + } + + public FunctionExprent(int functype, ListStack<Exprent> stack) { + this.functype = functype; + if(functype>=FUNCTION_BITNOT && functype<=FUNCTION_PPI && functype!=FUNCTION_CAST + && functype!=FUNCTION_INSTANCEOF) { + lstOperands.add(stack.pop()); + } else if(functype == FUNCTION_IIF) { + throw new RuntimeException("no direct instantiation possible"); + } else { + Exprent expr = stack.pop(); + lstOperands.add(stack.pop()); + lstOperands.add(expr); + } + } + + public FunctionExprent(int functype, List<Exprent> operands) { + this.functype = functype; + this.lstOperands = operands; + } + + public VarType getExprType() { + VarType exprType = null; + + if(functype <= FUNCTION_NEG || functype == FUNCTION_IPP || functype == FUNCTION_PPI + || functype == FUNCTION_IMM || functype == FUNCTION_MMI) { + + VarType type1 = lstOperands.get(0).getExprType(); + VarType type2 = null; + if(lstOperands.size() > 1) { + type2 = lstOperands.get(1).getExprType(); + } + + switch(functype) { + case FUNCTION_IMM: + case FUNCTION_MMI: + case FUNCTION_IPP: + case FUNCTION_PPI: + exprType = implicitType; + break; + case FUNCTION_BOOLNOT: + exprType = VarType.VARTYPE_BOOLEAN; + break; + case FUNCTION_SHL: + case FUNCTION_SHR: + case FUNCTION_USHR: + case FUNCTION_BITNOT: + case FUNCTION_NEG: + exprType = getMaxVarType(new VarType[]{type1}); + break; + case FUNCTION_ADD: + case FUNCTION_SUB: + case FUNCTION_MUL: + case FUNCTION_DIV: + case FUNCTION_REM: + exprType = getMaxVarType(new VarType[]{type1, type2}); + break; + case FUNCTION_AND: + case FUNCTION_OR: + case FUNCTION_XOR: + if(type1.type == CodeConstants.TYPE_BOOLEAN & type2.type == CodeConstants.TYPE_BOOLEAN) { + exprType = VarType.VARTYPE_BOOLEAN; + } else { + exprType = getMaxVarType(new VarType[]{type1, type2}); + } + } + } else if(functype == FUNCTION_CAST){ + exprType = lstOperands.get(1).getExprType(); + } else if(functype == FUNCTION_IIF){ + Exprent param1 = lstOperands.get(1); + Exprent param2 = lstOperands.get(2); + VarType supertype = VarType.getCommonSupertype(param1.getExprType(), param2.getExprType()); + + if(param1.type == Exprent.EXPRENT_CONST && param2.type == Exprent.EXPRENT_CONST && + supertype.type != CodeConstants.TYPE_BOOLEAN && VarType.VARTYPE_INT.isSuperset(supertype)) { + exprType = VarType.VARTYPE_INT; + } else { + exprType = supertype; + } + } else if(functype == FUNCTION_STRCONCAT){ + exprType = VarType.VARTYPE_STRING; + } else if(functype >= FUNCTION_EQ){ + exprType = VarType.VARTYPE_BOOLEAN; + } else if(functype == FUNCTION_INSTANCEOF) { + exprType = VarType.VARTYPE_BOOLEAN; + } else if(functype >= FUNCTION_ARRAYLENGTH) { + exprType = VarType.VARTYPE_INT; + } else { + exprType = types[functype - FUNCTION_I2L]; + } + + return exprType; + } + + public int getExprentUse() { + + if(functype >= FUNCTION_IMM && functype <= FUNCTION_PPI) { + return 0; + } else { + int ret = Exprent.MULTIPLE_USES | Exprent.SIDE_EFFECTS_FREE; + for(Exprent expr: lstOperands) { + ret &= expr.getExprentUse(); + } + return ret; + } + } + + public CheckTypesResult checkExprTypeBounds() { + CheckTypesResult result = new CheckTypesResult(); + + Exprent param1 = lstOperands.get(0); + VarType type1 = param1.getExprType(); + Exprent param2 = null; + VarType type2 = null; + + if(lstOperands.size() > 1) { + param2 = lstOperands.get(1); + type2 = param2.getExprType(); + } + + switch(functype) { + case FUNCTION_IIF: + VarType supertype = getExprType(); + if(supertype == null) { + supertype = getExprType(); + } + result.addMinTypeExprent(param1, VarType.VARTYPE_BOOLEAN); + result.addMinTypeExprent(param2, VarType.getMinTypeInFamily(supertype.type_family)); + result.addMinTypeExprent(lstOperands.get(2), VarType.getMinTypeInFamily(supertype.type_family)); + break; + case FUNCTION_I2L: + case FUNCTION_I2F: + case FUNCTION_I2D: + case FUNCTION_I2B: + case FUNCTION_I2C: + case FUNCTION_I2S: + result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR); + result.addMaxTypeExprent(param1, VarType.VARTYPE_INT); + break; + case FUNCTION_IMM: + case FUNCTION_IPP: + case FUNCTION_MMI: + case FUNCTION_PPI: + result.addMinTypeExprent(param1, implicitType); + result.addMaxTypeExprent(param1, implicitType); + break; + case FUNCTION_ADD: + case FUNCTION_SUB: + case FUNCTION_MUL: + case FUNCTION_DIV: + case FUNCTION_REM: + case FUNCTION_SHL: + case FUNCTION_SHR: + case FUNCTION_USHR: + case FUNCTION_LT: + case FUNCTION_GE: + case FUNCTION_GT: + case FUNCTION_LE: + result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR); + case FUNCTION_BITNOT: + // case FUNCTION_BOOLNOT: + case FUNCTION_NEG: + result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR); + break; + case FUNCTION_AND: + case FUNCTION_OR: + case FUNCTION_XOR: + if(type1.type == CodeConstants.TYPE_BOOLEAN && + ((type1.convinfo & VarType.FALSEBOOLEAN) != 0 || type2.type != CodeConstants.TYPE_BOOLEAN)) { + result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR); + } + if(type2.type == CodeConstants.TYPE_BOOLEAN && + ((type2.convinfo & VarType.FALSEBOOLEAN) != 0 || type1.type != CodeConstants.TYPE_BOOLEAN)) { + result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR); + } + break; + case FUNCTION_EQ: + case FUNCTION_NE: + + if(type1.type == CodeConstants.TYPE_BOOLEAN) { + + if(type2.isStrictSuperset(type1)) { + result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR); + } else { + if(param1.type == Exprent.EXPRENT_CONST && !((ConstExprent)param1).hasBooleanValue()) { + if(param2.type != Exprent.EXPRENT_CONST || !((ConstExprent)param2).hasBooleanValue()) { // variable or not boolean constant + result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR); + } + } + } + } + + if(type2.type == CodeConstants.TYPE_BOOLEAN) { + + if(type1.isStrictSuperset(type2)) { + result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR); + } else { + if(param2.type == Exprent.EXPRENT_CONST && !((ConstExprent)param2).hasBooleanValue()) { + if(param1.type != Exprent.EXPRENT_CONST || !((ConstExprent)param1).hasBooleanValue()) { // variable or not boolean constant + result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR); + } + } + } + } + } + + return result; + } + + public List<Exprent> getAllExprents() { + List<Exprent> lst = new ArrayList<Exprent>(); + lst.addAll(lstOperands); + return lst; + } + + public Exprent copy() { + List<Exprent> lst = new ArrayList<Exprent>(); + for(Exprent expr: lstOperands) { + lst.add(expr.copy()); + } + FunctionExprent func = new FunctionExprent(functype, lst); + func.setImplicitType(implicitType); + + return func; + } + + public boolean equals(Object o) { + if(o!=null && o instanceof FunctionExprent) { + FunctionExprent fe = (FunctionExprent)o; + + return functype==fe.getFunctype() && + InterpreterUtil.equalLists(lstOperands, fe.getLstOperands()); // TODO: order of operands insignificant + } + return false; + } + + public void replaceExprent(Exprent oldexpr, Exprent newexpr) { + for(int i=0;i<lstOperands.size();i++) { + if(oldexpr == lstOperands.get(i)) { + lstOperands.set(i, newexpr); + } + } + } + + public String toJava(int indent) { + + if(functype <= FUNCTION_USHR) { + return wrapOperandString(lstOperands.get(0), false, indent)+operators[functype]+ + wrapOperandString(lstOperands.get(1), true, indent); + } + + if(functype >= FUNCTION_EQ) { + return wrapOperandString(lstOperands.get(0), false, indent)+operators[functype-FUNCTION_EQ+11]+ + wrapOperandString(lstOperands.get(1), true, indent); + } + + switch(functype) { + case FUNCTION_BITNOT: + return "~"+wrapOperandString(lstOperands.get(0), true, indent); + case FUNCTION_BOOLNOT: + return "!"+wrapOperandString(lstOperands.get(0), true, indent); + case FUNCTION_NEG: + return "-"+wrapOperandString(lstOperands.get(0), true, indent); + case FUNCTION_CAST: + return "("+lstOperands.get(1).toJava(indent)+")"+wrapOperandString(lstOperands.get(0), true, indent); + case FUNCTION_ARRAYLENGTH: + Exprent arr = lstOperands.get(0); + + String res = wrapOperandString(arr, false, indent); + if(arr.getExprType().arraydim == 0) { + VarType objarr = VarType.VARTYPE_OBJECT.copy(); + objarr.arraydim = 1; // type family does not change + + res = "(("+ExprProcessor.getCastTypeName(objarr)+")"+res+")"; + } + return res+".length"; + case FUNCTION_IIF: + return wrapOperandString(lstOperands.get(0), true, indent)+"?"+wrapOperandString(lstOperands.get(1), true, indent)+":"+ + wrapOperandString(lstOperands.get(2), true, indent); + case FUNCTION_IPP: + return wrapOperandString(lstOperands.get(0), true, indent)+"++"; + case FUNCTION_PPI: + return "++"+wrapOperandString(lstOperands.get(0), true, indent); + case FUNCTION_IMM: + return wrapOperandString(lstOperands.get(0), true, indent)+"--"; + case FUNCTION_MMI: + return "--"+wrapOperandString(lstOperands.get(0), true, indent); + case FUNCTION_INSTANCEOF: + return wrapOperandString(lstOperands.get(0), true, indent)+" instanceof "+wrapOperandString(lstOperands.get(1), true, indent); + } + + if(functype <= FUNCTION_I2S) { + return "("+ExprProcessor.getTypeName(types[functype - FUNCTION_I2L])+")"+wrapOperandString(lstOperands.get(0), true, indent); + } + +// return "<unknown function>"; + throw new RuntimeException("invalid function"); + } + + public int getPrecedence() { + return getPrecedence(functype); + } + + public static int getPrecedence(int func) { + return precedence[func]; + } + + public VarType getSimpleCastType() { + return types[functype - FUNCTION_I2L]; + } + + private String wrapOperandString(Exprent expr, boolean eq, int indent) { + + int myprec = getPrecedence(); + int exprprec = expr.getPrecedence(); + + boolean parentheses = exprprec > myprec; + if(!parentheses && eq) { + parentheses = (exprprec == myprec); + if(parentheses) { + if(expr.type == Exprent.EXPRENT_FUNCTION && + ((FunctionExprent)expr).getFunctype() == functype) { + parentheses = !associativity.contains(functype); + } + } + } + + String res = expr.toJava(indent); + + if(parentheses) { + res = "("+res+")"; + } + + return res; + } + + private VarType getMaxVarType(VarType[] arr) { + + int[] types = new int[] {CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_LONG}; + VarType[] vartypes = new VarType[] {VarType.VARTYPE_DOUBLE, VarType.VARTYPE_FLOAT, VarType.VARTYPE_LONG}; + + for(int i=0;i<types.length;i++) { + for(int j=0;j<arr.length;j++) { + if(arr[j].type == types[i]) { + return vartypes[i]; + } + } + } + + return VarType.VARTYPE_INT; + } + + // ***************************************************************************** + // getter and setter methods + // ***************************************************************************** + + public int getFunctype() { + return functype; + } + + public void setFunctype(int functype) { + this.functype = functype; + } + + public List<Exprent> getLstOperands() { + return lstOperands; + } + + public void setLstOperands(List<Exprent> lstOperands) { + this.lstOperands = lstOperands; + } + + public VarType getImplicitType() { + return implicitType; + } + + public void setImplicitType(VarType implicitType) { + this.implicitType = implicitType; + } + +} + |