git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1024 379699f6-c40d-0410-875b-85095c16579estable
parent
f6f5d1707e
commit
71b1a85b6d
@ -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 <tInt -- tBoolean>. 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 <sp -- null>, 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 <null -- ep>, 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 <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…
Reference in new issue