ConstOperator.getValue() returns Object not String.

IIncOperator.getValue() returns int not String.
ACCESSCONSTRUCTOR handling added
InvokeOperator has new constructor syntax
InvokeOperator reworked


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1183 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 25 years ago
parent 6885078d96
commit 75f42b3167
  1. 4
      jode/jode/expr/ConstOperator.java
  2. 4
      jode/jode/expr/IIncOperator.java
  3. 10
      jode/jode/expr/IfThenElseOperator.java
  4. 329
      jode/jode/expr/InvokeOperator.java.in
  5. 3
      jode/jode/expr/StoreInstruction.java

@ -69,8 +69,8 @@ public class ConstOperator extends NoArgOperator {
value = constant; value = constant;
} }
public String getValue() { public Object getValue() {
return String.valueOf(value); return value;
} }
public int getPriority() { public int getPriority() {

@ -38,8 +38,8 @@ public class IIncOperator extends Operator
return (LValueExpression) subExpressions[0]; return (LValueExpression) subExpressions[0];
} }
public String getValue() { public int getValue() {
return Integer.toString(value); return value;
} }
public int getPriority() { public int getPriority() {

@ -50,11 +50,11 @@ public class IfThenElseOperator extends Operator {
&& subExpressions[2] instanceof ConstOperator) { && subExpressions[2] instanceof ConstOperator) {
ConstOperator c1 = (ConstOperator) subExpressions[1]; ConstOperator c1 = (ConstOperator) subExpressions[1];
ConstOperator c2 = (ConstOperator) subExpressions[2]; ConstOperator c2 = (ConstOperator) subExpressions[2];
if (c1.getValue().equals("1") && if (c1.getValue().equals(new Integer(1)) &&
c2.getValue().equals("0")) c2.getValue().equals(new Integer(0)))
return subExpressions[0].simplify(); return subExpressions[0].simplify();
if (c2.getValue().equals("1") && if (c2.getValue().equals(new Integer(1)) &&
c1.getValue().equals("0")) c1.getValue().equals(new Integer(0)))
return subExpressions[0].negate().simplify(); return subExpressions[0].negate().simplify();
} }
} }
@ -84,7 +84,7 @@ public class IfThenElseOperator extends Operator {
&& invoke.subExpressions[0] instanceof ConstOperator && invoke.subExpressions[0] instanceof ConstOperator
&& (invoke.subExpressions[0].getType() && (invoke.subExpressions[0].getType()
.equals(Type.tString))) { .equals(Type.tString))) {
String clazz = String clazz = (String)
((ConstOperator)invoke.subExpressions[0]).getValue(); ((ConstOperator)invoke.subExpressions[0]).getValue();
if (field.setClassConstant(clazz)) if (field.setClassConstant(clazz))
return new ClassFieldOperator(clazz.charAt(0) == '[' return new ClassFieldOperator(clazz.charAt(0) == '['

@ -41,11 +41,22 @@ import @COLLECTIONS@.Iterator;
public final class InvokeOperator extends Operator public final class InvokeOperator extends Operator
implements MatchableOperator { implements MatchableOperator {
public final static int VIRTUAL = 0;
public final static int SPECIAL = 1;
public final static int STATIC = 2;
public final static int CONSTRUCTOR = 3;
public final static int ACCESSSPECIAL = 4;
/**
* The methodAnalyzer of the method, that contains this invocation.
* This is not the method that we should call.
*/
MethodAnalyzer methodAnalyzer; MethodAnalyzer methodAnalyzer;
boolean staticFlag; int methodFlag;
boolean specialFlag;
MethodType methodType; MethodType methodType;
String methodName; String methodName;
int skippedArgs;
Type classType; Type classType;
Type[] hints; Type[] hints;
@ -112,8 +123,7 @@ public final class InvokeOperator extends Operator
public InvokeOperator(MethodAnalyzer methodAnalyzer, public InvokeOperator(MethodAnalyzer methodAnalyzer,
boolean staticFlag, boolean specialFlag, int methodFlag, Reference reference) {
Reference reference) {
super(Type.tUnknown, 0); super(Type.tUnknown, 0);
this.methodType = Type.tMethod(reference.getType()); this.methodType = Type.tMethod(reference.getType());
this.methodName = reference.getName(); this.methodName = reference.getName();
@ -134,17 +144,16 @@ public final class InvokeOperator extends Operator
else else
this.type = methodType.getReturnType(); this.type = methodType.getReturnType();
this.methodAnalyzer = methodAnalyzer; this.methodAnalyzer = methodAnalyzer;
this.staticFlag = staticFlag; this.methodFlag = methodFlag;
this.specialFlag = specialFlag; if (methodFlag == STATIC)
if (staticFlag)
methodAnalyzer.useType(classType); methodAnalyzer.useType(classType);
initOperands((staticFlag ? 0 : 1) skippedArgs = (methodFlag == STATIC ? 0 : 1);
+ methodType.getParameterTypes().length); initOperands(skippedArgs + methodType.getParameterTypes().length);
checkAnonymousClasses(); checkAnonymousClasses();
} }
public final boolean isStatic() { public final boolean isStatic() {
return staticFlag; return methodFlag == STATIC;
} }
public MethodType getMethodType() { public MethodType getMethodType() {
@ -166,7 +175,7 @@ public final class InvokeOperator extends Operator
public void checkAnonymousClasses() { public void checkAnonymousClasses() {
if ((Decompiler.options & Decompiler.OPTION_ANON) == 0) if ((Decompiler.options & Decompiler.OPTION_ANON) == 0)
return; return;
if (!isConstructor()) if (methodFlag != CONSTRUCTOR)
return; return;
ClassInfo clazz = getClassInfo(); ClassInfo clazz = getClassInfo();
InnerClassInfo outer = getOuterClassInfo(clazz); InnerClassInfo outer = getOuterClassInfo(clazz);
@ -210,7 +219,7 @@ public final class InvokeOperator extends Operator
} }
public boolean isConstructor() { public boolean isConstructor() {
return methodName.equals("<init>"); return methodFlag == CONSTRUCTOR;
} }
public ClassInfo getClassInfo() { public ClassInfo getClassInfo() {
@ -221,8 +230,6 @@ public final class InvokeOperator extends Operator
/** /**
* Checks, whether this is a call of a method from this class. * Checks, whether this is a call of a method from this class.
* @XXX check, if this class implements the method and if not
* allow super class
*/ */
public boolean isThis() { public boolean isThis() {
return getClassInfo() == methodAnalyzer.getClazz(); return getClassInfo() == methodAnalyzer.getClazz();
@ -237,6 +244,69 @@ public final class InvokeOperator extends Operator
return null; return null;
} }
/**
* Tries to locate the class analyzer for the callee class. This
* is mainly useful for inner and anonymous classes.
*
* @return The class analyzer, if the callee class is declared
* inside the same base class as the caller class, null otherwise.
*/
public ClassAnalyzer getClassAnalyzer() {
if ((Decompiler.options &
(Decompiler.OPTION_ANON | Decompiler.OPTION_INNER)) == 0)
return null;
ClassInfo callee = getClassInfo();
if (callee == null)
return null;
int nested = 0;
InnerClassInfo[] outers = callee.getOuterClasses();
if ((Decompiler.options & Decompiler.OPTION_INNER) != 0
&& outers != null) {
/* If the callee class is an inner class we take its
* (outermost) parent instead. This will assure that we
* find the callee class with one inner -> outer pass.
*/
nested = outers.length;
if (outers[nested - 1].outer == null
|| outers[nested - 1].name == null)
nested--;
if (nested > 0)
callee = ClassInfo.forName(outers[nested - 1].outer);
}
/* Now we iterate the caller analyzer queue to find the class
* analyzer for callee
*/
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
while (callee != ana.getClazz()) {
if (ana.getParent() == null)
return null;
if (ana.getParent() instanceof MethodAnalyzer
&& (Decompiler.options & Decompiler.OPTION_ANON) != 0)
ana = ((MethodAnalyzer) ana.getParent())
.getClassAnalyzer();
else if (ana.getParent() instanceof ClassAnalyzer
&& (Decompiler.options
& Decompiler.OPTION_INNER) != 0)
ana = (ClassAnalyzer) ana.getParent();
else
throw new jode.AssertError
("Unknown parent: "+ana+": "+ana.getParent());
}
/* Now get the ClassAnalyzer of the real callee */
while (nested > 0) {
nested--;
ana = ana.getInnerClassAnalyzer(outers[nested].name);
if (ana == null)
return null;
}
return ana;
}
/** /**
* Checks, whether this is a call of a method from this class or an * Checks, whether this is a call of a method from this class or an
* outer instance. * outer instance.
@ -266,26 +336,18 @@ public final class InvokeOperator extends Operator
return false; return false;
} }
/**
* Tries to locate the method analyzer for the callee. This
* is mainly useful for inner and anonymous classes.
*
* @return The method analyzer, if the callee is declared
* inside the same base class as the caller class, null otherwise.
*/
public MethodAnalyzer getMethodAnalyzer() { public MethodAnalyzer getMethodAnalyzer() {
ClassInfo clazz = getClassInfo(); ClassAnalyzer ana = getClassAnalyzer();
if (clazz != null) { if (ana == null)
ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer(); return null;
while (true) { return ana.getMethod(methodName, methodType);
if (clazz == ana.getClazz()) {
return ana.getMethod(methodName, methodType);
}
if (ana.getParent() == null)
return null;
if (ana.getParent() instanceof MethodAnalyzer)
ana = ((MethodAnalyzer) ana.getParent())
.getClassAnalyzer();
else if (ana.getParent() instanceof ClassAnalyzer)
ana = (ClassAnalyzer) ana.getParent();
else
throw new jode.AssertError("Unknown parent");
}
}
return null;
} }
/** /**
@ -378,7 +440,7 @@ public final class InvokeOperator extends Operator
String result; String result;
try { try {
result = (String) interpreter.interpretMethod result = (String) interpreter.interpretMethod
(ma.getBytecodeInfo(), null, new String[] { op.getValue() }); (ma.getBytecodeInfo(), null, new Object[] { op.getValue() });
} catch (InterpreterException ex) { } catch (InterpreterException ex) {
GlobalOptions.err.println("Warning: Can't interpret method " GlobalOptions.err.println("Warning: Can't interpret method "
+methodName); +methodName);
@ -520,18 +582,30 @@ public final class InvokeOperator extends Operator
synth.getReference())); synth.getReference()));
break; break;
case SyntheticAnalyzer.ACCESSMETHOD: case SyntheticAnalyzer.ACCESSMETHOD:
op = new InvokeOperator(methodAnalyzer, false, op = new InvokeOperator(methodAnalyzer, ACCESSSPECIAL,
false, synth.getReference()); synth.getReference());
break; break;
case SyntheticAnalyzer.ACCESSSTATICMETHOD: case SyntheticAnalyzer.ACCESSSTATICMETHOD:
op = new InvokeOperator(methodAnalyzer, true, op = new InvokeOperator(methodAnalyzer, STATIC,
false, synth.getReference()); synth.getReference());
break;
case SyntheticAnalyzer.ACCESSCONSTRUCTOR:
if (subExpressions[1] instanceof ConstOperator
&& ((ConstOperator)
subExpressions[1]).getValue() == null) {
op = new InvokeOperator(methodAnalyzer, CONSTRUCTOR,
synth.getReference());
}
break; break;
} }
if (op != null) { if (op != null) {
if (subExpressions != null) { if (subExpressions != null) {
for (int i=subExpressions.length; i-- > 0; ) { for (int i=subExpressions.length; i-- > 0; ) {
if (i == 1 && synth.getKind()
== SyntheticAnalyzer.ACCESSCONSTRUCTOR)
// skip the null param.
continue;
op = op.addOperand(subExpressions[i]); op = op.addOperand(subExpressions[i]);
if (subExpressions[i].getFreeOperandCount() > 0) if (subExpressions[i].getFreeOperandCount() > 0)
break; break;
@ -546,7 +620,7 @@ public final class InvokeOperator extends Operator
public boolean needsCast(int param, Type[] paramTypes) { public boolean needsCast(int param, Type[] paramTypes) {
Type realClassType; Type realClassType;
if (staticFlag) if (methodFlag == STATIC)
realClassType = classType; realClassType = classType;
else { else {
if (param == 0) if (param == 0)
@ -559,7 +633,7 @@ public final class InvokeOperator extends Operator
return false; return false;
} }
ClassInfo clazz = ((ClassInterfacesType) realClassType).getClassInfo(); ClassInfo clazz = ((ClassInterfacesType) realClassType).getClassInfo();
int offset = staticFlag ? 0 : 1; int offset = skippedArgs;
Type[] myParamTypes = methodType.getParameterTypes(); Type[] myParamTypes = methodType.getParameterTypes();
if (myParamTypes[param-offset].equals(paramTypes[param])) { if (myParamTypes[param-offset].equals(paramTypes[param])) {
@ -658,7 +732,7 @@ public final class InvokeOperator extends Operator
clazz = interfaces[0]; clazz = interfaces[0];
} else { } else {
clazz = (superClazz != null clazz = (superClazz != null
? superClazz : ClassInfo.javaLangObject); ? superClazz : ClassInfo.javaLangObject);
} }
outer = getOuterClassInfo(clazz); outer = getOuterClassInfo(clazz);
} }
@ -685,14 +759,10 @@ public final class InvokeOperator extends Operator
*/ */
public void dumpExpression(TabbedPrintWriter writer) public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException { throws java.io.IOException {
boolean opIsThis = !staticFlag
&& subExpressions[0] instanceof ThisOperator;
int arg = 1; int arg = 1;
int length = subExpressions.length; int length = subExpressions.length;
/* true, if this is the constructor of an anonymous class and we
* must therefore dump the class. boolean anonymousNew = false;
*/
boolean dumpBlock = false;
ClassInfo clazz = getClassInfo(); ClassInfo clazz = getClassInfo();
ClassAnalyzer clazzAna = null; ClassAnalyzer clazzAna = null;
@ -700,17 +770,28 @@ public final class InvokeOperator extends Operator
for (int i=0; i< subExpressions.length; i++) for (int i=0; i< subExpressions.length; i++)
paramTypes[i] = subExpressions[i].getType().getCanonic(); paramTypes[i] = subExpressions[i].getType().getCanonic();
if (isConstructor()) { switch (methodFlag) {
case CONSTRUCTOR: {
boolean qualifiedNew = false;
boolean jikesAnonymousInner = false; boolean jikesAnonymousInner = false;
/* Check if this is an anonymous constructor. In this case
* clazz and outer will be changed to point to the
* super class and anonymousNew will be set.
*/
InnerClassInfo outer = getOuterClassInfo(clazz); InnerClassInfo outer = getOuterClassInfo(clazz);
if (outer != null && outer.name == null)
anonymousNew = true;
clazzAna = methodAnalyzer.getClassAnalyzer(clazz); clazzAna = methodAnalyzer.getClassAnalyzer(clazz);
if ((~Decompiler.options &
if ((Decompiler.options & (Decompiler.OPTION_ANON | Decompiler.OPTION_CONTRAFO)) == 0
(Decompiler.OPTION_ANON | Decompiler.OPTION_CONTRAFO)) != 0
&& clazzAna != null && clazzAna != null
&& outer != null && outer != null
&& (outer.outer == null || outer.name == null)) { && (outer.outer == null || outer.name == null)) {
/* This is a method scoped class, skip the outerValues */
arg += clazzAna.getOuterValues().length; arg += clazzAna.getOuterValues().length;
jikesAnonymousInner = clazzAna.isJikesAnonymousInner(); jikesAnonymousInner = clazzAna.isJikesAnonymousInner();
@ -730,7 +811,6 @@ public final class InvokeOperator extends Operator
? superClazz : ClassInfo.javaLangObject); ? superClazz : ClassInfo.javaLangObject);
} }
outer = getOuterClassInfo(clazz); outer = getOuterClassInfo(clazz);
dumpBlock = true;
if (jikesAnonymousInner if (jikesAnonymousInner
&& outer.outer == null && outer.name != null) { && outer.outer == null && outer.name != null) {
Expression thisExpr = subExpressions[--length]; Expression thisExpr = subExpressions[--length];
@ -747,11 +827,15 @@ public final class InvokeOperator extends Operator
} }
} }
/* Check if this is an inner class. It will dump the outer
* class expression, except if its default.
*/
if (outer != null && outer.outer != null && outer.name != null if (outer != null && outer.outer != null && outer.name != null
&& !Modifier.isStatic(outer.modifiers) && !Modifier.isStatic(outer.modifiers)
&& (Decompiler.options & && (~Decompiler.options &
(Decompiler.OPTION_INNER (Decompiler.OPTION_INNER
| Decompiler.OPTION_CONTRAFO)) != 0) { | Decompiler.OPTION_CONTRAFO)) == 0) {
Expression outerExpr = jikesAnonymousInner Expression outerExpr = jikesAnonymousInner
? subExpressions[--length] ? subExpressions[--length]
: subExpressions[arg++]; : subExpressions[arg++];
@ -770,10 +854,12 @@ public final class InvokeOperator extends Operator
(((ThisOperator) outerExpr).getClassInfo(), (((ThisOperator) outerExpr).getClassInfo(),
Scope.CLASSSCOPE); Scope.CLASSSCOPE);
if (writer.conflicts(outer.name, scope, Scope.CLASSNAME)) { if (writer.conflicts(outer.name, scope, Scope.CLASSNAME)) {
qualifiedNew = true;
outerExpr.dumpExpression(writer, 950); outerExpr.dumpExpression(writer, 950);
writer.print("."); writer.print(".");
} }
} else { } else {
qualifiedNew = true;
if (outerExpr.getType() instanceof NullType) { if (outerExpr.getType() instanceof NullType) {
writer.print("(("); writer.print("((");
writer.printType(Type.tClass writer.printType(Type.tClass
@ -786,52 +872,94 @@ public final class InvokeOperator extends Operator
writer.print("."); writer.print(".");
} }
} }
}
if (specialFlag) { if (subExpressions[0] instanceof NewOperator
if (opIsThis && paramTypes[0].equals(classType)) {
writer.print("new ");
if (qualifiedNew)
writer.print(outer.name);
else
writer.printType(Type.tClass(clazz));
break;
}
if (subExpressions[0] instanceof ThisOperator
&& (((ThisOperator)subExpressions[0]).getClassInfo() && (((ThisOperator)subExpressions[0]).getClassInfo()
== methodAnalyzer.getClazz())) { == methodAnalyzer.getClazz())) {
if (isThis()) { if (isThis())
/* XXX check if this is a private or final method. */ writer.print("this");
} else { else
/* XXX check that this is the first defined writer.print("super");
* super method. */ break;
}
writer.print("((UNCONSTRUCTED)");
subExpressions[0].dumpExpression(writer, 950);
writer.print(").");
writer.printType(Type.tClass(clazz));
break;
}
case SPECIAL:
if (subExpressions[0] instanceof ThisOperator
&& (((ThisOperator)subExpressions[0]).getClassInfo()
== methodAnalyzer.getClazz())) {
if (!isThis()) {
/* We don't have to check if this is the real super
* class, as long as ACC_SUPER is set.
*/
writer.print("super"); writer.print("super");
ClassInfo superClazz = getClassInfo().getSuperclass(); ClassInfo superClazz = getClassInfo().getSuperclass();
paramTypes[0] = superClazz == null paramTypes[0] = superClazz == null
? Type.tObject : Type.tClass(superClazz); ? Type.tObject : Type.tClass(superClazz);
opIsThis = false; writer.print(".");
} else {
/* XXX check if this is a private method. */
} }
} else if (isConstructor()
&& subExpressions[0] instanceof NewOperator) {
writer.print("new ");
writer.printType(Type.tClass(clazz));
} else { } else {
/* XXX check if this is a private or final method. */ writer.print("((NON VIRTUAL ");
int minPriority = 950; /* field access */ writer.printType(classType);
if (!isThis()) { writer.print(")");
writer.print("(NON VIRTUAL "); paramTypes[0] = classType;
writer.printType(classType); subExpressions[0].dumpExpression(writer, 700);
writer.print(")"); writer.print(").");
paramTypes[0] = classType; }
minPriority = 700; writer.print(methodName);
} break;
subExpressions[0].dumpExpression(writer, minPriority);
case ACCESSSPECIAL:
/* Calling a private method in another class. (This is
* allowed for inner classes.)
*/
if (paramTypes[0].equals(classType))
subExpressions[0].dumpExpression(writer, 950);
else {
writer.print("((");
writer.printType(classType);
writer.print(")");
paramTypes[0] = classType;
subExpressions[0].dumpExpression(writer, 700);
writer.print(")");
} }
} else if (staticFlag) { writer.print(".");
writer.print(methodName);
break;
case STATIC: {
arg = 0; arg = 0;
Scope scope = writer.getScope(getClassInfo(), Scope scope = writer.getScope(getClassInfo(),
Scope.CLASSSCOPE); Scope.CLASSSCOPE);
if (scope != null if (scope == null
&& !writer.conflicts(methodName, scope, Scope.METHODNAME)) ||writer.conflicts(methodName, scope, Scope.METHODNAME)) {
opIsThis = true;
else
writer.printType(classType); writer.printType(classType);
} else { writer.print(".");
if (opIsThis) { }
writer.print(methodName);
break;
}
case VIRTUAL:
if (subExpressions[0] instanceof ThisOperator) {
ThisOperator thisOp = (ThisOperator) subExpressions[0]; ThisOperator thisOp = (ThisOperator) subExpressions[0];
Scope scope = writer.getScope(thisOp.getClassInfo(), Scope scope = writer.getScope(thisOp.getClassInfo(),
Scope.CLASSSCOPE); Scope.CLASSSCOPE);
@ -868,20 +996,14 @@ public final class InvokeOperator extends Operator
paramTypes[0] = classType; paramTypes[0] = classType;
} else } else
subExpressions[0].dumpExpression(writer, 950); subExpressions[0].dumpExpression(writer, 950);
}
}
if (isConstructor()) {
if (opIsThis)
writer.print("this");
} else {
if (!opIsThis)
writer.print("."); writer.print(".");
}
writer.print(methodName); writer.print(methodName);
} }
writer.print("("); writer.print("(");
boolean first = true; boolean first = true;
int offset = staticFlag ? 0 : 1; int offset = skippedArgs;
while (arg < length) { while (arg < length) {
if (!first) if (!first)
writer.print(", "); writer.print(", ");
@ -899,7 +1021,11 @@ public final class InvokeOperator extends Operator
subExpressions[arg++].dumpExpression(writer, priority); subExpressions[arg++].dumpExpression(writer, priority);
} }
writer.print(")"); writer.print(")");
if (dumpBlock) {
if (anonymousNew) {
/* If this was an anonymous constructor call, we must now
* dump the source code of the anonymous class.
*/
writer.openBrace(); writer.openBrace();
writer.tab(); writer.tab();
clazzAna.dumpBlock(writer); clazzAna.dumpBlock(writer);
@ -907,4 +1033,15 @@ public final class InvokeOperator extends Operator
writer.closeBraceNoSpace(); writer.closeBraceNoSpace();
} }
} }
public boolean opEquals(Operator o) {
if (o instanceof InvokeOperator) {
InvokeOperator i = (InvokeOperator)o;
return classType.equals(i.classType)
&& methodName.equals(i.methodName)
&& methodType.equals(i.methodType)
&& methodFlag == i.methodFlag;
}
return false;
}
} }

@ -90,8 +90,7 @@ public class StoreInstruction extends Operator
if ((getOperatorIndex() == OPASSIGN_OP+ADD_OP || if ((getOperatorIndex() == OPASSIGN_OP+ADD_OP ||
getOperatorIndex() == OPASSIGN_OP+SUB_OP) && getOperatorIndex() == OPASSIGN_OP+SUB_OP) &&
(one.getValue().equals("1") ((Number)one.getValue()).doubleValue() == 1.0) {
|| one.getValue().equals("1.0"))) {
int op = (getOperatorIndex() == OPASSIGN_OP+ADD_OP) int op = (getOperatorIndex() == OPASSIGN_OP+ADD_OP)
? INC_OP : DEC_OP; ? INC_OP : DEC_OP;

Loading…
Cancel
Save