diff options
Diffstat (limited to 'plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java')
-rw-r--r-- | plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java | 615 |
1 files changed, 615 insertions, 0 deletions
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java new file mode 100644 index 000000000000..4fa2ab385cee --- /dev/null +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java @@ -0,0 +1,615 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.java.decompiler.modules.decompiler.exps; + +import org.jetbrains.java.decompiler.code.CodeConstants; +import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; +import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; +import org.jetbrains.java.decompiler.struct.gen.VarType; +import org.jetbrains.java.decompiler.util.InterpreterUtil; +import org.jetbrains.java.decompiler.util.ListStack; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + + +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 || 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: + case FUNCTION_EQ: + case FUNCTION_NE: { + if (type1.type == CodeConstants.TYPE_BOOLEAN) { + + if (type2.isStrictSuperset(type1)) { + + result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR); + } + else { // both are booleans + + boolean param1_false_boolean = + type1.isFalseBoolean() || (param1.type == Exprent.EXPRENT_CONST && !((ConstExprent)param1).hasBooleanValue()); + boolean param2_false_boolean = + type1.isFalseBoolean() || (param2.type == Exprent.EXPRENT_CONST && !((ConstExprent)param2).hasBooleanValue()); + + if (param1_false_boolean || param2_false_boolean) { + result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR); + result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR); + } + } + } + else if (type2.type == CodeConstants.TYPE_BOOLEAN) { + + if (type1.isStrictSuperset(type2)) { + 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 == this) return true; + if (o == null || !(o instanceof FunctionExprent)) return false; + + FunctionExprent fe = (FunctionExprent)o; + return functype == fe.getFunctype() && + InterpreterUtil.equalLists(lstOperands, fe.getLstOperands()); // TODO: order of operands insignificant + } + + 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); + case FUNCTION_LCMP: // shouldn't appear in the final code + return "__lcmp__(" + + wrapOperandString(lstOperands.get(0), true, indent) + + "," + + wrapOperandString(lstOperands.get(1), true, indent) + + ")"; + case FUNCTION_FCMPL: // shouldn't appear in the final code + return "__fcmpl__(" + + wrapOperandString(lstOperands.get(0), true, indent) + + "," + + wrapOperandString(lstOperands.get(1), true, indent) + + ")"; + case FUNCTION_FCMPG: // shouldn't appear in the final code + return "__fcmpg__(" + + wrapOperandString(lstOperands.get(0), true, indent) + + "," + + wrapOperandString(lstOperands.get(1), true, indent) + + ")"; + case FUNCTION_DCMPL: // shouldn't appear in the final code + return "__dcmpl__(" + + wrapOperandString(lstOperands.get(0), true, indent) + + "," + + wrapOperandString(lstOperands.get(1), true, indent) + + ")"; + case FUNCTION_DCMPG: // shouldn't appear in the final code + return "__dcmpg__(" + + wrapOperandString(lstOperands.get(0), true, indent) + + "," + + 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 static 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; + } +} + |