diff --git a/jode/jode/expr/ArrayLengthOperator.java b/jode/jode/expr/ArrayLengthOperator.java
index eca6a55..e4c128f 100644
--- a/jode/jode/expr/ArrayLengthOperator.java
+++ b/jode/jode/expr/ArrayLengthOperator.java
@@ -23,33 +23,25 @@ import jode.decompiler.TabbedPrintWriter;
public class ArrayLengthOperator extends Operator {
- Type arrayType;
-
public ArrayLengthOperator() {
super(Type.tInt, 0);
- arrayType = Type.tArray(Type.tUnknown);
+ initOperands(1);
}
public int getPriority() {
return 950;
}
- public int getOperandCount() {
- return 1;
- }
-
- public Type getOperandType(int i) {
- return arrayType;
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tArray(Type.tUnknown));
}
- public void setOperandType(Type[] types) {
- arrayType = arrayType.intersection(types[0]);
+ public void updateType() {
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
- operands[0].dumpExpression(writer, 900);
+ subExpressions[0].dumpExpression(writer, 900);
writer.print(".length");
}
}
diff --git a/jode/jode/expr/ArrayLoadOperator.java b/jode/jode/expr/ArrayLoadOperator.java
index 024f425..161ee1b 100644
--- a/jode/jode/expr/ArrayLoadOperator.java
+++ b/jode/jode/expr/ArrayLoadOperator.java
@@ -22,46 +22,37 @@ import jode.type.Type;
import jode.type.ArrayType;
import jode.decompiler.TabbedPrintWriter;
-public class ArrayLoadOperator extends SimpleOperator {
+public class ArrayLoadOperator extends Operator {
String value;
public ArrayLoadOperator(Type type) {
- super(type, 0, 2);
- operandTypes[0] = Type.tArray(type);
- operandTypes[1] = Type.tInt;
+ super(type, 0);
+ initOperands(2);
}
public int getPriority() {
return 950;
}
- /**
- * Sets the return type of this operator.
- */
- public void setType(Type type) {
- if (!type.equals(this.type)) {
- super.setType(type);
- operandTypes[0] = Type.tArray(type);
- }
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tSubType(Type.tArray(type)));
+ subExpressions[1].setType(Type.tSubType(Type.tInt));
}
- public void setOperandType(Type[] t) {
- super.setOperandType(t);
- if (operandTypes[0] == Type.tError)
- type = Type.tError;
- else if (operandTypes[0] instanceof ArrayType)
- type = type.intersection
- (((ArrayType)operandTypes[0]).getElementType());
- else
- throw new jode.AssertError("No Array type: "+operandTypes[0]);
+ public void updateType() {
+ Type subType = Type.tSuperType(subExpressions[0].getType())
+ .intersection(Type.tArray(type));
+ if (!(subType instanceof ArrayType))
+ updateParentType(Type.tError);
+ else
+ updateParentType(((ArrayType)subType).getElementType());
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
- operands[0].dumpExpression(writer, 950);
+ subExpressions[0].dumpExpression(writer, 950);
writer.print("[");
- operands[1].dumpExpression(writer, 0);
+ subExpressions[1].dumpExpression(writer, 0);
writer.print("]");
}
}
diff --git a/jode/jode/expr/ArrayStoreOperator.java b/jode/jode/expr/ArrayStoreOperator.java
index 9d5e5f0..a565889 100644
--- a/jode/jode/expr/ArrayStoreOperator.java
+++ b/jode/jode/expr/ArrayStoreOperator.java
@@ -22,53 +22,40 @@ import jode.type.Type;
import jode.type.ArrayType;
import jode.decompiler.TabbedPrintWriter;
-public class ArrayStoreOperator extends StoreInstruction {
- Type indexType;
-
- public ArrayStoreOperator(Type type, int operator) {
- super(type, operator);
- indexType = Type.tInt;
- }
+public class ArrayStoreOperator extends LValueExpression {
public ArrayStoreOperator(Type type) {
- this(type, ASSIGN_OP);
+ super(type);
+ initOperands(2);
}
-
public boolean matches(Operator loadop) {
return loadop instanceof ArrayLoadOperator;
}
- public int getLValuePriority() {
+ public int getPriority() {
return 950;
}
- public int getLValueOperandCount() {
- return 2;
- }
-
- public Type getLValueOperandType(int i) {
- if (i == 0)
- return Type.tArray(lvalueType);
- else
- return indexType;
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tArray(type));
+ subExpressions[1].setType(Type.tSubType(Type.tInt));
}
- public void setLValueOperandType(Type[] t) {
- indexType = indexType.intersection(t[1]);
- Type arrayType = t[0].intersection(Type.tArray(lvalueType));
- if (arrayType == Type.tError)
- lvalueType = Type.tError;
- else
- lvalueType = ((ArrayType)arrayType).getElementType();
+ public void updateType() {
+ Type subType = subExpressions[0].getType()
+ .intersection(Type.tArray(type));
+ if (!(subType instanceof ArrayType))
+ updateParentType(Type.tError);
+ else
+ updateParentType(((ArrayType)subType).getElementType());
}
- public void dumpLValue(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
- operands[0].dumpExpression(writer, 950);
+ subExpressions[0].dumpExpression(writer, 950);
writer.print("[");
- operands[1].dumpExpression(writer, 0);
+ subExpressions[1].dumpExpression(writer, 0);
writer.print("]");
}
}
diff --git a/jode/jode/expr/BinaryOperator.java b/jode/jode/expr/BinaryOperator.java
index adea755..cbeb926 100644
--- a/jode/jode/expr/BinaryOperator.java
+++ b/jode/jode/expr/BinaryOperator.java
@@ -21,14 +21,15 @@ package jode.expr;
import jode.type.Type;
import jode.decompiler.TabbedPrintWriter;
-public class BinaryOperator extends SimpleOperator {
+public class BinaryOperator extends Operator {
public BinaryOperator(Type type, int op) {
- super(type, op, 2);
+ super(type, op);
+ initOperands(2);
}
public int getPriority() {
- switch (operator) {
+ switch (operatorIndex) {
case 1: case 2:
return 610;
case 3: case 4: case 5:
@@ -52,28 +53,42 @@ public class BinaryOperator extends SimpleOperator {
throw new RuntimeException("Illegal operator");
}
- public int getOperandPriority(int i) {
- return getPriority() + i;
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tSubType(type));
+ subExpressions[1].setType(Type.tSubType(type));
}
- public Type getOperandType(int i) {
- return type;
+ public void updateType() {
+ Type leftType = Type.tSuperType(subExpressions[0].getType());
+ Type rightType = Type.tSuperType(subExpressions[1].getType());
+ subExpressions[0].setType(Type.tSubType(rightType));
+ subExpressions[1].setType(Type.tSubType(leftType));
+ /* propagate hints? XXX */
+ updateParentType(leftType.intersection(rightType));
}
- public void setOperandType(Type[] inputTypes) {
- setType(inputTypes[0].intersection(inputTypes[1]));
+ public Expression negate() {
+ if (getOperatorIndex() == LOG_AND_OP ||
+ getOperatorIndex() == LOG_OR_OP) {
+ setOperatorIndex(getOperatorIndex() ^ 1);
+ for (int i=0; i< 2; i++) {
+ subExpressions[i] = subExpressions[i].negate();
+ subExpressions[i].parent = this;
+ }
+ return this;
+ }
+ return super.negate();
}
- public boolean equals(Object o) {
+ public boolean opEquals(Operator o) {
return (o instanceof BinaryOperator) &&
- ((BinaryOperator)o).operator == operator;
+ o.operatorIndex == operatorIndex;
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
- operands[0].dumpExpression(writer, getPriority());
+ subExpressions[0].dumpExpression(writer, getPriority());
writer.print(getOperatorString());
- operands[1].dumpExpression(writer, getPriority()+1);
+ subExpressions[1].dumpExpression(writer, getPriority()+1);
}
}
diff --git a/jode/jode/expr/CheckCastOperator.java b/jode/jode/expr/CheckCastOperator.java
index 2960448..429e991 100644
--- a/jode/jode/expr/CheckCastOperator.java
+++ b/jode/jode/expr/CheckCastOperator.java
@@ -21,25 +21,27 @@ package jode.expr;
import jode.type.Type;
import jode.decompiler.TabbedPrintWriter;
-public class CheckCastOperator extends SimpleOperator {
+public class CheckCastOperator extends Operator {
Type castType;
public CheckCastOperator(Type type) {
- super(type, 0, 1);
+ super(type, 0);
castType = type;
- operandTypes[0] = Type.tUnknown;
+ initOperands(1);
}
public int getPriority() {
return 700;
}
- public void setOperandType(Type[] type) {
- super.setOperandType(type);
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tUObject);
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void updateType() {
+ }
+
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
writer.print("(");
writer.printType(castType);
@@ -49,12 +51,12 @@ public class CheckCastOperator extends SimpleOperator {
* to the common super type before. This cases always give a runtime
* error, but we want to decompile even bad programs.
*/
- Type superType = castType.getCastHelper(operands[0].getType());
+ Type superType = castType.getCastHelper(subExpressions[0].getType());
if (superType != null) {
writer.print("(");
writer.printType(superType);
writer.print(") ");
}
- operands[0].dumpExpression(writer, 700);
+ subExpressions[0].dumpExpression(writer, 700);
}
}
diff --git a/jode/jode/expr/CheckNullOperator.java b/jode/jode/expr/CheckNullOperator.java
index 6dfd6ac..758ec5a 100644
--- a/jode/jode/expr/CheckNullOperator.java
+++ b/jode/jode/expr/CheckNullOperator.java
@@ -40,56 +40,38 @@ import jode.decompiler.TabbedPrintWriter;
*/
public class CheckNullOperator extends Operator {
-
- Type operandType;
LocalInfo local;
public CheckNullOperator(Type type, LocalInfo li) {
super(type, 0);
- operandType = type;
local = li;
- local.setType(type);
- }
-
- public int getOperandCount() {
- return 1;
+ initOperands(1);
}
public int getPriority() {
return 200;
}
- public int getOperandPriority(int i) {
- return 0;
- }
-
- public Type getOperandType(int i) {
- return operandType;
+ public void updateSubTypes() {
+ local.setType(type);
+ subExpressions[0].setType(Type.tSubType(type));
}
- public void setOperandType(Type[] inputTypes) {
- operandType = operandType.intersection(inputTypes[0]);
- type = operandType;
- local.setType(type);
+ public void updateType() {
+ Type newType = Type.tSuperType(subExpressions[0].getType())
+ .intersection(type);
+ local.setType(newType);
+ updateParentType(newType);
}
public void removeLocal() {
local.remove();
}
- /**
- * Sets the return type of this operator.
- */
- public void setType(Type newType) {
- type = operandType = operandType.intersection(newType);
- local.setType(type);
- }
-
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
writer.print("("+local.getName()+" = ");
- operands[0].dumpExpression(writer, 0);
+ subExpressions[0].dumpExpression(writer, 0);
writer.print(").getClass() != null ? "+local.getName()+" : null");
}
}
diff --git a/jode/jode/expr/ClassFieldOperator.java b/jode/jode/expr/ClassFieldOperator.java
index 4a9dfa0..30e080c 100644
--- a/jode/jode/expr/ClassFieldOperator.java
+++ b/jode/jode/expr/ClassFieldOperator.java
@@ -34,8 +34,7 @@ public class ClassFieldOperator extends NoArgOperator {
return 950;
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
writer.printType(classType);
writer.print(".class");
diff --git a/jode/jode/expr/CombineableOperator.java b/jode/jode/expr/CombineableOperator.java
index c722d72..cae38b3 100644
--- a/jode/jode/expr/CombineableOperator.java
+++ b/jode/jode/expr/CombineableOperator.java
@@ -19,7 +19,15 @@
package jode.expr;
-public interface CombineableOperator extends MatchableOperator {
+public interface CombineableOperator {
+ /**
+ * Returns the LValue.
+ */
+ public LValueExpression getLValue();
+ /**
+ * Checks if the loadOp is combinable with the lvalue.
+ */
+ public boolean lvalueMatches(Operator loadOp);
/**
* Make this operator return a value compatible with the loadOp
* that it should replace.
diff --git a/jode/jode/expr/CompareBinaryOperator.java b/jode/jode/expr/CompareBinaryOperator.java
index 22f644b..e708737 100644
--- a/jode/jode/expr/CompareBinaryOperator.java
+++ b/jode/jode/expr/CompareBinaryOperator.java
@@ -21,10 +21,13 @@ package jode.expr;
import jode.type.Type;
import jode.decompiler.TabbedPrintWriter;
-public class CompareBinaryOperator extends SimpleOperator {
+public class CompareBinaryOperator extends Operator {
+ Type compareType;
+
public CompareBinaryOperator(Type type, int op) {
- super(Type.tBoolean, op, 2);
- operandTypes[0] = operandTypes[1] = type;
+ super(Type.tBoolean, op);
+ compareType = type;
+ initOperands(2);
}
public int getPriority() {
@@ -41,22 +44,41 @@ public class CompareBinaryOperator extends SimpleOperator {
throw new RuntimeException("Illegal operator");
}
- public void setOperandType(Type[] inputTypes) {
- super.setOperandType(inputTypes);
- operandTypes[0] = operandTypes[1] =
- operandTypes[0].intersection(operandTypes[1]);
+ public Type getCompareType() {
+ return compareType;
+ }
+
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tSubType(compareType));
+ subExpressions[1].setType(Type.tSubType(compareType));
+ }
+
+ public void updateType() {
+ Type leftType = Type.tSuperType(subExpressions[0].getType());
+ Type rightType = Type.tSuperType(subExpressions[1].getType());
+ subExpressions[0].setType(Type.tSubType(rightType));
+ subExpressions[1].setType(Type.tSubType(leftType));
+ /* propagate hints? XXX */
+ }
+
+ public Expression negate() {
+ if ((getType() != Type.tFloat && getType() != Type.tDouble)
+ || getOperatorIndex() <= NOTEQUALS_OP) {
+ setOperatorIndex(getOperatorIndex() ^ 1);
+ return this;
+ }
+ return super.negate();
}
- public boolean equals(Object o) {
- return (o instanceof CompareBinaryOperator) &&
- ((CompareBinaryOperator)o).operator == operator;
+ public boolean opEquals(Operator o) {
+ return (o instanceof CompareBinaryOperator)
+ && o.operatorIndex == operatorIndex;
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
- operands[0].dumpExpression(writer, getPriority());
+ subExpressions[0].dumpExpression(writer, getPriority());
writer.print(getOperatorString());
- operands[1].dumpExpression(writer, getPriority()+1);
+ subExpressions[1].dumpExpression(writer, getPriority()+1);
}
}
diff --git a/jode/jode/expr/CompareToIntOperator.java b/jode/jode/expr/CompareToIntOperator.java
index 2f75e95..8c51ceb 100644
--- a/jode/jode/expr/CompareToIntOperator.java
+++ b/jode/jode/expr/CompareToIntOperator.java
@@ -21,35 +21,43 @@ package jode.expr;
import jode.type.Type;
import jode.decompiler.TabbedPrintWriter;
-public class CompareToIntOperator extends SimpleOperator {
+public class CompareToIntOperator extends Operator {
+ boolean allowsNAN;
boolean greaterOnNAN;
+ Type compareType;
public CompareToIntOperator(Type type, boolean greaterOnNAN) {
- super(Type.tInt, 0, 2);
- operandTypes[0] = operandTypes[1] = type;
+ super(Type.tInt, 0);
+ compareType = type;
+ this.allowsNAN = (type == Type.tFloat || type == Type.tDouble);
this.greaterOnNAN = greaterOnNAN;
+ initOperands(2);
}
public int getPriority() {
return 499;
}
- public void setOperandType(Type[] inputTypes) {
- super.setOperandType(inputTypes);
- Type operandType = operandTypes[0].intersection(operandTypes[1]);
- operandTypes[0] = operandTypes[1] = operandType;
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tSubType(compareType));
+ subExpressions[1].setType(Type.tSubType(compareType));
}
- public boolean equals(Object o) {
+ public void updateType() {
+ }
+
+ public boolean opEquals(Operator o) {
return (o instanceof CompareToIntOperator);
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException
{
- operands[0].dumpExpression(writer, 550);
- writer.print(" <=>" + (greaterOnNAN ? 'g' : 'l') + ' ');
- operands[1].dumpExpression(writer, 551);
+ subExpressions[0].dumpExpression(writer, 550);
+ writer.print(" <=>");
+ if (allowsNAN)
+ writer.print(greaterOnNAN ? "g" : "l");
+ writer.print(" ");
+ subExpressions[1].dumpExpression(writer, 551);
}
}
diff --git a/jode/jode/expr/CompareUnaryOperator.java b/jode/jode/expr/CompareUnaryOperator.java
index 90047b4..11894cf 100644
--- a/jode/jode/expr/CompareUnaryOperator.java
+++ b/jode/jode/expr/CompareUnaryOperator.java
@@ -21,13 +21,15 @@ package jode.expr;
import jode.type.Type;
import jode.decompiler.TabbedPrintWriter;
-public class CompareUnaryOperator extends SimpleOperator {
+public class CompareUnaryOperator extends Operator {
boolean objectType;
+ Type compareType;
public CompareUnaryOperator(Type type, int op) {
- super(Type.tBoolean, op, 1);
- operandTypes[0] = type;
+ super(Type.tBoolean, op);
+ compareType = type;
objectType = (type.isOfType(Type.tUObject));
+ initOperands(1);
}
public int getPriority() {
@@ -44,15 +46,69 @@ public class CompareUnaryOperator extends SimpleOperator {
throw new RuntimeException("Illegal operator");
}
- public boolean equals(Object o) {
- return (o instanceof CompareUnaryOperator) &&
- ((CompareUnaryOperator)o).operator == operator;
+ public Type getCompareType() {
+ return compareType;
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tSubType(compareType));
+ }
+
+ public void updateType() {
+ }
+
+ public Expression simplify() {
+ if (subExpressions[0] instanceof CompareToIntOperator) {
+
+ CompareToIntOperator cmpOp
+ = (CompareToIntOperator) subExpressions[0];
+
+ boolean negated = false;
+ int opIndex = getOperatorIndex();
+ if (cmpOp.allowsNAN && getOperatorIndex() > NOTEQUALS_OP) {
+ if (cmpOp.greaterOnNAN ==
+ (opIndex == GREATEREQ_OP || opIndex == GREATER_OP)) {
+ negated = true;
+ opIndex ^= 1;
+ }
+ }
+ Expression newOp = new CompareBinaryOperator
+ (cmpOp.compareType, opIndex)
+ .addOperand(cmpOp.subExpressions[1])
+ .addOperand(cmpOp.subExpressions[0]);
+
+ if (negated)
+ return newOp.negate().simplify();
+ return newOp.simplify();
+ }
+ if (subExpressions[0].getType().isOfType(Type.tBoolean)) {
+ /* xx == false */
+ if (getOperatorIndex() == EQUALS_OP)
+ return subExpressions[0].negate().simplify();
+ /* xx != false */
+ if (getOperatorIndex() == NOTEQUALS_OP)
+ return subExpressions[0].simplify();
+ }
+ return super.simplify();
+ }
+
+ public Expression negate() {
+ if ((getType() != Type.tFloat && getType() != Type.tDouble)
+ || getOperatorIndex() <= NOTEQUALS_OP) {
+ setOperatorIndex(getOperatorIndex() ^ 1);
+ return this;
+ }
+ return super.negate();
+ }
+
+ public boolean opEquals(Operator o) {
+ return (o instanceof CompareUnaryOperator)
+ && o.getOperatorIndex() == getOperatorIndex();
+ }
+
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
- operands[0].dumpExpression(writer, getPriority());
+ subExpressions[0].dumpExpression(writer, getPriority());
writer.print(getOperatorString());
writer.print(objectType?"null":"0");
}
diff --git a/jode/jode/expr/ConstOperator.java b/jode/jode/expr/ConstOperator.java
index b994560..aab1725 100644
--- a/jode/jode/expr/ConstOperator.java
+++ b/jode/jode/expr/ConstOperator.java
@@ -34,11 +34,11 @@ public class ConstOperator extends NoArgOperator {
public ConstOperator(Object constant) {
super(Type.tUnknown);
if (constant instanceof Boolean) {
- setType(Type.tBoolean);
+ updateParentType(Type.tBoolean);
constant = new Integer(((Boolean)constant).booleanValue() ? 1 : 0);
} else if (constant instanceof Integer) {
int intVal = ((Integer) constant).intValue();
- setType
+ updateParentType
((intVal == 0 || intVal == 1) ? tBoolConstInt
: (intVal < Short.MIN_VALUE
|| intVal > Character.MAX_VALUE) ? Type.tInt
@@ -54,15 +54,15 @@ public class ConstOperator extends NoArgOperator {
? IntegerType.IT_S|IntegerType.IT_C|IntegerType.IT_I
: IntegerType.IT_C|IntegerType.IT_I));
} else if (constant instanceof Long)
- setType(Type.tLong);
+ updateParentType(Type.tLong);
else if (constant instanceof Float)
- setType(Type.tFloat);
+ updateParentType(Type.tFloat);
else if (constant instanceof Double)
- setType(Type.tDouble);
+ updateParentType(Type.tDouble);
else if (constant instanceof String)
- setType(Type.tString);
+ updateParentType(Type.tString);
else if (constant == null)
- setType(Type.tUObject);
+ updateParentType(Type.tUObject);
else
throw new IllegalArgumentException("Illegal constant type: "
+constant.getClass());
@@ -77,7 +77,7 @@ public class ConstOperator extends NoArgOperator {
return 1000;
}
- public boolean equals(Object o) {
+ public boolean opEquals(Operator o) {
if (o instanceof ConstOperator) {
Object otherValue = ((ConstOperator)o).value;
return value == null
@@ -173,7 +173,7 @@ public class ConstOperator extends NoArgOperator {
} else if (type.equals(Type.tString)) {
return quoted(strVal);
} else if (parent != null) {
- int opindex = parent.getOperator().getOperatorIndex();
+ int opindex = parent.getOperatorIndex();
if (opindex >= OPASSIGN_OP + ADD_OP
&& opindex < OPASSIGN_OP + ASSIGN_OP)
opindex -= OPASSIGN_OP;
@@ -204,8 +204,9 @@ public class ConstOperator extends NoArgOperator {
&& (type.getHint().equals(Type.tByte)
|| type.getHint().equals(Type.tShort))
&& !isInitializer
- && (parent == null
- || parent.getOperator().getOperatorIndex() != ASSIGN_OP)) {
+ && !(parent instanceof StoreInstruction
+ && parent.getOperatorIndex() != ASSIGN_OP
+ && parent.subExpressions[1] == this)) {
/* One of the strange things in java. All constants
* are int and must be explicitly casted to byte,...,short.
* But in assignments and initializers this cast is unnecessary.
@@ -217,8 +218,7 @@ public class ConstOperator extends NoArgOperator {
return strVal;
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
writer.print(toString());
}
diff --git a/jode/jode/expr/ConstantArrayOperator.java b/jode/jode/expr/ConstantArrayOperator.java
index 1ef7724..8ecab4b 100644
--- a/jode/jode/expr/ConstantArrayOperator.java
+++ b/jode/jode/expr/ConstantArrayOperator.java
@@ -22,18 +22,16 @@ import jode.type.Type;
import jode.type.ArrayType;
import jode.decompiler.TabbedPrintWriter;
-public class ConstantArrayOperator extends NoArgOperator {
-
+public class ConstantArrayOperator extends Operator {
+ boolean isInitializer;
ConstOperator empty;
- Expression[] values;
Type argType;
- boolean isInitializer;
public ConstantArrayOperator(Type type, int size) {
super(type);
- values = new Expression[size];
argType = (type instanceof ArrayType)
? Type.tSubType(((ArrayType)type).getElementType()) : Type.tError;
+
Object emptyVal;
if (argType == type.tError || argType.isOfType(Type.tUObject))
emptyVal = null;
@@ -48,31 +46,33 @@ public class ConstantArrayOperator extends NoArgOperator {
else
throw new IllegalArgumentException("Illegal Type: "+argType);
- empty = new ConstOperator(emptyVal);
+ empty = new ConstOperator(emptyVal);
empty.setType(argType);
empty.makeInitializer();
+ initOperands(size);
+ for (int i=0; i < subExpressions.length; i++)
+ setSubExpressions(i, empty);
}
- public void setType(Type newtype) {
- super.setType(newtype);
- Type newArgType = (this.type instanceof ArrayType)
- ? Type.tSubType(((ArrayType)this.type).getElementType())
- : Type.tError;
- if (!newArgType.equals(argType)) {
- argType = newArgType;
- empty.setType(argType);
- for (int i=0; i< values.length; i++)
- if (values[i] != null)
- values[i].setType(argType);
- }
+ public void updateSubTypes() {
+ argType = (type instanceof ArrayType)
+ ? Type.tSubType(((ArrayType)type).getElementType()) : Type.tError;
+ for (int i=0; i< subExpressions.length; i++)
+ if (subExpressions[i] != null)
+ subExpressions[i].setType(argType);
+ }
+
+ public void updateType() {
}
public boolean setValue(int index, Expression value) {
- if (index < 0 || index > values.length || values[index] != null)
+ if (index < 0 ||
+ index > subExpressions.length ||
+ subExpressions[index] != empty)
return false;
value.setType(argType);
setType(Type.tSuperType(Type.tArray(value.getType())));
- values[index] = value;
+ subExpressions[index] = value;
value.parent = this;
value.makeInitializer();
return true;
@@ -87,15 +87,14 @@ public class ConstantArrayOperator extends NoArgOperator {
}
public Expression simplify() {
- for (int i=0; i< values.length; i++) {
- if (values[i] != null)
- values[i] = values[i].simplify();
+ for (int i=0; i< subExpressions.length; i++) {
+ if (subExpressions[i] != null)
+ subExpressions[i] = subExpressions[i].simplify();
}
return this;
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
if (!isInitializer) {
writer.print("new ");
@@ -104,15 +103,15 @@ public class ConstantArrayOperator extends NoArgOperator {
}
writer.openBraceNoSpace();
writer.tab();
- for (int i=0; i< values.length; i++) {
+ for (int i=0; i< subExpressions.length; i++) {
if (i>0) {
if (i % 10 == 0)
writer.println(",");
else
writer.print(", ");
}
- if (values[i] != null)
- values[i].dumpExpression(writer, 0);
+ if (subExpressions[i] != null)
+ subExpressions[i].dumpExpression(writer, 0);
else
empty.dumpExpression(writer, 0);
}
diff --git a/jode/jode/expr/ConstructorOperator.java b/jode/jode/expr/ConstructorOperator.java
index 1b3446a..5240dd6 100644
--- a/jode/jode/expr/ConstructorOperator.java
+++ b/jode/jode/expr/ConstructorOperator.java
@@ -18,12 +18,15 @@
*/
package jode.expr;
+import java.lang.reflect.Modifier;
+
import jode.type.Type;
import jode.type.NullType;
import jode.type.ClassInterfacesType;
import jode.type.MethodType;
import jode.bytecode.ClassInfo;
import jode.bytecode.InnerClassInfo;
+import jode.bytecode.Reference;
import jode.Decompiler;
import jode.decompiler.CodeAnalyzer;
import jode.decompiler.ClassAnalyzer;
@@ -38,11 +41,22 @@ public class ConstructorOperator extends Operator
ClassAnalyzer anonymousClass = null;
boolean removedCheckNull = false;
+ public ConstructorOperator(Reference ref, CodeAnalyzer codeAna,
+ boolean isVoid) {
+ super(isVoid ? Type.tVoid : Type.tType(ref.getClazz()), 0);
+ this.classType = Type.tType(ref.getClazz());
+ this.methodType = Type.tMethod(ref.getType());
+ this.codeAnalyzer = codeAna;
+ initOperands(methodType.getParameterTypes().length);
+ checkAnonymousClasses();
+ }
+
public ConstructorOperator(InvokeOperator invoke, boolean isVoid) {
super(isVoid ? Type.tVoid : invoke.getClassType(), 0);
this.classType = invoke.getClassType();
this.methodType = invoke.getMethodType();
this.codeAnalyzer = invoke.codeAnalyzer;
+ initOperands(methodType.getParameterTypes().length);
checkAnonymousClasses();
}
@@ -54,16 +68,6 @@ public class ConstructorOperator extends Operator
return codeAnalyzer;
}
- /**
- * Checks if the value of the given expression can change, due to
- * side effects in this expression. If this returns false, the
- * expression can safely be moved behind the current expresion.
- * @param expr the expression that should not change.
- */
- public boolean hasSideEffects(Expression expr) {
- return expr.containsConflictingLoad(this);
- }
-
/**
* Checks if the value of the operator can be changed by this expression.
*/
@@ -77,30 +81,46 @@ public class ConstructorOperator extends Operator
return 950;
}
- public int getOperandCount() {
- return methodType.getParameterTypes().length;
- }
-
- public int getOperandPriority(int i) {
- return 0;
- }
-
public Type getClassType() {
return classType;
}
- public Type getOperandType(int i) {
- return methodType.getParameterTypes()[i];
+ public void updateSubTypes() {
+ Type[] paramTypes = methodType.getParameterTypes();
+ for (int i=0; i < paramTypes.length; i++)
+ subExpressions[i].setType(Type.tSubType(paramTypes[i]));
}
- public void setOperandType(Type types[]) {
+ public void updateType() {
}
public Expression simplifyStringBuffer() {
+ if (getClassType() == Type.tStringBuffer) {
+ if (methodType.getParameterTypes().length == 0)
+ return EMPTYSTRING;
+ if (methodType.getParameterTypes().length == 1
+ && methodType.getParameterTypes()[0].equals(Type.tString))
+ return subExpressions[0].simplifyString();
+ }
return (getClassType() == Type.tStringBuffer)
? EMPTYSTRING : null;
}
+ public Expression simplify() {
+ InnerClassInfo outer = getOuterClassInfo();
+ if (outer != null && outer.outer != null
+ && !Modifier.isStatic(outer.modifiers)
+ && (Decompiler.options & Decompiler.OPTION_INNER) != 0) {
+ if (subExpressions[0] instanceof CheckNullOperator) {
+ CheckNullOperator cno = (CheckNullOperator) subExpressions[0];
+ cno.removeLocal();
+ subExpressions[0] = cno.subExpressions[0];
+ removedCheckNull = true;
+ }
+ }
+ return super.simplify();
+ }
+
public ClassInfo getClassInfo() {
if (classType instanceof ClassInterfacesType) {
return ((ClassInterfacesType) classType).getClassInfo();
@@ -135,8 +155,7 @@ public class ConstructorOperator extends Operator
}
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
int arg = 0;
@@ -146,8 +165,10 @@ public class ConstructorOperator extends Operator
return;
}
InnerClassInfo outer = getOuterClassInfo();
- if (outer != null && outer.name != null) {
- Expression outExpr = operands[arg++];
+ if (outer != null && outer.outer != null
+ && !Modifier.isStatic(outer.modifiers)
+ && (Decompiler.options & Decompiler.OPTION_INNER) != 0) {
+ Expression outExpr = subExpressions[arg++];
if (!removedCheckNull && !(outExpr instanceof ThisOperator))
writer.print("MISSING CHECKNULL");
if (outExpr instanceof ThisOperator) {
@@ -180,10 +201,8 @@ public class ConstructorOperator extends Operator
for (int i = arg; i < methodType.getParameterTypes().length; i++) {
if (i>arg)
writer.print(", ");
- operands[i].dumpExpression(writer, 0);
+ subExpressions[i].dumpExpression(writer, 0);
}
writer.print(")");
}
}
-
-
diff --git a/jode/jode/expr/ConvertOperator.java b/jode/jode/expr/ConvertOperator.java
index 0556fdc..3f3a58d 100644
--- a/jode/jode/expr/ConvertOperator.java
+++ b/jode/jode/expr/ConvertOperator.java
@@ -27,29 +27,24 @@ public class ConvertOperator extends Operator {
public ConvertOperator(Type from, Type to) {
super(to, 0);
this.from = from;
+ initOperands(1);
}
public int getPriority() {
return 700;
}
- public int getOperandCount() {
- return 1;
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tSubType(from));
}
-
- public Type getOperandType(int i) {
- return from;
- }
-
- public void setOperandType(Type[] inputTypes) {
- from = from.intersection(inputTypes[0]);
+ public void updateType() {
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] ops) throws java.io.IOException {
+ public void dumpExpression(TabbedPrintWriter writer)
+ throws java.io.IOException {
writer.print("(");
writer.printType(type);
- writer.print(")");
- ops[0].dumpExpression(writer, 700);
+ writer.print(") ");
+ subExpressions[0].dumpExpression(writer, 700);
}
}
diff --git a/jode/jode/expr/Expression.java b/jode/jode/expr/Expression.java
index 5fb7464..9312f0a 100644
--- a/jode/jode/expr/Expression.java
+++ b/jode/jode/expr/Expression.java
@@ -21,50 +21,117 @@ package jode.expr;
import jode.type.Type;
import jode.GlobalOptions;
import jode.decompiler.TabbedPrintWriter;
+import jode.flow.VariableSet;
public abstract class Expression {
protected Type type;
- Expression parent = null;
+ Operator parent = null;
public Expression(Type type) {
this.type = type;
}
+ public void setType(Type otherType) {
+ Type newType = otherType.intersection(type);
+ if (type.equals(newType))
+ return;
+ if (newType == Type.tError && otherType != Type.tError) {
+ GlobalOptions.err.println("setType: Type error in "+this
+ +": merging "+type+" and "+otherType);
+ if (parent != null)
+ GlobalOptions.err.println("\tparent is "+parent);
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_TYPES) != 0)
+ Thread.dumpStack();
+ }
+ type = newType;
+ if (type != Type.tError)
+ updateSubTypes();
+ }
+
+ public void updateParentType(Type otherType) {
+ Type newType = otherType.intersection(type);
+ if (type.equals(newType))
+ return;
+
+ if (newType == Type.tError) {
+ if (otherType == Type.tError) {
+ // Don't propagate type errors.
+ return;
+ }
+ GlobalOptions.err.println("updateParentType: Type error in "
+ +this+": merging "+getType()
+ +" and "+otherType);
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_TYPES) != 0)
+ Thread.dumpStack();
+ }
+ type = newType;
+ if (parent != null)
+ parent.updateType();
+ }
+
+ /**
+ * Tells an expression that an inner expression may have changed and
+ * that the type should be recalculated.
+ *
+ * This may call setType of the caller again.
+ */
+ public abstract void updateType();
+
+ /**
+ * Tells an expression that an outer expression has changed our type
+ * and that the inner types should be recalculated.
+ */
+ public abstract void updateSubTypes();
+
public Type getType() {
return type;
}
- public Expression getParent() {
+ public Operator getParent() {
return parent;
}
- public void setType(Type otherType) {
- Type newType = type.intersection(otherType);
- if (newType == Type.tError
- && type != Type.tError && otherType != Type.tError)
- GlobalOptions.err.println("Type error in "+this+": "
- +"merging "+type+" and "+otherType);
- type = newType;
- }
- public void updateType() {
- if (parent != null)
- parent.updateType();
- }
+ /**
+ * Get priority of the operator.
+ * Currently this priorities are known:
+ *
- 1000 constant
+ *
- 950 new, .(field access), []
+ *
- 900 new[]
+ *
- 800 ++,-- (post)
+ *
- 700 ++,--(pre), +,-(unary), ~, !, cast
+ *
- 650 *,/, %
+ *
- 610 +,-
+ *
- 600 <<, >>, >>>
+ *
- 550 >, <, >=, <=, instanceof
+ *
- 500 ==, !=
+ *
- 450 &
+ *
- 420 ^
+ *
- 410 |
+ *
- 350 &&
+ *
- 310 ||
+ *
- 200 ?:
+ *
- 100 =, +=, -=, etc.
+ *
+ */
+ public abstract int getPriority();
/**
* Get the number of operands.
* @return The number of stack entries this expression needs.
*/
- public abstract int getOperandCount();
+ public abstract int getFreeOperandCount();
public abstract Expression addOperand(Expression op);
public Expression negate() {
Operator negop =
new UnaryOperator(Type.tBoolean, Operator.LOG_NOT_OP);
- return new ComplexExpression(negop, new Expression[] { this });
+ negop.addOperand(this);
+ return negop;
}
/**
@@ -74,7 +141,6 @@ public abstract class Expression {
* @param expr the expression that should not change.
*/
public boolean hasSideEffects(Expression expr) {
- // Most expression don't have side effects.
return false;
}
@@ -85,21 +151,20 @@ public abstract class Expression {
* @return 1, if it can, 0, if no match was found and -1, if a
* conflict was found. You may wish to check for >0.
*/
- public int canCombine(Expression e) {
-// jode.GlobalOptions.err.println("Try to combine "+e+" into "+this);
- return containsMatchingLoad(e)? 1 : 0;
+ public int canCombine(CombineableOperator combOp) {
+ return 0;
}
/**
* Checks if this expression contains a load, that matches the
- * given Expression (which should be a StoreInstruction/IIncOperator).
+ * given CombineableOperator (which must be an Operator)
* @param e The store expression.
* @return if this expression contains a matching load.
* @exception ClassCastException, if e.getOperator
* is not a CombineableOperator.
*/
- public boolean containsMatchingLoad(Expression e) {
- return ((CombineableOperator)e.getOperator()).matches(getOperator());
+ public boolean containsMatchingLoad(CombineableOperator e) {
+ return false;
}
/**
@@ -109,7 +174,7 @@ public abstract class Expression {
* @param op The combineable operator.
* @return if this expression contains a matching load. */
public boolean containsConflictingLoad(MatchableOperator op) {
- return op.matches(getOperator());
+ return false;
}
/**
@@ -122,14 +187,7 @@ public abstract class Expression {
* @exception ClassCastException, if e.getOperator
* is not a CombineableOperator.
*/
- public Expression combine(Expression e) {
- CombineableOperator op = (CombineableOperator) e.getOperator();
- if (op.matches(getOperator())) {
- op.makeNonVoid();
- /* Do not call setType, we don't want to intersect. */
- e.type = e.getOperator().getType();
- return e;
- }
+ public Expression combine(CombineableOperator comb) {
return null;
}
@@ -158,8 +216,6 @@ public abstract class Expression {
return null;
}
- public abstract Operator getOperator();
-
public void makeInitializer() {
}
@@ -167,24 +223,33 @@ public abstract class Expression {
return true;
}
+ public void fillInGenSet(VariableSet in, VariableSet gen) {
+ }
+
public abstract void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException;
public void dumpExpression(TabbedPrintWriter writer, int minPriority)
throws java.io.IOException {
boolean needParen1 = false, needParen2 = false;
- if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0) {
+ if (type == Type.tError) {
+ if (minPriority > 700) {
+ needParen1 = true;
+ writer.print("(");
+ }
+ writer.print("/*TYPE ERROR*/ ");
+ minPriority = 700;
+ }
+ else if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_TYPES) != 0) {
if (minPriority > 700) {
needParen1 = true;
writer.print("(");
}
- writer.print("("+getType()+") ");
+ writer.print("(TYPE "+type+") ");
minPriority = 700;
- } else if (getType() == Type.tError) {
- writer.print("(/*type error */");
- needParen1 = true;
}
- if (getOperator().getPriority() < minPriority) {
+ if (getPriority() < minPriority) {
needParen2 = true;
writer.print("(");
}
@@ -208,7 +273,6 @@ public abstract class Expression {
}
}
-
public boolean isVoid() {
return getType() == Type.tVoid;
}
diff --git a/jode/jode/expr/GetFieldOperator.java b/jode/jode/expr/GetFieldOperator.java
index df39f75..cc7cd4b 100644
--- a/jode/jode/expr/GetFieldOperator.java
+++ b/jode/jode/expr/GetFieldOperator.java
@@ -35,7 +35,6 @@ public class GetFieldOperator extends Operator {
CodeAnalyzer codeAnalyzer;
Reference ref;
Type classType;
- boolean needCast = false;
public GetFieldOperator(CodeAnalyzer codeAnalyzer, boolean staticFlag,
Reference ref) {
@@ -46,27 +45,18 @@ public class GetFieldOperator extends Operator {
this.ref = ref;
if (staticFlag)
codeAnalyzer.useType(classType);
+ initOperands(staticFlag ? 0 : 1);
}
public int getPriority() {
return 950;
}
- public int getOperandCount() {
- return staticFlag?0:1;
- }
-
- public int getOperandPriority(int i) {
- return 900;
- }
-
- public Type getOperandType(int i) {
- return classType;
- }
-
- public void setOperandType(Type types[]) {
+ public void updateSubTypes() {
if (!staticFlag)
- needCast = types[0].getHint().equals(Type.tNull);
+ subExpressions[0].setType(Type.tSubType(classType));
+ }
+ public void updateType() {
}
/**
@@ -98,7 +88,7 @@ public class GetFieldOperator extends Operator {
return null;
}
- public FieldAnalyzer getFieldAnalyzer() {
+ public FieldAnalyzer getField() {
ClassInfo clazz = getClassInfo();
if (clazz != null) {
ClassAnalyzer ana = codeAnalyzer.getClassAnalyzer();
@@ -119,9 +109,10 @@ public class GetFieldOperator extends Operator {
return null;
}
- public void dumpExpression(TabbedPrintWriter writer, Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
- boolean opIsThis = !staticFlag && operands[0] instanceof ThisOperator;
+ boolean opIsThis = !staticFlag
+ && subExpressions[0] instanceof ThisOperator;
String fieldName = ref.getName();
if (staticFlag) {
if (!classType.equals(Type.tClass(codeAnalyzer.getClazz()))
@@ -130,48 +121,56 @@ public class GetFieldOperator extends Operator {
writer.print(".");
}
writer.print(fieldName);
- } else if (operands[0].getType() instanceof NullType) {
+ } else if (subExpressions[0].getType() instanceof NullType) {
writer.print("((");
writer.printType(classType);
writer.print(")");
- operands[0].dumpExpression(writer, 700);
+ subExpressions[0].dumpExpression(writer, 700);
writer.print(").");
writer.print(fieldName);
} else {
if (opIsThis) {
- ThisOperator thisOp = (ThisOperator) operands[0];
+ ThisOperator thisOp = (ThisOperator) subExpressions[0];
Scope scope = writer.getScope(thisOp.getClassInfo(),
Scope.CLASSSCOPE);
- if (scope == null)
- writer.println("UNKNOWN ");
-
if (scope == null || writer.conflicts(fieldName, scope,
Scope.FIELDNAME)) {
thisOp.dumpExpression(writer, 950);
writer.print(".");
} else if (writer.conflicts(fieldName, scope,
- Scope.AMBIGUOUSNAME)) {
+ Scope.AMBIGUOUSNAME)
+ || (/* This is a inherited field conflicting
+ * with a field name in some outer class.
+ */
+ getField() == null
+ && writer.conflicts(fieldName, null,
+ Scope.FIELDNAME))) {
writer.print("this.");
}
} else {
- operands[0].dumpExpression(writer, 950);
+ subExpressions[0].dumpExpression(writer, 950);
writer.print(".");
}
writer.print(fieldName);
}
}
- public Expression simplifyThis(Expression[] subs) {
- if (!staticFlag && subs[0] instanceof ThisOperator) {
- Expression constant = getFieldAnalyzer().getConstant();
- if (constant instanceof ThisOperator)
- return constant;
+ public Expression simplify() {
+ if (!staticFlag) {
+ subExpressions[0] = subExpressions[0].simplify();
+ subExpressions[0].parent = this;
+ if (subExpressions[0] instanceof ThisOperator
+ && getField() != null) {
+ Expression constant = getField().getConstant();
+ if (constant instanceof ThisOperator)
+ return constant;
+ }
}
- return null;
+ return this;
}
- public boolean equals(Object o) {
+ public boolean opEquals(Operator o) {
return o instanceof GetFieldOperator
&& ((GetFieldOperator)o).ref.equals(ref);
}
diff --git a/jode/jode/expr/IIncOperator.java b/jode/jode/expr/IIncOperator.java
index 8b1b16d..cb6eaa7 100644
--- a/jode/jode/expr/IIncOperator.java
+++ b/jode/jode/expr/IIncOperator.java
@@ -22,53 +22,38 @@ import jode.type.Type;
import jode.decompiler.LocalInfo;
import jode.decompiler.TabbedPrintWriter;
-public class IIncOperator extends NoArgOperator
- implements LocalVarOperator, CombineableOperator {
- String value;
- LocalInfo local;
+public class IIncOperator extends Operator
+ implements CombineableOperator {
+ int value;
- public IIncOperator(LocalInfo local, String value, int operator) {
+ public IIncOperator(LocalStoreOperator localStore, int value,
+ int operator) {
super(Type.tVoid, operator);
- this.local = local;
this.value = value;
- local.setType(Type.tUInt);
- local.setOperator(this);
+ initOperands(1);
+ setSubExpressions(0, localStore);
}
- public String getValue() {
- return value;
- }
-
- public boolean isRead() {
- return true;
- }
-
- public boolean isWrite() {
- return true;
- }
-
- public void updateType() {
- if (parent != null)
- parent.updateType();
+ public LValueExpression getLValue() {
+ return (LValueExpression) subExpressions[0];
}
- public LocalInfo getLocalInfo() {
- return local;
+ public String getValue() {
+ return Integer.toString(value);
}
public int getPriority() {
return 100;
}
+ public void updateSubTypes() {
+ subExpressions[0].setType(type != Type.tVoid ? type : Type.tUInt);
+ }
- /**
- * Checks if the value of the given expression can change, due to
- * side effects in this expression. If this returns false, the
- * expression can safely be moved behind the current expresion.
- * @param expr the expression that should not change.
- */
- public boolean hasSideEffects(Expression expr) {
- return expr.containsConflictingLoad(this);
+
+ public void updateType() {
+ if (type != Type.tVoid)
+ updateParentType(subExpressions[0].getType());
}
/**
@@ -77,29 +62,27 @@ public class IIncOperator extends NoArgOperator
public void makeNonVoid() {
if (type != Type.tVoid)
throw new jode.AssertError("already non void");
- type = local.getType();
+ type = subExpressions[0].getType();
}
- public boolean matches(Operator loadop) {
- return loadop instanceof LocalLoadOperator &&
- ((LocalLoadOperator)loadop).getLocalInfo().getLocalInfo()
- == local.getLocalInfo();
+ public boolean lvalueMatches(Operator loadop) {
+ return getLValue().matches(loadop);
}
public Expression simplify() {
- if (value.equals("1")) {
+ if (value == 1) {
int op = (getOperatorIndex() == OPASSIGN_OP+ADD_OP)
? INC_OP : DEC_OP;
-
- return new LocalPrePostFixOperator
- (getType(), op, this, isVoid()).simplify();
+ return new PrePostFixOperator
+ (getType(), op, getLValue(), isVoid()).simplify();
}
return super.simplify();
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
- writer.print(local.getName() + getOperatorString() + value);
+ subExpressions[0].dumpExpression(writer, 950);
+ writer.print(getOperatorString() + value);
}
}
+
diff --git a/jode/jode/expr/IfThenElseOperator.java b/jode/jode/expr/IfThenElseOperator.java
index 3792037..57adc7a 100644
--- a/jode/jode/expr/IfThenElseOperator.java
+++ b/jode/jode/expr/IfThenElseOperator.java
@@ -19,52 +19,91 @@
package jode.expr;
import jode.type.Type;
+import jode.decompiler.FieldAnalyzer;
import jode.decompiler.TabbedPrintWriter;
-public class IfThenElseOperator extends SimpleOperator {
+public class IfThenElseOperator extends Operator {
public IfThenElseOperator(Type type) {
- super(type, 0, 3);
- operandTypes[0] = Type.tBoolean;
+ super(type, 0);
+ initOperands(3);
}
- public int getOperandCount() {
- return 3;
- }
-
public int getPriority() {
return 200;
}
- public void setOperandType(Type[] inputTypes) {
- super.setOperandType(inputTypes);
- Type operandType =
- type.intersection(operandTypes[1]).intersection(operandTypes[2]);
- type = operandTypes[1] = operandTypes[2] = operandType;
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tBoolean);
+ subExpressions[1].setType(Type.tSubType(type));
+ subExpressions[2].setType(Type.tSubType(type));
+ }
+
+ public void updateType() {
+ Type subType = Type.tSuperType(subExpressions[1].getType())
+ .intersection(Type.tSuperType(subExpressions[2].getType()));
+ updateParentType(subType);
}
- /**
- * Sets the return type of this operator.
- * @return true if the operand types changed
- */
- public void setType(Type newType) {
- Type operandType =
- type.intersection(operandTypes[1]).intersection(newType);
- if (!type.equals(operandType)) {
- type = operandTypes[1] = operandTypes[2] = operandType;
+ public Expression simplify() {
+ if (getType().isOfType(Type.tBoolean)) {
+ if (subExpressions[1] instanceof ConstOperator
+ && subExpressions[2] instanceof ConstOperator) {
+ ConstOperator c1 = (ConstOperator) subExpressions[1];
+ ConstOperator c2 = (ConstOperator) subExpressions[2];
+ if (c1.getValue().equals("1") &&
+ c2.getValue().equals("0"))
+ return subExpressions[0].simplify();
+ if (c2.getValue().equals("1") &&
+ c1.getValue().equals("0"))
+ return subExpressions[0].negate().simplify();
+ }
}
+ if (subExpressions[0] instanceof CompareUnaryOperator
+ && (subExpressions[1] instanceof GetFieldOperator)
+ && (subExpressions[2] instanceof StoreInstruction)) {
+ // Check for
+ // class$classname != null ? class$classname :
+ // (class$classname = class$("classname"))
+ // and replace with
+ // classname.class
+ CompareUnaryOperator cmp
+ = (CompareUnaryOperator) subExpressions[0];
+ GetFieldOperator get = (GetFieldOperator) subExpressions[1];
+ StoreInstruction put = (StoreInstruction) subExpressions[2];
+ FieldAnalyzer field;
+ if (cmp.getOperatorIndex() == Operator.NOTEQUALS_OP
+ && put.getLValue() instanceof PutFieldOperator
+ && ((field = ((PutFieldOperator)put.getLValue()).getField())
+ != null) && field.isSynthetic()
+ && put.lvalueMatches(get)
+ && cmp.subExpressions[0] instanceof GetFieldOperator
+ && put.lvalueMatches((GetFieldOperator)cmp.subExpressions[0])
+ && put.subExpressions[1] instanceof InvokeOperator) {
+ InvokeOperator invoke = (InvokeOperator) put.subExpressions[1];
+ if (invoke.isGetClass()
+ && invoke.subExpressions[0] instanceof ConstOperator
+ && (invoke.subExpressions[0].getType()
+ .equals(Type.tString))) {
+ String clazz =
+ ((ConstOperator)invoke.subExpressions[0]).getValue();
+ if (field.setClassConstant(clazz))
+ return new ClassFieldOperator(Type.tClass(clazz));
+ }
+ }
+ }
+ return super.simplify();
}
- public boolean equals(Object o) {
+ public boolean opEquals(Operator o) {
return (o instanceof IfThenElseOperator);
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
- operands[0].dumpExpression(writer, 201);
+ subExpressions[0].dumpExpression(writer, 201);
writer.print(" ? ");
- operands[1].dumpExpression(writer, 0);
+ subExpressions[1].dumpExpression(writer, 0);
writer.print(" : ");
- operands[2].dumpExpression(writer, 200);
+ subExpressions[2].dumpExpression(writer, 200);
}
}
diff --git a/jode/jode/expr/InstanceOfOperator.java b/jode/jode/expr/InstanceOfOperator.java
index 0405f38..8d9508d 100644
--- a/jode/jode/expr/InstanceOfOperator.java
+++ b/jode/jode/expr/InstanceOfOperator.java
@@ -21,50 +21,42 @@ package jode.expr;
import jode.type.Type;
import jode.decompiler.TabbedPrintWriter;
-public class InstanceOfOperator extends SimpleOperator {
+public class InstanceOfOperator extends Operator {
- Type instanceType;
- /**
- * There are special cases where a instanceof isn't allowed. We must cast
- * to the common super type before. This cases always give a runtime
- * error, but we want to decompile even bad programs.
- */
- Type superType = null;
-
+ Type instanceType;
public InstanceOfOperator(Type type) {
- super(Type.tBoolean, 0, 1);
+ super(Type.tBoolean, 0);
this.instanceType = type;
- this.operandTypes[0] = Type.tUnknown;
- }
- public int getOperandCount() {
- return 1;
+ initOperands(1);
}
public int getPriority() {
return 550;
}
- public void setOperandType(Type[] type) {
- super.setOperandType(type);
- superType = instanceType.getCastHelper(type[0]);
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tUObject);
+ }
+
+ public void updateType() {
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
/* There are special cases where a cast isn't allowed. We must cast
* to the common super type before. This cases always give a runtime
* error, but we want to decompile even bad programs.
*/
- Type superType = instanceType.getCastHelper(operands[0].getType());
+ Type superType
+ = instanceType.getCastHelper(subExpressions[0].getType());
if (superType != null) {
writer.print("(");
writer.printType(superType);
writer.print(") ");
- operands[0].dumpExpression(writer, 700);
+ subExpressions[0].dumpExpression(writer, 700);
} else
- operands[0].dumpExpression(writer, 550);
+ subExpressions[0].dumpExpression(writer, 550);
writer.print(" instanceof ");
writer.printType(instanceType);
}
diff --git a/jode/jode/expr/InvokeOperator.java b/jode/jode/expr/InvokeOperator.java
index b306f3a..d9ded9a 100644
--- a/jode/jode/expr/InvokeOperator.java
+++ b/jode/jode/expr/InvokeOperator.java
@@ -18,6 +18,8 @@
*/
package jode.expr;
+import java.lang.reflect.Modifier;
+
import jode.Decompiler;
import jode.decompiler.CodeAnalyzer;
import jode.decompiler.MethodAnalyzer;
@@ -43,7 +45,7 @@ public final class InvokeOperator extends Operator
boolean staticFlag, boolean specialFlag,
Reference reference) {
super(Type.tUnknown, 0);
- this.methodType = (MethodType) Type.tType(reference.getType());
+ this.methodType = Type.tMethod(reference.getType());
this.methodName = reference.getName();
this.classType = Type.tType(reference.getClazz());
this.type = methodType.getReturnType();
@@ -52,25 +54,8 @@ public final class InvokeOperator extends Operator
this.specialFlag = specialFlag;
if (staticFlag)
codeAnalyzer.useType(classType);
- }
-
- /**
- * Checks if the value of the given expression can change, due to
- * side effects in this expression. If this returns false, the
- * expression can safely be moved behind the current expresion.
- * @param expr the expression that should not change.
- */
- public boolean hasSideEffects(Expression expr) {
- return expr.containsConflictingLoad(this);
- }
-
- /**
- * Checks if the value of the operator can be changed by this expression.
- */
- public boolean matches(Operator loadop) {
- return (loadop instanceof InvokeOperator
- || loadop instanceof ConstructorOperator
- || loadop instanceof GetFieldOperator);
+ initOperands((staticFlag ? 0 : 1)
+ + methodType.getParameterTypes().length);
}
public final boolean isStatic() {
@@ -93,21 +78,16 @@ public final class InvokeOperator extends Operator
return 950;
}
- public int getOperandCount() {
- return (isStatic()?0:1)
- + methodType.getParameterTypes().length;
- }
-
- public Type getOperandType(int i) {
+ public void updateSubTypes() {
+ int offset = 0;
if (!isStatic()) {
- if (i == 0)
- return getClassType();
- i--;
+ subExpressions[offset++].setType(Type.tSubType(getClassType()));
}
- return methodType.getParameterTypes()[i];
+ Type[] paramTypes = methodType.getParameterTypes();
+ for (int i=0; i < paramTypes.length; i++)
+ subExpressions[offset++].setType(Type.tSubType(paramTypes[i]));
}
-
- public void setOperandType(Type types[]) {
+ public void updateType() {
}
public boolean isConstructor() {
@@ -129,13 +109,12 @@ public final class InvokeOperator extends Operator
return getClassInfo() == codeAnalyzer.getClazz();
}
- public ClassInfo getOuterClass() {
+ public InnerClassInfo getOuterClassInfo() {
ClassInfo clazz = getClassInfo();
if (clazz != null) {
InnerClassInfo[] outers = clazz.getOuterClasses();
- if (outers != null && outers[0].outer != null
- && (Decompiler.options & Decompiler.OPTION_INNER) != 0)
- return ClassInfo.forName(outers[0].outer);
+ if (outers != null)
+ return outers[0];
}
return null;
}
@@ -202,90 +181,13 @@ public final class InvokeOperator extends Operator
return false;
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
- throws java.io.IOException {
- boolean opIsThis = !staticFlag && operands[0] instanceof ThisOperator;
- int arg = 1;
-
- if (isConstructor()) {
- ClassInfo outer = getOuterClass();
- if (outer != null) {
- operands[arg++].dumpExpression(writer, 0);
- writer.print(".");
- }
- }
- if (specialFlag) {
- if (opIsThis
- && (((ThisOperator)operands[0]).getClassInfo()
- == codeAnalyzer.getClazz())) {
- if (isThis()) {
- /* XXX check if this is a private or final method. */
- } else {
- /* XXX check that this is the first defined
- * super method. */
- writer.print("super");
- opIsThis = false;
- }
- } else {
- /* XXX check if this is a private or final method. */
- int minPriority = 950; /* field access */
- if (!isThis()) {
- writer.print("(NON VIRTUAL ");
- writer.printType(classType);
- writer.print(")");
- minPriority = 700;
- }
- operands[0].dumpExpression(writer, minPriority);
- }
- } else if (staticFlag) {
- arg = 0;
- Scope scope = writer.getScope(getClassInfo(),
- Scope.CLASSSCOPE);
- if (scope != null
- && !writer.conflicts(methodName, scope, Scope.METHODNAME))
- opIsThis = true;
- else
- writer.printType(classType);
- } else {
- if (opIsThis) {
- ThisOperator thisOp = (ThisOperator) operands[0];
- Scope scope = writer.getScope(thisOp.getClassInfo(),
- Scope.CLASSSCOPE);
- if (writer.conflicts(methodName, scope, Scope.METHODNAME)) {
- thisOp.dumpExpression(writer, 950);
- writer.print(".");
- }
- } else {
- if (operands[0].getType() instanceof NullType) {
- writer.print("((");
- writer.printType(classType);
- writer.print(") ");
- operands[0].dumpExpression(writer, 700);
- writer.print(")");
- } else
- operands[0].dumpExpression(writer, 950);
- }
- }
-
- if (isConstructor()) {
- if (opIsThis)
- writer.print("this");
- } else {
- if (!opIsThis)
- writer.print(".");
- writer.print(methodName);
- }
- writer.print("(");
- boolean first = true;
- while (arg < operands.length) {
- if (!first)
- writer.print(", ");
- else
- first = false;
- operands[arg++].dumpExpression(writer, 0);
- }
- writer.print(")");
+ /**
+ * Checks if the value of the operator can be changed by this expression.
+ */
+ public boolean matches(Operator loadop) {
+ return (loadop instanceof InvokeOperator
+ || loadop instanceof ConstructorOperator
+ || loadop instanceof GetFieldOperator);
}
/**
@@ -329,11 +231,6 @@ public final class InvokeOperator extends Operator
}
public ConstOperator deobfuscateString(ConstOperator op) {
- if (!isThis() || !isStatic()
- || methodType.getParameterTypes().length != 1
- || !methodType.getParameterTypes()[0].equals(Type.tString)
- || !methodType.getReturnType().equals(Type.tString))
- return null;
ClassAnalyzer clazz = codeAnalyzer.getClassAnalyzer();
CodeAnalyzer ca = clazz.getMethod(methodName, methodType).getCode();
if (ca == null)
@@ -361,8 +258,89 @@ public final class InvokeOperator extends Operator
return new ConstOperator(result);
}
- public Expression simplifyAccess(Expression[] subs) {
- if (isOuter()) {
+ public Expression simplifyStringBuffer() {
+ if (getClassType().equals(Type.tStringBuffer)
+ && !isStatic()
+ && getMethodName().equals("append")
+ && getMethodType().getParameterTypes().length == 1) {
+
+ Expression e = subExpressions[0].simplifyStringBuffer();
+ if (e == null)
+ return null;
+
+ subExpressions[1] = subExpressions[1].simplifyString();
+
+ if (e == EMPTYSTRING
+ && subExpressions[1].getType().isOfType(Type.tString))
+ return subExpressions[1];
+
+ if (e instanceof StringAddOperator
+ && ((Operator)e).getSubExpressions()[0] == EMPTYSTRING)
+ e = ((Operator)e).getSubExpressions()[1];
+
+ Operator result = new StringAddOperator();
+ result.addOperand(subExpressions[1]);
+ result.addOperand(e);
+ return result;
+ }
+ return null;
+ }
+
+ public Expression simplifyString() {
+ if (getMethodName().equals("toString")
+ && !isStatic()
+ && getClassType().equals(Type.tStringBuffer)
+ && subExpressions.length == 1) {
+ Expression simple = subExpressions[0].simplifyStringBuffer();
+ if (simple != null)
+ return simple;
+ }
+ else if (getMethodName().equals("valueOf")
+ && isStatic()
+ && getClassType().equals(Type.tString)
+ && subExpressions.length == 1) {
+
+ if (subExpressions[0].getType().isOfType(Type.tString))
+ return subExpressions[0];
+
+ Operator op = new StringAddOperator();
+ op.addOperand(subExpressions[0]);
+ op.addOperand(EMPTYSTRING);
+ }
+ /* The pizza way (pizza is the compiler of kaffe) */
+ else if (getMethodName().equals("concat")
+ && !isStatic()
+ && getClassType().equals(Type.tString)) {
+
+ Expression result = new StringAddOperator();
+ Expression right = subExpressions[1].simplify();
+ if (right instanceof StringAddOperator) {
+ Operator op = (Operator) right;
+ if (op.subExpressions != null
+ && op.subExpressions[0] == EMPTYSTRING)
+ right = op.subExpressions[1];
+ }
+ result.addOperand(right);
+ result.addOperand(subExpressions[0].simplify());
+ }
+ else if ((Decompiler.options & Decompiler.OPTION_DECRYPT) != 0
+ && isThis() && isStatic()
+ && methodType.getParameterTypes().length == 1
+ && methodType.getParameterTypes()[0].equals(Type.tString)
+ && methodType.getReturnType().equals(Type.tString)) {
+
+ Expression expr = subExpressions[0].simplifyString();
+ if (expr instanceof ConstOperator) {
+ expr = deobfuscateString((ConstOperator)expr);
+ if (expr != null)
+ return expr;
+ }
+ }
+ return this;
+ }
+
+ public Expression simplifyAccess() {
+ if (isOuter() && getMethodAnalyzer() != null) {
SyntheticAnalyzer synth = getMethodAnalyzer().getSynthetic();
if (synth != null) {
Operator op = null;
@@ -376,12 +354,14 @@ public final class InvokeOperator extends Operator
synth.getReference());
break;
case SyntheticAnalyzer.ACCESSPUTFIELD:
- op = new PutFieldOperator(codeAnalyzer, false,
- synth.getReference());
+ op = new StoreInstruction
+ (new PutFieldOperator(codeAnalyzer, false,
+ synth.getReference()));
break;
case SyntheticAnalyzer.ACCESSPUTSTATIC:
- op = new PutFieldOperator(codeAnalyzer, true,
- synth.getReference());
+ op = new StoreInstruction
+ (new PutFieldOperator(codeAnalyzer, true,
+ synth.getReference()));
break;
case SyntheticAnalyzer.ACCESSMETHOD:
op = new InvokeOperator(codeAnalyzer, false,
@@ -394,9 +374,11 @@ public final class InvokeOperator extends Operator
}
if (op != null) {
- if (subs == null)
- return op;
- return new ComplexExpression(op, subs);
+ if (subExpressions != null) {
+ for (int i=subExpressions.length; i-- > 0; )
+ op.addOperand(subExpressions[i]);
+ }
+ return op;
}
}
}
@@ -404,9 +386,12 @@ public final class InvokeOperator extends Operator
}
public Expression simplify() {
- Expression expr = simplifyAccess(null);
+ Expression expr = simplifyAccess();
if (expr != null)
return expr.simplify();
+ expr = simplifyString();
+ if (expr != this)
+ return expr.simplify();
return super.simplify();
}
@@ -414,4 +399,102 @@ public final class InvokeOperator extends Operator
/* Invokes never equals: they may return different values even if
* they have the same parameters.
*/
+
+ public void dumpExpression(TabbedPrintWriter writer)
+ throws java.io.IOException {
+ boolean opIsThis = !staticFlag
+ && subExpressions[0] instanceof ThisOperator;
+ int arg = 1;
+
+ if (isConstructor()) {
+ InnerClassInfo outer = getOuterClassInfo();
+ if (outer != null && outer.outer != null
+ && !Modifier.isStatic(outer.modifiers)
+ && (Decompiler.options & Decompiler.OPTION_INNER) != 0) {
+ Expression outerInstance = subExpressions[arg++];
+ if (!(outerInstance instanceof ThisOperator)) {
+ outerInstance.dumpExpression(writer, 0);
+ writer.print(".");
+ }
+ }
+ }
+ if (specialFlag) {
+ if (opIsThis
+ && (((ThisOperator)subExpressions[0]).getClassInfo()
+ == codeAnalyzer.getClazz())) {
+ if (isThis()) {
+ /* XXX check if this is a private or final method. */
+ } else {
+ /* XXX check that this is the first defined
+ * super method. */
+ writer.print("super");
+ opIsThis = false;
+ }
+ } else {
+ /* XXX check if this is a private or final method. */
+ int minPriority = 950; /* field access */
+ if (!isThis()) {
+ writer.print("(NON VIRTUAL ");
+ writer.printType(classType);
+ writer.print(")");
+ minPriority = 700;
+ }
+ subExpressions[0].dumpExpression(writer, minPriority);
+ }
+ } else if (staticFlag) {
+ arg = 0;
+ Scope scope = writer.getScope(getClassInfo(),
+ Scope.CLASSSCOPE);
+ if (scope != null
+ && !writer.conflicts(methodName, scope, Scope.METHODNAME))
+ opIsThis = true;
+ else
+ writer.printType(classType);
+ } else {
+ if (opIsThis) {
+ ThisOperator thisOp = (ThisOperator) subExpressions[0];
+ Scope scope = writer.getScope(thisOp.getClassInfo(),
+ Scope.CLASSSCOPE);
+ if (writer.conflicts(methodName, scope, Scope.METHODNAME)) {
+ thisOp.dumpExpression(writer, 950);
+ writer.print(".");
+ } else if (/* This is a inherited field conflicting
+ * with a field name in some outer class.
+ */
+ getMethodAnalyzer() == null
+ && writer.conflicts(methodName, null,
+ Scope.METHODNAME)) {
+ writer.print("this.");
+ }
+ } else {
+ if (subExpressions[0].getType() instanceof NullType) {
+ writer.print("((");
+ writer.printType(classType);
+ writer.print(") ");
+ subExpressions[0].dumpExpression(writer, 700);
+ writer.print(")");
+ } else
+ subExpressions[0].dumpExpression(writer, 950);
+ }
+ }
+
+ if (isConstructor()) {
+ if (opIsThis)
+ writer.print("this");
+ } else {
+ if (!opIsThis)
+ writer.print(".");
+ writer.print(methodName);
+ }
+ writer.print("(");
+ boolean first = true;
+ while (arg < subExpressions.length) {
+ if (!first)
+ writer.print(", ");
+ else
+ first = false;
+ subExpressions[arg++].dumpExpression(writer, 0);
+ }
+ writer.print(")");
+ }
}
diff --git a/jode/jode/expr/LValueExpression.java b/jode/jode/expr/LValueExpression.java
new file mode 100644
index 0000000..8c65fa2
--- /dev/null
+++ b/jode/jode/expr/LValueExpression.java
@@ -0,0 +1,31 @@
+/* LValueExpression Copyright (C) 1999 Jochen Hoenicke.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+package jode.expr;
+import jode.type.Type;
+import jode.GlobalOptions;
+import jode.decompiler.TabbedPrintWriter;
+
+public abstract class LValueExpression extends Operator
+ implements MatchableOperator {
+
+ public LValueExpression(Type lvalueType) {
+ super(lvalueType, 0);
+ }
+}
diff --git a/jode/jode/expr/LocalLoadOperator.java b/jode/jode/expr/LocalLoadOperator.java
index a05e854..9aba19e 100644
--- a/jode/jode/expr/LocalLoadOperator.java
+++ b/jode/jode/expr/LocalLoadOperator.java
@@ -25,7 +25,7 @@ import jode.decompiler.ClassAnalyzer;
import jode.decompiler.LocalInfo;
import jode.decompiler.TabbedPrintWriter;
-public class LocalLoadOperator extends NoArgOperator
+public class LocalLoadOperator extends Operator
implements LocalVarOperator {
CodeAnalyzer codeAnalyzer;
LocalInfo local;
@@ -35,8 +35,8 @@ public class LocalLoadOperator extends NoArgOperator
super(type);
this.codeAnalyzer = codeAnalyzer;
this.local = local;
- local.setType(type);
local.setOperator(this);
+ initOperands(0);
}
public boolean isRead() {
@@ -51,43 +51,30 @@ public class LocalLoadOperator extends NoArgOperator
return false;
}
+ public int getPriority() {
+ return 1000;
+ }
+
public LocalInfo getLocalInfo() {
return local.getLocalInfo();
}
+ public void updateSubTypes() {
+ if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0)
+ GlobalOptions.err.println("setType of "+local.getName()+": "
+ +local.getType());
+ local.setType(type);
+ }
+
public void updateType() {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("local "+local.getName()+" changed: "
+type+" to "+local.getType()
+" in "+parent);
- super.setType(local.getType());
- if (parent != null)
- parent.updateType();
+ updateParentType(local.getType());
}
- public int getPriority() {
- return 1000;
- }
-
- public Type getType() {
-// GlobalOptions.err.println("LocalLoad.getType of "+local.getName()+": "+local.getType());
- return local.getType();
- }
-
- public void setType(Type type) {
-// GlobalOptions.err.println("LocalLoad.setType of "+local.getName()+": "+local.getType());
- super.setType(local.setType(type));
- }
-
-// public int getSlot() {
-// return slot;
-// }
-
- public String toString() {
- return local.getName().toString();
- }
-
- public boolean equals(Object o) {
+ public boolean opEquals(Operator o) {
return (o instanceof LocalLoadOperator &&
((LocalLoadOperator) o).local.getSlot() == local.getSlot());
}
@@ -102,10 +89,8 @@ public class LocalLoadOperator extends NoArgOperator
return super.simplify();
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
- writer.print(toString());
+ writer.print(local.getName());
}
}
-
diff --git a/jode/jode/expr/LocalStoreOperator.java b/jode/jode/expr/LocalStoreOperator.java
index 09e307a..a56a926 100644
--- a/jode/jode/expr/LocalStoreOperator.java
+++ b/jode/jode/expr/LocalStoreOperator.java
@@ -22,72 +22,48 @@ import jode.type.Type;
import jode.decompiler.LocalInfo;
import jode.decompiler.TabbedPrintWriter;
-public class LocalStoreOperator extends StoreInstruction
+public class LocalStoreOperator extends LValueExpression
implements LocalVarOperator {
LocalInfo local;
- public LocalStoreOperator(Type lvalueType, LocalInfo local, int operator) {
- super(lvalueType, operator);
+ public LocalStoreOperator(Type lvalueType, LocalInfo local) {
+ super(lvalueType);
this.local = local;
- local.setType(lvalueType);
local.setOperator(this);
+ initOperands(0);
}
public boolean isRead() {
- return operator != ASSIGN_OP;
+ return parent != null && parent.getOperatorIndex() != ASSIGN_OP;
}
public boolean isWrite() {
return true;
}
+ public void updateSubTypes() {
+ local.setType(type);
+ }
+
public void updateType() {
- if (parent != null)
- parent.updateType();
+ updateParentType(local.getType());
}
public LocalInfo getLocalInfo() {
return local.getLocalInfo();
}
- public Type getLValueType() {
- return local.getType();
- }
-
- public void setLValueType(Type type) {
- local.setType(type);
- }
-
public boolean matches(Operator loadop) {
return loadop instanceof LocalLoadOperator &&
((LocalLoadOperator)loadop).getLocalInfo().getSlot()
== local.getSlot();
}
- public int getLValuePriority() {
+ public int getPriority() {
return 1000;
}
- public int getLValueOperandCount() {
- return 0;
- }
-
- public int getLValueOperandPriority(int i) {
- /* shouldn't be called */
- throw new RuntimeException("LocalStoreOperator has no operands");
- }
-
- public Type getLValueOperandType(int i) {
- /* shouldn't be called */
- throw new RuntimeException("LocalStoreOperator has no operands");
- }
-
- public void setLValueOperandType(Type []t) {
- /* shouldn't be called */
- throw new RuntimeException("LocalStoreOperator has no operands");
- }
-
- public void dumpLValue(TabbedPrintWriter writer, Expression[] operands) {
+ public void dumpExpression(TabbedPrintWriter writer) {
writer.print(local.getName());
}
}
diff --git a/jode/jode/expr/LocalVarOperator.java b/jode/jode/expr/LocalVarOperator.java
index 988f390..baa8966 100644
--- a/jode/jode/expr/LocalVarOperator.java
+++ b/jode/jode/expr/LocalVarOperator.java
@@ -31,5 +31,3 @@ public interface LocalVarOperator {
*/
public void updateType();
}
-
-
diff --git a/jode/jode/expr/MonitorEnterOperator.java b/jode/jode/expr/MonitorEnterOperator.java
index 5509048..3c4ab05 100644
--- a/jode/jode/expr/MonitorEnterOperator.java
+++ b/jode/jode/expr/MonitorEnterOperator.java
@@ -21,20 +21,26 @@ package jode.expr;
import jode.type.Type;
import jode.decompiler.TabbedPrintWriter;
-public class MonitorEnterOperator extends SimpleOperator {
+public class MonitorEnterOperator extends Operator {
public MonitorEnterOperator() {
- super(Type.tVoid, 0, 1);
- operandTypes[0] = Type.tObject;
+ super(Type.tVoid, 0);
+ initOperands(1);
}
public int getPriority() {
return 700;
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tUObject);
+ }
+
+ public void updateType() {
+ }
+
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
writer.print("MONITORENTER ");
- operands[0].dumpExpression(writer, 700);
+ subExpressions[0].dumpExpression(writer, 700);
}
}
diff --git a/jode/jode/expr/MonitorExitOperator.java b/jode/jode/expr/MonitorExitOperator.java
index 8acd9a0..7ec64f4 100644
--- a/jode/jode/expr/MonitorExitOperator.java
+++ b/jode/jode/expr/MonitorExitOperator.java
@@ -21,20 +21,26 @@ package jode.expr;
import jode.type.Type;
import jode.decompiler.TabbedPrintWriter;
-public class MonitorExitOperator extends SimpleOperator {
+public class MonitorExitOperator extends Operator {
public MonitorExitOperator() {
- super(Type.tVoid, 0, 1);
- operandTypes[0] = Type.tObject;
+ super(Type.tVoid, 0);
+ initOperands(1);
}
public int getPriority() {
return 700;
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tUObject);
+ }
+
+ public void updateType() {
+ }
+
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
writer.print("MONITOREXIT ");
- operands[0].dumpExpression(writer, 700);
+ subExpressions[0].dumpExpression(writer, 700);
}
}
diff --git a/jode/jode/expr/NewArrayOperator.java b/jode/jode/expr/NewArrayOperator.java
index d66124c..40b5e80 100644
--- a/jode/jode/expr/NewArrayOperator.java
+++ b/jode/jode/expr/NewArrayOperator.java
@@ -22,22 +22,31 @@ import jode.type.Type;
import jode.type.ArrayType;
import jode.decompiler.TabbedPrintWriter;
-public class NewArrayOperator extends SimpleOperator {
+public class NewArrayOperator extends Operator {
String baseTypeString;
public NewArrayOperator(Type arrayType, int dimensions) {
- super(arrayType, 0, dimensions);
- for (int i=0; i< dimensions; i++) {
- operandTypes[i] = Type.tUInt;
- }
+ super(arrayType, 0);
+ initOperands(dimensions);
+ }
+
+ public int getDimensions() {
+ return subExpressions.length;
}
public int getPriority() {
return 900;
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void updateSubTypes() {
+ for (int i=0; i< subExpressions.length; i++)
+ subExpressions[i].setType(Type.tUInt);
+ }
+
+ public void updateType() {
+ }
+
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
Type flat = type;
int depth = 0;
@@ -49,8 +58,8 @@ public class NewArrayOperator extends SimpleOperator {
writer.printType(flat);
for (int i=0; i< depth; i++) {
writer.print("[");
- if (i < getOperandCount())
- operands[i].dumpExpression(writer, 0);
+ if (i < subExpressions.length)
+ subExpressions[i].dumpExpression(writer, 0);
writer.print("]");
}
}
diff --git a/jode/jode/expr/NewOperator.java b/jode/jode/expr/NewOperator.java
index 76e3412..2d0f298 100644
--- a/jode/jode/expr/NewOperator.java
+++ b/jode/jode/expr/NewOperator.java
@@ -30,8 +30,8 @@ public class NewOperator extends NoArgOperator {
return 950;
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] expr) throws java.io.IOException{
+ public void dumpExpression(TabbedPrintWriter writer)
+ throws java.io.IOException {
writer.print("new ");
writer.printType(type);
}
diff --git a/jode/jode/expr/NoArgOperator.java b/jode/jode/expr/NoArgOperator.java
index 8dd2a51..ab03f0b 100644
--- a/jode/jode/expr/NoArgOperator.java
+++ b/jode/jode/expr/NoArgOperator.java
@@ -26,25 +26,15 @@ public abstract class NoArgOperator extends Operator {
public NoArgOperator(Type type, int operator) {
super(type, operator);
+ initOperands(0);
}
public NoArgOperator(Type type) {
this(type, 0);
}
- public int getOperandCount() {
- return 0;
+ public void updateType() {
}
-
- public int getOperandPriority(int i) {
- throw new AssertError("This operator has no operands");
- }
-
- public Type getOperandType(int i) {
- throw new AssertError("This operator has no operands");
- }
-
- public void setOperandType(Type[] types) {
- throw new AssertError("This operator has no operands");
+ public void updateSubTypes() {
}
}
diff --git a/jode/jode/expr/NopOperator.java b/jode/jode/expr/NopOperator.java
index 54c600e..25a6e3f 100644
--- a/jode/jode/expr/NopOperator.java
+++ b/jode/jode/expr/NopOperator.java
@@ -22,33 +22,36 @@ import jode.type.Type;
import jode.decompiler.TabbedPrintWriter;
/**
- * A NopOperator takes one or zero arguments and returns it again. It
- * is mainly used as placeholder when the real operator is not yet
- * known (e.g. in SwitchBlock). But there also exists a nop opcode in
- * the java virtual machine (The compiler can't create such a opcode,
- * though).
+ * A NopOperator takes one arguments and returns it again. It is used
+ * as placeholder when the real operator is not yet known (e.g. in
+ * SwitchBlock, but also in every other Operator).
+ *
+ * A Nop operator doesn't have subExpressions; getSubExpressions() simply
+ * returns zero.
*
* @author Jochen Hoenicke */
-public class NopOperator extends SimpleOperator {
+public class NopOperator extends Expression {
public NopOperator(Type type) {
- super(type, 0, 1);
+ super(type);
}
- public NopOperator() {
- super(Type.tVoid, 0, 0);
+ public int getFreeOperandCount() {
+ return 1;
}
public int getPriority() {
return 1000;
}
- public Expression addOperand(Expression op) {
- op.setType(type.getSubType());
- return op;
+ public void updateSubTypes() {
+ }
+ public void updateType() {
}
- public int getOperandPriority(int i) {
- return 0;
+ public Expression addOperand(Expression op) {
+ op.setType(type);
+ op.parent = parent;
+ return op;
}
public boolean isConstant() {
@@ -59,15 +62,12 @@ public class NopOperator extends SimpleOperator {
return (o instanceof NopOperator);
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
- throws java.io.IOException {
- if (type == Type.tVoid)
- writer.print("/* NOP */");
- operands[0].dumpExpression(writer);
+ public Expression simplify() {
+ return this;
}
- public void dumpExpression(TabbedPrintWriter writer) {
+ public void dumpExpression(TabbedPrintWriter writer)
+ throws java.io.IOException {
writer.print("POP");
}
}
diff --git a/jode/jode/expr/Operator.java b/jode/jode/expr/Operator.java
index e5f9e9c..1d470e5 100644
--- a/jode/jode/expr/Operator.java
+++ b/jode/jode/expr/Operator.java
@@ -19,7 +19,9 @@
package jode.expr;
import jode.type.Type;
+import jode.GlobalOptions;
import jode.decompiler.TabbedPrintWriter;
+import jode.flow.VariableSet;
public abstract class Operator extends Expression {
public final static int ADD_OP = 1;
@@ -33,6 +35,10 @@ public abstract class Operator extends Expression {
public final static int COMPARE_OP = 26; /* must be even! */
public final static int EQUALS_OP = 26;
public final static int NOTEQUALS_OP = 27;
+ public final static int LESS_OP = 28;
+ public final static int GREATEREQ_OP = 29;
+ public final static int GREATER_OP = 30;
+ public final static int LESSEQ_OP = 31;
public final static int LOG_AND_OP = 32; /* must be even! */
public final static int LOG_OR_OP = 33;
public final static int LOG_NOT_OP = 34;
@@ -47,73 +53,271 @@ public abstract class Operator extends Expression {
"!", "~", "-"
};
- protected int operator;
+ protected int operatorIndex;
+ private int operandcount;
- Operator (Type type, int op) {
+ Expression[] subExpressions;
+
+ public Operator(Type type) {
+ this(type,0);
+ }
+
+ public Operator(Type type, int op) {
super(type);
- this.operator = op;
+ this.operatorIndex = op;
if (type == null)
throw new jode.AssertError("type == null");
}
+ public void initOperands(int opcount) {
+ operandcount = opcount;
+ subExpressions = new Expression[opcount];
+ for (int i=0; i < opcount; i++) {
+ subExpressions[i] = new NopOperator(Type.tUnknown);
+ subExpressions[i].parent = this;
+ }
+ updateSubTypes();
+ }
+
+ public int getFreeOperandCount() {
+ return operandcount;
+ }
+
+ /**
+ * Tells if this is an operator, that doesn't have any
+ * subExpression, yet.
+ */
+ public boolean isFreeOperator() {
+ return subExpressions.length == 0
+ || subExpressions[subExpressions.length-1] instanceof NopOperator;
+ }
+
+ /**
+ * Tells if this is an operator, that doesn't have any
+ * subExpression, yet, and that expects opcount operands
+ */
+ public boolean isFreeOperator(int opcount) {
+ return subExpressions.length == opcount
+ && (opcount == 0
+ || subExpressions[opcount-1] instanceof NopOperator);
+ }
+
public Expression addOperand(Expression op) {
- return new ComplexExpression
- (this, new Expression[getOperandCount()]).addOperand(op);
+ for (int i= subExpressions.length; i-- > 0;) {
+ int opcount = subExpressions[i].getFreeOperandCount();
+ if (opcount > 0) {
+ subExpressions[i] = subExpressions[i].addOperand(op);
+ operandcount
+ += subExpressions[i].getFreeOperandCount() - opcount;
+ updateType();
+ return this;
+ }
+ }
+ throw new jode.AssertError("addOperand called, but no operand needed");
}
public Operator getOperator() {
return this;
}
+ public Expression[] getSubExpressions() {
+ return subExpressions;
+ }
+
+ public void setSubExpressions(int i, Expression expr) {
+ int diff = expr.getFreeOperandCount()
+ - subExpressions[i].getFreeOperandCount();
+ subExpressions[i] = expr;
+ expr.parent = this;
+ for (Operator ce = this; ce != null; ce = (Operator) ce.parent)
+ ce.operandcount += diff;
+ updateType();
+ }
+
public int getOperatorIndex() {
- return operator;
+ return operatorIndex;
}
public void setOperatorIndex(int op) {
- operator = op;
+ operatorIndex = op;
}
public String getOperatorString() {
- return opString[operator];
+ return opString[operatorIndex];
+ }
+
+ public boolean opEquals(Operator o) {
+ return this == o;
+ }
+
+ public Expression simplify() {
+ for (int i=0; i< subExpressions.length; i++) {
+ subExpressions[i] = subExpressions[i].simplify();
+ subExpressions[i].parent = this;
+ }
+ return this;
+ }
+
+ public void fillInGenSet(VariableSet in, VariableSet gen) {
+ if (this instanceof LocalVarOperator) {
+ LocalVarOperator varOp = (LocalVarOperator) this;
+ if (varOp.isRead() && in != null)
+ in.addElement(varOp.getLocalInfo());
+ if (gen != null)
+ gen.addElement(varOp.getLocalInfo());
+ }
+ for (int i=0; i< subExpressions.length; i++)
+ subExpressions[i].fillInGenSet(in,gen);
+
}
/**
- * Get priority of the operator.
- * Currently this priorities are known:
- * - 1000 constant
- *
- 950 new, .(field access), []
- *
- 900 new[]
- *
- 800 ++,-- (post)
- *
- 700 ++,--(pre), +,-(unary), ~, !, cast
- *
- 650 *,/, %
- *
- 610 +,-
- *
- 600 <<, >>, >>>
- *
- 550 >, <, >=, <=, instanceof
- *
- 500 ==, !=
- *
- 450 &
- *
- 420 ^
- *
- 410 |
- *
- 350 &&
- *
- 310 ||
- *
- 200 ?:
- *
- 100 =, +=, -=, etc.
- *
+ * Checks if the value of the given expression can change, due to
+ * side effects in this expression. If this returns false, the
+ * expression can safely be moved behind the current expresion.
+ * @param expr the expression that should not change.
*/
- public abstract int getPriority();
+ public boolean hasSideEffects(Expression expr) {
+ if (expr instanceof MatchableOperator
+ && expr.containsConflictingLoad((MatchableOperator)expr))
+ return true;
+ for (int i=0; i < subExpressions.length; i++) {
+ if (subExpressions[i].hasSideEffects(expr))
+ return true;
+ }
+ return false;
+ }
- public abstract Type getOperandType(int i);
- public abstract int getOperandCount();
- public abstract void setOperandType(Type[] inputTypes);
+ /**
+ * Checks if this expression contains a conflicting load, that
+ * matches the given CombineableOperator. The sub expressions are
+ * not checked.
+ * @param op The combineable operator.
+ * @return if this expression contains a matching load.
+ */
+ public boolean containsConflictingLoad(MatchableOperator op) {
+ if (op.matches(this))
+ return true;
+ for (int i=0; i < subExpressions.length; i++) {
+ if (subExpressions[i].containsConflictingLoad(op))
+ return true;
+ }
+ return false;
+ }
- public abstract void dumpExpression
- (TabbedPrintWriter writer, Expression[] operands)
- throws java.io.IOException;
+ /**
+ * Checks if this expression contains a matching load, that matches the
+ * given Expression.
+ * @param comb The store expression.
+ * @return true, iff this expression contains a matching load.
+ * @exception ClassCastException, if e.getOperator
+ * is not a CombineableOperator.
+ */
+ public boolean containsMatchingLoad(CombineableOperator comb) {
+ Operator combOp = (Operator) comb;
+ if (comb.getLValue().matches(this)) {
+ if (subsEquals(comb.getLValue()))
+ return true;
+ }
+ for (int i=0; i < subExpressions.length; i++) {
+ if (subExpressions[i].containsMatchingLoad(comb))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the given Expression (which must be a CombineableOperator)
+ * can be combined into this expression.
+ * @param e The store expression, must be of type void.
+ * @return 1, if it can, 0, if no match was found and -1, if a
+ * conflict was found. You may wish to check for >0.
+ * @exception ClassCastException, if e.getOperator
+ * is not a CombineableOperator.
+ */
+ public int canCombine(CombineableOperator combOp) {
+// GlobalOptions.err.println("Try to combine "+e+" into "+this);
+ if (combOp.getLValue() instanceof LocalStoreOperator
+ && ((Operator)combOp).getFreeOperandCount() == 0) {
+ // Special case for locals created on inlining methods, which may
+ // combine everywhere, as long as there are no side effects.
+
+ for (int i=0; i < subExpressions.length; i++) {
+ int result = subExpressions[i].canCombine(combOp);
+ if (result != 0)
+ return result;
+ if (subExpressions[i].hasSideEffects((Expression)combOp))
+ return -1;
+ }
+ }
- public void dumpExpression(TabbedPrintWriter writer)
- throws java.io.IOException {
- Expression[] operands = new Expression[getOperandCount()];
- for (int i=0; i< operands.length; i++)
- operands[i] = new NopOperator(getOperandType(i));
- dumpExpression(writer, operands);
+ if (combOp.lvalueMatches(this))
+ return subsEquals((Operator)combOp) ? 1 : -1;
+ if (subExpressions.length > 0)
+ return subExpressions[0].canCombine(combOp);
+ return 0;
}
+
+ /**
+ * Combines the given Expression (which should be a StoreInstruction)
+ * into this expression. You must only call this if
+ * canCombine returns the value 1.
+ * @param e The store expression.
+ * @return The combined expression.
+ * @exception ClassCastException, if e.getOperator
+ * is not a CombineableOperator.
+ */
+ public Expression combine(CombineableOperator comb) {
+ Operator combOp = (Operator) comb;
+ if (comb.lvalueMatches(this)) {
+ /* We already checked in canCombine that subExpressions match */
+ comb.makeNonVoid();
+ combOp.parent = parent;
+ return combOp;
+ }
+ for (int i=0; i < subExpressions.length; i++) {
+ Expression combined = subExpressions[i].combine(comb);
+ if (combined != null) {
+ subExpressions[i] = combined;
+ updateType();
+ return this;
+ }
+ }
+ return null;
+ }
+
+ public boolean subsEquals(Operator other) {
+ if (this == other)
+ return true;
+ if (other.subExpressions == null)
+ return (subExpressions == null);
+
+ if (subExpressions.length != other.subExpressions.length)
+ return false;
+
+ for (int i=0; i 0)
- setLValueOperandType(t);
- if (getOperatorIndex() == ASSIGN_OP)
- /* In a direct assignment, lvalueType is rvalueType */
- setLValueType(t[count]);
- else
- rvalueType = rvalueType.intersection(t[count]);
+ public void updateType() {
+
+ Type newType;
+
+ if (!isOpAssign) {
+ /* An opassign (+=, -=, etc.) doesn't merge rvalue type. */
+ Type lvalueType = subExpressions[0].getType();
+ Type rvalueType = subExpressions[1].getType();
+ subExpressions[0].setType(Type.tSuperType(rvalueType));
+ subExpressions[1].setType(Type.tSubType(lvalueType));
+ }
+
+ if (!isVoid())
+ updateParentType(subExpressions[0].getType());
}
- public int getOperandCount() {
- return 1 + getLValueOperandCount();
+ public Expression simplify() {
+ if (subExpressions[1] instanceof ConstOperator) {
+ ConstOperator one = (ConstOperator) subExpressions[1];
+
+ if ((getOperatorIndex() == OPASSIGN_OP+ADD_OP ||
+ getOperatorIndex() == OPASSIGN_OP+SUB_OP) &&
+ (one.getValue().equals("1")
+ || one.getValue().equals("1.0"))) {
+
+ int op = (getOperatorIndex() == OPASSIGN_OP+ADD_OP)
+ ? INC_OP : DEC_OP;
+
+ return new PrePostFixOperator
+ (getType(), op, getLValue(), isVoid()).simplify();
+ }
+ }
+ return super.simplify();
}
- public abstract void dumpLValue(TabbedPrintWriter writer,
- Expression[] operands)
- throws java.io.IOException;
+ public boolean opEquals(Operator o) {
+ return o instanceof StoreInstruction
+ && o.operatorIndex == operatorIndex
+ && o.isVoid() == isVoid();
+ }
- public void dumpExpression(TabbedPrintWriter writer, Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException
{
- dumpLValue(writer, operands);
+ subExpressions[0].dumpExpression(writer, 950);
writer.print(getOperatorString());
- operands[getLValueOperandCount()].dumpExpression(writer, 100);
+ subExpressions[1].dumpExpression(writer, 100);
}
}
diff --git a/jode/jode/expr/StringAddOperator.java b/jode/jode/expr/StringAddOperator.java
index a2007c7..4c3c473 100644
--- a/jode/jode/expr/StringAddOperator.java
+++ b/jode/jode/expr/StringAddOperator.java
@@ -21,31 +21,40 @@ package jode.expr;
import jode.type.Type;
import jode.decompiler.TabbedPrintWriter;
-public class StringAddOperator extends SimpleOperator {
+public class StringAddOperator extends Operator {
protected Type operandType;
public StringAddOperator() {
- super(Type.tString, ADD_OP, 2);
- operandTypes[1] = Type.tUnknown;
+ super(Type.tString, ADD_OP);
+ initOperands(2);
}
- public void clearFirstType() {
- operandTypes[0] = Type.tUnknown;
- }
-
public int getPriority() {
return 610;
}
- public boolean equals(Object o) {
+ public boolean opEquals(Operator o) {
return (o instanceof StringAddOperator);
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void updateSubTypes() {
+ /* A string add allows everything */
+ }
+
+ public void updateType() {
+ }
+
+
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
- operands[0].dumpExpression(writer, 610);
+
+ if (!subExpressions[0].getType().isOfType(Type.tString)
+ && !subExpressions[1].getType().isOfType(Type.tString))
+ writer.print("\"\" + ");
+
+ subExpressions[0].dumpExpression(writer, 610);
writer.print(getOperatorString());
- operands[1].dumpExpression(writer, 611);
+ subExpressions[1].dumpExpression(writer, 611);
}
}
+
diff --git a/jode/jode/expr/ThisOperator.java b/jode/jode/expr/ThisOperator.java
index c41625e..d7a43b7 100644
--- a/jode/jode/expr/ThisOperator.java
+++ b/jode/jode/expr/ThisOperator.java
@@ -20,6 +20,7 @@
package jode.expr;
import jode.type.Type;
import jode.bytecode.ClassInfo;
+import jode.decompiler.Scope;
import jode.decompiler.TabbedPrintWriter;
public class ThisOperator extends NoArgOperator {
@@ -48,19 +49,18 @@ public class ThisOperator extends NoArgOperator {
return classInfo+".this";
}
- public boolean equals(Object o) {
+ public boolean opEquals(Operator o) {
return (o instanceof ThisOperator &&
((ThisOperator) o).classInfo.equals(classInfo));
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
if (!isInnerMost) {
- writer.print(writer.getClassString(classInfo));
+ writer.print(writer.getClassString(classInfo,
+ Scope.AMBIGUOUSNAME));
writer.print(".");
}
writer.print("this");
}
}
-
diff --git a/jode/jode/expr/UnaryOperator.java b/jode/jode/expr/UnaryOperator.java
index ea38967..1722442 100644
--- a/jode/jode/expr/UnaryOperator.java
+++ b/jode/jode/expr/UnaryOperator.java
@@ -21,33 +21,42 @@ package jode.expr;
import jode.type.Type;
import jode.decompiler.TabbedPrintWriter;
-public class UnaryOperator extends SimpleOperator {
+public class UnaryOperator extends Operator {
public UnaryOperator(Type type, int op) {
- super(type, op, 1);
+ super(type, op);
+ initOperands(1);
}
public int getPriority() {
return 700;
}
- /**
- * Sets the return type of this operator.
- */
- public void setType(Type type) {
- super.setType(type);
- Type newOpType = type.intersection(operandTypes[0]);
- operandTypes[0] = newOpType;
+ public Expression negate() {
+ if (getOperatorIndex() == LOG_NOT_OP) {
+ if (subExpressions != null)
+ return subExpressions[0];
+ else
+ return new NopOperator(Type.tBoolean);
+ }
+ return super.negate();
}
- public boolean equals(Object o) {
- return (o instanceof UnaryOperator) &&
- ((UnaryOperator)o).operator == operator;
+ public void updateSubTypes() {
+ subExpressions[0].setType(Type.tSubType(type));
}
- public void dumpExpression(TabbedPrintWriter writer,
- Expression[] operands)
+ public void updateType() {
+ updateParentType(Type.tSuperType(subExpressions[0].getType()));
+ }
+
+ public boolean opEquals(Operator o) {
+ return (o instanceof UnaryOperator)
+ && o.operatorIndex == operatorIndex;
+ }
+
+ public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
writer.print(getOperatorString());
- operands[0].dumpExpression(writer, 700);
+ subExpressions[0].dumpExpression(writer, 700);
}
}