removed unneeded files from CVS repository

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1024 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 25 years ago
parent f6f5d1707e
commit 71b1a85b6d
  1. 18
      jode/Block.java
  2. 54
      jode/CombineCatchLocal.java
  3. 76
      jode/CreateBreakStatement.java
  4. 109
      jode/CreateConstantArray.java
  5. 48
      jode/CreateDoWhileStatements.java
  6. 109
      jode/CreateIfStatements.java
  7. 61
      jode/CreateNewConstructor.java
  8. 197
      jode/CreateSwitchStatements.java
  9. 80
      jode/CreateTryCatchStatements.java
  10. 59
      jode/CreateWhileStatements.java
  11. 98
      jode/FlowTransformation.java
  12. 178
      jode/JodeAppletOneZero.java
  13. 40
      jode/RemoveNop.java
  14. 24
      jode/Transformation.java
  15. 104
      jode/jode/bytecode/AttributeInfo.java
  16. 177
      jode/jode/bytecode/ClassHierarchy.java
  17. 63
      jode/jode/bytecode/CodeInfo.java
  18. 535
      jode/jode/decompiler/CodeAnalyzer.java
  19. 27
      jode/jode/decompiler/LocalVariable.java
  20. 229
      jode/jode/decompiler/LocalVariableAnalyzer.java
  21. 41
      jode/jode/decompiler/LocalVariableHash.java
  22. 79
      jode/jode/expr/AssignOperator.java
  23. 89
      jode/jode/expr/BreakInstructionHeader.java
  24. 80
      jode/jode/expr/CaseInstructionHeader.java
  25. 95
      jode/jode/expr/CatchInstructionHeader.java
  26. 70
      jode/jode/expr/CombineIfGotoExpressions.java
  27. 617
      jode/jode/expr/ComplexExpression.java
  28. 86
      jode/jode/expr/CreateAssignExpression.java
  29. 55
      jode/jode/expr/CreateExpression.java
  30. 139
      jode/jode/expr/CreateIfThenElseOperator.java
  31. 118
      jode/jode/expr/CreatePostIncExpression.java
  32. 177
      jode/jode/expr/DoWhileInstructionHeader.java
  33. 43
      jode/jode/expr/DupOperator.java
  34. 40
      jode/jode/expr/EmptyStringOperator.java
  35. 40
      jode/jode/expr/GotoOperator.java
  36. 39
      jode/jode/expr/IfGotoOperator.java
  37. 182
      jode/jode/expr/IfInstructionHeader.java
  38. 42
      jode/jode/expr/Instruction.java
  39. 581
      jode/jode/expr/InstructionHeader.java
  40. 44
      jode/jode/expr/JsrInstructionHeader.java
  41. 14
      jode/jode/expr/JsrOperator.java
  42. 12
      jode/jode/expr/JumpInstruction.java
  43. 25
      jode/jode/expr/LoadOperator.java
  44. 37
      jode/jode/expr/LocalPostFixOperator.java
  45. 49
      jode/jode/expr/LocalPrePostFixOperator.java
  46. 110
      jode/jode/expr/MethodInstructionHeader.java
  47. 19
      jode/jode/expr/NewConstructorOperator.java
  48. 71
      jode/jode/expr/PostFixOperator.java
  49. 64
      jode/jode/expr/RetInstructionHeader.java
  50. 15
      jode/jode/expr/RetOperator.java
  51. 44
      jode/jode/expr/ReturnOperator.java
  52. 80
      jode/jode/expr/SimpleSwitchInstructionHeader.java
  53. 28
      jode/jode/expr/SimplifyExpression.java
  54. 46
      jode/jode/expr/StoreOperator.java
  55. 31
      jode/jode/expr/SwapOperator.java
  56. 208
      jode/jode/expr/SwitchInstructionHeader.java
  57. 70
      jode/jode/expr/SwitchOperator.java
  58. 32
      jode/jode/expr/ThrowOperator.java
  59. 195
      jode/jode/expr/TryCatchInstructionHeader.java
  60. 73
      jode/jode/expr/TryInstructionHeader.java
  61. 174
      jode/jode/expr/WhileInstructionHeader.java
  62. 108
      jode/jode/flow/CatchFinallyBlock.java
  63. 148
      jode/jode/flow/CreatePostIncExpression.java
  64. 116
      jode/jode/flow/MarkInlineExpression.java
  65. 140
      jode/jode/flow/RawTryCatchBlock.java
  66. 105
      jode/jode/flow/RemoveEmpty.java
  67. 40
      jode/jode/flow/SimplifyExpression.java
  68. 24
      jode/jode/flow/Transformation.java
  69. 30
      jode/jode/jvm/ReturnAddress.java
  70. 174
      jode/jode/obfuscator/ClassReachability.java
  71. 35
      jode/jode/obfuscator/FieldListener.java
  72. 47
      jode/jode/obfuscator/IdentifierEvent.java
  73. 34
      jode/jode/obfuscator/IdentifierListener.java
  74. 28
      jode/jode/obfuscator/LoadedClassIdentifier.java
  75. 224
      jode/jode/obfuscator/LogicalDeadCodeOptimizer.java
  76. 132
      jode/jode/obfuscator/MethodReachability.java
  77. 298
      jode/jode/type/ClassRangeType.java
  78. 182
      jode/jode/type/MyType.java
  79. 125
      jode/jode/type/UnfoundClassType.java
  80. 22
      jode/jode/type/UnknownSubType.java
  81. 22
      jode/jode/type/UnknownSuperType.java
  82. 204
      jode/jode/type/UnknownType.java
  83. 253
      jode/test/Test.java

@ -1,18 +0,0 @@
package jode;
public class Block extends Instruction {
Expression[] exprs;
public Block(int addr, int length, Expression[] exprs) {
super(addr,length);
this.exprs = exprs;
}
public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca)
throws java.io.IOException
{
for (int i=0; i< exprs.length; i++)
exprs[i].dumpSource(writer,ca);
}
}

@ -1,54 +0,0 @@
/*
* CombineCatchLocal (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Vector;
import sun.tools.java.Identifier;
public class CombineCatchLocal implements Transformation{
// static Identifier idException = Identifier.lookup("exception");
public InstructionHeader transform(InstructionHeader ih) {
CatchInstructionHeader catchIH;
LocalInfo local;
try {
catchIH = (CatchInstructionHeader)ih;
ih = ih.nextInstruction;
if (ih.getPredecessors().size() != 1)
return null;
Instruction instr = ih.getInstruction();
if (instr instanceof PopOperator) {
local = new LocalInfo(99);
} else if (instr instanceof LocalStoreOperator) {
local = ((LocalStoreOperator) instr).getLocalInfo();
} else
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
if (!catchIH.combineWithLocal(local))
return null;
if(Decompiler.isVerbose)
System.err.print("c");
return catchIH;
}
}

@ -1,76 +0,0 @@
/*
* CreateBreakStatement (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class CreateBreakStatement implements Transformation {
public InstructionHeader transform(InstructionHeader ih) {
InstructionHeader breakDest;
if (ih.getFlowType() == ih.GOTO)
breakDest = ih.successors[0].getShadow();
else if (ih.getFlowType() == ih.IFGOTO)
breakDest = ih.successors[1].getShadow();
else
return null;
if (breakDest == ih.getEndBlock()) {
/* This is an unnecessary goto, remove it.
*/
if (ih.prevInstruction != null)
ih.prevInstruction.nextInstruction = ih.nextInstruction;
if (ih.nextInstruction != null)
ih.nextInstruction.prevInstruction = ih.prevInstruction;
breakDest.addPredecessors(ih);
breakDest.predecessors.removeElement(ih);
if (Decompiler.isVerbose)
System.err.print("g");
return null;
}
boolean needBreakLabel = false, needContLabel = false;
InstructionHeader outer = ih.outer;
while (outer != null) {
if (outer.getBreak() == breakDest) {
if (Decompiler.isVerbose)
System.err.print("b");
return new BreakInstructionHeader
(ih.BREAK, ih, needBreakLabel?outer.getLabel(): null);
}
if (outer.getContinue() == breakDest) {
if (Decompiler.isVerbose)
System.err.print("c");
return new BreakInstructionHeader
(ih.CONTINUE, ih, needContLabel?outer.getLabel(): null);
}
if (outer.outer == null && outer.getEndBlock() == breakDest) {
if (Decompiler.isVerbose)
System.err.print("r");
return new BreakInstructionHeader
(ih.VOIDRETURN, ih, null);
}
if (outer.getBreak() != null)
needBreakLabel = true;
if (outer.getContinue() != null)
needContLabel = true;
outer = outer.outer;
}
return null;
}
}

@ -1,109 +0,0 @@
/*
* CreateConstantArray (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import sun.tools.java.Type;
public class CreateConstantArray implements Transformation {
public InstructionHeader transform(InstructionHeader ih) {
Expression[] consts = null;
int count = 0;
Type type;
try {
if (ih.getInstruction() instanceof DupOperator)
/* this is not the end of the array assign */
return null;
ih = ih.getSimpleUniquePredecessor();
int lastindex = -1;
while (ih.getInstruction() instanceof ArrayStoreOperator) {
ArrayStoreOperator store =
(ArrayStoreOperator) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
Expression lastconst = (Expression) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
Expression indexexpr = (Expression) ih.getInstruction();
ConstOperator indexop =
(ConstOperator) indexexpr.getOperator();
if (!MyType.isOfType(indexop.getType(), MyType.tUInt))
return null;
int index = Integer.parseInt(indexop.getValue());
if (index >= 0 && consts == null) {
lastindex = index;
consts = new Expression[lastindex+1];
} else if (index < 0 || index > lastindex)
return null;
else {
while (index < lastindex) {
consts[lastindex--] = new Expression
(new ConstOperator(MyType.tUnknown, "0"),
new Expression[0]);
}
}
consts[lastindex--] = lastconst;
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != 0 ||
dup.getCount() != store.getLValueType().stackSize())
return null;
count++;
ih = ih.getSimpleUniquePredecessor();
}
if (count == 0)
return null;
while (lastindex >= 0) {
consts[lastindex--] = new Expression
(new ConstOperator(MyType.tUnknown, "0"),
new Expression[0]);
}
Expression newArrayExpr = (Expression) ih.getInstruction();
NewArrayOperator newArrayOp =
(NewArrayOperator) newArrayExpr.getOperator();
type = newArrayOp.getType();
if (newArrayOp.getOperandCount() != 1)
return null;
Expression countexpr =
(Expression) newArrayExpr.getSubExpressions()[0];
ConstOperator countop =
(ConstOperator) countexpr.getOperator();
if (!MyType.isOfType(countop.getType(), MyType.tUInt))
return null;
int arraylength = Integer.parseInt(countop.getValue());
if (arraylength != consts.length) {
if (arraylength < consts.length)
return null;
Expression[] newConsts = new Expression[arraylength];
System.arraycopy(consts, 0, newConsts, 0, consts.length);
for (int i=consts.length; i<arraylength; i++)
newConsts[i] = new Expression
(new ConstOperator(MyType.tUnknown, "0"),
new Expression[0]);
consts = newConsts;
}
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
if (Decompiler.isVerbose)
System.err.print("a");
Operator op = new ConstantArrayOperator(type, consts.length);
return ih.combine(4*count+1, new Expression(op, consts));
}
}

@ -1,48 +0,0 @@
/*
* CreateDoWhileStatements (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Enumeration;
public class CreateDoWhileStatements extends FlowTransformation
implements Transformation {
public InstructionHeader transform(InstructionHeader head) {
if (head.predecessors.size() == 0 ||
head.flowType == head.DOWHILESTATEMENT)
return null;
InstructionHeader end = head;
Enumeration enum = head.predecessors.elements();
while (enum.hasMoreElements()) {
InstructionHeader pre = (InstructionHeader) enum.nextElement();
if (pre.outer == head.outer && pre.addr > end.addr)
end = pre;
}
if (end != head)
if (end.flowType == end.IFGOTO || end.flowType == end.GOTO) {
if(Decompiler.isVerbose)
System.err.print("d");
return new DoWhileInstructionHeader(head, end);
}
return null;
}
}

@ -1,109 +0,0 @@
/*
* CreateIfStatements (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class CreateIfStatements extends FlowTransformation
implements Transformation {
public InstructionHeader transform(InstructionHeader ifgoto) {
if (ifgoto.getFlowType() != ifgoto.IFGOTO ||
ifgoto.nextInstruction == null ||
ifgoto.getSuccessors()[1].getAddress() <=
ifgoto.getSuccessors()[0].getAddress())
return null;
/* elseBlock points to the first instruction of the
* elseBlock or is null if the else block is empty.
* next points to the next instruction after this block
* or is null, if this if is the last instruction in
* this block.
*/
InstructionHeader elseBlock = null, next = null;
if (ifgoto.outer != ifgoto.successors[1].outer) {
if (ifgoto.outer.getEndBlock() != ifgoto.successors[1].getShadow())
/* This doesn't seem to be an if but a if-break
*/
return null;
/* This is an if without else that goes to the end
* of the current block. May be this was a continue,
* but who would know it?
*
* If you like breaks and continues more than ifs,
* simply do the break transformation before the
* if transformation.
*/
next = null;
} else {
/* This is a normal if, let us first assume, that there is
* no else part. Then end is successors[1], but that may
* be a while loop, so unoptimized it...
*/
next = UnoptimizeWhileLoops(ifgoto.successors[1]);
if (next != ifgoto.successors[1]) {
ifgoto.successors[1].predecessors.removeElement(ifgoto);
ifgoto.successors[1] = next;
ifgoto.successors[1].predecessors.addElement(ifgoto);
}
/* next.prevInstruction is the end of the `then' block.
* If this a goto statement that jumps downward, this is
* probably an `if-then-else'.
*/
InstructionHeader thenEnd = next.prevInstruction;
if (thenEnd.flowType == thenEnd.GOTO) {
if (thenEnd.successors[0].outer == next.outer &&
thenEnd.successors[0].addr >= next.addr) {
/* this is a normal if-then-else that is
* fully contained in this block.
*/
elseBlock = next;
next = UnoptimizeWhileLoops(thenEnd.successors[0]);
} else if (thenEnd.successors[0].getShadow() ==
ifgoto.outer.getEndBlock()) {
/* this is a normal if-then-else that goes
* to the end of the block.
*
* Again this may also be a continue/break statement,
* but again, who knows.
*/
elseBlock = next;
next = null;
}
}
}
/* This was all, the rest is done in the constructor of
* IfInstructionHeader.
*/
if(Decompiler.isVerbose)
System.err.print("i");
return new IfInstructionHeader
(ifgoto, elseBlock, next);
}
}

@ -1,61 +0,0 @@
/*
* CreateNewConstructor (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class CreateNewConstructor implements Transformation{
public InstructionHeader transform(InstructionHeader ih) {
InvokeOperator constrCall;
Expression exprs[];
try {
constrCall = (InvokeOperator) ih.getInstruction();
if (!constrCall.isConstructor())
return null;
int params = constrCall.getOperandCount();
exprs = new Expression[params];
for (int i = params-1; i>0; i--) {
ih = ih.getSimpleUniquePredecessor();
exprs[i] = (Expression) ih.getInstruction();
if (exprs[i].isVoid())
return null; /* XXX */
}
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getCount() != 1 && dup.getDepth() != 0)
return null;
ih = ih.getSimpleUniquePredecessor();
exprs[0] = (Expression) ih.getInstruction();
if (exprs[0].isVoid())
return null;
NewOperator op = (NewOperator) exprs[0].getOperator();
if (constrCall.getClassType() != op.getType())
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
ConstructorOperator conOp =
new ConstructorOperator(constrCall.getClassType(),
constrCall.getField());
return ih.combine(exprs.length+2, new Expression(conOp, exprs));
}
}

@ -1,197 +0,0 @@
/*
* CreateSwitchStatements (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Enumeration;
public class CreateSwitchStatements extends FlowTransformation
implements Transformation {
public InstructionHeader transform(InstructionHeader ih) {
if (ih.getFlowType() != ih.SWITCH)
return null;
SimpleSwitchInstructionHeader switchIH =
(SimpleSwitchInstructionHeader) ih;
int defaultCase = switchIH.successors.length - 1;
int addr = switchIH.nextInstruction.addr;
int count = 1;
for (int i=0; i < switchIH.successors.length; i++) {
if (switchIH.successors[i] != switchIH.successors[defaultCase])
count ++;
}
int[] cases = new int[count];
InstructionHeader[] sorted = new InstructionHeader[count];
count = 0;
for (int i=0; i < switchIH.successors.length; i++) {
if (i != defaultCase &&
switchIH.successors[i] == switchIH.successors[defaultCase])
continue;
InstructionHeader next =
UnoptimizeWhileLoops(switchIH.successors[i]);
if (next != switchIH.successors[i]) {
switchIH.successors[i].predecessors.removeElement(switchIH);
switchIH.successors[i] = next;
switchIH.successors[i].predecessors.addElement(switchIH);
}
int insert;
for (insert = 0; insert < count; insert++) {
if (sorted[insert].addr > switchIH.successors[i].addr)
break;
}
if (insert < count) {
System.arraycopy(cases, insert,
cases, insert+1, count-insert);
System.arraycopy(sorted, insert,
sorted, insert+1, count-insert);
}
if (i == defaultCase)
defaultCase = insert;
else
cases[insert] = switchIH.cases[i];
sorted[insert] = switchIH.successors[i];
count++;
}
InstructionHeader endBlock = switchIH.outer.getEndBlock();
int lastBlock;
for (lastBlock = count-1; lastBlock>= 0; lastBlock--)
if (sorted[lastBlock].outer == switchIH.outer)
break;
if (lastBlock >= 0) {
EndSearch:
ih = sorted[lastBlock];
while (ih != null) {
Enumeration enum;
if (ih.flowType == ih.GOTO)
enum = ih.successors[0].getPredecessors().elements();
else
enum = ih.getPredecessors().elements();
while (enum.hasMoreElements()) {
InstructionHeader pred =
(InstructionHeader)enum.nextElement();
if (pred.addr < sorted[lastBlock].addr &&
pred.outer == switchIH.outer &&
(pred.flowType == ih.GOTO ||
(pred.flowType == ih.IFGOTO &&
pred.successors[1] == ih)) &&
ih == UnoptimizeWhileLoops(ih)) {
endBlock = ih;
/* search further down, if there are other
* more suitible instructions.
*/
}
}
ih = ih.nextInstruction;
}
}
for (int i=0; i< sorted.length; i++) {
if (sorted[i].outer != switchIH.outer) {
if (sorted[i].getShadow() != endBlock) {
/* Create a new goto at the beginning of
* the switch statement, jumping to the right
* successor.
*/
InstructionHeader[] successors = { sorted[i] };
InstructionHeader dummyGoto =
new InstructionHeader(switchIH.GOTO,
switchIH.addr, switchIH.addr,
successors, switchIH.outer);
sorted[i].predecessors.addElement(dummyGoto);
/* Connect it in the prev/next Instruction chain.
*/
dummyGoto.nextInstruction = switchIH.nextInstruction;
if (dummyGoto.nextInstruction != null)
dummyGoto.nextInstruction.prevInstruction = dummyGoto;
switchIH.nextInstruction = dummyGoto;
dummyGoto.prevInstruction = switchIH;
/* Search all instructions that jump to this point and
* stack them together.
*/
int length = 1;
while (i+length < sorted.length &&
sorted[i+length] == sorted[i])
length++;
/* Move them to the beginning of this array.
*/
System.arraycopy(sorted, 0, sorted, length, i);
int[] tmp = new int[length];
System.arraycopy(cases, i, tmp, 0, length);
System.arraycopy(cases, 0, cases, length, i);
System.arraycopy(tmp, 0, cases, 0, length);
if (defaultCase < i)
defaultCase += length;
else if (defaultCase <= i+length)
defaultCase -= i;
for (int j=0; j<length; j++)
sorted[j] = dummyGoto;
i += length - 1;
} else {
/* Search all instructions that jump to this point and
* stack them together.
*/
int length = 1;
while (i+length < sorted.length &&
sorted[i+length] == sorted[i])
length++;
/* Move them to the end of this array, if they
* aren't already there.
*/
if (i+length < sorted.length) {
System.arraycopy(sorted, i + length, sorted, i,
sorted.length - i - length);
for (int j=length; j>0; j--)
sorted[sorted.length-j] = endBlock;
int[] tmp = new int[length];
System.arraycopy(cases, i, tmp, 0, length);
System.arraycopy(cases, i + length, cases, i,
cases.length - i - length);
System.arraycopy(tmp, 0, cases,
sorted.length - length, length);
if (defaultCase >= i + length)
defaultCase -= length;
else if (defaultCase >=i)
defaultCase += cases.length-i-length;
}
}
}
}
if(Decompiler.isVerbose)
System.err.print("s");
return new SwitchInstructionHeader
(switchIH, cases, sorted, defaultCase, endBlock);
}
}

@ -1,80 +0,0 @@
/*
* CreateTryCatchStatements (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class CreateTryCatchStatements extends FlowTransformation
implements Transformation {
public InstructionHeader transform(InstructionHeader tryIH) {
if (tryIH.getFlowType() != tryIH.TRY ||
tryIH.successors.length == 1 ||
tryIH.nextInstruction == null)
return null;
/* find handler with largest end address
* and count the catches.
*/
InstructionHeader endIH = tryIH;
int index = 0, count = 0;
for (int i=1; i < tryIH.successors.length; i+=2) {
if (tryIH.successors[i] == endIH)
count++;
else if (tryIH.successors[i].addr > endIH.addr) {
endIH = tryIH.successors[i];
count = 1;
}
}
if (count == 0 || endIH.outer != tryIH.outer)
return null;
/* now find all corresponding catches */
InstructionHeader[] catchIH = new InstructionHeader[count+1];
InstructionHeader[] remaining =
new InstructionHeader[tryIH.successors.length-2*count];
int index1 = 0, index2=0;
remaining[index2++] = tryIH.successors[0];
catchIH[index1++] = tryIH;
for (int i=1; i < tryIH.successors.length; i+=2) {
if (tryIH.successors[i] == endIH) {
/* assume that the catches are already sorted */
if (tryIH.successors[i+1].outer != tryIH.outer ||
tryIH.successors[i+1].flowType != InstructionHeader.CATCH)
return null;
catchIH[index1] = tryIH.successors[i+1];
index1++;
} else {
remaining[index2++] = tryIH.successors[i];
remaining[index2++] = tryIH.successors[i+1];
}
}
InstructionHeader endBlock;
if (endIH != catchIH[1]) {
if (endIH.flowType != endIH.GOTO)
return null;
endBlock = UnoptimizeWhileLoops(endIH.successors[0]);
} else
endBlock = tryIH.outer.getEndBlock();
if (Decompiler.isVerbose)
System.err.print("t");
return new TryCatchInstructionHeader
(catchIH, endIH, remaining, endBlock);
}
}

@ -1,59 +0,0 @@
/*
* CreateWhileStatements (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class CreateWhileStatements extends FlowTransformation
implements Transformation {
public InstructionHeader transform(InstructionHeader gotoIH) {
if (gotoIH.flowType == gotoIH.IFGOTO &&
gotoIH.successors[1] == gotoIH)
/* This is an empty while loop
*/
return new WhileInstructionHeader(gotoIH, gotoIH);
if (gotoIH.flowType != gotoIH.GOTO ||
gotoIH.nextInstruction == null ||
gotoIH.successors[0].addr < gotoIH.nextInstruction.addr ||
gotoIH.outer != gotoIH.successors[0].outer)
return null;
InstructionHeader ifgoto = gotoIH.successors[0];
if (ifgoto.getFlowType() != ifgoto.IFGOTO ||
ifgoto.outer != ifgoto.successors[1].outer)
return null;
InstructionHeader next = UnoptimizeWhileLoops(ifgoto.successors[1]);
if (next != gotoIH.nextInstruction)
return null;
if (next != ifgoto.successors[1]) {
ifgoto.successors[1].predecessors.removeElement(ifgoto);
ifgoto.successors[1] = next;
ifgoto.successors[1].predecessors.addElement(ifgoto);
}
if(Decompiler.isVerbose)
System.err.print("w");
return new WhileInstructionHeader(gotoIH, ifgoto);
}
}

@ -1,98 +0,0 @@
/*
* FlowTransformation (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
abstract public class FlowTransformation {
/**
* This class reverses javac's optimization of while loops.
* A while loop is normally implemented as follows:
*
* <pre>
* loop: goto cond;
* head: <inner block>
* cond: if <condition> goto head;
* </pre>
*
* The problem is, if a while loop is the destination of a jump
* (e.g. it's in the else-part of an if, but there are many more
* cases). Then the first goto may or may not be removed (depends
* on the special case) and the previous instruction jumps
* directly to cond. <p>
*
* If we detect an if, that jumps backwards, but in the same block
* we assume that it belongs to a while statement and bring it to
* the above standard format. <p>
*
* If this function returns with another Header, it is guaranteed
* that lies in the same block.
*
* @param cond The destination of a jump.
* @return loop, if this is an while. loop is generated on
* the fly if it didn't exists before. If this isn't a while at
* all, the parameter is returned unchanged.
*/
public InstructionHeader UnoptimizeWhileLoops(InstructionHeader dest) {
if (dest.flowType != dest.IFGOTO ||
dest.successors[1].addr >= dest.addr ||
dest.successors[1].outer != dest.outer)
return dest;
/* Okay, initial checking done, this really looks like a while
* statement. Now we call us recursively, in case the first
* instruction of this while loop is a while loop again.<p>
*
* This won't lead to infinite recursion because the
* address of the instruction will always decrease.
*/
InstructionHeader head = UnoptimizeWhileLoops(dest.successors[1]);
/* Now we are at head. Look in front of this if loop is
* already existing. If this is the case simply return it.
*/
if (head.prevInstruction != null &&
head.prevInstruction.flowType == head.GOTO &&
head.prevInstruction.successors[0] == dest)
return head.prevInstruction;
/* No there was no loop label. Create a new one.
*/
InstructionHeader[] successors = { dest };
InstructionHeader loop =
new InstructionHeader(head.GOTO, head.addr, head.addr,
successors, head.outer);
/* Connect it in the prev/next Instruction chain.
*/
loop.prevInstruction = head.prevInstruction;
if (loop.prevInstruction != null)
loop.prevInstruction.nextInstruction = loop;
loop.nextInstruction = head;
head.prevInstruction = loop;
/* Loop has no predecessors, but a successor namely dest.
* The calling function may change this situation.
*/
dest.predecessors.addElement(loop);
return loop;
}
}

@ -1,178 +0,0 @@
package jode;
import java.applet.*;
import java.awt.*;
import java.io.*;
import jode.decompiler.TabbedPrintWriter;
public class JodeAppletOneZero extends Applet implements Runnable {
TextField classpathField, classField;
TextArea sourcecodeArea, errorArea;
Checkbox verboseCheck, prettyCheck;
Button startButton, saveButton;
String lastClassName;
public JodeAppletOneZero() {
buildComponents(this);
}
public void init() {
String cp = getParameter("classpath");
if (cp != null)
setClasspath(cp);
String cls = getParameter("class");
if (cls != null)
setClass(cls);
}
private void buildComponents(Container window) {
classpathField = new TextField(50);
classField = new TextField(50);
sourcecodeArea = new TextArea(20, 80);
errorArea = new TextArea(3, 80);
verboseCheck = new Checkbox("verbose");
prettyCheck = new Checkbox("pretty");
startButton = new Button("start");
saveButton = new Button("save");
saveButton.disable();
sourcecodeArea.setEditable(false);
errorArea.setEditable(false);
GridBagLayout gbl = new GridBagLayout();
window.setLayout(gbl);
GridBagConstraints labelConstr = new GridBagConstraints();
GridBagConstraints textConstr = new GridBagConstraints();
GridBagConstraints areaConstr = new GridBagConstraints();
GridBagConstraints checkConstr = new GridBagConstraints();
GridBagConstraints buttonConstr = new GridBagConstraints();
labelConstr.fill = GridBagConstraints.NONE;
textConstr.fill = GridBagConstraints.HORIZONTAL;
areaConstr.fill = GridBagConstraints.BOTH;
checkConstr.fill = GridBagConstraints.NONE;
buttonConstr.fill = GridBagConstraints.NONE;
labelConstr.anchor = GridBagConstraints.EAST;
textConstr.anchor = GridBagConstraints.CENTER;
checkConstr.anchor = GridBagConstraints.WEST;
buttonConstr.anchor = GridBagConstraints.CENTER;
labelConstr.anchor = GridBagConstraints.EAST;
textConstr.gridwidth = GridBagConstraints.REMAINDER;
textConstr.weightx = 1.0;
areaConstr.gridwidth = GridBagConstraints.REMAINDER;
areaConstr.weightx = 1.0;
areaConstr.weighty = 1.0;
Label label = new Label("class path: ");
gbl.setConstraints(label, labelConstr);
window.add(label);
gbl.setConstraints(classpathField, textConstr);
window.add(classpathField);
label = new Label("class name: ");
gbl.setConstraints(label, labelConstr);
window.add(label);
gbl.setConstraints(classField, textConstr);
window.add(classField);
gbl.setConstraints(verboseCheck, checkConstr);
window.add(verboseCheck);
gbl.setConstraints(prettyCheck, checkConstr);
window.add(prettyCheck);
labelConstr.weightx = 1.0;
label = new Label();
gbl.setConstraints(label, labelConstr);
window.add(label);
gbl.setConstraints(startButton, buttonConstr);
window.add(startButton);
buttonConstr.gridwidth = GridBagConstraints.REMAINDER;
gbl.setConstraints(saveButton, buttonConstr);
window.add(saveButton);
gbl.setConstraints(sourcecodeArea, areaConstr);
window.add(sourcecodeArea);
areaConstr.gridheight = GridBagConstraints.REMAINDER;
areaConstr.weighty = 0.0;
gbl.setConstraints(errorArea, areaConstr);
window.add(errorArea);
Decompiler.err = new PrintStream(new AreaOutputStream(errorArea));
}
public void setClasspath(String cp) {
classpathField.setText(cp);
}
public void setClass(String cls) {
classField.setText(cls);
}
public boolean action(Event e, Object arg) {
if (e.target == startButton) {
startButton.disable();
Thread decompileThread = new Thread(this);
sourcecodeArea.setText("Please wait, while decompiling...\n");
decompileThread.start();
} else if (e.target == saveButton) {
FileDialog fd = new FileDialog(new Frame(),
"Save decompiled code",
FileDialog.SAVE);
fd.setFile(lastClassName.substring
(lastClassName.lastIndexOf('.')+1).concat(".java"));
fd.show();
String fileName = fd.getFile();
if (fileName == null)
return true;
try {
File f = new File(new File(fd.getDirectory()), fileName);
FileWriter out = new FileWriter(f);
out.write(sourcecodeArea.getText());
out.close();
} catch (IOException ex) {
errorArea.setText("");
Decompiler.err.println("Couldn't write to file "
+ fileName + ": ");
ex.printStackTrace(Decompiler.err);
}
}
return true;
}
public class AreaOutputStream extends OutputStream {
private TextArea area;
public AreaOutputStream(TextArea a) {
area = a;
}
public void write(int b) throws IOException {
area.appendText(String.valueOf((byte)b));
}
public void write(byte[] b, int off, int len) throws IOException {
area.appendText(new String(b, off, len));
}
}
public void run() {
Decompiler.isVerbose = verboseCheck.getState();
Decompiler.prettyLocals = prettyCheck.getState();
errorArea.setText("");
saveButton.disable();
lastClassName = classField.getText();
String cp = classpathField.getText();
cp = cp.replace(':', jode.bytecode.SearchPath.protocolSeparator);
cp = cp.replace(',', File.pathSeparatorChar);
JodeEnvironment env = new JodeEnvironment(cp);
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
TabbedPrintWriter writer = new TabbedPrintWriter(out);
env.doClass(classField.getText(), writer);
sourcecodeArea.setText(out.toString());
saveButton.enable();
} catch (Throwable t) {
sourcecodeArea.setText("Didn't succeed.\n"
+"Check the below area for more info.");
t.printStackTrace(Decompiler.err);
} finally {
startButton.enable();
}
}
}

@ -1,40 +0,0 @@
/*
* RemoveNop (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class RemoveNop implements Transformation {
public InstructionHeader transform (InstructionHeader ih) {
Instruction pred;
try {
NopOperator op = (NopOperator) ih.getInstruction();
if (op == null)
return null;
ih = ih.getSimpleUniquePredecessor();
pred = ih.getInstruction();
if (pred == null)
return null;
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
return ih.combine(2, pred);
}
}

@ -1,24 +0,0 @@
/*
* Transformation (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public interface Transformation {
public InstructionHeader transform(InstructionHeader ih);
}

@ -1,104 +0,0 @@
/* AttributeInfo Copyright (C) 1998-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.bytecode;
import jode.decompiler.TabbedPrintWriter;
import java.io.*;
import java.lang.reflect.Modifier;
public class AttributeInfo {
ClassInfo classinfo;
String name;
byte[] data;
public AttributeInfo(String name) {
this.name = name;
}
public AttributeInfo(String name, byte[] data) {
this.name = name;
this.data = data;
}
public void read(ConstantPool constantPool,
DataInputStream input, int howMuch) throws IOException {
int length = input.readInt();
data = new byte[length];
input.readFully(data);
}
public void prepareWriting(GrowableConstantPool gcp) {
gcp.putUTF8(name);
}
public void write(GrowableConstantPool constantPool,
DataOutputStream output) throws IOException {
output.writeShort(constantPool.putUTF8(name));
output.writeInt(data.length);
output.write(data);
}
public String getName() {
return name;
}
public byte[] getContents() {
return data;
}
static final char[] hex = "0123456789abcdef".toCharArray();
public void dumpSource(TabbedPrintWriter writer) throws IOException{
if (data != null) {
writer.println("/* Attribute "+name+" ["+data.length+"]");
writer.tab();
StringBuffer sb = new StringBuffer();
for (int i=0; i< data.length; i++) {
byte b = data[i];
int h = (b<0)?b+256:b;
writer.print(" " + hex[h/16] + hex[h%16]);
if (b >=32 && b < 127) {
sb.append((char)b);
} else {
sb.append(".");
}
if (i % 16 == 15) {
writer.println(" "+sb.toString());
sb.setLength(0);
}
}
if ((data.length % 16) != 0) {
for (int i=data.length % 16; i<16; i++)
writer.print(" ");
writer.println(" "+sb.toString());
}
writer.untab();
writer.println("*/");
}
}
public boolean equals(Object o) {
return (o instanceof AttributeInfo
&& ((AttributeInfo) o).name.equals(name));
}
public int hashCode() {
return name.hashCode();
}
}

@ -1,177 +0,0 @@
/* jode.bytecode.ClassHierarchy Copyright (C) 1997-1998 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.bytecode;
import jode.SearchPath;
import java.io.*;
import java.util.Hashtable;
/**
* This class does represent a class similar to java.lang.Class. You
* can get the super class and the interfaces.
*
* The main difference to java.lang.Class is, that the objects are builded
* from a stream containing the .class file, and that it uses the
* <code>jode.Type</code> to represent types instead of Class itself.
*
* @author Jochen Hoenicke
*/
public class ClassHierarchy {
private String name;
private int modifiers = -1;
private ClassHierarchy superclass;
private ClassHierarchy[] interfaces;
private static SearchPath classpath;
private ConstantPool constantPool;
private static Hashtable classes = new Hashtable(); // XXX - weak map
public final static ClassHierarchy javaLangObject =
ClassHierarchy.forName("java.lang.Object");
public static void setClassPath(SearchPath path) {
classpath = path;
}
public static ClassHierarchy forName(String name) {
if (name == null)
return null;
name = name.replace('/', '.');
ClassHierarchy clazz = (ClassHierarchy) classes.get(name);
if (clazz == null) {
clazz = new ClassHierarchy(name);
classes.put(name, clazz);
}
return clazz;
}
public ClassHierarchy(String name) {
this.name = name;
}
private void readHeader(DataInputStream input)
throws IOException {
if (input.readInt() != 0xcafebabe)
throw new ClassFormatException("Wrong magic");
if (input.readUnsignedShort() > 3)
throw new ClassFormatException("Wrong minor");
if (input.readUnsignedShort() != 45)
throw new ClassFormatException("Wrong major");
}
private void readConstants(DataInputStream input)
throws IOException {
constantPool = new ConstantPool();
constantPool.read(input);
}
private void readNameAndSuper(DataInputStream input)
throws IOException {
modifiers = input.readUnsignedShort();
String name = constantPool.getClassName(input.readUnsignedShort());
if (!this.name.equals(name))
new ClassFormatException("Class has wrong name: "+name);
superclass = ClassHierarchy.forName
(constantPool.getClassName(input.readUnsignedShort()));
}
private void readInterfaces(DataInputStream input)
throws IOException {
int count = input.readUnsignedShort();
interfaces = new ClassHierarchy[count];
for (int i=0; i< count; i++) {
interfaces[i] = ClassHierarchy.forName
(constantPool.getClassName(input.readUnsignedShort()));
}
}
private void loadHierarchy() {
try {
DataInputStream input =
new DataInputStream(classpath.getFile(name.replace('.', '/')
+ ".class"));
readHeader(input);
readConstants(input);
readNameAndSuper(input);
readInterfaces(input);
constantPool = null; // Now allow clean up
} catch (IOException ex) {
String message = ex.getLocalizedMessage();
System.err.println("Can't read class " + name
+ ", types may be incorrect. ("
+ ex.getClass().getName()
+ (message != null ? ": " + message : "")+")");
if (name.equals("java.lang.Object"))
superclass = null;
else
superclass = ClassHierarchy.forName("java.lang.Object");
interfaces = new ClassHierarchy[0];
}
}
public ClassHierarchy getSuperclass() {
if (interfaces == null)
loadHierarchy();
return superclass;
}
public ClassHierarchy[] getInterfaces() {
if (interfaces == null)
loadHierarchy();
return interfaces;
}
public int getModifiers() {
return modifiers;
}
public boolean isInterface() {
if (interfaces == null)
loadHierarchy();
return java.lang.reflect.Modifier.isInterface(modifiers);
}
public String toString() {
return name;
}
public String getName() {
return name;
}
public boolean superClassOf(ClassHierarchy son) {
while (son != this && son != null) {
son = son.getSuperclass();
}
return son == this;
}
public boolean implementedBy(ClassHierarchy clazz) {
while (clazz != this && clazz != null) {
ClassHierarchy[] ifaces = clazz.getInterfaces();
for (int i=0; i< ifaces.length; i++) {
if (implementedBy(ifaces[i]))
return true;
}
clazz = clazz.getSuperclass();
}
return clazz == this;
}
}

@ -1,63 +0,0 @@
/* CodeInfo Copyright (C) 1998-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.bytecode;
import java.io.*;
import java.lang.reflect.Modifier;
public class CodeInfo extends BinaryInfo {
int maxStack, maxLocals;
byte[] code;
int[] exceptionTable;
public int getMaxStack() {
return maxStack;
}
public int getMaxLocals() {
return maxLocals;
}
public byte[] getCode() {
return code;
}
public int[] getExceptionHandlers() {
return exceptionTable;
}
public void read(ConstantPool constantPool,
DataInputStream input) throws IOException {
maxStack = input.readUnsignedShort();
maxLocals = input.readUnsignedShort();
int codeLength = input.readInt();
code = new byte[codeLength];
input.readFully(code);
int count = 4*input.readUnsignedShort();
exceptionTable = new int[count];
for (int i = 0; i< count; i+=4) {
exceptionTable[i+0] = input.readUnsignedShort();
exceptionTable[i+1] = input.readUnsignedShort();
exceptionTable[i+2] = input.readUnsignedShort();
exceptionTable[i+3] = input.readUnsignedShort();
}
readAttributes(constantPool, input, FULLINFO);
}
}

@ -1,535 +0,0 @@
/* CodeAnalyzer Copyright (C) 1998-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.decompiler;
import jode.Decompiler;
import jode.GlobalOptions;
import jode.type.Type;
import jode.util.SimpleDictionary;
import jode.bytecode.*;
import jode.expr.Expression;
import jode.expr.ConstOperator;
import jode.expr.CheckNullOperator;
import jode.expr.ThisOperator;
import jode.expr.LocalLoadOperator;
import jode.expr.OuterLocalOperator;
import jode.expr.ConstructorOperator;
import jode.flow.StructuredBlock;
import jode.flow.FlowBlock;
import jode.flow.TransformExceptionHandlers;
import jode.flow.Jump;
import jode.jvm.CodeVerifier;
import jode.jvm.VerifyException;
import java.util.BitSet;
import java.util.Stack;
import java.util.Vector;
import java.util.Dictionary;
import java.util.Enumeration;
import java.io.DataInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class CodeAnalyzer implements Analyzer, Scope, ClassDeclarer {
FlowBlock methodHeader;
BytecodeInfo code;
MethodAnalyzer method;
ImportHandler imports;
boolean analyzedAnonymous = false;
StructuredBlock insertBlock = null;
Vector allLocals = new Vector();
/**
* This dictionary maps an anonymous ClassInfo to the
* ConstructorOperator that creates this class.
*/
Dictionary anonClasses = new SimpleDictionary();
Vector anonAnalyzers = new Vector();
Vector innerAnalyzers = new Vector();
LocalInfo[] param;
LocalVariableTable lvt;
public CodeAnalyzer(MethodAnalyzer ma, MethodInfo minfo,
ImportHandler i)
{
method = ma;
imports = i;
code = minfo.getBytecode();
if ((Decompiler.options & Decompiler.OPTION_VERIFY) != 0) {
CodeVerifier verifier = new CodeVerifier(getClazz(), minfo, code);
try {
verifier.verify();
} catch (VerifyException ex) {
ex.printStackTrace(GlobalOptions.err);
throw new jode.AssertError("Verification error");
}
}
if ((Decompiler.options & Decompiler.OPTION_LVT) != 0) {
LocalVariableInfo[] localvars = code.getLocalVariableTable();
if (localvars != null)
lvt = new LocalVariableTable(code.getMaxLocals(),
localvars);
}
initParams();
}
public void initParams() {
Type[] paramTypes = method.getType().getParameterTypes();
int paramCount = (method.isStatic() ? 0 : 1) + paramTypes.length;
param = new LocalInfo[paramCount];
int offset = 0;
int slot = 0;
if (!method.isStatic())
param[offset++] = getLocalInfo(0, slot++);
for (int i=0; i < paramTypes.length; i++) {
param[offset++] = getLocalInfo(0, slot);
slot += paramTypes[i].stackSize();
}
}
public BytecodeInfo getBytecodeInfo() {
return code;
}
public FlowBlock getMethodHeader() {
return methodHeader;
}
public void insertStructuredBlock(StructuredBlock superBlock) {
if (insertBlock != null)
throw new jode.AssertError();
insertBlock = superBlock;
}
void readCode() {
/* The adjacent analyzation relies on this */
DeadCodeAnalysis.removeDeadCode(code);
Handler[] handlers = code.getExceptionHandlers();
int returnCount;
TransformExceptionHandlers excHandlers;
{
/* First create a FlowBlock for every block that has a
* predecessor other than the previous instruction.
*/
for (Instruction instr = code.getFirstInstr();
instr != null; instr = instr.nextByAddr) {
if (instr.prevByAddr == null
|| instr.prevByAddr.alwaysJumps
|| instr.preds != null)
instr.tmpInfo = new FlowBlock
(this, instr.addr, instr.length);
}
for (int i=0; i < handlers.length; i++) {
Instruction instr = handlers[i].start;
if (instr.tmpInfo == null)
instr.tmpInfo
= new FlowBlock(this, instr.addr, instr.length);
instr = handlers[i].catcher;
if (instr.tmpInfo == null)
instr.tmpInfo
= new FlowBlock(this, instr.addr, instr.length);
}
/* While we read the opcodes into FlowBlocks
* we try to combine sequential blocks, as soon as we
* find two sequential instructions in a row, where the
* second has no predecessors.
*/
int mark = 1000;
FlowBlock lastBlock = null;
boolean lastSequential = false;
for (Instruction instr = code.getFirstInstr();
instr != null; instr = instr.nextByAddr) {
jode.flow.StructuredBlock block
= Opcodes.readOpcode(instr, this);
if (GlobalOptions.verboseLevel > 0 && instr.addr > mark) {
GlobalOptions.err.print('.');
mark += 1000;
}
if (lastSequential && instr.tmpInfo == null
/* Only merge with previous block, if this is sequential,
* too.
* Why? doSequentialT2 does only handle sequential blocks.
*/
&& !instr.alwaysJumps && instr.succs == null) {
lastBlock.doSequentialT2(block, instr.length);
} else {
if (instr.tmpInfo == null)
instr.tmpInfo = new FlowBlock
(this, instr.addr, instr.length);
FlowBlock flowBlock = (FlowBlock) instr.tmpInfo;
flowBlock.setBlock(block);
if (lastBlock != null)
lastBlock.setNextByAddr(flowBlock);
instr.tmpInfo = lastBlock = flowBlock;
lastSequential = !instr.alwaysJumps && instr.succs == null;
}
}
methodHeader = (FlowBlock) code.getFirstInstr().tmpInfo;
if (insertBlock != null) {
insertBlock.setJump(new Jump(methodHeader));
FlowBlock insertFlowBlock = new FlowBlock(this, 0, 0);
insertFlowBlock.setBlock(insertBlock);
insertFlowBlock.setNextByAddr(methodHeader);
methodHeader = insertFlowBlock;
}
excHandlers = new TransformExceptionHandlers();
for (int i=0; i<handlers.length; i++) {
Type type = null;
FlowBlock start
= (FlowBlock) handlers[i].start.tmpInfo;
int endAddr = handlers[i].end.nextByAddr.addr;
FlowBlock handler
= (FlowBlock) handlers[i].catcher.tmpInfo;
if (handlers[i].type != null)
type = Type.tClass(handlers[i].type);
excHandlers.addHandler(start, endAddr, handler, type);
}
}
for (Instruction instr = code.getFirstInstr();
instr != null; instr = instr.nextByAddr)
instr.tmpInfo = null;
if (GlobalOptions.verboseLevel > 0)
GlobalOptions.err.print('-');
// try {
// TabbedPrintWriter writer = new TabbedPrintWriter(System.err);
// methodHeader.dumpSource(writer);
// } catch (java.io.IOException ex) {
// }
excHandlers.analyze();
methodHeader.analyze();
}
public void analyze()
{
if (code == null)
return;
readCode();
if ((Decompiler.options & Decompiler.OPTION_PUSH) == 0
&& methodHeader.mapStackToLocal())
methodHeader.removePush();
if ((Decompiler.options & Decompiler.OPTION_ONETIME) != 0)
methodHeader.removeOnetimeLocals();
methodHeader.mergeParams(param);
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.pushScope(this);
if (methodHeader != null)
methodHeader.dumpSource(writer);
else
writer.println("COULDN'T DECOMPILE METHOD!");
writer.popScope();
}
public LocalInfo getLocalInfo(int addr, int slot) {
LocalInfo li = new LocalInfo(slot);
if (lvt != null) {
LocalVarEntry entry = lvt.getLocal(slot, addr);
if (entry != null)
li.addHint(entry);
}
allLocals.addElement(li);
return li;
}
/**
* Checks if the variable set contains a local with the given name.
*/
public LocalInfo findLocal(String name) {
Enumeration enum = allLocals.elements();
while (enum.hasMoreElements()) {
LocalInfo li = (LocalInfo) enum.nextElement();
if (li.getName().equals(name))
return li;
}
return null;
}
/**
* Checks if an anonymous class with the given name exists.
*/
public ClassAnalyzer findAnonClass(String name) {
Enumeration enum = anonAnalyzers.elements();
while (enum.hasMoreElements()) {
ClassAnalyzer classAna = (ClassAnalyzer) enum.nextElement();
if (classAna.getName() != null
&& classAna.getName().equals(name))
return classAna;
}
return null;
}
public void addAnonymousConstructor(ConstructorOperator cop) {
ClassInfo cinfo = cop.getClassInfo();
ConstructorOperator[] cops =
(ConstructorOperator[]) anonClasses.get(cinfo);
ConstructorOperator[] newCops;
if (cops == null) {
newCops = new ConstructorOperator[] { cop };
} else {
newCops = new ConstructorOperator[cops.length + 1];
System.arraycopy(cops, 0, newCops, 0, cops.length);
newCops[cops.length] = cop;
}
anonClasses.put(cinfo, newCops);
}
public void createAnonymousClasses() {
int serialnr = 0;
Enumeration keys = anonClasses.keys();
Enumeration elts = anonClasses.elements();
while (keys.hasMoreElements()) {
ClassInfo clazz = (ClassInfo) keys.nextElement();
ConstructorOperator[] cops =
(ConstructorOperator[]) elts.nextElement();
ClassAnalyzer anonAnalyzer = getParent().getClassAnalyzer(clazz);
int copsNr = 0;
Expression[] outerValues;
int maxOuter;
if (anonAnalyzer != null) {
outerValues = anonAnalyzer.getOuterValues();
maxOuter = outerValues.length;
} else {
System.err.println("aac: expr0 = "+cops[0]);
outerValues = new Expression[maxOuter];
Expression[] subExprs1 = cops[copsNr++].getSubExpressions();
maxOuter = subExprs1.length;
for (int j=0; j < maxOuter; j++) {
Expression expr = subExprs1[j].simplify();
if (expr instanceof CheckNullOperator)
expr = ((CheckNullOperator) expr).getSubExpressions()[0];
if (expr instanceof ThisOperator) {
outerValues[j] =
new ThisOperator(((ThisOperator)expr).getClassInfo());
continue;
}
if (expr instanceof LocalLoadOperator) {
LocalLoadOperator llop = (LocalLoadOperator) expr;
LocalInfo li = llop.getLocalInfo();
for (int i=1; i < cops.length; i++) {
Expression expr2 =
cops[i].getSubExpressions()[j].simplify();
if (expr2 instanceof CheckNullOperator)
expr2 = ((CheckNullOperator) expr2)
.getSubExpressions()[0];
LocalInfo li2 =
((LocalLoadOperator) expr2).getLocalInfo();
li2.combineWith(li);
}
if (li.markFinal()) {
outerValues[j] = new OuterLocalOperator(li);
continue;
}
}
maxOuter = j;
System.err.println("new maxOuter: "+maxOuter+" ("+expr);
}
}
for (int i=copsNr; i < cops.length; i++) {
Expression[] subExprs = cops[i].getSubExpressions();
for (j=0; j < maxOuter; j++) {
Expression expr = subExprs[j].simplify();
if (expr instanceof CheckNullOperator)
expr = ((CheckNullOperator) expr).getSubExpressions()[0];
if (expr instanceof ThisOperator
&& expr.equals(outerValues[j]))
continue;
if (expr instanceof LocalLoadOperator) {
// more thorough checks for constructors!
// combine locals!
// what else?
XXX
LocalLoadOperator llop = (LocalLoadOperator) expr;
LocalInfo li = llop.getLocalInfo();
for (int i=1; i < cops.length; i++) {
Expression expr2 =
cops[i].getSubExpressions()[j].simplify();
if (expr2 instanceof CheckNullOperator)
expr2 = ((CheckNullOperator) expr2)
.getSubExpressions()[0];
LocalInfo li2 =
((LocalLoadOperator) expr2).getLocalInfo();
li2.combineWith(li);
}
if (li.markFinal()) {
outerValues[j] = new OuterLocalOperator(li);
continue;
}
}
maxOuter = j;
System.err.println("new maxOuter: "+maxOuter+" ("+expr);
}
}
if (maxOuter > outerValues.length) {
Expression[] newOuter = new Expression[j];
System.arraycopy(outerValues, 0, newOuter, 0, j);
outerValues = newOuter;
break;
}
if (anonAnalyzer == null)
anonAnalyzer = new ClassAnalyzer(this, clazz, imports,
outerValues);
else
anonAnalyzer.setOuterValues(outerValues);
anonAnalyzer.analyze();
anonAnalyzers.addElement(anonAnalyzer);
}
analyzedAnonymous = true;
}
public void analyzeAnonymousClasses() {
createAnonymousClasses();
}
public void makeDeclaration() {
for (Enumeration enum = allLocals.elements();
enum.hasMoreElements(); ) {
LocalInfo li = (LocalInfo)enum.nextElement();
if (!li.isShadow())
imports.useType(li.getType());
}
for (int i=0; i < param.length; i++) {
param[i].guessName();
for (int j=0; j < i; j++) {
if (param[j].getName().equals(param[i].getName())) {
/* A name conflict happened. */
param[i].makeNameUnique();
break; /* j */
}
}
}
methodHeader.makeDeclaration(param);
methodHeader.simplify();
for (Enumeration enum = anonAnalyzers.elements();
enum.hasMoreElements(); ) {
ClassAnalyzer classAna = (ClassAnalyzer) enum.nextElement();
classAna.makeDeclaration();
addClassAnalyzer(classAna);
}
}
public boolean hasAnalyzedAnonymous() {
return analyzedAnonymous;
}
public LocalInfo getParamInfo(int nr) {
return param[nr];
}
public void addClassAnalyzer(ClassAnalyzer clazzAna) {
if (innerAnalyzers == null)
innerAnalyzers = new Vector();
innerAnalyzers.addElement(clazzAna);
getParent().addClassAnalyzer(clazzAna);
}
/**
* Get the class analyzer for the given class info. This searches
* the method scoped/anonymous classes in this method and all
* outer methods and the outer classes for the class analyzer.
* @param cinfo the classinfo for which the analyzer is searched.
* @return the class analyzer, or null if there is not an outer
* class that equals cinfo, and not a method scope/inner class in
* an outer method.
*/
public ClassAnalyzer getClassAnalyzer(ClassInfo cinfo) {
if (innerAnalyzers != null) {
Enumeration enum = innerAnalyzers.elements();
while (enum.hasMoreElements()) {
ClassAnalyzer classAna = (ClassAnalyzer) enum.nextElement();
if (classAna.getClazz().equals(cinfo)) {
if (classAna.getParent() != this) {
classAna.setParent(this);
}
return classAna;
}
}
}
return getParent().getClassAnalyzer(cinfo);
}
public ClassAnalyzer getClassAnalyzer() {
return method.classAnalyzer;
}
public ClassInfo getClazz() {
return method.classAnalyzer.clazz;
}
/**
* Get the method.
* @return The method to which this code belongs.
*/
public MethodAnalyzer getMethod() {return method;}
public ImportHandler getImportHandler() {
return imports;
}
public void useType(Type type) {
imports.useType(type);
}
public boolean isScopeOf(Object obj, int scopeType) {
if (scopeType == METHODSCOPE)
return anonClasses.get(obj) != null;
return false;
}
public boolean conflicts(String name, int usageType) {
if (usageType == AMBIGUOUSNAME || usageType == LOCALNAME)
return findLocal(name) != null;
if (usageType == AMBIGUOUSNAME || usageType == CLASSNAME)
return findAnonClass(name) != null;
return false;
}
public ClassDeclarer getParent() {
return getClassAnalyzer();
}
}

@ -1,27 +0,0 @@
/*
* LocalVariable (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import sun.tools.java.Type;
import sun.tools.java.Identifier;
public interface LocalVariable {
public LocalInfo getInfo(int addr);
public void combine(int addr1, int addr2);
}

@ -1,229 +0,0 @@
/*
* LocalVariableAnalyzer (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import sun.tools.java.*;
import java.io.*;
import java.util.*;
public class LocalVariableAnalyzer {
Vector locals;
LocalInfo[] argLocals;
LocalVariableTable lvt;
JodeEnvironment env;
FieldDefinition mdef;
int maxlocals;
LocalVariableAnalyzer(JodeEnvironment env, FieldDefinition mdef,
int maxlocals) {
this.env = env;
this.mdef = mdef;
this.maxlocals = maxlocals;
locals = new Vector();
}
/**
* Reads the local variable table from the class file
* if it exists.
*/
public void read(BinaryCode bc) {
BinaryAttribute attr = bc.getAttributes();
while (attr != null) {
if (attr.getName() == Constants.idLocalVariableTable) {
DataInputStream stream =
new DataInputStream
(new ByteArrayInputStream(attr.getData()));
try {
lvt = new LocalVariableTable(maxlocals);
lvt.read(env, stream);
} catch (IOException ex) {
throw new ClassFormatError(ex.toString());
}
}
attr = attr.getNextAttribute();
}
}
/**
* This method combines to LocalInfos to a single one.
* It also handles the special cases where one or both LocalInfo
* are null.
*/
private LocalInfo combine(int slot, LocalInfo li1, LocalInfo li2) {
if (li1 == null && li2 == null) {
li2 = new LocalInfo(slot);
locals.addElement(li2);
} else if (li1 != null && li2 != null)
li1.combineWith(li2.getLocalInfo());
else if (li2 == null)
li2 = li1;
return li2.getLocalInfo();
}
// public void analyze(MethodInstructionHeader mih) {
// {
// Type[] paramTypes = mdef.getType().getArgumentTypes();
// int length = (mdef.isStatic() ? 0 : 1) + paramTypes.length;
// argLocals = new LocalInfo[length];
// int offset = 0;
// if (!mdef.isStatic()) {
// argLocals[0] = new LocalInfo(0);
// argLocals[0].setType(mdef.getClassDefinition().getType());
// offset++;
// }
// for (int i=0; i< paramTypes.length; i++) {
// argLocals[offset+i] = new LocalInfo(i+offset);
// argLocals[offset+i].setType(paramTypes[i]);
// }
// }
// Hashtable done = new Hashtable();
// Stack instrStack = new Stack();
// Stack readsStack = new Stack();
// LocalInfo[] reads = new LocalInfo[maxlocals];
// Enumeration predec = mih.getReturns().elements();
// while (predec.hasMoreElements()) {
// instrStack.push(predec.nextElement());
// readsStack.push(reads);
// }
// while (!instrStack.empty()) {
// InstructionHeader instr =
// (InstructionHeader) instrStack.pop();
// LocalInfo[] prevReads =
// (LocalInfo[]) done.get(instr);
// reads = (LocalInfo[]) readsStack.pop();
// // System.err.println("");
// // System.err.print("Addr: "+instr.getAddress()+ " [");
// // for (int i=0; i< maxlocals; i++) {
// // if (reads[i] != null)
// // System.err.print(", "+reads[i].getName().toString());
// // }
// // System.err.print("] ");
// if (prevReads != null) {
// boolean changed = false;
// for (int i=0; i<maxlocals; i++) {
// if (reads[i] != null) {
// reads[i] = reads[i].getLocalInfo();
// if (prevReads[i] == null) {
// changed = true;
// } else if (prevReads[i].getLocalInfo() != reads[i]) {
// prevReads[i].combineWith(reads[i]);
// changed = true;
// }
// }
// }
// if (!changed)
// continue;
// }
// if (instr instanceof MethodInstructionHeader) {
// /* This is the first instruction
// */
// for (int i=0; i < argLocals.length; i++) {
// if (reads[i] != null)
// argLocals[i].combineWith(reads[i]);
// }
// } else if (instr.getInstruction() instanceof LocalVarOperator) {
// if (Decompiler.isVerbose)
// System.err.print(".");
// LocalVarOperator op =
// (LocalVarOperator)instr.getInstruction();
// int slot = op.getSlot();
// LocalInfo li = combine(slot, op.getLocalInfo(),
// reads[slot]);
// LocalInfo[] newReads = new LocalInfo[maxlocals];
// System.arraycopy(reads, 0, newReads, 0, maxlocals);
// op.setLocalInfo(li);
// if (op.isRead())
// newReads[slot] = li;
// else
// newReads[slot] = null;
// reads = newReads;
// done.put(instr, reads);
// }
// predec = instr.getPredecessors().elements();
// while (predec.hasMoreElements()) {
// instrStack.push(predec.nextElement());
// readsStack.push(reads);
// }
// }
// if (!mdef.isStatic())
// argLocals[0].setName(Constants.idThis);
// }
public void createLocalInfo(CodeAnalyzer code) {
// System.err.println("createLocalInfo");
// MethodInstructionHeader mih = code.methodHeader;
// if (lvt == null)
// analyze(mih);
// else {
int length = (mdef.isStatic() ? 0 : 1) +
mdef.getType().getArgumentTypes().length;
argLocals = new LocalInfo[length];
for (int i=0; i < length; i++)
argLocals[i] = lvt.getLocal(i).getInfo(-1);
// for (InstructionHeader ih = mih.getFirst();
// ih != null; ih = ih.getNextInstruction()) {
// if (ih.getInstruction() instanceof LocalVarOperator) {
// LocalVarOperator op =
// (LocalVarOperator)ih.getInstruction();
// int slot = op.getSlot();
// LocalInfo li =
// lvt.getLocal(slot).getInfo(ih.getAddress());
// op.setLocalInfo(li);
// }
// }
// }
}
public LocalInfo getLocal(int i) {
return argLocals[i];
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
Enumeration enum = locals.elements();
VAR:
while (enum.hasMoreElements()) {
LocalInfo li = (LocalInfo) enum.nextElement();
if (!li.isShadow()) {
for (int i=0; i< argLocals.length; i++)
if (argLocals[i].getLocalInfo() == li)
continue VAR;
writer.println(env.getTypeString(li.getType(),
li.getName())+";");
}
}
}
}

@ -1,41 +0,0 @@
package jode;
import sun.tools.java.Type;
import sun.tools.java.Identifier;
import java.util.Hashtable;
import java.util.Enumeration;
public class LocalVariableHash implements LocalVariable {
Hashtable locals;
int slot;
public LocalVariableHash(int slot) {
locals = new Hashtable();
this.slot = slot;
}
public LocalInfo getInfo(int addr) {
LocalInfo li = (LocalInfo) locals.get(new Integer(addr));
if (li == null) {
System.err.println("creating "+slot+": "+addr);
li = new LocalInfo(slot);
locals.put(new Integer(addr), li);
}
return li;
}
public void combine(int addr1, int addr2) {
System.err.println("combining "+slot+": "+addr1+" and "+addr2);
LocalInfo li1 = getInfo(addr1);
LocalInfo li2 = (LocalInfo) locals.get(new Integer(addr2));
if (li2 != null) {
li1.type = UnknownType.commonType(li1.type, li2.type);
Enumeration keys = locals.keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (locals.get(key) == li2)
locals.put(key, li1);
}
} else
locals.put(new Integer(addr2), li1);
}
}

@ -1,79 +0,0 @@
/*
* AssignOperator (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
/**
* This class represents an assign expression, i.e. an assignment,
* whose return value is used further.
*
* It contains the underlying store instruction, which you can get
* with <code>getStore</code>
*
* @author Jochen Hoenicke
*/
public class AssignOperator extends Operator {
StoreInstruction store;
public AssignOperator(int op, StoreInstruction store) {
super(store.getLValueType(), op);
this.store = store;
store.parent = this;
}
public StoreInstruction getStore() {
return store;
}
public int getPriority() {
return store.getPriority();
}
public int getOperandCount() {
return store.getOperandCount();
}
public int getOperandPriority(int i) {
return store.getOperandPriority(i);
}
public Type getOperandType(int i) {
return store.getOperandType(i);
}
/**
* Sets the return type of this operator.
*/
public void setType(Type type) {
store.setLValueType(type);
super.setType(store.getLValueType());
}
/**
* Overload this method if the resulting type depends on the input types
*/
public void setOperandType(Type[] inputTypes) {
store.setOperandType(inputTypes);
this.type = store.getLValueType();
}
public String toString(String[] operands) {
return store.toString(operands);
}
}

@ -1,89 +0,0 @@
/*
* BreakInstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Enumeration;
/** This instruction header represents an break, continue or an
* if + break/continue statement.
*/
public class BreakInstructionHeader extends InstructionHeader {
boolean conditional;
String breakLabel;
/**
* Creates a new break statement.
* @param gotoHeader the instruction header whichs contains the
* (maybe conditonal) goto statement.
* @param label the label where to break to, may be null.
* @param isBreak is this a break or a continue.
*/
public BreakInstructionHeader(int flowType,
InstructionHeader gotoHeader,
String label) {
super(flowType, gotoHeader.addr, gotoHeader.nextAddr,
gotoHeader.successors, gotoHeader.outer);
this.instr = gotoHeader.getInstruction();
this.conditional = (gotoHeader.flowType == IFGOTO);
this.breakLabel = label;
this.movePredecessors(gotoHeader);
this.successors = gotoHeader.successors;
for (int i=0; i< successors.length; i++) {
successors[i].predecessors.removeElement(gotoHeader);
successors[i].predecessors.addElement(this);
}
this.nextInstruction = gotoHeader.nextInstruction;
if (nextInstruction != null)
nextInstruction.prevInstruction = this;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
if (conditional) {
writer.println("if ("+instr.toString()+")");
writer.tab();
}
writer.println((flowType == BREAK ? "break" :
flowType == CONTINUE ? "continue" : "return") +
(breakLabel != null?" "+breakLabel:"")+";");
if (conditional)
writer.untab();
if (Decompiler.isDebugging)
writer.untab();
}
}

@ -1,80 +0,0 @@
/*
* CaseInstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Enumeration;
public class CaseInstructionHeader extends InstructionHeader {
int label;
boolean isDefault;
public CaseInstructionHeader(int label, boolean isDefault,
//Type type,
int addr,
InstructionHeader parent) {
super(CASESTATEMENT, addr, addr,
new InstructionHeader[1], parent);
this.label = label;
this.isDefault = isDefault;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (isDefault) {
if (nextInstruction == null && successors[0] == null)
return;
writer.println("default:");
} else
writer.println("case "+label+":" );
writer.tab();
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction)
ih.dumpSource(writer);
writer.untab();
if (Decompiler.isDebugging)
writer.untab();
}
/**
* Get the instruction header where the next instruction is.
*/
InstructionHeader getShadow() {
return (successors[0] != null ? successors[0].getShadow() :
getEndBlock());
}
public InstructionHeader doTransformations(Transformation[] trafo) {
InstructionHeader next;
if (successors[0] != getEndBlock()) {
for (InstructionHeader ih = successors[0]; ih != null; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
}
return super.doTransformations(trafo);
}
}

@ -1,95 +0,0 @@
/*
* CatchInstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import sun.tools.java.Type;
import java.util.Vector;
public class CatchInstructionHeader extends InstructionHeader {
Type type;
String typeString;
LocalInfo local;
CatchInstructionHeader(Type type, String typeString,
InstructionHeader firstInstr,
InstructionHeader outer) {
super(CATCH, firstInstr.addr, firstInstr.addr,
new InstructionHeader[1], outer);
movePredecessors(firstInstr);
successors[0] = firstInstr;
firstInstr.predecessors = new Vector();
firstInstr.predecessors.addElement(this);
prevInstruction = firstInstr.prevInstruction;
if (prevInstruction != null)
prevInstruction.nextInstruction = this;
nextInstruction = firstInstr;
firstInstr.prevInstruction = this;
this.type = type;
this.typeString = typeString;
}
public LocalInfo getLocal() {
return local;
}
/**
* Combines this catch instruction header with the next instruction
* header which should containt only a LocalStoreOperator or a pop
* according to the parameter. (This is where the exception gets
* stored.
* @param local The local where the exception is stored.
* @return true if the operation succeeded.
*/
public boolean combineWithLocal(LocalInfo local) {
InstructionHeader next = nextInstruction;
if (this.local != null || successors[0] != next)
return false;
this.local = local;
local.setType(type);
successors = next.successors;
nextInstruction = next.nextInstruction;
if (nextInstruction != null)
nextInstruction.prevInstruction = this;
for (int i=0; i< successors.length; i++) {
successors[i].predecessors.removeElement(next);
successors[i].predecessors.addElement(this);
}
return true;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging)
dumpDebugging(writer);
writer.println("} catch ("+typeString+" "+
(local != null ? local.getName()
: (Object) "stack_0") + ") {");
}
}

@ -1,70 +0,0 @@
/*
* CombineIfGotoExpressions (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Vector;
public class CombineIfGotoExpressions implements Transformation{
public InstructionHeader transform(InstructionHeader ih2) {
InstructionHeader ih1;
Expression[] e;
int operator;
try {
if (ih2.getFlowType() != ih2.IFGOTO)
return null;
InstructionHeader[] dests2 = ih2.getSuccessors();
/* if ih2.getSimpleUniquePredecessor.getOperator().isVoid() XXX */
Vector predec = ih2.getPredecessors();
if (predec.size() != 1)
return null;
ih1 = (InstructionHeader) predec.elementAt(0);
if (ih1.getFlowType() != ih1.IFGOTO)
return null;
InstructionHeader[] dests1 = ih1.getSuccessors();
if (dests1[0] != ih2)
return null;
if (dests1[1] == dests2[0]) {
e = new Expression[2];
operator = Operator.LOG_AND_OP;
e[1] = (Expression)ih2.getInstruction();
e[0] = ((Expression)ih1.getInstruction()).negate();
} else if (dests1[1] == dests2[1]) {
e = new Expression[2];
operator = Operator.LOG_OR_OP;
e[1] = (Expression)ih2.getInstruction();
e[0] = (Expression)ih1.getInstruction();
} else
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
Expression cond =
new Expression(new BinaryOperator(MyType.tBoolean, operator), e);
return ih1.combineConditional(cond);
}
}

@ -1,617 +0,0 @@
/* ComplexExpression Copyright (C) 1998-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.GlobalOptions;
import jode.Decompiler;
import jode.type.Type;
import jode.decompiler.TabbedPrintWriter;
public class ComplexExpression extends Expression {
Operator operator;
Expression[] subExpressions;
int operandcount = 0;
public ComplexExpression(Operator op, Expression[] sub) {
super(Type.tUnknown);
if (sub.length != op.getOperandCount())
throw new jode.AssertError ("Operand count mismatch: "+
sub.length + " != " +
op.getOperandCount());
operator = op;
operator.parent = this;
subExpressions = sub;
for (int i=0; i< subExpressions.length; i++) {
if (subExpressions[i] == null)
subExpressions[i] = new NopOperator(Type.tUnknown);
subExpressions[i].parent = this;
operandcount += subExpressions[i].getOperandCount();
}
updateType();
}
public int getOperandCount() {
return operandcount;
}
public Expression addOperand(Expression op) {
for (int i= subExpressions.length-1; i >= 0; i--) {
int opcount = subExpressions[i].getOperandCount();
if (opcount > 0) {
subExpressions[i] = subExpressions[i].addOperand(op);
subExpressions[i].parent = this;
operandcount += subExpressions[i].getOperandCount() - opcount;
updateType();
return this;
}
}
throw new jode.AssertError("addOperand called, but no operand needed");
}
public Expression negate() {
if (operator.getOperatorIndex() >= operator.COMPARE_OP &&
operator.getOperatorIndex() < operator.COMPARE_OP+6) {
operator.setOperatorIndex(operator.getOperatorIndex() ^ 1);
return this;
} else if (operator.getOperatorIndex() == operator.LOG_AND_OP ||
operator.getOperatorIndex() == operator.LOG_OR_OP) {
operator.setOperatorIndex(operator.getOperatorIndex() ^ 1);
for (int i=0; i< subExpressions.length; i++) {
subExpressions[i] = subExpressions[i].negate();
subExpressions[i].parent = this;
}
return this;
} else if (operator.operator == operator.LOG_NOT_OP) {
if (subExpressions[0] != null)
return subExpressions[0];
else
return new NopOperator(Type.tBoolean);
}
Operator negop =
new UnaryOperator(Type.tBoolean, Operator.LOG_NOT_OP);
return new ComplexExpression(negop, new Expression[] { this });
}
/**
* 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) {
if (operator.hasSideEffects(expr))
return true;
for (int i=0; i < subExpressions.length; i++) {
if (subExpressions[i].hasSideEffects(expr))
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(Expression e) {
// GlobalOptions.err.println("Try to combine "+e+" into "+this);
if (e.getOperator() instanceof LocalStoreOperator
&& e.getOperandCount() == 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(e);
if (result != 0)
return result;
if (subExpressions[i].hasSideEffects(e))
return -1;
}
}
if (e instanceof ComplexExpression) {
if (((CombineableOperator) e.getOperator()).matches(operator)) {
ComplexExpression ce = (ComplexExpression) e;
for (int i=0; i < ce.subExpressions.length-1; i++) {
if (!ce.subExpressions[i].equals(subExpressions[i]))
return -1;
}
return 1;
}
}
return subExpressions[0].canCombine(e);
}
/**
* 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(operator))
return true;
for (int i=0; i < subExpressions.length; i++) {
if (subExpressions[i].containsConflictingLoad(op))
return true;
}
return false;
}
/**
* Checks if this expression contains a conflicting load, that matches the
* given Expression (which must be a
* StoreInstruction/IIncOperator).
* @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) {
if (e instanceof ComplexExpression
&& e.getOperator() instanceof StoreInstruction
&& ((StoreInstruction) e.getOperator()).matches(operator)) {
ComplexExpression ce = (ComplexExpression) e;
int i;
for (i=0; i < ce.subExpressions.length-1; i++) {
if (!ce.subExpressions[i].equals(subExpressions[i]))
break;
}
if (i == ce.subExpressions.length-1)
return true;
}
for (int i=0; i < subExpressions.length; i++) {
if (subExpressions[i].containsMatchingLoad(e))
return true;
}
return false;
}
/**
* 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(Expression e) {
CombineableOperator op = (CombineableOperator) e.getOperator();
if (op.matches(operator)) {
op.makeNonVoid();
e.type = e.getOperator().getType();
return e;
}
for (int i=0; i < subExpressions.length; i++) {
Expression combined = subExpressions[i].combine(e);
if (combined != null) {
subExpressions[i] = combined;
subExpressions[i].parent = this;
return this;
}
}
return null;
}
public Operator getOperator() {
return operator;
}
public Expression[] getSubExpressions() {
return subExpressions;
}
public void setSubExpressions(int i, Expression expr) {
int diff = expr.getOperandCount()
- subExpressions[i].getOperandCount();
subExpressions[i] = expr;
for (ComplexExpression ce = this; ce != null;
ce = (ComplexExpression) ce.parent)
ce.operandcount += diff;
updateType();
}
void updateSubTypes() {
for (int i=0; i < subExpressions.length; i++) {
Type opType;
if (operator instanceof CheckNullOperator
|| i == 0 && operator instanceof ArrayStoreOperator) {
/* No rule without exception:
* We can always use tSubType, except for the
* check null operator and the
* array operand of an array store instruction.
*/
opType = operator.getOperandType(i);
} else
opType = Type.tSubType(operator.getOperandType(i));
if (opType != Type.tError) {
Type exprType = subExpressions[i].getType();
opType = opType.intersection(exprType);
if (!opType.equals(exprType)) {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("change in "+this+": "
+exprType+"->"+opType);
if (opType == Type.tError)
GlobalOptions.err.println("Type error in "+this+": "
+exprType+"->"
+operator.getOperandType(i));
subExpressions[i].setType(opType);
}
}
}
}
public void updateType() {
while (true) {
updateSubTypes();
Type types[] = new Type[subExpressions.length];
boolean changed = false;
for (int i=0; i < types.length; i++) {
if (operator instanceof CheckNullOperator
|| i == 0 && operator instanceof ArrayStoreOperator) {
/* No rule without exception:
* We can always use tSuperType, except for the
* array operand of an array store instruction.
*/
types[i] = subExpressions[i].getType();
} else
types[i] = Type.tSuperType
(subExpressions[i].getType());
Type opType = operator.getOperandType(i);
if (types[i] == Type.tError)
continue;
types[i] = types[i].intersection(opType);
if (types[i].equals(opType))
continue;
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("change in "+this+" at "+i+": "
+opType+"->"+types[i]);
if (types[i] == Type.tError)
GlobalOptions.err.println("Type error in "+this+" at "+i+": "
+subExpressions[i].getType()
+"->"+opType);
else
changed = true;
}
if (!changed)
break;
operator.setOperandType(types);
}
Type newType = type.intersection(operator.getType());
if (!newType.equals(type)) {
type = newType;
if (parent != null)
parent.updateType();
}
}
public void setType(Type newType) {
operator.setType(newType);
updateType();
}
public boolean isVoid() {
return operator.getType() == Type.tVoid;
}
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
operator.dumpExpression(writer, subExpressions);
}
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof ComplexExpression))
return false;
ComplexExpression expr = (ComplexExpression) o;
if (!operator.equals(expr.operator) ||
subExpressions.length != expr.subExpressions.length)
return false;
for (int i=0; i<subExpressions.length; i++) {
if(!subExpressions[i].equals(expr.subExpressions[i]))
return false;
}
return true;
}
/**
* This method should remove local variables that are only written
* and read one time directly after another. <br>
*
* In this case this is a non void LocalStoreOperator, whose local
* isn't used in other places.
* @return an expression where the locals are removed.
*/
public Expression removeOnetimeLocals() {
// System.err.println("removeOneTimeLocals: "+this);
if (operator instanceof LocalStoreOperator
&& operator.getType() != Type.tVoid) {
jode.decompiler.LocalInfo local = ((LocalStoreOperator)operator).getLocalInfo();
if ((local.getUseCount() == 2 /*XXX*/)) {
/* remove LocalInfo somehow XXX */
return subExpressions[0].removeOnetimeLocals();
} // else
// System.err.println("Can't remove local "+local);
}
for (int i=0; i< subExpressions.length; i++) {
subExpressions[i] = subExpressions[i].removeOnetimeLocals();
subExpressions[i].parent = this;
}
return this;
}
public Expression simplifyStringBuffer() {
if (operator instanceof InvokeOperator
&& (((InvokeOperator)operator).getClassType()
.equals(Type.tStringBuffer))
&& !((InvokeOperator)operator).isStatic()
&& (((InvokeOperator)operator).getMethodName().equals("append"))
&& (((InvokeOperator)operator).getMethodType()
.getParameterTypes().length == 1)) {
Expression e = subExpressions[0].simplifyStringBuffer();
if (e == null)
return null;
if (e == EMPTYSTRING
&& subExpressions[1].getType().isOfType(Type.tString))
return subExpressions[1];
subExpressions[1] = subExpressions[1].simplifyString();
return new ComplexExpression
(new StringAddOperator(), new Expression[]
{ e, subExpressions[1] });
}
if (operator instanceof ConstructorOperator
&& (((ConstructorOperator) operator).getClassType()
== Type.tStringBuffer)) {
if (subExpressions.length == 1
&& subExpressions[0].getType().isOfType(Type.tString))
return subExpressions[0].simplifyString();
}
return null;
}
public Expression simplifyString() {
if (operator instanceof InvokeOperator) {
InvokeOperator invoke = (InvokeOperator) operator;
if (invoke.getMethodName().equals("toString")
&& !invoke.isStatic()
&& invoke.getClassType().equals(Type.tStringBuffer)
&& subExpressions.length == 1) {
Expression simple = subExpressions[0].simplifyStringBuffer();
if (simple != null)
return simple;
}
else if (invoke.getMethodName().equals("valueOf")
&& invoke.isStatic()
&& invoke.getClassType().equals(Type.tString)
&& subExpressions.length == 1) {
if (subExpressions[0].getType().isOfType(Type.tString))
return subExpressions[0];
return new ComplexExpression
(new StringAddOperator(), new Expression[]
{ EMPTYSTRING, subExpressions[0] });
}
/* The pizza way (pizza is the compiler of kaffe) */
else if (invoke.getMethodName().equals("concat")
&& !invoke.isStatic()
&& invoke.getClassType().equals(Type.tString)) {
Expression left = subExpressions[0].simplify();
Expression right = subExpressions[1].simplify();
if (right instanceof ComplexExpression
&& right.getOperator() instanceof StringAddOperator
&& (((ComplexExpression) right).subExpressions[0]
== EMPTYSTRING))
right = ((ComplexExpression)right).subExpressions[1];
return new ComplexExpression
(new StringAddOperator(), new Expression[]
{ left, right });
} else if ((Decompiler.options & Decompiler.OPTION_DECRYPT) != 0) {
Expression expr = subExpressions[0].simplifyString();
if (expr instanceof ConstOperator) {
expr = invoke.deobfuscateString((ConstOperator)expr);
if (expr != null)
return expr;
}
}
}
return this;
}
public Expression simplify() {
for (int i=0; i< subExpressions.length; i++)
subExpressions[i] = subExpressions[i].simplify();
if (operator instanceof IfThenElseOperator &&
operator.getType().isOfType(Type.tBoolean)) {
if (subExpressions[1].getOperator() instanceof ConstOperator
&& subExpressions[2].getOperator() instanceof ConstOperator) {
ConstOperator c1 =
(ConstOperator) subExpressions[1].getOperator();
ConstOperator c2 =
(ConstOperator) subExpressions[2].getOperator();
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();
}
}
else if (operator instanceof StoreInstruction
&& (subExpressions[subExpressions.length-1]
.getOperator() instanceof ConstOperator)) {
StoreInstruction store = (StoreInstruction) operator;
ConstOperator one = (ConstOperator)
subExpressions[subExpressions.length-1].getOperator();
if ((operator.getOperatorIndex() ==
operator.OPASSIGN_OP+operator.ADD_OP ||
operator.getOperatorIndex() ==
operator.OPASSIGN_OP+operator.SUB_OP) &&
(one.getValue().equals("1")
|| one.getValue().equals("1.0"))) {
int op = (operator.getOperatorIndex() ==
operator.OPASSIGN_OP+operator.ADD_OP)
? operator.INC_OP : operator.DEC_OP;
Operator ppfixop = new PrePostFixOperator
(getType(), op, store, isVoid());
if (subExpressions.length == 1)
return ppfixop.simplify();
operator = ppfixop;
ppfixop.parent = this;
}
}
else if (operator instanceof CompareUnaryOperator
&& (subExpressions[0].getOperator()
instanceof CompareToIntOperator)) {
CompareBinaryOperator newOp = new CompareBinaryOperator
(subExpressions[0].getOperator().getOperandType(0),
operator.getOperatorIndex());
if (subExpressions[0] instanceof ComplexExpression) {
return new ComplexExpression
(newOp,
((ComplexExpression)subExpressions[0]).subExpressions).
simplify();
} else
return newOp.simplify();
}
else if (operator instanceof CompareUnaryOperator &&
operator.getOperandType(0).isOfType(Type.tBoolean)) {
/* xx == false */
if (operator.getOperatorIndex() == operator.EQUALS_OP)
return subExpressions[0].negate().simplify();
/* xx != false */
if (operator.getOperatorIndex() == operator.NOTEQUALS_OP)
return subExpressions[0].simplify();
} else if (operator instanceof IfThenElseOperator) {
if ((subExpressions[0] instanceof ComplexExpression)
&& (subExpressions[0].getOperator()
instanceof CompareUnaryOperator)
&& (subExpressions[0].getOperator().getOperatorIndex()
== Operator.NOTEQUALS_OP)
&& (subExpressions[1] instanceof GetFieldOperator)
&& (subExpressions[2] instanceof ComplexExpression)
&& (subExpressions[2].getOperator()
instanceof PutFieldOperator)) {
// Check for
// class$classname != null ? class$classname :
// (class$classname = class$("classname"))
// and replace with
// classname.class
ComplexExpression cmp = (ComplexExpression) subExpressions[0];
GetFieldOperator get = (GetFieldOperator) subExpressions[1];
ComplexExpression ass = (ComplexExpression) subExpressions[2];
PutFieldOperator put = (PutFieldOperator) ass.getOperator();
if (put.getField() != null
&& put.getField().isSynthetic() && put.matches(get)
&& cmp.subExpressions[0] instanceof GetFieldOperator
&& put.matches((GetFieldOperator)cmp.subExpressions[0])
&& ass.subExpressions[0] instanceof ComplexExpression
&& (ass.subExpressions[0].getOperator()
instanceof InvokeOperator)) {
InvokeOperator invoke = (InvokeOperator)
ass.subExpressions[0].getOperator();
Expression param =
((ComplexExpression)ass.subExpressions[0])
.subExpressions[0];
if (invoke.isGetClass()
&& param instanceof ConstOperator
&& param.getType().equals(Type.tString)) {
String clazz = ((ConstOperator)param).getValue();
if (put.getFieldName()
.equals("class$" + clazz.replace('.', '$'))
|| put.getFieldName()
.equals("class$L" + clazz.replace('.', '$'))) {
put.getField().analyzedSynthetic();
return new ClassFieldOperator(Type.tClass(clazz));
}
}
}
}
} else if (operator instanceof ConstructorOperator) {
ConstructorOperator cop = (ConstructorOperator) operator;
if (cop.getOuterClassInfo() != null) {
if (subExpressions[0] instanceof ComplexExpression
&& (subExpressions[0].getOperator()
instanceof CheckNullOperator)) {
((CheckNullOperator) subExpressions[0].getOperator())
.removeLocal();
subExpressions[0] = ((ComplexExpression) subExpressions[0])
.subExpressions[0];
cop.removedCheckNull = true;
}
}
} else if (operator instanceof GetFieldOperator) {
Expression thisExpr =
((GetFieldOperator)operator).simplifyThis(subExpressions);
if (thisExpr != null)
return thisExpr.simplify();
} else if (operator instanceof InvokeOperator) {
Expression accessExpr =
((InvokeOperator)operator).simplifyAccess(subExpressions);
if (accessExpr != null)
return accessExpr.simplify();
Expression stringExpr = simplifyString();
if (stringExpr != this)
return stringExpr.simplify();
}
for (int i=0; i< subExpressions.length; i++) {
subExpressions[i].parent = this;
}
return this;
}
public void makeInitializer() {
operator.makeInitializer();
}
public boolean isConstant() {
if (!operator.isConstant())
return false;
for (int i=0; i< subExpressions.length; i++)
if (!subExpressions[i].isConstant())
return false;
return true;
}
}

@ -1,86 +0,0 @@
/*
* CreateAssignExpression (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class CreateAssignExpression implements Transformation{
public InstructionHeader transform(InstructionHeader ih) {
InstructionHeader next = createAssignOp(ih);
if (next != null)
return next;
return createAssignExpression(ih);
}
public InstructionHeader createAssignOp(InstructionHeader ih) {
Expression rightHandSide;
StoreInstruction store;
BinaryOperator binop;
try {
store = (StoreInstruction) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
binop = (BinaryOperator) ih.getInstruction();
if (binop.getOperator() < binop.ADD_OP ||
binop.getOperator() >= binop.ASSIGN_OP)
return null;
ih = ih.getSimpleUniquePredecessor();
rightHandSide = (Expression) ih.getInstruction();
if (rightHandSide.isVoid())
return null; /* XXX */
ih = ih.getSimpleUniquePredecessor();
Operator load = (Operator) ih.getInstruction();
if (!store.matches(load))
return null;
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != 0 &&
dup.getCount() != store.getLValueOperandCount())
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
ih = ih.combine(3, rightHandSide);
InstructionHeader storeIH = ih.getNextInstruction();
store.setOperator(store.OPASSIGN_OP+binop.getOperator());
store.setLValueType(MyType.intersection(binop.getType(),
store.getLValueType()));
storeIH.combine(2, store);
return ih;
}
public InstructionHeader createAssignExpression(InstructionHeader ih) {
StoreInstruction store;
try {
store = (StoreInstruction) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != store.getLValueOperandCount() &&
dup.getCount() != store.getLValueType().stackSize())
return null;
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
return ih.combine(2, new AssignOperator(Operator.ASSIGN_OP, store));
}
}

@ -1,55 +0,0 @@
/*
* CreateExpression (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class CreateExpression implements Transformation {
public InstructionHeader transform(InstructionHeader ih) {
Operator op;
Expression exprs[];
int params;
try {
op = (Operator) ih.getInstruction();
params = op.getOperandCount();
exprs = new Expression[params];
for (int i = params-1; i>=0; i--) {
ih = ih.getSimpleUniquePredecessor();
exprs[i] = (Expression) ih.getInstruction();
if (exprs[i].isVoid()) {
if (i == params-1)
return null;
Expression e = exprs[i+1].tryToCombine(exprs[i]);
if (e == null)
return null;
i++;
exprs[i] = e;
ih = ih.combine(2, e);
}
}
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
if(Decompiler.isVerbose && params > 0)
System.err.print("x");
return ih.combine(params+1, new Expression(op, exprs));
}
}

@ -1,139 +0,0 @@
/*
* CreateIfThenElseOperator (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Enumeration;
import java.util.Vector;
public class CreateIfThenElseOperator implements Transformation{
public InstructionHeader createFunny(InstructionHeader ih) {
Expression cond = null;
try {
InstructionHeader ifHeader= ih;
if (ifHeader.getFlowType() != ifHeader.IFGOTO)
return null;
CompareUnaryOperator compare =
(CompareUnaryOperator) ifHeader.getInstruction();
if ((compare.getOperator() & ~1) != compare.EQUALS_OP)
return null;
Enumeration enum = ih.getPredecessors().elements();
while (enum.hasMoreElements()) {
try {
ih = (InstructionHeader) enum.nextElement();
if (ih.flowType == ih.GOTO)
ih = ih.getUniquePredecessor();
Expression zeroExpr = (Expression) ih.getInstruction();
ConstOperator zero =
(ConstOperator) zeroExpr.getOperator();
if (!zero.getValue().equals("0"))
continue;
ih = ih.getUniquePredecessor();
if (ih.getFlowType() != ih.IFGOTO)
continue;
if (compare.getOperator() == compare.EQUALS_OP &&
ih.getSuccessors()[1] != ifHeader.getSuccessors()[0]
|| compare.getOperator() == compare.NOTEQUALS_OP &&
ih.getSuccessors()[1] != ifHeader.getSuccessors()[1])
continue;
cond = (Expression) ih.getInstruction();
break;
} catch (ClassCastException ex) {
} catch (NullPointerException ex) {
}
}
if (cond == null)
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
InstructionHeader next = ih.nextInstruction;
ih.successors[1].predecessors.removeElement(ih);
next.instr = ih.instr;
next.movePredecessors(ih);
return next;
}
public InstructionHeader create(InstructionHeader ih2) {
InstructionHeader ifHeader;
InstructionHeader gotoIH;
Expression e[] = new Expression[3];
try {
Vector predec = ih2.getPredecessors();
if (predec.size() != 1)
return null;
ifHeader = (InstructionHeader) predec.elementAt(0);
if (ifHeader.getFlowType() != ifHeader.IFGOTO)
return null;
InstructionHeader ih1 = ifHeader.getSuccessors()[0];
gotoIH = ih1.getNextInstruction();
if (ifHeader.getSuccessors()[1] != ih2 ||
ih1.flowType != ifHeader.NORMAL ||
gotoIH.flowType != ifHeader.GOTO ||
ih2.flowType != ifHeader.NORMAL ||
gotoIH.getNextInstruction() != ih2 ||
gotoIH.getSuccessors()[0] != ih2.getNextInstruction())
return null;
e[1] = (Expression) ih1.getInstruction();
if (e[1].isVoid())
return null;
e[2] = (Expression) ih2.getInstruction();
if (e[2].isVoid())
return null;
e[0] = (Expression) ifHeader.getInstruction();
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
if (Decompiler.isVerbose)
System.err.print("?");
e[0] = e[0].negate();
IfThenElseOperator iteo = new IfThenElseOperator
(MyType.intersection(e[1].getType(),e[2].getType()));
ih2.instr = new Expression(iteo, e);
ih2.movePredecessors(ifHeader);
ih2.nextInstruction.predecessors.removeElement(gotoIH);
return ih2;
}
public InstructionHeader transform(InstructionHeader ih) {
InstructionHeader next = createFunny(ih);
if (next != null)
return next;
return create(ih);
}
}

@ -1,118 +0,0 @@
/*
* CreatePostIncExpression (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import sun.tools.java.Type;
public class CreatePostIncExpression implements Transformation {
public InstructionHeader transform(InstructionHeader ih)
{
InstructionHeader next = createLocalPostInc(ih);
if (next != null)
return next;
return createPostInc(ih);
}
public InstructionHeader createLocalPostInc(InstructionHeader ih) {
IIncOperator iinc;
int op;
Type type;
try {
Expression iincExpr = (Expression) ih.getInstruction();
iinc = (IIncOperator) iincExpr.getOperator();
if (iinc.getOperator() == iinc.ADD_OP + iinc.OPASSIGN_OP)
op = Operator.INC_OP;
else if (iinc.getOperator() == iinc.NEG_OP + iinc.OPASSIGN_OP)
op = Operator.DEC_OP;
else
return null;
if (!iinc.getValue().equals("1") &&
!iinc.getValue().equals("-1"))
return null;
if (iinc.getValue().equals("-1"))
op ^= 1;
ih = ih.getSimpleUniquePredecessor();
Expression loadExpr = (Expression) ih.getInstruction();
LocalLoadOperator load =
(LocalLoadOperator)loadExpr.getOperator();
if (!iinc.matches(load))
return null;
type = MyType.intersection(load.getType(), MyType.tUInt);
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
Operator postop = new LocalPostFixOperator(type, op, iinc);
return ih.combine(2, postop);
}
public InstructionHeader createPostInc(InstructionHeader ih) {
StoreInstruction store;
int op;
Type type;
try {
store = (StoreInstruction) ih.getInstruction();
if (store.getLValueOperandCount() == 0)
return null;
ih = ih.getSimpleUniquePredecessor();
BinaryOperator binOp = (BinaryOperator) ih.getInstruction();
if (binOp.getOperator() == store.ADD_OP)
op = Operator.INC_OP;
else if (store.getOperator() == store.NEG_OP)
op = Operator.DEC_OP;
else
return null;
ih = ih.getSimpleUniquePredecessor();
Expression expr = (Expression) ih.getInstruction();
ConstOperator constOp = (ConstOperator) expr.getOperator();
if (!constOp.getValue().equals("1") &&
!constOp.getValue().equals("-1"))
return null;
if (constOp.getValue().equals("-1"))
op ^= 1;
ih = ih.getSimpleUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getCount() != store.getLValueType().stackSize() ||
dup.getDepth() != store.getLValueOperandCount())
return null;
ih = ih.getSimpleUniquePredecessor();
Operator load = (Operator) ih.getInstruction();
if (!store.matches(load))
return null;
ih = ih.getSimpleUniquePredecessor();
DupOperator dup2 = (DupOperator) ih.getInstruction();
if (dup2.getCount() != store.getLValueOperandCount() ||
dup2.getDepth() != 0)
return null;
type = MyType.intersection(load.getType(), store.getLValueType());
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
Operator postop = new PostFixOperator(type, op, store);
return ih.combine(6, postop);
}
}

@ -1,177 +0,0 @@
/*
* DoWhileInstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
/**
* This instruction header represents an if instruction. The
* linkage of the instructions is as follow:
* <pre>
* A: ....
* <p>
* prev = A, next = H or null, pred = normal, succ = {H,C}
* B: while ( instr ) {
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* C: first block-instr
* <p>
* prev = C, next = E, pred = normal succ = normal
* D: ...
* <p>
* prev = D, next = null, pred = normal succ = {B}
* E: last block-instr
* }
* <p>
* prev = B, ..., pred = (normal+{G}) \ {C..F}, succ = normal
* H: ...
* </pre>
*/
public class DoWhileInstructionHeader extends InstructionHeader {
InstructionHeader endHeader;
/**
* Creates a new while statement.
* @param head the first instruction of this do-while loop
* @param end the last instruction which contains the
* if-goto (or goto) statement.
*/
public DoWhileInstructionHeader(InstructionHeader head,
InstructionHeader end) {
super(DOWHILESTATEMENT,
head.addr, end.nextAddr,
new InstructionHeader[1], end.outer);
this.endHeader = end;
if (end.flowType == GOTO) {
/* This is a for(;;) loop
*/
this.instr = null;
end.successors[0].predecessors.removeElement(end);
} else {
this.instr = end.instr;
end.successors[0].predecessors.removeElement(end);
end.successors[1].predecessors.removeElement(end);
}
this.addPredecessors(head);
this.successors[0] = head;
head.predecessors.addElement(this);
this.prevInstruction = head.prevInstruction;
if (prevInstruction != null)
prevInstruction.nextInstruction = this;
this.nextInstruction = end.nextInstruction;
if (nextInstruction != null)
nextInstruction.prevInstruction = this;
if (successors[0] != this) {
successors[0].prevInstruction = null;
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction) {
if (ih.outer == outer)
ih.outer = this;
if (ih.nextInstruction == end)
ih.nextInstruction = null;
}
}
}
/**
* This should be implemented for those blocks, that is headers
* which are outer of other headers. This gives the instruction
* where the control flows after this block.
* @return the first instruction after this block.
*/
InstructionHeader getEndBlock() {
return getContinue();
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
boolean braces = (successors[0].flowType != NORMAL ||
successors[0].nextInstruction != null);
writer.println((instr == null ? "for(;;)" : "do")+
(braces ? " {": ""));
writer.tab();
if (successors[0] != this) {
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction)
ih.dumpSource(writer);
} else
writer.println("/* empty */");
writer.untab();
if (instr != null)
writer.println((braces ? "} " : "") + "while ("+instr+");");
else if (braces)
writer.println("}");
if (Decompiler.isDebugging)
writer.untab();
}
/**
* Returns the InstructionHeader where a break of this instruction
* would jump to. Does only make sense for do/while/for-loops and
* switch instructions.
*/
public InstructionHeader getBreak() {
return super.getEndBlock();
}
public InstructionHeader getShadow() {
return successors[0];
}
/**
* Returns the InstructionHeader where a continue of this instruction
* would jump to. Does only make sense for do/while/for-loops.
*/
public InstructionHeader getContinue() {
return (instr == null)? this : endHeader;
}
public InstructionHeader doTransformations(Transformation[] trafo) {
InstructionHeader next;
if (successors[0] != this)
for (InstructionHeader ih = successors[0]; ih != null; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
return super.doTransformations(trafo);
}
}

@ -1,43 +0,0 @@
/*
* DupOperator (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class DupOperator extends Instruction {
int count, depth;
public DupOperator(int depth, int count) {
super(Type.tUnknown);
this.count = count;
this.depth = depth;
}
public int getCount(){
return count;
}
public int getDepth(){
return depth;
}
public String toString()
{
return "dup"+count+"_x"+depth;
}
}

@ -1,40 +0,0 @@
/*
* EmptyStringOperator (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class EmptyStringOperator extends NoArgOperator {
public EmptyStringOperator() {
super(Type.tString, 0);
}
public int getPriority() {
return 1000;
}
public boolean equals(Object o) {
return (o instanceof EmptyStringOperator);
}
public String toString(String[] operands) {
return "\"\"";
}
}

@ -1,40 +0,0 @@
package jode;
import sun.tools.java.Type;
public class GotoOperator extends JumpInstruction {
protected int destination;
public GotoOperator(int addr, int length, int dest) {
super(addr,length);
this.destination = dest;
}
public int getDestination() {
return destination;
}
public int getOperandCount() {
return 0;
}
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 int[] getSuccessors() {
int [] result = { destination };
return result;
}
public String toString(CodeAnalyzer ca, String[] operands) {
return "goto addr_" + destination;
}
}

@ -1,39 +0,0 @@
package jode;
import sun.tools.java.Type;
public class IfGotoOperator extends JumpInstruction {
protected int destination;
public IfGotoOperator(int addr, int length, int dest) {
super(addr,length);
destination = dest;
}
public int getDestination() {
return destination;
}
public int getOperandCount() {
return 1;
}
public int getOperandPriority(int i) {
return 200; /* force parentheses around assignments */
}
public Type getOperandType(int i) {
return Type.tBoolean;
}
public void setOperandType(Type types[]) {
}
public int[] getSuccessors() {
int [] result = { destination, getAddr() + getLength() };
return result;
}
public String toString(CodeAnalyzer ca, String[] operands) {
return "if ("+operands[0]+") goto addr_" + destination;
}
}

@ -1,182 +0,0 @@
/*
* IfInstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Enumeration;
/**
* This instruction header represents an if instruction. The
* linkage of the instructions is as follow:
* <pre>
* A: ....
* <p>
* prev = A, next = H, pred = normal, succ = {C,E}
* B: if ( instr ) {
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* C: then-instr 1
* <p>
* prev = C, next = H!, pred = normal succ = normal
* D: instructions of then part
* <p>
* } else {
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* E: else-instr 1
* <p>
* prev = E, next = null, pred = normal, succ = normal
* F: instructions of then part
* <p>
* }
* prev = B, ..., pred = normal, succ = normal
* H: ...
* </pre>
*/
public class IfInstructionHeader extends InstructionHeader {
boolean hasElsePart;
/**
* Creates a new if statement.
* @param ifHeader the instruction header whichs contains the
* if goto statement, must have a nextInstruction.
* @param elseBlock the start of the else part, same outer, may be null.
* if not null, it must equals ifHeader.successors[1].
* @param next the next instruction after the if statement,
* same outer, may be null.
* @param endBlock the instruction where the control flows after the if,
* outer may differ, not null.
*/
public IfInstructionHeader(InstructionHeader ifHeader,
InstructionHeader elseBlock,
InstructionHeader next) {
super(IFSTATEMENT, ifHeader.addr, ifHeader.addr,
ifHeader.successors, ifHeader.outer);
hasElsePart = elseBlock != null;
this.instr = ((Expression)ifHeader.getInstruction()).negate();
this.movePredecessors(ifHeader);
/* this.moveSuccessors(ifHeader); */
successors[0].predecessors.removeElement(ifHeader);
successors[1].predecessors.removeElement(ifHeader);
successors[0].predecessors.addElement(this);
successors[1].predecessors.addElement(this);
/* unlink the first instruction of the if */
ifHeader.nextInstruction.prevInstruction = null;
/* unlink the last instruction of the if */
if (next != null)
next.prevInstruction.nextInstruction = null;
this.hasElsePart = hasElsePart;
if (hasElsePart) {
/* unlink the instructions around the else */
elseBlock.prevInstruction.nextInstruction = null;
elseBlock.prevInstruction = null;
for (InstructionHeader ih = successors[1]; ih != null;
ih = ih.nextInstruction)
if (ih.outer == outer)
ih.outer = this;
}
/* Do this now, because the end of the then part is cut in
* the else part above.
*/
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction)
if (ih.outer == outer)
ih.outer = this;
this.nextInstruction = next;
if (next != null)
next.prevInstruction = this;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
boolean braces = successors[0].flowType != NORMAL ||
successors[0].nextInstruction != null;
writer.println("if (" + instr.toString() + ")" + (braces ? " {": ""));
writer.tab();
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction)
ih.dumpSource(writer);
writer.untab();
if (hasElsePart) {
if (braces)
writer.print("} ");
braces = successors[1].flowType != NORMAL ||
successors[1].nextInstruction != null;
if (successors[1].flowType == IFSTATEMENT &&
successors[1].nextInstruction == null) {
/* write "else if" */
braces = false;
writer.print("else ");
successors[1].dumpSource(writer);
} else {
writer.println("else" + (braces ? " {": ""));
writer.tab();
for (InstructionHeader ih = successors[1];
ih != null; ih = ih.nextInstruction)
ih.dumpSource(writer);
writer.untab();
}
}
if (braces)
writer.println("} ");
if (Decompiler.isDebugging)
writer.untab();
}
public InstructionHeader doTransformations(Transformation[] trafo) {
InstructionHeader next;
for (InstructionHeader ih = successors[0]; ih != null; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
if (hasElsePart) {
for (InstructionHeader ih = successors[1]; ih != null; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
}
return super.doTransformations(trafo);
}
}

@ -1,42 +0,0 @@
/*
* Instruction (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public abstract class Instruction {
protected Type type;
Instruction(Type type) {
this.type = type;
}
public Type getType() {
return type;
}
public void setType(Type newType) {
this.type = newType;
}
public Instruction simplify() {
return this;
}
public abstract String toString();
}

@ -1,581 +0,0 @@
/*
* InstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Vector;
import sun.tools.java.Type;
/**
* This class maintains the connections between the
* InstructionHeaders. They are connected in a doubly linked list
* (but a instruction may have multiple successors and predecessors).
* @see JumpInstructionHeader
* @see SwitchInstructionHeader
* @author Jochen Hoenicke
*/
public class InstructionHeader {
public final static int METHOD =-1;
public final static int NORMAL = 0;
public final static int GOTO = 1;
public final static int IFGOTO = 2;
public final static int SWITCH = 3;
public final static int JSR = 4;
public final static int RET = 5;
public final static int RETURN = 6;
public final static int TRY = 7;
public final static int CATCH = 8;
public final static int IFSTATEMENT = 10;
public final static int WHILESTATEMENT = 11;
public final static int DOWHILESTATEMENT = 12;
public final static int FORSTATEMENT = 13;
public final static int SWITCHSTATEMENT = 14;
public final static int TRYCATCHBLOCK = 15;
public final static int CASESTATEMENT = 16;
public final static int BREAK = 20;
public final static int CONTINUE = 21;
public final static int VOIDRETURN = 22;
public final static int EMPTY = 99;
/**
* The flow type of the instruction header, this is one of the
* above constants.
*/
int flowType;
/**
* The address of this and the following instruction header.
*/
int addr, nextAddr;
/**
* The underlying instruction. This is null for some special
* instructions (depends on flowType).
*/
Instruction instr;
/**
* The instruction header representing the surrounding block.
*/
InstructionHeader outer = null;
/**
* A simple doubly linked list of instructions in code order
* (without caring about jump instructions).
*/
InstructionHeader nextInstruction, prevInstruction;
/**
* This should be implemented for those blocks, that is headers
* which are outer of other headers. This gives the instruction
* where the control flows after this block.
* @return the first instruction after this block.
*/
InstructionHeader getEndBlock() {
if (nextInstruction != null) {
return nextInstruction.getShadow();
}
return outer.getEndBlock();
}
/**
* Get the instruction header where this jumps to if this is a
* unconditional goto. Otherwise returns this header.
*/
InstructionHeader getShadow() {
return (flowType == GOTO)? successors[0].getShadow() : this;
}
/**
* A more complex doubly linked list of instructions. The
* successors are the possible destinations of jump and switch
* instructions. The predecessors are the reverse things.
* The predeccors sits in a vector to make it easier to add
* or remove one, when creating or manipulating other instruction
* headers.
*/
InstructionHeader[] successors;
Vector predecessors = new Vector();
/**
* The addresses of the successors of this header. This are
* resolved by resolveSuccessors and then deleted.
*/
int[] succs = null;
/**
* Create a new InstructionHeader, that must be resolved later.
* @param flowType The type of this instruction header.
* @param addr The address of this instruction header.
* @param nextAddr The address of the next instruction header.
* @param instr The underlying Instruction.
* @param succs The successors of this instruction header
* (the addresses, are resolved later).
*/
protected InstructionHeader(int flowType, int addr, int nextAddr,
Instruction instr, int[] succs) {
this.flowType = flowType;
this.addr = addr;
this.nextAddr = nextAddr;
this.instr = instr;
this.succs = succs;
}
/**
* Create a new InstructionHeader.
* @param flowType The type of this instruction header.
* @param addr The address of this instruction header.
* @param nextAddr The address of the next instruction header.
* @param successors The successors of this instruction header.
* @param outer The instruction header of the surrounding block.
*/
protected InstructionHeader(int flowType, int addr, int nextAddr,
InstructionHeader[] successors,
InstructionHeader outer) {
this.flowType = flowType;
this.addr = addr;
this.nextAddr = nextAddr;
this.instr = instr;
this.successors = successors;
this.outer = outer;
}
/**
* Create a new InstructionHeader of zero length.
* @param flowType The type of this instruction header.
* @param addr The address of this Instruction.
* @param outer The instruction header of the surrounding block.
*/
protected InstructionHeader(int flowType, int addr,
InstructionHeader outer) {
this(flowType, addr, addr, new InstructionHeader[0], outer);
}
/**
* Create an InstructionHeader for a normal instruction.
* @param addr The address of this instruction.
* @param length The length of this instruction.
* @param instr The underlying Instruction.
*/
public static InstructionHeader createNormal(int addr, int length,
Instruction instr) {
int[] succs = { addr + length };
return new InstructionHeader(NORMAL, addr, addr + length,
instr, succs);
}
/**
* Create an InstructionHeader for a return
* @param addr The address of this instruction.
* @param length The length of this instruction.
* @param instr The underlying Instruction.
*/
public static InstructionHeader createReturn(int addr, int length,
Instruction instr)
{
return new InstructionHeader(RETURN, addr, addr + length,
instr, new int[0]);
}
/**
* Create an InstructionHeader for an unconditional jump.
* @param addr The address of this instruction.
* @param length The length of this instruction.
* @param instr The underlying Instruction.
* @param dest The destination address of the jump.
*/
public static InstructionHeader createGoto(int addr, int length, int dest)
{
int [] succs = { dest };
return new InstructionHeader(GOTO, addr, addr + length, null, succs);
}
/**
* Create an InstructionHeader for a conditional jump.
* @param addr The address of this instruction.
* @param length The length of this instruction.
* @param instr The underlying Instruction.
* @param dest The destination address of the jump.
*/
public static InstructionHeader createIfGoto(int addr, int length,
int dest, Instruction instr) {
int[] succs = { addr+length , dest };
return new InstructionHeader (IFGOTO, addr, addr + length,
instr, succs);
}
/**
* Create an InstructionHeader for a switch.
* @param addr The address of this Instruction.
* @param length The length of this Instruction.
* @param instr The underlying Instruction.
* @param cases The possible cases
* @param succs The destinations (one longer for default)
*/
public static InstructionHeader createSwitch(int addr, int length,
Instruction instr,
int[] cases, int[] succs) {
InstructionHeader ih =
new SimpleSwitchInstructionHeader(addr, addr+length, instr,
cases, succs);
return ih;
}
static int ids =0;
int id = -1;
public String toString() {
if (id == -1) id = ids++;
return addr+"__"+id;
}
/**
* Returns the InstructionHeader where a break of this instruction
* would jump to. Does only make sense for do/while/for-loops and
* switch instructions.
*/
public InstructionHeader getBreak() {
return null;
}
/**
* Returns the InstructionHeader where a continue of this instruction
* would jump to. Does only make sense for do/while/for-loops.
*/
public InstructionHeader getContinue() {
return null;
}
/**
* Get the flow type of this instruction.
* @return the flow type.
*/
public int getFlowType() {
return flowType;
}
static int serialnr = 0;
String label = null;
/**
* Get the label of this instruction. It is created on the fly
* if it didn't exists before.
* @return the label.
*/
public String getLabel() {
if (label == null)
label = "label_" + serialnr++;
return label;
}
/**
* Get the address of this instruction. This is probably only useful
* for debugging purposes.
* @return the address.
*/
public int getAddress() {
return addr;
}
/**
* Get the next address in code order.
* @return the next instruction
*/
public int getNextAddr() {
return nextAddr;
}
/**
* Get the underlying instruction.
* @return the underlying instruction.
*/
public Instruction getInstruction() {
return instr;
}
/**
* Set the underlying instruction.
* @param instr the underlying instruction.
*/
public void setInstruction(Instruction instr) {
this.instr = instr;
}
/**
* Get the next instruction in code order. This function mustn't
* be called before resolveSuccessors is executed for this
* InstructionHeaders.
* @return the next instruction
*/
public InstructionHeader getNextInstruction() {
return nextInstruction;
}
/**
* Get the successors of this instructions. This function mustn't
* be called before resolveSuccessors is executed for this
* InstructionHeaders.
* @return Array of successors.
*/
public InstructionHeader[] getSuccessors() {
return successors;
}
/**
* Returns true if this instruction header needs a label.
*/
protected boolean needsLabel() {
if (label != null)
return true;
/* An instruction my have only one prevInstruction, but
* may have more then one predecessor that has its
* nextInstruction pointing to us.
*/
for (int i=0; i<predecessors.size(); i++) {
InstructionHeader ih =
(InstructionHeader)predecessors.elementAt(i);
if ((ih.flowType == GOTO || ih.flowType == IFGOTO) &&
ih.getEndBlock() != this)
return true;
}
return false;
}
/**
* Get the unique predecessor or null if there isn't a
* unique predecessor.
*/
public InstructionHeader getUniquePredecessor() {
return (predecessors.size() == 1 &&
predecessors.elementAt(0) == prevInstruction) ?
prevInstruction : null;
}
/**
* Get the unique predecessor which mustn't be a conditional jump
* @return the predecessor or null if there isn't a such a thing
*/
public InstructionHeader getSimpleUniquePredecessor() {
InstructionHeader pre = getUniquePredecessor();
return (pre.getSuccessors().length != 1) ? null : pre;
}
/**
* Get the predecessors of this instruction. This function mustn't
* be called before resolveSuccessors is executed for all
* InstructionHeaders.
* @return Vector of predecessors.
*/
public Vector getPredecessors() {
return predecessors;
}
/**
* Resolve the successors and predecessors and build a doubly
* linked list.
* @param instHeaders an array of the InstructionHeaders, indexed
* by addresses.
*/
public void resolveSuccessors(InstructionHeader[] instHeaders) {
if (nextAddr < instHeaders.length) {
nextInstruction = instHeaders[nextAddr];
instHeaders[nextAddr].prevInstruction = this;
} else
nextInstruction = null;
successors = new InstructionHeader[succs.length];
for (int i=0; i< succs.length; i++) {
successors[i] = instHeaders[succs[i]];
successors[i].predecessors.addElement(this);
}
succs = null;
}
public void dumpDebugging(TabbedPrintWriter writer)
throws java.io.IOException
{
writer.println("");
writer.print(""+toString()+
": <"+addr + " - "+(nextAddr-1)+"> preds: ");
for (int i=0; i<predecessors.size(); i++) {
if (i>0) writer.print(", ");
writer.print(""+predecessors.elementAt(i));
}
writer.println("");
writer.print("out: "+outer +
" prev: "+prevInstruction+", next: "+ nextInstruction +
" succs: ");
for (int i=0; i<successors.length; i++) {
if (i>0) writer.print(", ");
writer.print(""+successors[i]);
}
writer.println("");
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
if (flowType == IFGOTO) {
writer.println("if ("+instr.toString()+")");
writer.tab();
if (successors[1] != getEndBlock())
writer.println("goto "+successors[1].getLabel());
else
writer.println("/*empty*/;");
writer.untab();
} else if (flowType == GOTO) {
if (successors[0] != getEndBlock())
writer.println("goto "+successors[0].getLabel());
} else if (flowType == RETURN) {
writer.println((instr != null ? instr.toString() :
"return") + ";");
} else {
if (flowType != EMPTY) {
if (!(instr instanceof NopOperator)) {
if (instr.getType() != MyType.tVoid)
writer.print("push ");
writer.println(instr.toString()+";");
}
}
}
if (Decompiler.isDebugging)
writer.untab();
}
/**
* Moves the predecessors from the InstructionHeader <em>from</em> to
* the current instruction. The current predecessors are overwritten
* and you must make sure that no live InstructionHeader points to
* the current. <p>
* The predecessors of <em>from</em> are informed about this change.
* @param from The instruction header which predecessors are moved.
*/
public void movePredecessors(InstructionHeader from) {
if (this == from)
return;
addr = from.addr;
prevInstruction = from.prevInstruction;
if (prevInstruction != null) {
prevInstruction.nextInstruction = this;
}
predecessors = from.predecessors;
for (int i=0; i < predecessors.size(); i++) {
InstructionHeader pre =
(InstructionHeader)predecessors.elementAt(i);
for (int j=0; j<pre.successors.length; j++)
if (pre.successors[j] == from)
pre.successors[j] = this;
}
from.predecessors = new Vector();
}
/**
* Moves the predecessors from the InstructionHeader <em>from</em> to
* the current instruction. <p>
* The predecessors of <em>from</em> are informed about this change.
* @param from The instruction header which predecessors are moved.
*/
public void addPredecessors(InstructionHeader from) {
for (int i=0; i < from.predecessors.size(); i++) {
InstructionHeader pre =
(InstructionHeader)from.predecessors.elementAt(i);
predecessors.addElement(pre);
for (int j=0; j < pre.successors.length; j++)
if (pre.successors[j] == from)
pre.successors[j] = this;
}
from.predecessors.removeAllElements();
}
/**
* Moves the successors from the InstructionHeader <em>from</em> to
* the current instruction. The current successors are overwritten
* and you must make sure that is has no live InstructionHeaders.
* Also the <em>from</em> InstructionHeader musnt't be used any more.<p>
*
* The successors of <em>from</em> are informed about this change.
* @param from The instruction header which successors are moved.
*/
public void moveSuccessors(InstructionHeader from) {
successors = from.successors;
from.successors = null;
for (int i=0; i < successors.length; i++) {
successors[i].predecessors.removeElement(from);
successors[i].predecessors.addElement(this);
}
}
/**
* This method replaces multiple InstructionHeaders by a single one.
* The next count Instructions must be unique.
* @param count the number of InstructionHeaders that should be replaced.
* @param instr the new instruction; this should be equivalent to the
* old <em>count</em instructions.
* @return the InstructionHeader representing the combined instructions.
*/
public InstructionHeader combine(int count, Instruction newInstr) {
InstructionHeader ih = this;
for (int i=1; i < count; i++) {
ih = ih.nextInstruction;
}
ih.instr = newInstr;
ih.movePredecessors(this);
return ih;
}
public InstructionHeader doTransformations(Transformation[] trafo) {
for (int i=0; i<trafo.length; i++) {
InstructionHeader newInstr = trafo[i].transform(this);
if (newInstr != null)
return newInstr;
}
return null;
}
/**
* This method replaces two conditional InstructionHeaders by a
* single one. You must make sure that this and the next instruction
* are both conditional Instructions and the destinations matches.
*
* @param newCondition the new instruction; this should be equivalent
* to the old two conditions.
*/
public InstructionHeader combineConditional(Instruction newCondition) {
successors[1].predecessors.removeElement(this);
InstructionHeader next = nextInstruction;
next.instr = newCondition;
next.movePredecessors(this);
return next;
}
}

@ -1,44 +0,0 @@
package jode;
/**
* This is an InstructionHeader for an JSR (jump subroutine) opcode.
* @author Jochen Hoenicke
*/
public class JsrInstructionHeader extends InstructionHeader {
int dest;
InstructionHeader destination;
/**
* Create an InstructionHeader for a conditional or unconditional
* Jsr.
* @param addr The address of this instruction.
* @param length The length of this instruction.
* @param dest The destination address of the Jsr.
* @param instr The undelying Instruction, the type of must be
* <ul><li> boolean for a conditional Jsr. </li>
* <li> void for an unconditional Jsr. </li></ul>
*/
public JsrInstructionHeader(int addr, int length, int dest,
Instruction instr, int[] succs) {
super(JSR, addr, addr+length, instr, succs);
this.dest = dest;
}
/**
* Resolve the successors and predecessors and build a doubly
* linked list.
* @param instHeaders an array of the InstructionHeaders, indexed
* by addresses.
*/
public void resolveSuccessors(InstructionHeader[] instHeaders) {
nextInstruction = instHeaders[nextAddr];
destination = instHeaders[dest];
destination.predecessors.addElement(this);
/* Ret.successors.addElement(nextInstruction); XXX */
}
public String toString() {
return "Jsr " + dest;
}
}

@ -1,14 +0,0 @@
package jode;
public class JsrOperator extends Instruction {
int destination;
public JsrOperator() {
super(MyType.tVoid);
}
public String toString()
{
return "JSR";
}
}

@ -1,12 +0,0 @@
package jode;
import sun.tools.java.Type;
public abstract class JumpInstruction extends Operator {
public JumpInstruction(int addr, int length) {
super(addr, length, Type.tVoid, 0);
}
public int getPriority() {
return 0;
}
}

@ -1,25 +0,0 @@
package jode;
import sun.tools.java.Type;
public class LoadOperator extends ConstOperator {
LocalVariable slot;
public LoadOperator(int addr, int length, Type type, LocalVariable slot) {
super(addr,length,
UnknownType.commonType(type,slot.getType(addr)), "");
this.slot = slot;
}
public LocalVariable getSlot() {
return slot;
}
public String toString(CodeAnalyzer ca, String[] operands) {
return slot.getName(getAddr()).toString();
}
public boolean equals(Object o) {
return (o instanceof LoadOperator &&
((LoadOperator) o).slot == slot);
}
}

@ -1,37 +0,0 @@
/*
* LocalPostFixOperator (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class LocalPostFixOperator extends NoArgOperator {
IIncOperator iinc;
public LocalPostFixOperator(Type type, int op, IIncOperator iinc) {
super(type, op);
this.iinc = iinc;
}
public int getPriority() {
return 800;
}
public String toString(String[] operands) {
return iinc.getLocalInfo().getName() + getOperatorString();
}
}

@ -1,49 +0,0 @@
/* LocalPrePostFixOperator Copyright (C) 1998-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.decompiler.TabbedPrintWriter;
public class LocalPrePostFixOperator extends NoArgOperator {
IIncOperator iinc;
boolean postfix;
public LocalPrePostFixOperator(Type type, int op,
IIncOperator iinc, boolean postfix) {
super(type, op);
this.iinc = iinc;
this.postfix = postfix;
}
public int getPriority() {
return postfix ? 800 : 700;
}
public void dumpExpression(TabbedPrintWriter writer,
Expression[] operands)
throws java.io.IOException {
String local = iinc.getLocalInfo().getName();
if (postfix) {
writer.print(local+getOperatorString());
} else {
writer.print(getOperatorString()+local);
}
}
}

@ -1,110 +0,0 @@
/*
* MethodInstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Vector;
import sun.tools.java.BinaryExceptionHandler;
import sun.tools.java.Type;
/**
* This class is the end point of the InstructionHeader list.
* @author Jochen Hoenicke
*/
public class MethodInstructionHeader extends InstructionHeader {
/**
* Create a new InstructionHeader.
* @param addr The address of this Instruction.
* @param length The length of this Instruction.
* @param instr The underlying Instruction.
*/
public MethodInstructionHeader(JodeEnvironment env,
InstructionHeader[] instr,
BinaryExceptionHandler[] handlers) {
super(METHOD, 0, instr.length, new InstructionHeader[1], null);
successors[0] = instr[0];
instr[0].predecessors.addElement(this);
nextInstruction = new InstructionHeader(EMPTY, instr.length, null);
nextInstruction.prevInstruction = this;
for (int addr = 0; addr < instr.length; addr = instr[addr].nextAddr) {
instr[addr].outer = this;
instr[addr].resolveSuccessors(instr);
if (instr[addr].flowType == RETURN) {
InstructionHeader[] retSuccs = { nextInstruction };
instr[addr].successors = retSuccs;
nextInstruction.predecessors.addElement(instr[addr]);
if (instr[addr].instr == null) {
/* if this is a void return, replace it by a
* goto to the nextInstruction.
*/
instr[addr].flowType = GOTO;
}
}
}
for (int i=0; i<handlers.length; i++) {
InstructionHeader tryIH = instr[handlers[i].startPC];
if (tryIH.flowType != TRY)
instr[handlers[i].startPC] = tryIH =
new TryInstructionHeader(tryIH, this);
Type type =
(handlers[i].exceptionClass != null)?
handlers[i].exceptionClass.getType() : MyType.tVoid;
instr[handlers[i].handlerPC] =
new CatchInstructionHeader
(type, env.getTypeString(type),
instr[handlers[i].handlerPC], this);
InstructionHeader endIH = instr[handlers[i].endPC];
InstructionHeader catchIH = instr[handlers[i].handlerPC];
((TryInstructionHeader)tryIH).addHandler(endIH, catchIH);
}
}
public InstructionHeader getFirst() {
return successors[0];
}
public Vector getReturns() {
return nextInstruction.predecessors;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction)
ih.dumpSource(writer);
// dump the last label if it was used.
nextInstruction.dumpSource(writer);
}
public InstructionHeader doTransformations(Transformation[] trafo) {
InstructionHeader next;
for (InstructionHeader ih = successors[0]; ih != null; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
return null;
}
}

@ -1,19 +0,0 @@
package jode;
import sun.tools.java.Type;
public class NewConstructorOperator extends NoArgOperator {
Expression constructor;
public NewConstructorOperator(Type type, Expression expr) {
super(type);
this.constructor = expr;
}
public int getPriority() {
return 950;
}
public String toString(CodeAnalyzer ca, String[] operands) {
return "new "+constructor.toString(ca, 0);
}
}

@ -1,71 +0,0 @@
/*
* PostFixOperator (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class PostFixOperator extends Operator {
StoreInstruction store;
boolean postfix;
public PostFixOperator(Type type, int op, StoreInstruction store,
boolean postfix) {
super(type, op);
this.store = store;
this.postfix = postfix;
}
public PostFixOperator(Type type, int op, StoreInstruction store) {
this (type, op, store, true);
}
public int getPriority() {
return postfix ? 800 : 700;
}
public int getOperandPriority(int i) {
return getPriority();
}
public Type getOperandType(int i) {
return store.getLValueOperandType(i);
}
public int getOperandCount() {
return store.getLValueOperandCount();
}
/**
* Sets the return type of this operator.
*/
public void setType(Type type) {
store.setLValueType(type);
super.setType(store.getLValueType());
}
public void setOperandType(Type[] inputTypes) {
store.setLValueOperandType(inputTypes);
}
public String toString(String[] operands) {
if (postfix)
return store.getLValueString(operands) + getOperatorString();
else
return getOperatorString() + store.getLValueString(operands);
}
}

@ -1,64 +0,0 @@
/*
* RetInstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
/**
* This is an InstructionHeader for an RET (return from JSR) opcode.
* @author Jochen Hoenicke
*/
public class RetInstructionHeader extends InstructionHeader {
int dest;
boolean conditional;
InstructionHeader destination;
InstructionHeader[] successors;/*XXX*/
/**
* Create an InstructionHeader for a conditional or unconditional
* Ret.
* @param addr The address of this instruction.
* @param length The length of this instruction.
* @param instr The underlying Instruction of int type (ret addr).
*/
public RetInstructionHeader(int addr, int length, Instruction instr) {
super(RET, addr, addr+length, instr, new int[0]);
}
/**
* Get the successors of this instructions. This function mustn't
* be called before resolveSuccessors is executed for this
* InstructionHeaders.
* @return Array of successors.
*/
public InstructionHeader[] getSuccessors() {
/* XXX */
return successors;
}
/**
* Resolve the successors and predecessors and build a doubly
* linked list.
* @param instHeaders an array of the InstructionHeaders, indexed
* by addresses.
*/
public void resolveSuccessors(InstructionHeader[] instHeaders) {
nextInstruction = instHeaders[nextAddr];
}
}

@ -1,15 +0,0 @@
package jode;
public class RetOperator extends Instruction {
int slot;
public RetOperator(int slot) {
super(MyType.tVoid);
this.slot = slot;
}
public String toString()
{
return "ret";
}
}

@ -1,44 +0,0 @@
/*
* ReturnOperator (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import sun.tools.java.Type;
public class ReturnOperator extends SimpleOperator {
public ReturnOperator(Type type) {
super(Type.tVoid, 0, (type == Type.tVoid)?0:1);
if (type != Type.tVoid)
operandTypes[0] = MyType.tSubType(type);
}
public int getPriority() {
return 0;
}
public int getOperandPriority(int i) {
return 0;
}
public String toString(String[] operands) {
StringBuffer result = new StringBuffer("return");
if (getOperandCount() != 0)
result.append(" ").append(operands[0]);
return result.toString();
}
}

@ -1,80 +0,0 @@
/*
* SimpleSwitchInstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
/**
* This is an InstructionHeader for simple switch statements. Simple
* means that this is without blocks.
* @author Jochen Hoenicke
*/
public class SimpleSwitchInstructionHeader extends InstructionHeader {
/**
* The case labels of a switch instruction header.
*/
int[] cases;
/**
* Create an InstructionHeader for a conditional or unconditional
* Switch.
* @param addr The address of this instruction.
* @param nextAddr The address of the next instruction header.
* @param instr The underlying Instruction, the type of must be
* an integer type.
* @param cases The value of the cases.
* @param dests The destination addresses belonging to the cases
* plus the default destination address.
*/
public SimpleSwitchInstructionHeader(int addr, int nextAddr,
Instruction instr,
int[] cases, int[] dests) {
super(SWITCH, addr, nextAddr, instr, dests);
this.cases = cases;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
writer.println("switch ("+instr.toString()+") {");
writer.tab();
for (int i=0; i<cases.length; i++)
writer.println("case "+cases[i]+": goto "+
successors[i].getLabel());
writer.println("default: "+
successors[successors.length-1].getLabel());
writer.println("}");
writer.untab();
if (Decompiler.isDebugging)
writer.untab();
}
}

@ -1,28 +0,0 @@
/*
* SimplifyExpression (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class SimplifyExpression implements Transformation {
public InstructionHeader transform(InstructionHeader ih) {
if (ih.getInstruction() != null)
ih.setInstruction(ih.getInstruction().simplify());
return null;
}
}

@ -1,46 +0,0 @@
package jode;
import sun.tools.java.Type;
public class StoreOperator extends StoreInstruction {
LocalVariable slot;
public StoreOperator(int addr, int length, Type type,
LocalVariable slot, int operator) {
super(addr,length,
UnknownType.commonType(type,slot.getType(addr+length)),
operator);
this.slot = slot;
}
public LocalVariable getSlot() {
return slot;
}
public boolean matches(Operator loadop) {
return loadop instanceof LoadOperator &&
((LoadOperator)loadop).getSlot() == slot;
}
public int getLValueOperandCount() {
return 0;
}
public int getLValueOperandPriority(int i) {
/* shouldn't be called */
throw new RuntimeException("StoreOperator has no operands");
}
public Type getLValueOperandType(int i) {
/* shouldn't be called */
throw new RuntimeException("StoreOperator has no operands");
}
public void setLValueOperandType(Type []t) {
/* shouldn't be called */
throw new RuntimeException("StoreOperator has no operands");
}
public String getLValueString(CodeAnalyzer ca, String[] operands) {
return slot.getName(getAddr()+getLength()).toString();
}
}

@ -1,31 +0,0 @@
/*
* SwapOperator (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
public class SwapOperator extends Instruction {
public SwapOperator() {
super(Type.tVoid);
}
public String toString()
{
return "swap";
}
}

@ -1,208 +0,0 @@
/*
* SwitchInstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Enumeration;
/**
* This instruction header represents an if instruction. The
* linkage of the instructions is as follow:
* <pre>
* A: ....
* <p>
* prev = A, next = H, pred = normal, succ = {C,E}
* B: switch ( value ) {
* <p>
* case 1:
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* C: then-instr 1
* <p>
* prev = C, next = H!, pred = normal succ = {E}
* D: instructions of then part
* <p>
* case 2:
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* E: else-instr 1
* <p>
* prev = E, next = null, pred = normal, succ = normal
* F: instructions of then part
* <p>
* }
* prev = B, ..., pred = normal, succ = normal
* H: ...
* </pre>
*/
public class SwitchInstructionHeader extends InstructionHeader {
/**
* Creates a new if statement. There are several conditions that
* must be met:
* <ul>
* <li><code> ifHeader.successors[0] == thenStart
* </code></li>
* <li><code> ifHeader.successors[1] == thenEnd.nextInstruction
* </code></li>
* <li><code> elseStart == null || (thenEnd.flowType = GOTO &&
* elseEnd.nextInstruction == thenEnd.successors[0])
* </code></li>
* <li><code> elseStart == null || elseStart = thenEnd.nextInstruction
* </code></li>
* <li><code> thenStart.nextInstruction....nextInstruction = thenEnd
* </code></li>
* <li><code> elseStart.nextInstruction....nextInstruction = elseEnd
* </code></li>
* </ul>
* @param ifHeader the instruction header whichs contains the
* if goto statement.
* @param cases the values belonging to the case labels.
* @param successors the successors of this instruction (the cases).
* This array must be sorted from low to high addresses.
* @param defaultCase the position of the default case in the array.
* @param endBlock the next instruction after this switch statement.
*/
public SwitchInstructionHeader(InstructionHeader switchIH,
int []cases,
InstructionHeader []caseIHs,
int defaultCase,
InstructionHeader endBlock) {
super(SWITCHSTATEMENT, switchIH.addr, switchIH.nextAddr,
new InstructionHeader[caseIHs.length], switchIH.outer);
this.instr = switchIH.getInstruction();
this.movePredecessors(switchIH);
/* switchIH may have more succesors than we:
* CreateSwitchStatements removes case labels, that are the
* default.
* And the successors of this switch may differ in case that
* dummy gotos were inserted.
*/
for (int i=0; i<switchIH.successors.length; i++)
switchIH.successors[i].predecessors.removeElement(switchIH);
if (endBlock.outer == outer) {
if (endBlock.prevInstruction != null)
endBlock.prevInstruction.nextInstruction = null;
nextInstruction = endBlock;
endBlock.prevInstruction = this;
} else if (endBlock.getShadow() == outer.getEndBlock())
nextInstruction = null;
else {
/* Create a goto after this block, that
* jumps to endBlock
*/
nextInstruction = new InstructionHeader
(GOTO, endBlock.addr, endBlock.addr,
new InstructionHeader[1], outer);
nextInstruction.prevInstruction = this;
nextInstruction.successors[0] = endBlock;
endBlock.predecessors.addElement(nextInstruction);
}
int label = 0;
InstructionHeader lastHeader = null;
InstructionHeader ih = switchIH.nextInstruction;
while (ih != null) {
ih.prevInstruction.nextInstruction = null;
ih.prevInstruction = null;
while (label < caseIHs.length && caseIHs[label] == ih) {
successors[label] = new CaseInstructionHeader
(cases[label], label == defaultCase, ih.addr, this);
if (label > 0) {
successors[label-1].
nextInstruction = successors[label];
successors[label].
prevInstruction = successors[label-1];
}
label++;
}
successors[label-1].successors[0] = ih;
ih.predecessors.addElement(successors[label-1]);
while (ih != null &&
(label == caseIHs.length ||
caseIHs[label] != ih)) {
if (ih.outer == outer)
ih.outer = successors[label-1];
ih = ih.nextInstruction;
}
}
while (label < caseIHs.length) {
successors[label] = new CaseInstructionHeader
(cases[label], label == defaultCase, getEndBlock().addr, this);
if (label > 0) {
successors[label-1].
nextInstruction = successors[label];
successors[label].
prevInstruction = successors[label-1];
}
label++;
}
}
/**
* Returns the InstructionHeader where a break of this instruction
* would jump to. Does only make sense for do/while/for-loops and
* switch instructions.
*/
public InstructionHeader getBreak() {
return getEndBlock();
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
writer.println("switch (" + instr.toString() + ") {");
int label = 0;
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction)
ih.dumpSource(writer);
writer.println("} ");
if (Decompiler.isDebugging)
writer.untab();
}
public InstructionHeader doTransformations(Transformation[] trafo) {
InstructionHeader next;
for (InstructionHeader ih = successors[0]; ih != null; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
return super.doTransformations(trafo);
}
}

@ -1,70 +0,0 @@
package jode;
import sun.tools.java.Type;
public class SwitchOperator extends JumpInstruction {
int[] cases;
int[] destinations;
Type operandType;
public SwitchOperator(int addr, int length, int[] cases, int[] dests) {
super(addr,length);
this.cases = cases;
this.destinations = dests;
this.operandType = UnknownType.tUInt;
}
public int[] getCases() {
return cases;
}
public int[] getSuccessors() {
return destinations;
}
public int getPriority() {
return 0;
}
public int getOperandCount() {
return 1;
}
public int getOperandPriority(int i) {
return 0;
}
public Type getOperandType(int i) {
return operandType;
}
public void setOperandType(Type types[]) {
operandType = UnknownType.commonType(operandType, types[0]);
}
public boolean setType(Type t) {
super.setType(type);
if (type != operandType) {
operandType = type;
return true;
}
return false;
}
public String toString(CodeAnalyzer ca, String[] operands) {
return "switch ("+operands[0]+") ";
}
public void dumpSource(TabbedPrintWriter writer, CodeAnalyzer ca)
throws java.io.IOException
{
writer.println("switch(stack_0) {");
writer.tab();
for (int i=0; i< cases.length; i++) {
writer.println("case "+cases[i]+
": goto addr_"+destinations[i]+";");
}
writer.println("default: goto addr_"+destinations[cases.length]);
writer.untab();
writer.println("}");
}
}

@ -1,32 +0,0 @@
/*
* ThrowOperator (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import sun.tools.java.Type;
public class ThrowOperator extends ReturnOperator {
public ThrowOperator() {
super(MyType.tUObject);
}
public String toString(String[] operands) {
return "throw " + operands[0];
}
}

@ -1,195 +0,0 @@
/*
* TryCatchInstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Vector;
/**
* This instruction header represents an if instruction. The
* linkage of the instructions is as follow:
* <pre>
* A: ....
* <p>
* prev = A, next = H, pred = normal, succ = {C,E}
* B: try {
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* C: then-instr 1
* <p>
* prev = C, next = H!, pred = normal succ = normal
* D: instructions of then part
* <p>
* } catch (...) {
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* E: else-instr 1
* <p>
* prev = E, next = null, pred = normal, succ = normal
* F: instructions of then part
* <p>
* }
* prev = B, ..., pred = normal, succ = normal
* H: ...
* </pre>
*
* TODO: Implement finally.
*/
public class TryCatchInstructionHeader extends InstructionHeader {
/**
* Creates a try catch statement. There are several conditions that
* must be met:
* <ul>
* <li><code>
* </code></li>
* </ul>
* @param successors the successors of this try, that is
* the try header and the catch headers.
* @param endHeader the end hader of the first try block.
* This must be successors[1] or a single goto or return
* statement jumping to endBlock.
* @param remaining the remaining successors of the old try header.
* @param endBlock the endBlock of this try statement
*/
public TryCatchInstructionHeader(InstructionHeader[] successors,
InstructionHeader endHeader,
InstructionHeader[] remaining,
InstructionHeader endBlock) {
super(TRYCATCHBLOCK, successors[0].addr, endBlock.addr,
successors, successors[0].outer);
InstructionHeader tryHeader = successors[0];
this.movePredecessors(tryHeader);
if (remaining.length > 1) {
tryHeader.predecessors = new Vector();
tryHeader.predecessors.addElement(this);
tryHeader.prevInstruction = null;
tryHeader.successors = remaining;
} else {
successors[0] = tryHeader.successors[0];
successors[0].predecessors.removeElement(tryHeader);
successors[0].predecessors.addElement(this);
if (tryHeader.nextInstruction != null)
tryHeader.nextInstruction.prevInstruction = null;
}
if (endBlock.outer == outer) {
nextInstruction = endBlock;
endBlock.prevInstruction = this;
} else if (endBlock.getShadow() != outer.getEndBlock()) {
/* Create a goto after this block, that
* jumps to endBlock
*/
nextInstruction = new InstructionHeader
(GOTO, endBlock.addr, endBlock.addr,
new InstructionHeader[1], this);
nextInstruction.instr = new NopOperator(MyType.tVoid);
nextInstruction.prevInstruction = this;
nextInstruction.successors[0] = endBlock;
endBlock.predecessors.addElement(nextInstruction);
} else
nextInstruction = null;
if (endHeader != successors[1])
endHeader.successors[0].predecessors.removeElement(endHeader);
for (int i=1; i< successors.length; i++) {
endHeader.predecessors.removeElement(tryHeader);
successors[i].predecessors.removeElement(tryHeader);
successors[i].predecessors.addElement(this);
}
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction) {
if (ih.outer == outer)
ih.outer = this;
if (ih.nextInstruction == endHeader)
ih.nextInstruction = null;
}
for (int i=1; i< successors.length; i++) {
for (InstructionHeader ih = successors[i]; ih != null;
ih = ih.nextInstruction) {
if (ih.outer == outer)
ih.outer = this;
if ((i < successors.length-1 &&
ih.nextInstruction == successors[i+1])
|| ih.nextInstruction == endBlock)
ih.nextInstruction = null;
}
}
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
writer.println("try {");
writer.tab();
if (successors[0] == getEndBlock())
writer.print("/* empty?? */");
else {
for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction)
ih.dumpSource(writer);
}
writer.untab();
for (int i=1; i< successors.length; i++) {
InstructionHeader catchIH = successors[i];
catchIH.dumpSource(writer);
writer.tab();
if (catchIH.nextInstruction == null)
writer.println("/* empty */");
else {
for (InstructionHeader ih = catchIH.nextInstruction;
ih != null; ih = ih.nextInstruction)
ih.dumpSource(writer);
}
writer.untab();
}
writer.println("} ");
if (Decompiler.isDebugging)
writer.untab();
}
public InstructionHeader doTransformations(Transformation[] trafo) {
InstructionHeader next;
for (int i=0; i < successors.length; i++) {
for (InstructionHeader ih = successors[i]; ih != null; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
}
return null;
}
}

@ -1,73 +0,0 @@
/*
* TryInstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Vector;
public class TryInstructionHeader extends InstructionHeader {
TryInstructionHeader(InstructionHeader firstInstr,
InstructionHeader outer) {
super(TRY, firstInstr.addr, firstInstr.addr,
new InstructionHeader[1], outer);
movePredecessors(firstInstr);
successors[0] = firstInstr;
firstInstr.predecessors = new Vector();
firstInstr.predecessors.addElement(this);
prevInstruction = firstInstr.prevInstruction;
if (prevInstruction != null)
prevInstruction.nextInstruction = this;
nextInstruction = firstInstr;
firstInstr.prevInstruction = this;
}
public void addHandler(InstructionHeader endInstr,
InstructionHeader catchInstr) {
InstructionHeader[] newSuccessors =
new InstructionHeader[successors.length+2];
System.arraycopy(successors, 0, newSuccessors, 0, successors.length);
successors = newSuccessors;
successors[successors.length-2] = endInstr;
successors[successors.length-1] = catchInstr;
endInstr.predecessors.addElement(this);
catchInstr.predecessors.addElement(this);
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging)
dumpDebugging(writer);
if (successors.length > 1) {
writer.print ("try: ");
for (int i=1; i<successors.length; i+=2)
writer.print("to "+successors[i].getLabel()+
" catch "+successors[i+1].getLabel()+"; ");
writer.println("");
}
}
}

@ -1,174 +0,0 @@
/*
* WhileInstructionHeader (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import java.util.Enumeration;
/**
* This instruction header represents an if instruction. The
* linkage of the instructions is as follow:
* <pre>
* A: ....
* <p>
* prev = A, next = H or null, pred = normal, succ = {H,C}
* B: while ( instr ) {
* <p>
* prev = null, next = D, pred = {B}, succ = {D}
* C: first block-instr
* <p>
* prev = C, next = E, pred = normal succ = normal
* D: ...
* <p>
* prev = D, next = null, pred = normal succ = {B}
* E: last block-instr
* }
* <p>
* prev = B, ..., pred = (normal+{G}) \ {C..F}, succ = normal
* H: ...
* </pre>
*/
public class WhileInstructionHeader extends InstructionHeader {
/**
* Creates a new while statement.
* @param gotoHeader the goto instruction in front of this while loop.
* @param ifHeader the instruction header which contains the
* if-goto statement.
*/
public WhileInstructionHeader(InstructionHeader gotoHeader,
InstructionHeader ifHeader) {
super(WHILESTATEMENT,
gotoHeader.addr, ifHeader.nextAddr,
ifHeader.successors, ifHeader.outer);
this.instr = ifHeader.instr;
this.outer = ifHeader.outer;
this.addPredecessors(ifHeader);
for (int i=0; i < successors.length; i++) {
successors[i].predecessors.removeElement(ifHeader);
successors[i].predecessors.addElement(this);
}
if (successors[0].flowType == GOTO) {
successors[0].predecessors.removeElement(this);
successors[0] = successors[0].successors[0];
successors[0].predecessors.addElement(this);
}
if (gotoHeader != ifHeader) {
this.addPredecessors(gotoHeader);
gotoHeader.successors[0].predecessors.removeElement(gotoHeader);
}
this.prevInstruction = gotoHeader.prevInstruction;
if (prevInstruction != null)
prevInstruction.nextInstruction = this;
this.nextInstruction = ifHeader.nextInstruction;
if (nextInstruction != null)
nextInstruction.prevInstruction = this;
if (successors[1] != this) {
successors[1].prevInstruction = null;
for (InstructionHeader ih = successors[1]; ih != null;
ih = ih.nextInstruction) {
if (ih.outer == outer)
ih.outer = this;
if (ih.nextInstruction == ifHeader)
ih.nextInstruction = null;
}
}
}
/**
* This should be implemented for those blocks, that is headers
* which are outer of other headers. This gives the instruction
* where the control flows after this block.
* @return the first instruction after this block.
*/
InstructionHeader getEndBlock() {
return this;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
if (Decompiler.isDebugging) {
dumpDebugging(writer);
writer.tab();
}
if (needsLabel()) {
writer.untab();
writer.println(getLabel()+": ");
writer.tab();
}
boolean braces = (successors[1].flowType != NORMAL ||
successors[1].nextInstruction != null);
writer.println("while (" + instr.toString() + ")" +
(braces ? " {": ""));
writer.tab();
if (successors[1] != this) {
for (InstructionHeader ih = successors[1]; ih != null;
ih = ih.nextInstruction)
ih.dumpSource(writer);
} else
writer.println("/* empty */");
writer.untab();
if (braces)
writer.println("} ");
if (Decompiler.isDebugging)
writer.untab();
}
/**
* Returns the InstructionHeader where a break of this instruction
* would jump to. Does only make sense for do/while/for-loops and
* switch instructions.
*/
public InstructionHeader getBreak() {
return successors[0];
}
/**
* Returns the InstructionHeader where a continue of this instruction
* would jump to. Does only make sense for do/while/for-loops.
*/
public InstructionHeader getContinue() {
return this;
}
public InstructionHeader doTransformations(Transformation[] trafo) {
InstructionHeader next;
if (successors[1] != this)
for (InstructionHeader ih = successors[1]; ih != null; ih = next) {
if ((next = ih.doTransformations(trafo)) == null)
next = ih.getNextInstruction();
}
return super.doTransformations(trafo);
}
}

@ -1,108 +0,0 @@
/* CatchFinallyBlock Copyright (C) 1997-1998 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.flow;
/**
*
* @author Jochen Hoenicke
*/
public class CatchFinallyBlock extends CatchBlock {
StructuredBlock finallyBlock;
public CatchFinallyBlock() {
super(null);
}
public void setFinallyBlock(StructuredBlock fin) {
finallyBlock = fin;
fin.outer = this;
fin.setFlowBlock(flowBlock);
}
/**
* Returns the block where the control will normally flow to, when
* the given sub block is finished (<em>not</em> ignoring the jump
* after this block). FinallyBlock have a special behaviour, since
* the finally block has no default successor at all (it is more a
* subroutine) that will be called by try or any exception.
* The try block has the normal successor.
*
* @return null, if the control flows to another FlowBlock.
*/
public StructuredBlock getNextBlock(StructuredBlock subBlock) {
return subBlock == tryBlock ? getNextBlock() : null;
}
public FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
return subBlock == tryBlock ? getNextFlowBlock() : null;
}
/**
* Replaces the given sub block with a new block.
* @param oldBlock the old sub block.
* @param newBlock the new sub block.
* @return false, if oldBlock wasn't a direct sub block.
*/
public boolean replaceSubBlock(StructuredBlock oldBlock,
StructuredBlock newBlock) {
if (tryBlock == oldBlock)
tryBlock = newBlock;
else if (finallyBlock == oldBlock)
finallyBlock = newBlock;
else
return false;
return true;
}
/**
* Returns all sub block of this structured block.
*/
public StructuredBlock[] getSubBlocks() {
return new StructuredBlock[] { tryBlock, finallyBlock };
}
/**
* Determines if there is a sub block, that flows through to the end
* of this block. If this returns true, you know that jump is null.
* @return true, if the jump may be safely changed.
*/
public boolean jumpMayBeChanged() {
return ( tryBlock.jump != null || tryBlock.jumpMayBeChanged())
&& (finallyBlock.jump != null || finallyBlock.jumpMayBeChanged());
}
public void dumpInstruction(jode.TabbedPrintWriter writer)
throws java.io.IOException {
/* avoid ugly nested tries */
if (!(outer instanceof CatchBlock)) {
writer.println("try {");
writer.tab();
}
tryBlock.dumpSource(writer);
writer.untab();
writer.println("} finally {");
writer.tab();
finallyBlock.dumpSource(writer);
if (!(outer instanceof CatchBlock)) {
writer.untab();
writer.println("}");
}
}
}

@ -1,148 +0,0 @@
/*
* CreatePostIncExpression (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
import jode.*;
public class CreatePostIncExpression implements Transformation {
public boolean transform(FlowBlock flow)
{
return (createLocalPostInc(flow) || createPostInc(flow));
}
public boolean createLocalPostInc(FlowBlock flow) {
IIncOperator iinc;
int op;
InstructionContainer lastBlock;
Type type;
try {
lastBlock = (InstructionContainer) flow.lastModified;
iinc = (IIncOperator) lastBlock.getInstruction();
if (iinc.getOperatorIndex() == iinc.ADD_OP + iinc.OPASSIGN_OP)
op = Operator.INC_OP;
else if (iinc.getOperatorIndex() == iinc.NEG_OP + iinc.OPASSIGN_OP)
op = Operator.DEC_OP;
else
return false;
if (!iinc.getValue().equals("1") &&
!iinc.getValue().equals("-1"))
return false;
if (iinc.getValue().equals("-1"))
op ^= 1;
SequentialBlock sequBlock = (SequentialBlock)lastBlock.outer;
if (sequBlock.subBlocks[1] != lastBlock)
return false;
InstructionBlock ib = (InstructionBlock) sequBlock.subBlocks[0];
LocalLoadOperator load = (LocalLoadOperator)ib.getInstruction();
if (!iinc.matches(load))
return false;
type = load.getType().intersection(Type.tUInt);
} catch (NullPointerException ex) {
return false;
} catch (ClassCastException ex) {
return false;
}
Operator postop = new LocalPostFixOperator(type, op, iinc);
lastBlock.setInstruction(postop);
lastBlock.replace(lastBlock.outer, lastBlock);
return true;
}
public boolean createPostInc(FlowBlock flow) {
StoreInstruction store;
int op;
Type type;
InstructionBlock lastBlock;
SequentialBlock sequBlock;
try {
lastBlock = (InstructionBlock) flow.lastModified;
Expression storeExpr = (Expression) lastBlock.getInstruction();
store = (StoreInstruction) storeExpr.getOperator();
sequBlock = (SequentialBlock) lastBlock.outer;
if (sequBlock.subBlocks[1] != lastBlock)
return false;
BinaryOperator binOp;
InstructionBlock ib;
if (store.getLValueOperandCount() > 0) {
ib = (InstructionBlock) sequBlock.subBlocks[0];
binOp = (BinaryOperator) ib.getInstruction();
sequBlock = (SequentialBlock) sequBlock.outer;
} else
binOp = (BinaryOperator)
((ComplexExpression) storeExpr).getSubExpressions()[0];
if (binOp.getOperatorIndex() == store.ADD_OP)
op = Operator.INC_OP;
else if (store.getOperatorIndex() == store.NEG_OP)
op = Operator.DEC_OP;
else
return false;
ib = (InstructionBlock) sequBlock.subBlocks[0];
ConstOperator constOp = (ConstOperator) ib.getInstruction();
if (!constOp.getValue().equals("1") &&
!constOp.getValue().equals("-1"))
return false;
if (constOp.getValue().equals("-1"))
op ^= 1;
sequBlock = (SequentialBlock) sequBlock.outer;
ib = (InstructionBlock) sequBlock.subBlocks[0];
DupOperator dup = (DupOperator) ib.getInstruction();
if (dup.getCount() != store.getLValueType().stackSize() ||
dup.getDepth() != store.getLValueOperandCount())
return false;
sequBlock = (SequentialBlock) sequBlock.outer;
ib = (InstructionBlock) sequBlock.subBlocks[0];
Operator load = (Operator) ib.getInstruction();
if (!store.matches(load))
return false;
if (store.getLValueOperandCount() > 0) {
sequBlock = (SequentialBlock) sequBlock.outer;
ib = (InstructionBlock) sequBlock.subBlocks[0];
DupOperator dup2 = (DupOperator) ib.getInstruction();
if (dup2.getCount() != store.getLValueOperandCount() ||
dup2.getDepth() != 0)
return false;
}
type = load.getType().intersection(store.getLValueType());
} catch (NullPointerException ex) {
return false;
} catch (ClassCastException ex) {
return false;
}
Operator postop = new PostFixOperator(type, op, store);
lastBlock.setInstruction(postop);
lastBlock.replace(sequBlock, lastBlock);
return true;
}
}

@ -1,116 +0,0 @@
/*
* MarkInlineExpression (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
import jode.Decompiler;
import jode.expr.*;
/**
* This handles inline methods. When you compile with -O flag javac will
* inline methods that are static, final or private (i.e. non virtual).
* The parameters may be stored in locals, before inlining the body of the
* method.
*
* Inlined methods look as follows:
*
* local_1 = expr_1
* local_2 = expr_2
* [PUSH ]expr(local_1,local_2,constants...)
*
* where local_1 and local_2 aren't used any more.
*
* If later one finds a reuse of local_x, the inline transformation
* must be reverted: If there is no surrounding expression, the locals
* are moved to initializers around; otherwise if the locals are used
* in the expression or a super expression, they are combined with the
* next occurence; otherwise the locals are moved behind the next expression.
* This doesn't care for side effects though :-(
*
* There are many other reasons why a part could look like this; only
* if a matching method is found, that does exactly this (or if the
* options createInlines is given), we may call this method.
*
* As long as inlines are not supported, if the local is never used, it
* is simply removed; if the local is used only one time and there are
* no side effects to the expression on the right hand side between usage
* and initialization, the usage is replaced by the right hand side.
*/
public class MarkInlineExpression {
/**
* This does the transformation.
* @param FlowBlock the flow block to transform.
* @return true if flow block was simplified.
*/
public static boolean transform(InstructionContainer ic,
StructuredBlock last) {
int params = ic.getInstruction().getOperandCount();
if (params == 0)
return false;
ComplexExpression parent = null;
Expression expr = ic.getInstruction();
if (!(last.outer instanceof SequentialBlock))
return false;
SequentialBlock sequBlock = (SequentialBlock)last.outer;
int localCount = 0;
while (sequBlock.subBlocks[0] instanceof InstructionBlock) {
InstructionBlock assign =
(InstructionBlock) sequBlock.subBlocks[0];
if (!(assign.getInstruction().getOperator()
instanceof LocalStoreOperator)
|| assign.getInstruction().getOperandCount() == 0)
break;
LocalStoreOperator store = (LocalStoreOperator)
assign.getInstruction().getOperator();
if (!store.getLocal().onlyUsedInside(expr))
break;
localCount++;
if (!(sequBlock.outer instanceof SequentialBlock))
break;
sequBlock = (SequentialBlock)sequBlock.outer;
}
if (localCount == 0)
return false;
Expression[] stores = new Expression[localCount];
sequBlock = (SequentialBlock) last.outer;
for (int i=0; i<stores; i++) {
stores[i] = ((InstructionBlock)sequBlock.subBlocks[0])
.getInstruction();
LocalStoreOperator store =
(LocalStoreOperator) stores[i].getOperator();
if (!store.getLocal().onlyUsedInside(expr))
stores[i].get.markInlinedIn(expr);
sequBlock = (SequentialBlock)sequBlock.outer;
}
expr.markInlineExpression(stores);
ic.moveDefinitions(sequBlock, last);
last.replace(sequBlock);
return true;
}
}

@ -1,140 +0,0 @@
/* jode.flow.RawTryCatchBlock (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
import jode.TabbedPrintWriter;
/**
* A RawTryCatchBlock is created for each exception in the
* ExceptionHandlers-Attribute. <p>
*
* For each catch block (there may be more than one catch block
* appending a single try block) and for each finally and each
* synchronized block such a RawTryCatchBlock is created. The
* finally/synchronized-blocks have a null exception type so that they
* are easily distinguishable from the catch blocks. <p>
*
* A RawTryCatchBlock is an intermediate representation that gets
* converted later to a CatchBlock, a FinallyBlock or a
* SynchronizedBlock (after the body is parsed).
*
* @date 1998/09/16
* @author Jochen Hoenicke
* @see CatchBlock
* @see FinallyBlock
* @see SynchronizedBlock
*/
public class RawTryCatchBlock extends StructuredBlock {
int endAddr;
public RawTryCatchBlock(jode.Type type,
Jump endDest, Jump catchDest) {
this.type = type;
endAddr = endDest.destAddr;
catchBlock = new EmptyBlock(catchDest);
catchBlock.outer = this;
}
public FlowBlock chainTo(FlowBlock flow) {
FlowBlock first = flow;
RawTryCatchBlock parent = null;
while (flow.getBlock() instanceof RawTryCatchBlock
&& (((RawTryCatchBlock) flow.getBlock()).getCatchAddr()
> this.getCatchAddr())) {
parent = (RawTryCatchBlock) flow.getBlock();
flow = parent.getTryBlock().jump.destination;
}
tryBlock = new EmptyBlock(new Jump(flow));
tryBlock.outer = this;
new FlowBlock(flow.code, flow.addr, 0, this);
if (parent == null) {
/* We are the outermost try block */
return flowBlock;
} else {
/* Chain into existing try block list */
parent.getTryBlock().jump.destination = flowBlock;
return first;
}
}
/**
* The try block.
*/
StructuredBlock tryBlock;
/**
* The catch block.
*/
StructuredBlock catchBlock;
/**
* The type of the exception that is catched. This is null for a
* synchronized/finally block
*/
jode.Type type;
/**
* Replaces the given sub block with a new block.
* @param oldBlock the old sub block.
* @param newBlock the new sub block.
* @return false, if oldBlock wasn't a direct sub block.
*/
public boolean replaceSubBlock(StructuredBlock oldBlock,
StructuredBlock newBlock) {
if (tryBlock == oldBlock)
tryBlock = newBlock;
else if (catchBlock == oldBlock)
catchBlock = newBlock;
else
return false;
return true;
}
/**
* Returns all sub block of this structured block.
*/
public StructuredBlock[] getSubBlocks() {
return new StructuredBlock[] { tryBlock, catchBlock };
}
public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException {
writer.println("TRY "+(type != null ? type.toString() : "ALL"));
writer.tab();
tryBlock.dumpSource(writer);
writer.untab();
writer.println("CATCH TO");
writer.tab();
catchBlock.dumpSource(writer);
writer.untab();
}
public StructuredBlock getTryBlock() {
return tryBlock;
}
public int getCatchAddr() {
return catchBlock.jump.destination.addr;
}
}

@ -1,105 +0,0 @@
/* RemoveEmpty Copyright (C) 1998-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.flow;
import jode.Decompiler;
import jode.expr.*;
public class RemoveEmpty {
public static boolean removeSwap(SpecialBlock swapBlock,
StructuredBlock last) {
/* Remove non needed swaps; convert:
*
* PUSH expr1
* PUSH expr2
* SWAP
*
* to:
*
* PUSH expr2
* PUSH expr1
*/
if (last.outer instanceof SequentialBlock
&& last.outer.outer instanceof SequentialBlock
&& last.outer.getSubBlocks()[0] instanceof InstructionBlock
&& last.outer.outer.getSubBlocks()[0]
instanceof InstructionBlock) {
InstructionBlock block1
= (InstructionBlock) last.outer.outer.getSubBlocks()[0];
InstructionBlock block2
= (InstructionBlock) last.outer.getSubBlocks()[0];
/* XXX check if blocks may be swapped
* (there mustn't be side effects in one of them).
*/
Decompiler.err.println("WARNING: this program contains a SWAP "
+"opcode and may not be translated correctly.");
if (block1.getInstruction().isVoid()
|| block2.getInstruction().isVoid())
return false;
/* PUSH expr1 == block1
* PUSH expr2
* SWAP
* ...
*/
last.outer.replace(block1.outer);
/* PUSH expr2
* SWAP
* ...
*/
block1.replace(swapBlock);
block1.moveJump(swapBlock.jump);
/* PUSH expr2
* PUSH expr1
*/
block1.flowBlock.lastModified = block1;
return true;
}
return false;
}
public boolean removeEmpty(FlowBlock flow) {
StructuredBlock lastBlock = flow.lastModified;
if (lastBlock instanceof EmptyBlock &&
lastBlock.outer instanceof SequentialBlock &&
lastBlock.outer.getSubBlocks()[1] == lastBlock) {
StructuredBlock block = lastBlock.outer.getSubBlocks()[0];
block.replace(block.outer);
if (lastBlock.jump != null)
block.moveJump(lastBlock.jump);
flow.lastModified = block;
return true;
}
if (lastBlock.outer instanceof SequentialBlock &&
lastBlock.outer.getSubBlocks()[0] instanceof EmptyBlock &&
lastBlock.outer.getSubBlocks()[0].jump == null) {
lastBlock.replace(lastBlock.outer);
flow.lastModified = lastBlock;
return true;
}
return false;
}
}

@ -1,40 +0,0 @@
/*
* SimplifyExpression (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
public class SimplifyExpression implements Transformation {
public boolean transform(FlowBlock flow) {
// try {
// jode.TabbedPrintWriter writer =
// new jode.TabbedPrintWriter(System.err, " ");
// System.out.println("Transforming: ");
// flow.lastModified.dumpSource(writer);
if (flow.lastModified instanceof InstructionContainer) {
InstructionContainer ic = (InstructionContainer) flow.lastModified;
ic.setInstruction(ic.getInstruction().simplify());
}
// System.out.println("Result: ");
// flow.lastModified.dumpSource(writer);
// } catch (java.io.IOException ex) {
// }
return false;
}
}

@ -1,24 +0,0 @@
/*
* Transformation (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.flow;
public interface Transformation {
public boolean transform(FlowBlock flowBlock);
}

@ -1,30 +0,0 @@
/*
* ReturnAddress (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.jvm;
class ReturnAddress {
int pc;
public ReturnAddress(int pc) {
this.pc = pc;
}
public int getPC() {
return pc;
}
}

@ -1,174 +0,0 @@
/*
* ClassReachability (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.obfuscator;
import jode.bytecode.ClassInfo;
import jode.bytecode.FieldInfo;
import jode.bytecode.MethodInfo;
import jode.MethodType;
import jode.Type;
import java.lang.reflect.Modifier;
import java.util.*;
public class ClassReachability {
ClassBundle bundle;
ClassInfo clazz;
Vector subclasses;
public FieldInfo[] fields;
public MethodInfo[] methods;
public boolean reachable = false;
public boolean[] reachFields;
public boolean[] reachMethods;
public boolean preserve = false;
public boolean[] preserveFields;
public boolean[] preserveMethods;
public Object[] fromClassFields;
public Object[] fromClassMethods;
public ClassReachability(ClassBundle bundle, ClassInfo clazz) {
this.bundle = bundle;
this.clazz = clazz;
fields = clazz.getFields();
methods = clazz.getMethods();
reachFields = new boolean[fields.length];
preserveFields = new boolean[fields.length];
reachMethods = new boolean[methods.length];
preserveMethods = new boolean[methods.length];
clazz.loadInfo(clazz.FULLINFO);
}
public void addSubclass(ClassReachability subclass) {
subclasses.addElement(subclass);
}
public void markReachableField(int i) {
reachFields[i] = true;
}
public void markReachableField(Type type, String name) {
for (int i=0; i < fields.length; i++) {
if (fields[i].getType().equals(type)
&& fields[i].getName().equals(name))
markReachableField(i);
}
}
public void markReachableMethod(int i) {
reachMethods[i] = true;
Enumeration enum = subclasses.elements();
while (enum.hasMoreElements()) {
ClassReachability subclass =
(ClassReachability) enum.nextElement();
subclass.markReachableMethod(methods[i].getType(),
methods[i].getName());
}
/*XXX read code and check reachability*/
}
public void markReachableMethod(MethodType type, String name) {
for (int i=0; i < methods.length; i++) {
if (methods[i].getType().equals(type)
&& methods[i].getName().equals(name))
markReachableMethod(i);
}
}
public void markReachable() {
reachable = true;
}
private void markPreservedField(int i) {
reachFields[i] = true;
preserveFields[i] = true;
}
public void markPreservedField(Type type, String name) {
for (int i=0; i < fields.length; i++) {
if (fields[i].getType().equals(type)
&& fields[i].getName().equals(name))
markPreservedField(i);
}
}
private void markPreservedMethod(int i) {
markReachableMethod(i);
preserveMethods[i] = true;
Enumeration enum = subclasses.elements();
while (enum.hasMoreElements()) {
ClassReachability subclass =
(ClassReachability) enum.nextElement();
subclass.markPreservedMethod(methods[i].getType(),
methods[i].getName());
}
}
public void markPreservedMethod(MethodType type, String name) {
for (int i=0; i < methods.length; i++) {
if (methods[i].getType().equals(type)
&& methods[i].getName().equals(name))
markPreservedMethod(i);
}
}
public void markPreserved() {
preserve = true;
}
public void doPreserveRule(int preserveRule) {
preserve = (clazz.getModifiers() & preserveRule) != 0;
for (int i=0; i < fields.length; i++) {
if (((fields[i].getModifiers() ^ Modifier.PRIVATE)
& preserveRule) != 0)
markPreservedField(i);
}
for (int i=0; i < methods.length; i++) {
if (((methods[i].getModifiers() ^ Modifier.PRIVATE)
& preserveRule) != 0)
markPreservedMethod(i);
}
}
public void checkReachableThroughSuper(ClassInfo superInfo) {
ClassReachability superReach =
bundle.getLoadedClass(superInfo.getName());
if (superReach != null) {
superReach.addSubclass(this);
} else {
for (int i=0; i< methods.length; i++) {
if (!methods[i].getType().isStatic()
&& superInfo.findMethod(methods[i].getName(),
methods[i].getType()) != null) {
markPreservedMethod(i);
}
}
}
}
public void postInitialize() {
checkReachableThroughSuper(clazz.getSuperclass());
ClassInfo[] ifaces = clazz.getInterfaces();
for (int i=0; i<ifaces.length; i++)
checkReachableThroughSuper(ifaces[i]);
}
}

@ -1,35 +0,0 @@
/* FieldListener 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.obfuscator;
/**
* This is the interface for field listeners, to get information when
* something interesting happens to a field.
*
* @author Jochen Hoenicke
*/
public interface FieldListener extends java.util.EventListener {
/**
* This method gets called, when a field can no longer be constant.
*/
public void fieldNotConstant(IdentifierEvent ev);
}

@ -1,47 +0,0 @@
/* IdentifierEvent 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.obfuscator;
/**
*
* @author Jochen Hoenicke
*/
public class IdentifierEvent extends java.util.EventObject {
/* 0 - 9: general events */
public final static int REACHABLE = 0;
public final static int PRESERVED = 1;
/* 10 - 19: field events */
public final static int CONSTANT = 10;
/* 20 - 29: method events */
/* 30 - 39: class events */
/* 40 - 49: package events */
public final int id;
public IdentifierEvent(Identifier source, int id) {
super(source);
this.id = id;
}
public final int getID() {
return id;
}
}

@ -1,34 +0,0 @@
/* IdentifierListener 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.obfuscator;
/**
* This is the interface for identifier listeners, to get information when
* something interesting happens to a identifier.
*
* @author Jochen Hoenicke
*/
public interface IdentifierListener extends java.util.EventListener {
/**
* This method gets called, when a identifier is reachable.
*/
public void identifierReachable(IdentifierEvent ev);
}

@ -1,28 +0,0 @@
/* LoadedClassIdentifier 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.obfuscator;
import jode.Obfuscator;
import jode.bytecode.ClassInfo;
import jode.bytecode.FieldInfo;
import jode.bytecode.MethodInfo;
import java.lang.reflect.Modifier;
import java.util.*;
import java.io.*;

@ -1,224 +0,0 @@
/* LogicalDeadCodeOptimizer 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.obfuscator;
/**
* This class analyzes the method to detect and remove logical dead
* code. If a field, local or stack entry, is tested to have a
* certain value, that is remembered and if a similar test occurs
* again, we may know, that it always evaluates to true
* resp. false.<br>
*
* Each field/local/stack entry has a Constraint, that tells e.g. if
* that value is always a constant, always not zero, always zero, or
* always equal to another stack entry etc. These constraints can be
* propagated, and if the condition of a opc_if is always the same,
* that opc_if can be removed resp. replaces by a opc_goto. <br>
*
* @author Jochen Hoenicke
*/
public class LogicalDeadCodeOptimizer {
class Constraint {
/* The constant are aligned so that the operation ^1 negates the
* comparison and like the VM opcodes.
*/
public int EQ = 0;
public int NE = 1;
public int LT = 2;
public int GE = 3;
public int GT = 4;
public int LE = 5;
/**
* This gives the compareOps for this constraint (one of
* EQ/NE/GE/GT/LE/LT). */
int compareOp;
/**
* The reference value to which is compared (this is the
* second argument of the compare).
*/
ConstrainedValue reference;
}
class ConstrainedValue {
boolean isConstant;
Object constant;
/**
* If this is not constant, this are all constraints.
*/
Constraint[] constraints;
public boolean implies(Constraint constraint) {
if (isConstant) {
// check if always
// value.constant compareOp reference
return constraint.reference.compareToConstant
(value.constant, compareOp) == 1;
} else {
//
}
}
/**
* Compares this object with other.
* @param compareOp one of Constraint.EQ/NE/LT/LE/GT/GE.
* @param other a constant, null, a String or a Number.
* @return 1, if (other compareOp this) always true, <br>
* 0, if (other compareOp this) always false, <br>
* -1, otherwise
*/
public int compareToConstant(Object other, int compareOp) {
if (isConstant) {
switch (compareOp) {
case EQ:
return other.equals(constant) ? 1 : 0;
case NE:
return other.equals(constant) ? 0 : 1;
case LE:
case LT:
case GE:
case GT: {
/* This must be a number */
int cmp = ((Number)other).compareTo((Number)constant);
if (compareOp == LE && cmp <= 0
|| compareOp == LT && cmp < 0
|| compareOp == GE && cmp >= 0
|| compareOp == GT && cmp > 0)
return 1;
return 0;
}
}
} else {
/* Not a constant, try the constraints. */
/* First we find all equal references */
Vector equalRefs = new Vector();
equalRefs.add(this);
for (int i=0; i < equalRefs.size(); i++) {
Constraint[] cs = ((ConstrainedValue)
equalRefs.elementAt(i)).constraints;
for (int j=0; j < cs.count; j++) {
if (cs[j].compareOp == EQ
&& !equalRefs.contains(cs[j].reference))
equalRefs.addElement(cs[j].reference);
}
}
/* If we wanted to only check for EQ or NE we can do this now.
*/
if (compareOp == EQ || compareOp == NE) {
for (int i=0; i < equalRefs.size(); i++) {
Constraint[] cs = ((ConstrainedValue)
equalRefs.elementAt(i)).constraints;
for (int j=0; j < cs.count; j++) {
if ((1 << cs[j].compareOp
& (1<<NE | 1<<LT | 1<<GT)) != 0
&& cs[j].reference.isConstant
&& cs[j].reference.constant.equals(other)) {
/* Yeah, we are not equal to that constant. */
return (compareOp == NE) ? 1 : 0;
}
}
}
/* No helpful constraints found */
return -1;
}
/* Check if we are greater / greater or equal */
if (cs[j])
/* This is a constant, check if constraint
* is okay and compare.
*/
if (cmpOp == cs[j].compareOp
&& cs[j].compareOp == cmpOp
|| cs[j].compareOp ^ 7 == cmpOp)
/* We are lucky, this is a constant
* (can this happen?)
*/
return cs[j].reference.compareToConstant
(other, compareOp);
/* Now try to prove that always greater */
Stack stack = new Stack();
Stack cmpopStack = new Stack();
stack.push(this);
cmpopStack.push(new Integer(compareOp));
while (!stack.isEmpty()) {
ConstrainedValue cv = (ConstrainedValue) stack.pop();
Constraint[] cs = cv.constraints;
int cmpop = ((Integer) cmpopStack.pop()).intValue();
for (int i=0; i < cs.count; i++) {
if (/* always consider equals. */
cs.compareOp == EQ
/* never consider nonequals */
|| (cs.compareOp >= NE
/* consider same compares */
&& cs.compareOp == cmpop
/* and consider same compares except equal */
&& cs.compareOp ^ 7 == cmpop)) {
/* if cs.compareOp is greater or lower
* (not equal), we can allow equal in cmpop */
if (cs.compareOp != EQ
&& (cs.compareOp & 1) == 0
&& (cmpop & 1) == 0)
cmpop ^= 7;
if (cs.reference.isConstant()) {
if (other.compareToConstant
(cmpop, cs.reference.isConstant()) == 1)
return 1;
} else if (!stack.contains(cs.reference)) {
stack.push(cs.reference);
cmpopStack.push(new Integer(cmpop));
}
}
}
}
return -1;
}
}
}
/**
* OPEN QUESTIONS:
* we have a variable whose value is > 0.
* is after an increase the value still >0?
* (not necessarily, e.g. value == Integer.MAX_VALUE)
*/
/* Every local/stack has a list of Constraint.
* Operations:
* -when two control flows flow together, we need to intersect
* Constraints: All constraints are considered, a constraint
* is taken, if it is implied by a constraint in the other list.
*
* -load operations copy local Constraint to stack Constraint.
* -store operations copy stack Constraint to local Constraint.
*/
}

@ -1,132 +0,0 @@
/*
* MethodReachability (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode.obfuscator;
import jode.bytecode.ConstantPool;
import jode.bytecode.MethodInfo;
import jode.MethodType;
import jode.Type;
import java.lang.reflect.Modifier;
import java.util.*;
public class MethodReachability {
ClassReachability clazz;
MethodInfo info;
public ClassReachability inheritedFromClass;
public boolean reachable = false;
public boolean preserve = false;
public Vector references;
public MethodReachability(ClassReachability clazz, MethodInfo info) {
this.clazz = clazz;
this.info = info;
AttributeInfo codeattr = minfo.findAttribute("Code");
if (codeattr != null) {
DataInputStream stream = new DataInputStream
(new ByteArrayInputStream(codeattr.getContents()));
CodeInfo codeinfo = new CodeInfo();
try {
codeinfo.read(classAnalyzer.getConstantPool(), stream);
analyzeCode(codeinfo);
} catch (IOException ex) {
ex.printStackTrace();
code = null;
}
}
}
public void analyzeCode(CodeInfo codeinfo) {
references = new Vector();
byte[] code = codeinfo.getCode();
try {
DataInputStream stream =
new DataInputStream(new ByteArrayInputStream(code));
Opcodes.getReferences(stream, references);
} catch (IOException ex) {
ex.printStackTrace();
throw new ClassFormatError(ex.getMessage());
}
}
public void markReachable() {
ConstantPool cp = clazz.getClassInfo().getConstantPool();
if (!reachable) {
reachable = true;
Enumeration enum = references.elements();
while (enum.hasMoreElements()) {
int ref = ((Integer) enum.nextElement()).intValue();
int tag = cp.getTag(ref);
switch (tag) {
case ConstantPool.FIELDREF:
case ConstantPool.METHODREF:
case ConstantPool.INTERFACEMETHODREF:
String[] refs = cp.getRef(ref);
if (tag == ConstantPool.FIELDREF)
clazz.getBundle()
.markReachableField(refs[0], refs[1],
new MethodType(refs[2]));
else
clazz.getBundle()
.markReachableMethod(refs[0], refs[1],
new MethodTyp(refs[2]));
break;
case ConstantPool.CLASS:
String clName = cp.getClassName(ref);
clazz.getBundle().markReachable(clName);
break;
}
}
}
}
public void markPreserved() {
ConstantPool cp = clazz.getClassInfo().getConstantPool();
if (!preserved) {
preserved = true;
Enumeration enum = references.elements();
while (enum.hasMoreElements()) {
int ref = ((Integer) enum.nextElement()).intValue();
int tag = cp.getTag(ref);
switch (tag) {
case ConstantPool.FIELDREF:
case ConstantPool.METHODREF:
case ConstantPool.INTERFACEMETHODREF:
String[] refs = cp.getRef(ref);
if (tag == ConstantPool.FIELDREF)
clazz.getBundle()
.markPreservedField(refs[0], refs[1],
new MethodType(refs[2]));
else
clazz.getBundle()
.markPreservedMethod(refs[0], refs[1],
new MethodTyp(refs[2]));
break;
case ConstantPool.CLASS:
String clName = cp.getClassName(ref);
clazz.getBundle().markPreserved(clName);
break;
}
}
}
}
}

@ -1,298 +0,0 @@
/*
* ClassRangeType (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import sun.tools.java.*;
/**
* This class represents an object type which isn't fully known.
* The real object type lies in a range of types between topType
* and bottomType. <p>
*
* For a totally unknown type topType is tObject and bottomType is
* null. It is always garanteed that topType is an Array or an Object
* and that bottomType is null or an Array or an Object. <p>
*
* @author Jochen Hoenicke
* @date 98/08/06
*/
public class ClassRangeType extends MyType {
final Type bottomType;
final Type topType;
public ClassRangeType(Type bottomType, Type topType) {
super(103, "-");
if (bottomType != null && bottomType.getTypeCode() == 103)
bottomType = ((ClassRangeType)bottomType).bottomType;
if (topType != null && topType.getTypeCode() == 103)
topType = ((ClassRangeType)topType).topType;
typeSig = "-"+
(bottomType == null ? "0" : bottomType.getTypeSignature()) +
(topType == null ? "0" : topType.getTypeSignature());
this.bottomType = bottomType;
this.topType = topType;
}
public static Type createRangeType(Type bottom, Type top) {
// TODO: XXX calculate < top, ...> \cap <..., bottom>
// e.g. top , bottom result
// x , null <x, null>
// tUnknown, object <tObject, object>
// Fahrrad , Fahrzeug error
// Fahrzeug, Fahrrad <Fahrzeug, Fahrrad>
// int , Fahrrad error
if (bottom != null && bottom.getTypeCode() == 103) {
bottom = ((ClassRangeType)bottom).bottomType;
}
if (top != null && top.getTypeCode() == 103) {
top = ((ClassRangeType)top).topType;
}
/* First the trivial cases
*/
if (top == tError || bottom == tError)
return tError;
/* This is always okay (right open interval, maybe left open)
*/
if (top == null)
return new ClassRangeType(bottom,top);
/* <null, object> -> <tObject, object>
* if bottom is tObject, its okay.
*/
if (bottom == top)
return bottom;
if (top.getTypeCode() <= 4 && bottom == null)
return top;
if (bottom != null && bottom.getTypeCode() <= 4 &&
top.getTypeCode() <= bottom.getTypeCode())
return bottom;
if (top.getTypeCode() != 9
&& top.getTypeCode() != 10
&& top.getTypeCode() != 104)
return tError;
if (bottom == null || bottom == tObject)
return new ClassRangeType(tObject, top);
/* now bottom != null and top != null */
if (bottom.getTypeCode() == 9 && top.getTypeCode() == 9) {
Type type = createRangeType(bottom.getElementType(),
top.getElementType());
if (type == tError)
return tError;
return tArray(type);
}
if (bottom.getTypeCode() == 10)
bottom = new ClassInterfacesType(bottom);
if (top.getTypeCode() == 10)
top = new ClassInterfacesType(top);
if (bottom.getTypeCode() != 104 || top.getTypeCode() != 104)
return tError;
return ClassInterfacesType.createRangeType
((ClassInterfacesType) bottom, (ClassInterfacesType) top);
}
public Type getElementType() {
Type bottom = bottomType != null ? bottomType.getElementType() : null;
Type top = topType != null ? topType.getElementType() : null;
return new ClassRangeType(bottom, top);
}
/**
* Returns the specialized type of t1 and t2, e.g
* null , xx -> xx
* tObject, object -> object
* int , short -> short
* tArray(tObject), tArray(tUnknown) -> tArray(tObject)
* tArray(tUnknown), tObject -> tArray(tUnknown)
*/
public static Type getSpecializedType(Type t1, Type t2) {
if (t1 == null || t2 == tError)
return t2;
if (t2 == null || t1 == tError)
return t1;
if (t1.getTypeCode() == 103) {
t1 = ((ClassRangeType)t1).bottomType;
if (t1 == null)
return t2;
}
if (t2.getTypeCode() == 103) {
t2 = ((ClassRangeType)t2).bottomType;
if (t2 == null)
return t1;
}
if (t1 == t2)
return t1;
if (t1.getTypeCode() <= 4 && t2.getTypeCode() <= 4) {
if (t1.getTypeCode() < t2.getTypeCode())
return t1;
else
return t2;
}
if ((t1.getTypeCode() != 9
&& t1.getTypeCode() != 10
&& t1.getTypeCode() != 104)
|| (t2.getTypeCode() != 9
&& t2.getTypeCode() != 10
&& t2.getTypeCode() != 104))
return tError;
if (t1 == MyType.tObject)
return t2;
if (t2 == MyType.tObject)
return t1;
if (t1.getTypeCode() == 9 && t2.getTypeCode() == 9)
return tArray(getSpecializedType(t1.getElementType(),
t2.getElementType()));
if (t1.getTypeCode() == 10)
t1 = new ClassInterfacesType(t1);
if (t2.getTypeCode() == 10)
t2 = new ClassInterfacesType(t2);
if (t1.getTypeCode() != 104 || t2.getTypeCode() != 104)
return tError;
return ClassInterfacesType.getSpecializedType
((ClassInterfacesType) t1, (ClassInterfacesType) t2);
}
/**
* Returns the generalized type of t1 and t2, e.g
* tObject, tString -> tObject
* object , interface -> object
* since a sub class of object may implement interface
* int , short -> int
* tArray(tObject), tArray(tUnknown) -> tArray(tUnknown)
* tArray(tUnknown), tObject -> tObject
* tUnknown, tString -> tString !!
* null , tString -> tString !!
*/
public static Type getGeneralizedType(Type t1, Type t2) {
if (t1 != null && t1.getTypeCode() == 103)
t1 = ((ClassRangeType)t1).topType;
if (t2 != null && t2.getTypeCode() == 103)
t2 = ((ClassRangeType)t2).topType;
if (t1 == t2 ||
t1 == tError || t2 == null)
return t1;
if (t2 == tError || t1 == null)
return t2;
if (t1.getTypeCode() <= 4 && t2.getTypeCode() <= 4) {
if (t1.getTypeCode() < t2.getTypeCode())
return t1;
else
return t2;
}
if ((t1.getTypeCode() != 9
&& t1.getTypeCode() != 10
&& t1.getTypeCode() != 104)
|| (t2.getTypeCode() != 9
&& t2.getTypeCode() != 10
&& t2.getTypeCode() != 104))
return tError;
if (t1 == MyType.tObject)
return t1;
if (t2 == MyType.tObject)
return t2;
if (t1.getTypeCode() == 9 && t2.getTypeCode() == 9) {
Type type = getGeneralizedType(t1.getElementType(),
t2.getElementType());
if (type == null)
return null;
return tArray(type);
}
if (t1.getTypeCode() == 10)
t1 = new ClassInterfacesType(t1);
if (t2.getTypeCode() == 10)
t2 = new ClassInterfacesType(t2);
if (t1.getTypeCode() != 104 || t2.getTypeCode() != 104)
return tError;
return ClassInterfacesType.getGeneralizedType
((ClassInterfacesType) t1, (ClassInterfacesType) t2);
}
public Type getIntersection(ClassRangeType type)
{
Type bottom = getSpecializedType(bottomType, type.bottomType);
Type top = getGeneralizedType(topType, type.topType);
Type newType = createRangeType(bottom,top);
if (newType == tError) {
boolean oldTypeDebugging = Decompiler.isTypeDebugging;
Decompiler.isTypeDebugging = true;
System.err.println("intersecting "+ this +" and "+ type +
" to <" + bottom + "-" + top +
"> to <error>");
Decompiler.isTypeDebugging = oldTypeDebugging;
Thread.dumpStack();
} else if (Decompiler.isTypeDebugging) {
System.err.println("intersecting "+ this +" and "+ type +
" to <" + bottom + "-" + top +
"> to " + newType);
}
return newType;
}
public boolean intersects(ClassRangeType type)
{
return getIntersection(type) != tError;
}
public String typeString(String string, boolean flag1, boolean flag2)
{
if (Decompiler.isTypeDebugging)
return "<"+bottomType+"-"+topType+">" + string;
else if (topType != null)
return topType.typeString(string, flag1, flag2);
else if (bottomType != null)
/* This means, that the local variable is never assigned to.
* If bottom type is a ClassRangeType, there may be problems,
* that are ignored. They produce compiler errors.
*/
return bottomType.typeString(string, flag1, flag2);
else
return "<Unknown>"+string;
}
}

@ -1,182 +0,0 @@
/*
* MyType (c) 1998 Jochen Hoenicke
*
* You may distribute under the terms of the GNU General Public License.
*
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* $Id$
*/
package jode;
import sun.tools.java.Constants;
import sun.tools.java.Type;
import sun.tools.java.Identifier;
import java.util.Hashtable;
/**
* This is my own type class. It differs from sun.tools.java.Type, in
* that it maintains a type range. This type range may be implicit or
* explicit. <p>
*
* The type tInt (which is the same as Type.tInt) is a good example
* for the implicit range &lt;tInt -- tBoolean&gt;. Most other
* standard types stand for the range consisting only of themselve.
* The explicit form is the class range type <p>
*
* The main operation on a type range is the intersection. To do this
* on class ranges we need two more operations: specialization and
* generalization. <p>
*
* specialization chooses the startpoint of two intervals which
* lies in the open range &lt;sp -- null&gt;, where sp is the startpoint
* of the other interval, or returns tError on failure.<p>
*
* generalization chooses the endpoint of two intervals which lies in
* the open range &lt;null -- ep&gt;, where ep is the endpoint of
* the other interval, or returns tError on failure.<p>
*/
public class MyType extends Type {
static Hashtable superclasses = new Hashtable();
protected static JodeEnvironment env;
public static final Type tStringBuffer =
Type.tClass(idJavaLangStringBuffer);
public static final Type tUnknown = new ClassRangeType(null, null);
public static final Type tUInt = tInt;
public static final Type tUIndex = tInt;
public static final Type tUObject = new ClassRangeType(tObject, null);
public static Type tSuperType(Type type) {
int typeCode = type.getTypeCode();
if (typeCode == 9 || typeCode == 10)
return new ClassRangeType(tObject, type);
else if (typeCode == 103)
return (((ClassRangeType)type).topType == null
? tUnknown : new ClassRangeType(tObject, type));
else
return type;
}
public static Type tSubType(Type type) {
int typeCode = type.getTypeCode();
if (typeCode == 9 || typeCode == 10 || typeCode == 103)
return new ClassRangeType(type, null);
else
return type;
}
public static Type tClassOrArray(Identifier ident) {
if (ident.toString().charAt(0) == '[')
return MyType.tType(ident.toString());
else
return MyType.tClass(ident);
}
public static void setEnvironment(JodeEnvironment e) {
env = e;
}
protected MyType(int i, String str) {
super (i, str);
}
public int stackSize()
{
return 1;
}
public String typeString(String var, boolean flag1, boolean flag2)
{
String typeStr;
switch (typeCode) {
case 100: typeStr="unknown"; break;
default:
throw new RuntimeException("Wrong typeCode "+typeCode);
}
if (var.length() > 0)
return typeStr+" "+var;
return typeStr;
}
/**
* Find the intersection of two types
* @param t1 the first type.
* @param t2 the second type.
* @return the intersection, or tError, if a type conflict happens.
*/
public static Type intersection(Type t1, Type t2) {
// System.err.println("intersecting "+ t1 +" and "+ t2);
/* Trivial cases first.
*/
if (t1 == tError || t2 == tError) {
System.err.println("intersecting "+ t1 +" and "+ t2 +
" to <error>");
Thread.dumpStack();
return tError;
}
if (t1 == t2 || t2 == tUnknown)
return t1;
if (t1 == tUnknown)
return t2;
/* This is the integer case
* tBoolean = 0 ,..., tInt = 4
* return the smaller type code.
*/
if (t1.getTypeCode() <= 4 && t2.getTypeCode() <= 4) {
if (t1.getTypeCode() < t2.getTypeCode())
return t1;
else
return t2;
}
/* If this is an array or a class convert to class range.
*/
if (t1.getTypeCode() == 9 || t1.getTypeCode() == 10)
t1 = new ClassRangeType(t1,t1);
if (t2.getTypeCode() == 9 || t2.getTypeCode() == 10)
t2 = new ClassRangeType(t2,t2);
/* Now it must be a class range type, or we have lost!
*/
if (t1.getTypeCode() != 103 || t2.getTypeCode() != 103) {
System.err.println("intersecting "+ t1 +" and "+ t2 +
" to <error>");
Thread.dumpStack();
return tError;
}
return ((ClassRangeType)t1).getIntersection((ClassRangeType)t2);
}
/**
* @deprecated renamed to intersection.
*/
public static Type commonType(Type t1, Type t2) {
return intersection(t1, t2);
}
/**
* Check if t1 and &lt;unknown -- t2&rt; are not disjunct.
* @param t1 the type that should be checked
* @param t2 a simple type; this mustn't be a range type.
* @return true if this is the case.
*/
public static boolean isOfType(Type t1, Type t2) {
return (ClassRangeType.getGeneralizedType(t1,t2) == t2 &&
ClassRangeType.getSpecializedType(t1,t2) == t2);
}
}

@ -1,125 +0,0 @@
/* UnfoundClassType Copyright (C) 1997-1998 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;
import java.util.Vector;
import java.util.Stack;
/**
* This class represents a type aproximation, consisting of multiple
* interfaces and a class type.<p>
*
* If this is the bottom boundary, this specifies, which class our
* type must extend and which interfaces it must implement.
*
* If this is the top boundary, this gives all interfaces and classes
* that may extend the type. I.e. the type may be one of the
* interfaces or the class type or any of their super types.
*
* @author Jochen Hoenicke */
public class UnfoundClassType extends Type {
String clazzName;
public UnfoundClassType(String clazzName) {
super(TC_UCLASS);
this.clazzName = clazzName;
}
/**
* Create the type corresponding to the range from bottomType to
* this. Checks if the given type range may be not empty. This
* means, that bottom.clazz is extended by this.clazz and that all
* interfaces in bottom are implemented by an interface or by
* clazz.
* @param bottom the start point of the range
* @return the range type, or tError if range is empty.
*/
public Type createRangeType(Type bottomType) {
/* Unknown classes are only compatible to tObject and themself.
*/
if (bottomType == tUnknown || bottomType == tObject)
return tRange(tObject, this);
if (!bottomType.equals(this))
return tError;
return this;
}
/**
* Returns the specialized type of this and type.
* We have two classes and multiple interfaces. The result
* should be the object that extends both objects
* and the union of all interfaces.
*/
public Type getSpecializedType(Type type) {
return (type.typecode == TC_UNKNOWN
|| type == tObject || type.equals(this)) ? this : tError;
}
/**
* Returns the generalized type of this and type. We have two
* classes and multiple interfaces. The result should be the
* object that is the the super class of both objects and all
* interfaces, that one class or interface of each type
* implements. */
public Type getGeneralizedType(Type type) {
int code = type.typecode;
if (code == TC_UNKNOWN || type.equals(this))
return this;
if (code == TC_ARRAY || code == TC_CLASS || code == TC_UCLASS)
return tObject;
return tError;
}
/**
* Marks this type as used, so that the class is imported.
*/
public void useType() {
env.useClass(clazzName);
}
public String toString()
{
return env.classString(clazzName);
}
public boolean isClassType() {
return true;
}
public String getDefaultName() {
String name = clazzName;
int dot = name.lastIndexOf('.');
if (dot >= 0)
name = name.substring(dot+1);
if (Character.isUpperCase(name.charAt(0)))
return name.toLowerCase();
else
return name+"_var";
}
public boolean equals(Object o) {
return o == this
|| (o instanceof UnfoundClassType
&& ((UnfoundClassType)o).clazzName.equals(clazzName));
}
}

@ -1,22 +0,0 @@
package jode;
import sun.tools.java.Type;
public class UnknownSubType extends MyType {
Type elemType;
public UnknownSubType(Type type) {
super(103, "<");
elemType = type;
}
public Type getElementType()
{
return elemType;
}
public String typeString(String string, boolean flag1, boolean flag2)
{
return "<superclass of "+
String.valueOf(elemType.typeString(string, flag1, flag2))+">";
}
}

@ -1,22 +0,0 @@
package jode;
import sun.tools.java.Type;
public class UnknownSuperType extends MyType {
Type elemType;
public UnknownSuperType(Type type) {
super(103, "<");
elemType = type;
}
public Type getElementType()
{
return elemType;
}
public String typeString(String string, boolean flag1, boolean flag2)
{
return "<superclass of "+
String.valueOf(elemType.typeString(string, flag1, flag2))+">";
}
}

@ -1,204 +0,0 @@
package jode;
import sun.tools.java.Type;
import java.util.Hashtable;
public class UnknownType extends Type {
static Hashtable subclasses = new Hashtable();
public static Type tUnknown = new UnknownType(100, "x");
public static Type tUInt = new UnknownType(101, "i");
public static Type tUIndex = new UnknownType(104, "[");
public static Type tUObject = new UnknownType(102, "*");
public static Type tSubClass(Type type) {
Type subtype = (Type) subclasses.get(type);
if (subtype == null) {
subtype = new UnknownSubType(type);
subclasses.put(type, subtype);
}
return subtype;
}
protected UnknownType(int i, String str) {
super (i, str);
}
public int stackSize()
{
return 1;
}
public String typeString(String var, boolean flag1, boolean flag2)
{
String typeStr;
switch (typeCode) {
case 100: typeStr="<unknown>"; break;
case 101: typeStr="<int>"; break; /*XXX*/
case 102: typeStr="<Object>"; break;
case 104: typeStr="<arrindex>"; break; /*XXX*/
default:
throw new RuntimeException("Wrong typeCode "+typeCode);
}
if (var.length() > 0)
return typeStr+" "+var;
return typeStr;
}
public static Type commonType(Type t1, Type t2) {
if (t1 == t2 || t2 == tUnknown)
return t1;
switch (t1.getTypeCode()) {
case 0: /* boolean*/
case 1: /* byte */
case 2: /* char */
case 3: /* short */
case 4: /* int */
if (t2.getTypeCode() <= 4) {
if (t2.getTypeCode() > t1.getTypeCode())
return t2;
else
return t1;
}
if (t2 == tUInt || t2 == tUIndex)
return t1;
break;
case 5: /* long */
case 6: /* float */
case 7: /* double */
case 8: /* null? */
case 11: /* void */
case 12: /* method */
case 13: /* error */
break;
case 9: /* array */
if (t2 == tUObject)
return t1;
if (t2.getTypeCode() == 9) /* array, array case */
return tArray(commonType(t1.getElementType(),
t2.getElementType()));
break;
case 10: /* class */
if (t2 == tUObject)
return t1;
if (t2.getTypeCode() == 103) {
/* find suitable subclass of t2 */
return t2; /*XXX*/
}
if (t2.getTypeCode() == 10) {
return t1; /*XXX*/
}
break;
case 100: /* unknown */
return t2;
case 101: /* unknown int */
if ((t2.getTypeCode() >= 0 && t2.getTypeCode() <= 4) ||
t2 == tUIndex)
return t2;
break;
case 104: /* unknown index */
if (t2.getTypeCode() >= 1 && t2.getTypeCode() <= 4)
return t2;
if (t2 == tUInt)
return t1;
break;
case 102: /* unknown object */
if (t2.getTypeCode() == 9 || t2.getTypeCode() == 10 ||
t2.getTypeCode() == 103)
return t2;
break;
case 103: /* unknown super class */
if (t2.getTypeCode() == 10 || t2.getTypeCode() == 103)
return t2; /*XXX*/
if (t2 == tUObject)
return t1;
break;
default:
throw new AssertError("Wrong typeCode "+t1.getTypeCode());
}
return tError;
}
/**
* Check if t1 is a t2.
* @return true if t1 is a more specific type than t2, e.g.
* if t2 is a superclass of t1
*/
public static boolean isOfType(Type t1, Type t2) {
if ((t1 == t2 || t2 == tUnknown) && t1 != tError)
return true;
switch (t1.getTypeCode()) {
case 0: /* boolean*/
case 1: /* byte */
case 2: /* char */
case 3: /* short */
case 4: /* int */
/* JavaC thinks, that this is okay. */
if (t2.getTypeCode() >= 0 && t2.getTypeCode() <=4)
return true;
/* fallthrough */
case 104: /* unknown index */
if (t2 == tUInt || t2 == tUIndex)
return true;
break;
case 5: /* long */
case 6: /* float */
case 7: /* double */
case 8: /* null? */
case 11: /* void */
case 12: /* method */
case 13: /* error */
case 100: /* unknown */
case 101: /* unknown int */
case 102: /* unknown object */
break;
case 9: /* array */
if (t2 == tUObject)
return true;
if (t2.getTypeCode() == 9) /* array,array case */
return isOfType(t1.getElementType(), t2.getElementType());
break;
case 10: /* class */
if (t2 == tUObject)
return true;
if (t2.getTypeCode() == 103)
/* Always true because t2 may be an Object XXX I think not*/
return true;
if (t2.getTypeCode() == 10)
/* true if t2 is a superclass of t1 */
return true; /*XXX*/
break;
case 103: /* unknown super class */
if (t2.getTypeCode() == 103)
/* Always true because t2 may be an Object XXX I think not*/
return true;
if (t2.getTypeCode() == 10) {
/* true if t2 is a real super class
(or interface) of t1.getElementType() */
return true; /*XXX*/
}
if (t2 == tUObject)
return true;
break;
default:
throw new AssertError("Wrong typeCode "+t1.getTypeCode());
}
return false;
}
}

@ -1,253 +0,0 @@
package jode.test;
class A {
}
interface I1 {
}
interface I2 {
}
interface I12 extends I1, I2 {
}
class B extends A implements I1 {
}
class C extends B implements I2, I12 {
}
class D extends A implements I12 {
}
class E extends A implements I2 {
}
public class Test {
A a;
B b;
C c;
D d;
E e;
I1 i1;
I2 i2;
I12 i12;
boolean g_bo;
byte g_by;
short g_sh;
int g_in;
int z;
int[]ain;
void skip() {
for (int i=0; i<3; i++) {
if (z > 5) {
for (int j=0; j<5; j++) {
z++;
}
}
i--;
}
}
public void arithTest() {
int a=1,b=2;
boolean x = true,y = false;
int c=0;
skip();
if (x & y) {
c = 5;
skip();
x &= y;
skip();
x = x | y;
skip();
x ^= y;
skip();
x = x && y;
skip();
b <<= a;
b <<= c;
}
a&=b;
}
public void switchWhileTest() {
int local_1__114 = g_in;
int local_2__115 = 0;
int local_3__116 = 0;
int local_4__117 = 0;
z = 5;
switch (local_1__114) {
case 1:
while (local_4__117 == 0) {
local_4__117 = 1;
local_2__115 = g_in;
local_3__116 = g_in;
if (local_2__115 > 7)
local_2__115 = local_2__115 - 4;
int local_5__118 = 0;
while (local_5__118 < 4) {
int local_6__119 = 0;
while (local_6__119 < 5) {
if (ain[local_6__119] == local_2__115 + local_5__118 && ain[local_6__119] == local_3__116)
local_4__117 = 0;
local_6__119 += 1;
}
local_5__118 += 1;
}
}
int local_5__120 = 0;
while (local_5__120 < 5) {
ain[z] = local_2__115 + local_5__120;
ain[z] = local_3__116;
z += 1;
local_5__120 += 1;
}
break;
case 2:
while (local_4__117 == 0) {
local_4__117 = 1;
local_2__115 = g_in;
local_3__116 = g_in;
if (local_3__116 > 7)
local_3__116 = local_3__116 - 4;
int local_5__121 = 0;
while (local_5__121 < 4) {
int local_6__122 = 0;
while (local_6__122 < 4) {
if (ain[local_6__122] == local_2__115 && ain[local_6__122] == local_3__116 + local_5__121)
local_4__117 = 0;
local_6__122 += 1;
}
local_5__121 += 1;
}
}
int local_5__123 = 0;
while (local_5__123 < 4) {
ain[z] = local_2__115;
ain[z] = local_3__116 + local_5__123;
z += 1;
local_5__123 += 1;
}
break;
}
}
public void intTypeTest() {
boolean b = false;
boolean abo[] = null;
byte aby[] = null;
byte by;
int in;
short sh;
b = g_bo;
in = g_sh;
sh = (short)g_in;
by = (byte)sh;
sh = by;
in = by;
abo[0] = g_bo;
abo[1] = false;
abo[2] = true;
aby[0] = g_by;
aby[1] = 0;
aby[2] = 1;
}
/**
* This is an example where our flow analysis doesn't find an
* elegant solution. The reason is, that we try to make
* while(true)-loops as small as possible (you can't see the real
* end of the loop, if it is breaked there like here).
*
* Look at the assembler code and you know why my Decompiler has
* problems with this. But the decompiler does produce compilable
* code which produces the same assembler code.
*
* A solution would be, to make switches as big as possible (like we
* already do it with try-catch-blocks).
*/
void WhileTrueSwitch() {
int i = 1;
while (true) {
switch (i) {
case 0:
return;
case 1:
i = 5;
continue;
case 2:
i = 6;
continue;
case 3:
throw new RuntimeException();
default:
i = 7;
return;
}
}
}
native void arrFunc(B[] b);
/**
* This is an example where it is really hard to know, which type
* each local has.
*/
void DifficultType () {
B myB = c;
C myC = c;
I2 myI2 = c;
I12 myI12 = c;
boolean bool = true;
B[] aB = new C[3];
arrFunc(new C[3]);
while (bool) {
if (bool) {
i1 = myB;
i2 = myC;
i1 = aB[0];
} else if (bool) {
i1 = myI12;
i2 = myI2;
} else {
i1 = myC;
i2 = myI12;
}
myB = b;
if (bool)
myI2 = i12;
else {
myI12 = d;
myI2 = e;
}
}
}
/**
* This is an example where it is really hard to know, which type
* each local has.
*/
void DifficultArrayType () {
boolean bool = true;
B[] aB = new C[3];
arrFunc(new C[3]);
C[][][][][] x = new C[4][3][4][][];
int[][][][][] y = new int[1][2][][][];
while (bool) {
if (bool) {
i1 = aB[0];
aB[0] = b;
}
}
}
}
Loading…
Cancel
Save