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