git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@324 379699f6-c40d-0410-875b-85095c16579estable
parent
9a5ccb5a86
commit
c3320ae555
@ -0,0 +1,155 @@ |
||||
package jode.flow; |
||||
import jode.decompiler.LocalInfo; |
||||
import jode.expr.ComplexExpression; |
||||
import jode.expr.Expression; |
||||
import jode.expr.LocalLoadOperator; |
||||
import jode.expr.Operator; |
||||
|
||||
/** |
||||
* This class represents the state of the stack at various points in |
||||
* the program. Each entry is a anonymous local, which is used instead |
||||
* of the PUSH / stack_i statements. <p> |
||||
* |
||||
* This class is immutable, but note, that the local infos can get merged. |
||||
* @see FlowBlock.mapStackToLocal |
||||
* @see FlowBlock.removePush |
||||
*/ |
||||
public class VariableStack { |
||||
public final static VariableStack EMPTY = |
||||
new VariableStack(new LocalInfo[0]); |
||||
|
||||
final LocalInfo[] stackMap; |
||||
|
||||
private VariableStack(LocalInfo[] stack) { |
||||
stackMap = stack; |
||||
} |
||||
|
||||
public boolean isEmpty() { |
||||
return stackMap.length == 0; |
||||
} |
||||
|
||||
public VariableStack pop(int count) { |
||||
LocalInfo[] newStack = new LocalInfo[stackMap.length - count]; |
||||
System.arraycopy(stackMap, 0, newStack, 0, stackMap.length - count); |
||||
return new VariableStack(newStack); |
||||
} |
||||
|
||||
public VariableStack push(LocalInfo li) { |
||||
return poppush(0, li); |
||||
} |
||||
|
||||
public VariableStack poppush(int count, LocalInfo li) { |
||||
LocalInfo[] newStack = new LocalInfo[stackMap.length - count + 1]; |
||||
System.arraycopy(stackMap, 0, newStack, 0, stackMap.length - count); |
||||
newStack[stackMap.length - count] = li; |
||||
return new VariableStack(newStack); |
||||
} |
||||
|
||||
public VariableStack peek(int count) { |
||||
LocalInfo[] peeked = new LocalInfo[count]; |
||||
System.arraycopy(stackMap, stackMap.length - count, peeked, 0, count); |
||||
return new VariableStack(peeked); |
||||
} |
||||
|
||||
public void merge(VariableStack other) { |
||||
if (stackMap.length != other.stackMap.length) |
||||
throw new IllegalArgumentException("stack length differs"); |
||||
for (int i=0; i<stackMap.length; i++) { |
||||
if (stackMap[i].getType().stackSize() |
||||
!= other.stackMap[i].getType().stackSize()) |
||||
throw new IllegalArgumentException |
||||
("stack element length differs at "+i); |
||||
stackMap[i].combineWith(other.stackMap[i]); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Merge to VariableStacks. Either one may be null, in which case |
||||
* the other is returned. |
||||
*/ |
||||
public static VariableStack merge(VariableStack first, |
||||
VariableStack second) { |
||||
if (first == null) |
||||
return second; |
||||
else if (second == null) |
||||
return first; |
||||
first.merge(second); |
||||
return first; |
||||
} |
||||
|
||||
public Expression mergeIntoExpression(Expression expr, VariableSet used) { |
||||
/* assert expr.getOperandCount() == stackMap.length */ |
||||
|
||||
ComplexExpression parent = null; |
||||
Expression inner = expr; |
||||
while (inner instanceof ComplexExpression) { |
||||
parent = (ComplexExpression)inner; |
||||
inner = parent.getSubExpressions()[0]; |
||||
} |
||||
Expression[] loads = new Expression[stackMap.length]; |
||||
for (int i=0; i< stackMap.length; i++) { |
||||
used.addElement(stackMap[i]); |
||||
loads[i] = new LocalLoadOperator(stackMap[i].getType(), |
||||
stackMap[i]); |
||||
} |
||||
Expression newExpr = new ComplexExpression((Operator)inner, loads); |
||||
if (parent != null) |
||||
parent.setSubExpressions(0, newExpr); |
||||
else |
||||
expr = newExpr; |
||||
return expr; |
||||
} |
||||
|
||||
public VariableStack executeSpecial(SpecialBlock special) { |
||||
if (special.type == special.POP) { |
||||
int popped = 0; |
||||
int newLength = stackMap.length; |
||||
while (popped < special.count) { |
||||
newLength--; |
||||
popped += stackMap[newLength].getType().stackSize(); |
||||
} |
||||
if (popped != special.count) |
||||
throw new IllegalArgumentException("wrong POP"); |
||||
LocalInfo[] newStack = new LocalInfo[newLength]; |
||||
System.arraycopy(stackMap, 0, newStack, 0, newLength); |
||||
return new VariableStack(newStack); |
||||
} else if (special.type == special.DUP) { |
||||
int popped = 0; |
||||
int numDup = 0; |
||||
int startDup = stackMap.length; |
||||
while (popped < special.count) { |
||||
startDup--; |
||||
numDup++; |
||||
popped += stackMap[startDup].getType().stackSize(); |
||||
} |
||||
if (popped != special.count) |
||||
throw new IllegalArgumentException("wrong DUP"); |
||||
int destDup = startDup; |
||||
int depth = 0; |
||||
while (depth < special.depth) { |
||||
destDup--; |
||||
depth += stackMap[destDup].getType().stackSize(); |
||||
} |
||||
if (depth != special.depth) |
||||
throw new IllegalArgumentException("wrong DUP"); |
||||
LocalInfo[] newStack = new LocalInfo[stackMap.length + numDup]; |
||||
System.arraycopy(stackMap, 0, newStack, 0, destDup); |
||||
System.arraycopy(stackMap, startDup, newStack, destDup, numDup); |
||||
System.arraycopy(stackMap, destDup, newStack, destDup + numDup, |
||||
startDup - destDup); |
||||
System.arraycopy(stackMap, startDup, newStack, startDup + numDup, |
||||
numDup); |
||||
return new VariableStack(newStack); |
||||
} else if (special.type == special.SWAP) { |
||||
LocalInfo[] newStack = new LocalInfo[stackMap.length]; |
||||
System.arraycopy(stackMap, 0, newStack, 0, stackMap.length - 2); |
||||
if (stackMap[stackMap.length-2].getType().stackSize() != 1 |
||||
|| stackMap[stackMap.length-1].getType().stackSize() != 1) |
||||
throw new IllegalArgumentException("wrong SWAP"); |
||||
newStack[stackMap.length-2] = stackMap[stackMap.length-1]; |
||||
newStack[stackMap.length-1] = stackMap[stackMap.length-2]; |
||||
return new VariableStack(newStack); |
||||
} else |
||||
throw new jode.AssertError("Unknown SpecialBlock"); |
||||
} |
||||
} |
@ -0,0 +1,53 @@ |
||||
package jode.test; |
||||
|
||||
public class ConstantTypes { |
||||
static boolean bool = true; |
||||
static byte b = (byte) 0x80; |
||||
static char c = '\u0080'; |
||||
static short s = (short)'\u8234'; |
||||
static int i = '\uffff'; |
||||
|
||||
static void intFunc(int i){} |
||||
static void shortFunc(short s){} |
||||
static void charFunc(char c){} |
||||
static void byteFunc(byte b){} |
||||
|
||||
static { |
||||
/* All casts are necessaray */ |
||||
intFunc(25); |
||||
shortFunc((short) 25); |
||||
charFunc((char) 25); |
||||
byteFunc((byte) 25); |
||||
intFunc('\u0019'); |
||||
shortFunc((short) '\u0019'); |
||||
charFunc('\u0019'); |
||||
byteFunc((byte) '\u0019'); |
||||
intFunc(b); |
||||
intFunc(c); |
||||
intFunc(s); |
||||
intFunc(i); |
||||
shortFunc(b); |
||||
shortFunc((short)c); |
||||
shortFunc(s); |
||||
shortFunc((short)i); |
||||
charFunc((char)b); |
||||
charFunc(c); |
||||
charFunc((char)s); |
||||
charFunc((char)i); |
||||
byteFunc(b); |
||||
byteFunc((byte)c); |
||||
byteFunc((byte)s); |
||||
byteFunc((byte)i); |
||||
b = 42; |
||||
c = 42; |
||||
s = 42; |
||||
i = 42; |
||||
i = c; |
||||
s = b; |
||||
i = s; |
||||
c = (char) s; |
||||
s = (short) c; |
||||
c = (char) b; |
||||
b = (byte) c; |
||||
} |
||||
} |
Loading…
Reference in new issue