Mirror of the JODE repository
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
jode/jode/src/net/sf/jode/flow/VariableStack.java

176 lines
5.8 KiB

/* VariableStack Copyright (C) 1999-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.flow;
import net.sf.jode.decompiler.LocalInfo;
import net.sf.jode.expr.Expression;
import net.sf.jode.expr.LocalLoadOperator;
/**
* 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.
Documentation updates (INSTALL, javadoc). Added JUnit Test cases. * build.xml: Big update. * net/sf/jode/bytecode/BasicBlock.java: (updateMaxStackLocals): new method to calculate maxStack and maxLocals. (setBlocks): fixed calculation of handlers, call updateMaxLocals. * net/sf/jode/bytecode/BasicBlockReader.java: (maxLocals, maxStack): new fields. (readCode): read maxStack/Locals into private fields. (convert): check that maxStack/Locals match what we calculate. * net/sf/jode/bytecode/BinaryInfo.java: (getKnownAttributeCount): renamed to... (getAttributeCount): ... this, and also count internal attributes. Made it protected. (readAttribute): made protected. (drop): made protected. (prepareAttributes): made protected. (writeKnownAttributes): removed. (writeAttributes): made protected, use getAttributeCount. Changed policy: it doesn't call writeKnownAttribute, but instead it expects sub classes to override this method. (getAttributeSize): made protected, subclasses should override it. Changed all subclasses to new policy. * net/sf/jode/bytecode/Block.java: (lineNr): Removed, it wasn't used. (pop,push): Removed, replaced by ... (maxpop,maxpush,delta): ... these, with slightly changed semantics. (stackHeight): New variable. (Block): Default Constructor doesn't initialize fields now. (getCatchers): Renamed to ... (getHandlers): ... this, changed all callers. (initCode): Calculate maxpop, maxpush, delta correctly. (getStackPopPush): Changed accordingly to new fields. (setCode): Removed debugging output for illegal contents. * net/sf/jode/bytecode/Classes.java: Reworked handling of inner classes. (innerClasses): Field mustn't be null anymore when loaded. (setName): Update class in classpath. * net/sf/jode/bytecode/ClassPath.java: (renameClassInfo): new function, should only used by ClassInfo. * net/sf/jode/bytecode/ConstantPool.java: made public. (getUTF8,getRef,getClassType,getClassName): Don't allow the 0 index. (iterateClassNames): New method. * net/sf/jode/decompiler/Main.java: (decompileClass): Catch ClassFormatExceptions and decompile remaining classes. * net/sf/jode/obfuscator/ClassIdentifier.java: Updated handling of inner/extra classes to new ClassInfo behaviour. (initSuperClasses): Load DECLARATION of super classes. * net/sf/jode/obfuscator/PackageIdentifier.java: Replace deprecated methods of ClassInfo with corresponding classpath calls. (loadMatchingClasses): Initialize packages loaded on demand if we are initialize. * net/sf/jode/obfuscator/modules/ConstantAnalyzer.java: Now extends SimpleAnalyzer. (canonizeIfaceRef): Removed; it is now inherited. (canonizeRef): likewise. Big updates to handle jsr correctly. (handleOpcode): Moved method to BlockInfo. * net/sf/jode/obfuscator/modules/SimpleAnalyzer.java: (canonizeIfaceRef): New method, copied from ConstantAnalyzer. (canonizeRef): call canonizeIfaceRef for interfaces. * net/sf/jode/util/UnifyHash.java (iterateHashCode): iterator now supports remove(). (remove): New method. git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1337 379699f6-c40d-0410-875b-85095c16579e
23 years ago
* @see FlowBlock#mapStackToLocal
* @see FlowBlock#removePush
*/
public class VariableStack {
public final static VariableStack EMPTY = new VariableStack();
final LocalInfo[] stackMap;
private VariableStack() {
stackMap = new LocalInfo[0];
}
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) {
/* assert expr.getFreeOperandCount() == stackMap.length */
for (int i = stackMap.length-1; i >= 0; i--) {
// if (!used.contains(stackMap[i]))
// used.addElement(stackMap[i]);
expr = expr.addOperand
(new LocalLoadOperator(stackMap[i].getType(), null,
stackMap[i]));
}
return expr;
}
public VariableStack executeSpecial(SpecialBlock special) {
if (special.type == SpecialBlock.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 == SpecialBlock.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 == SpecialBlock.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 InternalError("Unknown SpecialBlock");
}
public String toString() {
StringBuffer result = new StringBuffer("[");
for (int i=0; i < stackMap.length; i++) {
if (i>0)
result.append(", ");
result.append(stackMap[i].getName());
}
return result.append("]").toString();
}
}