diff --git a/jode/jode/jvm/CodeVerifier.java b/jode/jode/jvm/CodeVerifier.java
new file mode 100644
index 0000000..c008128
--- /dev/null
+++ b/jode/jode/jvm/CodeVerifier.java
@@ -0,0 +1,1523 @@
+/* CodeVerifier 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.jvm;
+import jode.AssertError;
+import jode.GlobalOptions;
+import jode.bytecode.BasicBlocks;
+import jode.bytecode.Block;
+import jode.bytecode.ClassPath;
+import jode.bytecode.ClassInfo;
+import jode.bytecode.Handler;
+import jode.bytecode.Instruction;
+import jode.bytecode.MethodInfo;
+import jode.bytecode.Opcodes;
+import jode.bytecode.Reference;
+import jode.bytecode.TypeSignature;
+
+import java.io.IOException;
+import java.util.BitSet;
+///#def COLLECTIONS java.util
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+///#enddef
+
+/**
+ * Verifies a given method.
+ *
+ * @author Jochen Hoenicke
+ */
+public class CodeVerifier implements Opcodes {
+ ClassInfo ci;
+ MethodInfo mi;
+ BasicBlocks bb;
+ ClassPath classpath;
+
+ String methodType;
+
+ Type returnType;
+ Type tInt;
+ Type tLong;
+ Type tFloat;
+ Type tDouble;
+ Type tNone;
+ Type tSecondPart;
+
+ Type tString;
+ Type tObject;
+
+ Map typeHash = new HashMap();
+
+ private Type tType(String typeSig) {
+ Type type = (Type) typeHash.get(typeSig);
+ if (type == null) {
+ int obj = typeSig.charAt(0) == 'N' ? 0 : typeSig.indexOf('L');
+ int semi = typeSig.indexOf(';');
+ if (obj != -1 && semi != -1) {
+ String subTypeSig = typeSig.substring(0, obj+1)
+ + typeSig.substring(semi+1);
+ String className
+ = typeSig.substring(obj+1, semi).replace('/', '.');
+ ClassInfo classInfo = classpath.getClassInfo(className);
+ type = new Type(subTypeSig, classInfo, null);
+ } else
+ type = new Type(typeSig, null, null);
+ typeHash.put(typeSig, type);
+ }
+ return type;
+ }
+
+ private Type tType(Block jsrTarget) {
+ Type type = (Type) typeHash.get(jsrTarget);
+ if (type == null) {
+ type = new Type("R", null, jsrTarget);
+ typeHash.put(jsrTarget, type);
+ }
+ return type;
+ }
+
+ private Type tType(String head, ClassInfo classInfo) {
+ String typeSig = head + classInfo.getName().replace('.', '/') + ';';
+ Type type = (Type) typeHash.get(typeSig);
+ if (type == null) {
+ type = new Type(head, classInfo, null);
+ typeHash.put(typeSig, type);
+ }
+ return type;
+ }
+
+ /**
+ * We need some more types, than mentioned in jvm.
+ */
+ private static class Type {
+ /* "ZBCSIFJD" are the normal primitive types.
+ * "V" stands for void type.
+ * "L" is normal class type, the class is in classInfo field.
+ * "[..." is normal array type
+ * "?" stands for type error
+ * "N" stands for the uninitialized this of a constructor,
+ * and classInfo is set.
+ * "Nxxx" stands for a new uninitialized type, where xxx is
+ * a unique identifier for the new instruction
+ * and classInfo is set.
+ * "0" stands for null type.
+ * "R" stands for return address type.
+ * "2" stands for second half of a two word type.
+ */
+ private String typeSig;
+
+ /* The classInfo if this is or contains a class type.
+ */
+ private ClassInfo classInfo;
+
+ /**
+ * The target block of the jsr if this is a "R" type.
+ */
+ private Block jsrTarget;
+
+ public Type(String typeSig, ClassInfo classInfo, Block jsrTarget) {
+ if ((typeSig.indexOf('L') >= 0 || typeSig.charAt(0) == 'N')
+ && classInfo == null)
+ throw new IllegalArgumentException();
+ this.typeSig = typeSig;
+ this.classInfo = classInfo;
+ this.jsrTarget = jsrTarget;
+ }
+
+ public String getTypeSig() {
+ return typeSig;
+ }
+
+ public Block getJsrTarget() {
+ return jsrTarget;
+ }
+
+ /**
+ * @param t2 the type signature of the type to check for.
+ * This may be one of the special signatures:
+ *
- "[*"
- array of something
+ * - "+"
- (uninitialized) object/returnvalue type
+ * - "L"
- (initialized) object/returnvalue type
+ * - "2", "R"
- as the typeSig parameter
+ *
+ * @return true, iff this is castable to t2 by a
+ * widening cast. */
+ public boolean isOfType(Type destType) {
+ String thisSig = typeSig;
+ String destSig = destType.typeSig;
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_VERIFIER) != 0)
+ GlobalOptions.err.println("isOfType("+thisSig+","+destSig+")");
+ if (thisSig.equals(destSig))
+ return true;
+
+ char c1 = thisSig.charAt(0);
+ char c2 = destSig.charAt(0);
+ switch (c2) {
+ case 'Z': case 'B': case 'C': case 'S': case 'I':
+ /* integer type */
+ return ("ZBCSI".indexOf(c1) >= 0);
+ case '+':
+ return ("L[nNR0".indexOf(c1) >= 0);
+
+ case '[':
+ if (c1 == '0')
+ return true;
+ while (c1 == '[' && c2 == '[') {
+ thisSig = thisSig.substring(1);
+ destSig = destSig.substring(1);
+ c1 = thisSig.charAt(0);
+ c2 = destSig.charAt(0);
+ }
+
+ if (c2 == '*')
+ /* destType is array of unknowns */
+ return true;
+ /* Note that short[] is only compatible to short[],
+ * therefore we only need to handle Object types specially.
+ */
+
+ if (c2 != 'L')
+ return false;
+ case 'L':
+ if (c1 == '0')
+ return true;
+ if ("L[".indexOf(c1) < 0)
+ return false;
+
+ ClassInfo wantedType = destType.classInfo;
+ if (wantedType == null
+ || wantedType.getName() == "java.lang.Object")
+ return true;
+
+ try {
+ wantedType.load(ClassInfo.HIERARCHY);
+ if (wantedType.isInterface())
+ return true;
+ if (c1 == 'L')
+ return wantedType.superClassOf(classInfo);
+ } catch (IOException ex) {
+ GlobalOptions.err.println
+ ("WARNING: Can't get full hierarchy of "
+ + wantedType + ".");
+ return true;
+ }
+ case 'N':
+ if (typeSig.charAt(0) != 'N')
+ return false;
+
+ /* New types must match exactly ... */
+ if (this.classInfo == destType.classInfo)
+ return true;
+
+ /* ... except that a constructor can call the super
+ * constructor */
+ if (typeSig.length() > 1)
+ return false;
+
+ try {
+ classInfo.load(ClassInfo.HIERARCHY);
+ return (classInfo.getSuperclass() == destType.classInfo);
+ } catch (IOException ex) {
+ /* ignore, type is maybe correct. */
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return The common super type of this and type2.
+ */
+ public Type mergeType(CodeVerifier cv, Type type2) {
+ String sig1 = typeSig;
+ String sig2 = type2.typeSig;
+
+ if (this.equals(type2))
+ return this;
+
+ char c1 = sig1.charAt(0);
+ char c2 = sig2.charAt(0);
+ if (c1 == '*')
+ return type2;
+ if (c2 == '*')
+ return this;
+ if ("ZBCSI".indexOf(c1) >= 0 && "ZBCSI".indexOf(c2) >= 0)
+ return this;
+
+ if (c1 == '0')
+ return ("L[0".indexOf(c2) >= 0) ? type2 : cv.tNone;
+ if (c2 == '0')
+ return ("L[".indexOf(c1) >= 0) ? this : cv.tNone;
+
+
+ int dimensions = 0;
+ /* Note that short[] is only compatible to short[],
+ * therefore we make the array handling after the primitive
+ * type handling. Also note that we don't allow arrays of
+ * special types.
+ */
+ while (c1 == '[' && c2 == '[') {
+ sig1 = sig1.substring(1);
+ sig2 = sig2.substring(1);
+ c1 = sig1.charAt(0);
+ c2 = sig2.charAt(0);
+ dimensions++;
+ }
+
+ if (c1 == '[' || c2 == '[') {
+ // Only one of them is array now, the other must be an
+ // object, the common super is tObject
+ if (c1 == 'L' || c2 == 'L') {
+ if (dimensions == 0)
+ return cv.tObject;
+ StringBuffer result = new StringBuffer(dimensions + 18);
+ for (int i=0; i< dimensions; i++)
+ result.append("[");
+ result.append("Ljava/lang/Object;");
+ return cv.tType(result.toString());
+ }
+ return cv.tNone;
+ }
+
+ if (c1 == 'L' && c2 == 'L') {
+ ClassInfo clazz1 = classInfo;
+ ClassInfo clazz2 = type2.classInfo;
+ try {
+ if (clazz1.superClassOf(clazz2))
+ return this;
+ } catch (IOException ex) {
+ /* clazz1 has no complete hierarchy, we can assume
+ * that it extends class2.
+ */
+ return this;
+ }
+ try {
+ if (clazz2.superClassOf(clazz1))
+ return type2;
+ } catch (IOException ex) {
+ /* clazz1 has no complete hierarchy, we can assume
+ * that it extends class2.
+ */
+ return this;
+ }
+ /* Now the complete hierarchy of clazz1 and
+ * clazz2 is loaded */
+ try {
+ do {
+ clazz1 = clazz1.getSuperclass();
+ } while (!clazz1.superClassOf(clazz2));
+ } catch (IOException ex) {
+ throw new InternalError("Hierarchy vanished?");
+ }
+ StringBuffer result = new StringBuffer
+ (dimensions + clazz1.getName().length() + 2);
+ for (int i=0; i< dimensions; i++)
+ result.append("[");
+ result.append("L");
+ return cv.tType(result.toString(), clazz1);
+ }
+ return cv.tNone;
+ }
+
+ public boolean equals(Object other) {
+ if (other instanceof Type) {
+ Type type2 = (Type) other;
+ return typeSig.equals(type2.typeSig)
+ && classInfo == type2.classInfo
+ && jsrTarget == type2.jsrTarget;
+ }
+ return false;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer(typeSig);
+ if (classInfo != null)
+ sb.append(classInfo.getName());
+ if (jsrTarget != null)
+ sb.append(jsrTarget);
+ return sb.toString();
+ }
+ }
+
+ /**
+ * JLS 4.9.6: Verifying code that contains a finally clause:
+ * - Each instruction keeps track of the list of jsr targets.
+ * - For each instruction and each jsr needed to reach that instruction
+ * a bit vector is maintained of all local vars accessed or modified.
+ */
+ final class JsrUsedInfo {
+ /**
+ * The last jsrTarget that must have been traversed.
+ */
+ Block jsrTarget;
+
+ /**
+ * The set of locals changed since the last jsrTarget.
+ */
+ BitSet jsrUsed;
+
+ JsrUsedInfo(Block jsrTarget, BitSet jsrUsed) {
+ this.jsrTarget = jsrTarget;
+ this.jsrUsed = jsrUsed;
+ }
+
+ JsrUsedInfo(JsrUsedInfo orig) {
+ this.jsrTarget = orig.jsrTarget;
+ this.jsrUsed = orig.jsrUsed;
+ }
+
+ public String toString() {
+ return ""+jsrTarget+'-'+jsrUsed;
+ }
+ }
+
+ class SubroutineInfo {
+ /**
+ * The previous used Info, null if this is the outermost jsr.
+ */
+ JsrUsedInfo prevInfo;
+ /**
+ * Block number of the return.
+ */
+ Block retBlock = null;
+ /**
+ * The VerifyInfo after the ret.
+ */
+ VerifyInfo retInfo;
+ /**
+ * The locals used in this subroutine
+ */
+ BitSet usedLocals;
+ /**
+ * The bitset containing the numbers of the blocks following
+ * that may follow a JSR to this subroutine.
+ */
+ BitSet jsrSuccessors = new BitSet();
+ }
+
+ /**
+ * The VerifyInfo contains informations about the state of the stack
+ * and local variables, as well as the current subroutine.
+ *
+ * We create a VerifyInfo for every reachable basic block in the
+ * verifyInfos array. For not yet reached basic blocks, that are
+ * the successor of an jsr, it contains the state just _before_
+ * the jsr. If later a ret is found, it will take care to correct
+ * that.
+ *
+ * We also have an intermediate VerifyInfo, which is modified
+ * while we are "simulating" the instructions in a basic block.
+ * After the basic block is fully simulated, we merge that temporary
+ * VerifyInfo (cloning() it if necessary) and free it afterwards.
+ *
+ * Last but not least, we have a VerifyInfo in SubroutineInfo, that
+ * records the local/stack state just after the ret.
+ *
+ * For information about typechecking jsrs:
+ *
+ * JLS 4.9.6: Verifying code that contains a finally clause:
+ * - Each instruction keeps track of the list of jsr targets.
+ * - For each instruction and each jsr needed to reach that instruction
+ * a bit vector is maintained of all local vars accessed or modified.
+ *
+ * The difficult part are subroutines inside a method (the jsr and
+ * ret instructions). We remember the last jsrtarget that must be
+ * traversed to reach this block (a jsrTarget is a basic block to
+ * which a jsr jumps). Since a jsrTarget has a "R"
+ * type on the stack there is no possibility to reach a jsrTarget
+ * on another way.
+ *
+ * We only remember the innermost subroutine, but its SubroutineInfo
+ * will contain the information about outer subroutines.
+ *
+ * If we change a local we remember it in jsrUsed. This is
+ * needed for the local merging on a ret as specified in the jvm
+ * spec.
+ */
+ final class VerifyInfo implements Cloneable {
+ /**
+ * The jsr and used info for the innermost surrounding jsr.
+ * Normally this is null.
+ */
+ JsrUsedInfo jsrInfo;
+
+ /**
+ * The current stack height
+ */
+ int stackHeight = 0;
+ /**
+ * The types currently on the stack. The entries at indices
+ * bigger or equal stackHeight are _undefined_.
+ * @see Type
+ */
+ Type[] stack = new Type[bb.getMaxStack()];
+
+ /**
+ * The types currently in local slots. An entry is null, if
+ * the local may not be used.
+ * @see Type
+ */
+ Type[] locals = new Type[bb.getMaxLocals()];
+
+ public Object clone() {
+ try {
+ VerifyInfo result = (VerifyInfo) super.clone();
+ result.stack = (Type[]) stack.clone();
+ result.locals = (Type[]) locals.clone();
+ if (jsrInfo != null)
+ result.jsrInfo = new JsrUsedInfo(jsrInfo);
+ return result;
+ } catch(CloneNotSupportedException ex) {
+ throw new AssertError("Clone not supported?");
+ }
+ }
+
+ public final void reserve(int count) throws VerifyException {
+ if (stackHeight + count > stack.length)
+ throw new VerifyException("stack overflow");
+ }
+
+ public final void need(int count) throws VerifyException {
+ if (stackHeight < count)
+ throw new VerifyException("stack underflow");
+ }
+
+ public final void push(Type type) throws VerifyException {
+ reserve(1);
+ stack[stackHeight++] = type;
+ }
+
+ public final Type pop() throws VerifyException {
+ need(1);
+ return stack[--stackHeight];
+ }
+
+ public String toString() {
+ StringBuffer result = new StringBuffer("locals:[");
+ String comma = "";
+ for (int i=0; i= bb.getMaxLocals())
+ throw new VerifyException("Too few local slots");
+ if (mi.getName().equals(""))
+ info.locals[slot++] = tType("N", ci);
+ else
+ info.locals[slot++] = tType("L", ci);
+ }
+ while (methodType.charAt(pos) != ')') {
+ int start = pos;
+ pos = TypeSignature.skipType(methodType, pos);
+ String paramType = methodType.substring(start, pos);
+ if (slot >= bb.getMaxLocals())
+ throw new VerifyException("Too few local slots");
+ info.locals[slot++] = tType(paramType);
+ if (TypeSignature.getTypeSize(paramType) == 2) {
+ if (slot >= bb.getMaxLocals())
+ throw new VerifyException("Too few local slots");
+ info.locals[slot++] = tSecondPart;
+ }
+ }
+ while (slot < bb.getMaxLocals())
+ info.locals[slot++] = tNone;
+ return info;
+ }
+
+ /**
+ * Merges the second JsrUsedInfo into the first.
+ * @return true if first JsrUsedInfo changed in this merge, i.e.
+ * got more specific.
+ */
+ private boolean mergeJsrTarget(JsrUsedInfo first, JsrUsedInfo second) {
+ /* trivial cases first. */
+ if (first.jsrTarget == second.jsrTarget)
+ return false;
+ if (first.jsrTarget == null || second.jsrTarget == null)
+ return false;
+
+ /* Now the bitsets can't be null */
+ int firstDepth = 0;
+ for (JsrUsedInfo t = first; t != null;
+ t = subInfos[t.jsrTarget.getBlockNr()].prevInfo)
+ firstDepth++;
+ int secondDepth = 0;
+ for (JsrUsedInfo t = second; t != null;
+ t = subInfos[t.jsrTarget.getBlockNr()].prevInfo)
+ secondDepth++;
+
+ boolean changed = false;
+ Block secondTarget = second.jsrTarget;
+ while (firstDepth > secondDepth) {
+ JsrUsedInfo firstPrev
+ = subInfos[first.jsrTarget.getBlockNr()].prevInfo;
+ if (firstPrev == null)
+ first.jsrTarget = null;
+ else
+ first.jsrTarget = firstPrev.jsrTarget;
+ firstDepth--;
+ }
+ while (secondDepth > firstDepth) {
+ changed = true;
+ JsrUsedInfo secondPrev
+ = subInfos[secondTarget.getBlockNr()].prevInfo;
+ if (secondPrev != null) {
+ first.jsrUsed.or(secondPrev.jsrUsed);
+ secondTarget = secondPrev.jsrTarget;
+ } else
+ secondTarget = null;
+ secondDepth--;
+ }
+ while (first.jsrTarget != secondTarget) {
+ changed = true;
+ JsrUsedInfo firstPrev
+ = subInfos[first.jsrTarget.getBlockNr()].prevInfo;
+ if (firstPrev == null)
+ first.jsrTarget = null;
+ else
+ first.jsrTarget = firstPrev.jsrTarget;
+ JsrUsedInfo secondPrev
+ = subInfos[secondTarget.getBlockNr()].prevInfo;
+ if (secondPrev != null) {
+ first.jsrUsed.or(secondPrev.jsrUsed);
+ secondTarget = secondPrev.jsrTarget;
+ } else
+ secondTarget = null;
+ }
+ return changed;
+ }
+
+ private boolean mergeInfo(Block block, VerifyInfo info)
+ throws VerifyException {
+ int blockNr = block.getBlockNr();
+ if (verifyInfos[blockNr] == null) {
+ verifyInfos[blockNr] = (VerifyInfo) info.clone();
+ return true;
+ }
+ boolean changed = false;
+ VerifyInfo oldInfo = verifyInfos[blockNr];
+ if (oldInfo.stackHeight != info.stackHeight)
+ throw new VerifyException("Stack height differ at: " + blockNr);
+ for (int i=0; i < oldInfo.stackHeight; i++) {
+ Type newType = oldInfo.stack[i].mergeType(this, info.stack[i]);
+ if (!newType.equals(oldInfo.stack[i])) {
+ if (newType == tNone)
+ throw new VerifyException("Type error while merging: "
+ + oldInfo.stack[i]
+ + " and " + info.stack[i]);
+ changed = true;
+ oldInfo.stack[i] = newType;
+ }
+ }
+ for (int i=0; i < bb.getMaxLocals(); i++) {
+ Type newType = oldInfo.locals[i].mergeType(this, info.locals[i]);
+ if (!newType.equals(oldInfo.locals[i])) {
+ changed = true;
+ oldInfo.locals[i] = newType;
+ }
+ }
+ if (oldInfo.jsrInfo != null) {
+ if (info.jsrInfo == null) {
+ oldInfo.jsrInfo = null;
+ changed = true;
+ } else if (mergeJsrTarget(oldInfo.jsrInfo, info.jsrInfo)) {
+ if (oldInfo.jsrInfo.jsrTarget == null)
+ oldInfo.jsrInfo = null;
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ private void modelEffect(Instruction instr, VerifyInfo info)
+ throws VerifyException {
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_VERIFIER) != 0)
+ GlobalOptions.err.println(""+info+instr);
+ int opcode = instr.getOpcode();
+ switch (opcode) {
+ case opc_nop:
+ case opc_goto:
+ break;
+ case opc_ldc: {
+ Type type;
+ Object constant = instr.getConstant();
+ if (constant == null)
+ type = tType("0");
+ else if (constant instanceof Integer)
+ type = tInt;
+ else if (constant instanceof Float)
+ type = tFloat;
+ else
+ type = tString;
+ info.push(type);
+ break;
+ }
+ case opc_ldc2_w: {
+ Type type;
+ Object constant = instr.getConstant();
+ if (constant instanceof Long)
+ type = tLong;
+ else
+ type = tDouble;
+ info.push(type);
+ info.push(tSecondPart);
+ break;
+ }
+ case opc_iload:
+ case opc_lload:
+ case opc_fload:
+ case opc_dload:
+ case opc_aload: {
+ if (info.jsrInfo != null) {
+ info.jsrInfo.jsrUsed.set(instr.getLocalSlot());
+ if ((opcode & 0x1) == 0)
+ info.jsrInfo.jsrUsed.set(instr.getLocalSlot() + 1);
+ }
+ if ((opcode & 0x1) == 0
+ && info.locals[instr.getLocalSlot()+1] != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ Type type = info.locals[instr.getLocalSlot()];
+ if (!type.isOfType(types[opcode - opc_iload]))
+ throw new VerifyException(instr.getDescription());
+ info.push(type);
+ if ((opcode & 0x1) == 0)
+ info.push(tSecondPart);
+ break;
+ }
+ case opc_iaload: case opc_laload:
+ case opc_faload: case opc_daload: case opc_aaload:
+ case opc_baload: case opc_caload: case opc_saload: {
+ if (!info.pop().isOfType(tInt))
+ throw new VerifyException(instr.getDescription());
+ Type arrType = info.pop();
+ if (!arrType.isOfType(arrayTypes[opcode - opc_iaload])
+ && (opcode != opc_baload
+ || !arrType.isOfType(tType("[Z"))))
+ throw new VerifyException(instr.getDescription());
+
+ String typeSig = arrType.getTypeSig();
+ Type elemType;
+ if (typeSig.charAt(0) == '[') {
+ if (arrType.classInfo != null)
+ elemType = tType(typeSig.substring(1), arrType.classInfo);
+ else
+ elemType = tType(typeSig.substring(1));
+ } else if(opcode == opc_aaload)
+ elemType = tType("0");
+ else
+ elemType = types[opcode - opc_iaload];
+ info.push(elemType);
+ if (((1 << opcode - opc_iaload) & 0xa) != 0)
+ info.push(tSecondPart);
+ break;
+ }
+ case opc_istore: case opc_lstore:
+ case opc_fstore: case opc_dstore: case opc_astore: {
+ if (info.jsrInfo != null) {
+ info.jsrInfo.jsrUsed.set(instr.getLocalSlot());
+ if ((opcode & 0x1) != 0)
+ info.jsrInfo.jsrUsed.set(instr.getLocalSlot()+1);
+ }
+ if ((opcode & 0x1) != 0
+ && info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ Type type = info.pop();
+ if (!type.isOfType(types[opcode - opc_istore]))
+ if (opcode != opc_astore || !type.isOfType(tType("R")))
+ throw new VerifyException(instr.getDescription());
+ info.locals[instr.getLocalSlot()] = type;
+ if ((opcode & 0x1) != 0)
+ info.locals[instr.getLocalSlot()+1] = tSecondPart;
+ break;
+ }
+ case opc_iastore: case opc_lastore:
+ case opc_fastore: case opc_dastore: case opc_aastore:
+ case opc_bastore: case opc_castore: case opc_sastore: {
+ if (((1 << opcode - opc_iastore) & 0xa) != 0
+ && info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ Type type = info.pop();
+ if (!info.pop().isOfType(tInt))
+ throw new VerifyException(instr.getDescription());
+ Type arrType = info.pop();
+ if (!arrType.isOfType(arrayTypes[opcode - opc_iastore])
+ && (opcode != opc_bastore || !arrType.isOfType(tType("[Z"))))
+ throw new VerifyException(instr.getDescription());
+ Type elemType = opcode >= opc_bastore ? tInt
+ : types[opcode - opc_iastore];
+ if (!type.isOfType(elemType))
+ throw new VerifyException(instr.getDescription());
+ break;
+ }
+ case opc_pop: case opc_pop2: {
+ int count = opcode - (opc_pop-1);
+ info.need(count);
+ info.stackHeight -= count;
+ break;
+ }
+ case opc_dup: case opc_dup_x1: case opc_dup_x2: {
+ int depth = opcode - opc_dup;
+ info.reserve(1);
+ info.need(depth+1);
+ if (info.stack[info.stackHeight-1] == tSecondPart)
+ throw new VerifyException(instr.getDescription());
+
+ int stackdepth = info.stackHeight - (depth + 1);
+ if (info.stack[stackdepth] == tSecondPart)
+ throw new VerifyException(instr.getDescription()
+ + " on long or double");
+ for (int i=info.stackHeight; i > stackdepth; i--)
+ info.stack[i] = info.stack[i-1];
+ info.stack[stackdepth] = info.stack[info.stackHeight++];
+ break;
+ }
+ case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: {
+ int depth = opcode - opc_dup2;
+ info.reserve(2);
+ info.need(depth+2);
+ if (info.stack[info.stackHeight-2] == tSecondPart)
+ throw new VerifyException(instr.getDescription()
+ + " on misaligned long or double");
+ int stacktop = info.stackHeight;
+ int stackdepth = stacktop - (depth + 2);
+ if (info.stack[stackdepth] == tSecondPart)
+ throw new VerifyException(instr.getDescription()
+ + " on long or double");
+ for (int i=stacktop; i > stackdepth; i--)
+ info.stack[i+1] = info.stack[i-1];
+ info.stack[stackdepth+1] = info.stack[stacktop+1];
+ info.stack[stackdepth] = info.stack[stacktop];
+ info.stackHeight+=2;
+ break;
+ }
+ case opc_swap: {
+ info.need(2);
+ if (info.stack[info.stackHeight-2] == tSecondPart
+ || info.stack[info.stackHeight-1] == tSecondPart)
+ throw new VerifyException(instr.getDescription()
+ + " on misaligned long or double");
+ Type tmp = info.stack[info.stackHeight-1];
+ info.stack[info.stackHeight-1] =
+ info.stack[info.stackHeight-2];
+ info.stack[info.stackHeight-2] = tmp;
+ break;
+ }
+ case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
+ case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
+ case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
+ case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
+ case opc_irem: case opc_lrem: case opc_frem: case opc_drem: {
+ Type type = types[(opcode - opc_iadd) & 3];
+ if ((opcode & 1) != 0
+ && info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(type))
+ throw new VerifyException(instr.getDescription());
+ if ((opcode & 1) != 0) {
+ info.need(2);
+ if (info.stack[info.stackHeight-1] != tSecondPart
+ || !info.stack[info.stackHeight-2].isOfType(type))
+ throw new VerifyException(instr.getDescription());
+ } else {
+ info.need(1);
+ if (!info.stack[info.stackHeight-1].isOfType(type))
+ throw new VerifyException(instr.getDescription());
+ }
+ break;
+ }
+ case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: {
+ Type type = types[(opcode - opc_ineg) & 3];
+ if ((opcode & 1) != 0) {
+ info.need(2);
+ if (info.stack[info.stackHeight-1] != tSecondPart
+ || !info.stack[info.stackHeight-2].isOfType(type))
+ throw new VerifyException(instr.getDescription());
+ } else {
+ info.need(1);
+ if (!info.stack[info.stackHeight-1].isOfType(type))
+ throw new VerifyException(instr.getDescription());
+ }
+ break;
+ }
+ case opc_ishl: case opc_lshl:
+ case opc_ishr: case opc_lshr:
+ case opc_iushr: case opc_lushr:
+ if (!info.pop().isOfType(tInt))
+ throw new VerifyException(instr.getDescription());
+
+ if ((opcode & 1) != 0) {
+ info.need(2);
+ if (info.stack[info.stackHeight-1] != tSecondPart ||
+ !info.stack[info.stackHeight-2].isOfType(tLong))
+ throw new VerifyException(instr.getDescription());
+ } else {
+ info.need(1);
+ if (!info.stack[info.stackHeight-1].isOfType(tInt))
+ throw new VerifyException(instr.getDescription());
+ }
+ break;
+
+ case opc_iand: case opc_land:
+ case opc_ior : case opc_lor :
+ case opc_ixor: case opc_lxor:
+ if ((opcode & 1) != 0
+ && info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(types[opcode & 1]))
+ throw new VerifyException(instr.getDescription());
+ if ((opcode & 1) != 0) {
+ info.need(2);
+ if (info.stack[info.stackHeight-1] != tSecondPart
+ || !info.stack[info.stackHeight-2].isOfType(tLong))
+ throw new VerifyException(instr.getDescription());
+ } else {
+ info.need(1);
+ if (!info.stack[info.stackHeight-1].isOfType(tInt))
+ throw new VerifyException(instr.getDescription());
+ }
+ break;
+
+ case opc_iinc:
+ if (!info.locals[instr.getLocalSlot()].isOfType(tInt))
+ throw new VerifyException(instr.getDescription());
+ break;
+ case opc_i2l: case opc_i2f: case opc_i2d:
+ case opc_l2i: case opc_l2f: case opc_l2d:
+ case opc_f2i: case opc_f2l: case opc_f2d:
+ case opc_d2i: case opc_d2l: case opc_d2f: {
+ int from = (opcode-opc_i2l)/3;
+ int to = (opcode-opc_i2l)%3;
+ if (to >= from)
+ to++;
+ if ((from & 1) != 0
+ && info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(types[from]))
+ throw new VerifyException(instr.getDescription());
+
+ info.push(types[to]);
+ if ((to & 1) != 0)
+ info.push(tSecondPart);
+ break;
+ }
+ case opc_i2b: case opc_i2c: case opc_i2s:
+ info.need(1);
+ if (!info.stack[info.stackHeight-1].isOfType(tInt))
+ throw new VerifyException(instr.getDescription());
+ break;
+
+ case opc_lcmp:
+ if (info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(tLong))
+ throw new VerifyException(instr.getDescription());
+ if (info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(tLong))
+ throw new VerifyException(instr.getDescription());
+ info.push(tInt);
+ break;
+ case opc_dcmpl: case opc_dcmpg:
+ if (info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(tDouble))
+ throw new VerifyException(instr.getDescription());
+ if (info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(tDouble))
+ throw new VerifyException(instr.getDescription());
+ info.push(tInt);
+ break;
+ case opc_fcmpl: case opc_fcmpg:
+ if (!info.pop().isOfType(tFloat))
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(tFloat))
+ throw new VerifyException(instr.getDescription());
+ info.push(tInt);
+ break;
+
+ case opc_ifeq: case opc_ifne:
+ case opc_iflt: case opc_ifge:
+ case opc_ifgt: case opc_ifle:
+ case opc_tableswitch:
+ case opc_lookupswitch:
+ if (!info.pop().isOfType(tInt))
+ throw new VerifyException(instr.getDescription());
+ break;
+
+ case opc_if_icmpeq: case opc_if_icmpne:
+ case opc_if_icmplt: case opc_if_icmpge:
+ case opc_if_icmpgt: case opc_if_icmple:
+ if (!info.pop().isOfType(tInt))
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(tInt))
+ throw new VerifyException(instr.getDescription());
+ break;
+ case opc_if_acmpeq: case opc_if_acmpne:
+ if (!info.pop().isOfType(tType("+")))
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(tType("+")))
+ throw new VerifyException(instr.getDescription());
+ break;
+ case opc_ifnull: case opc_ifnonnull:
+ if (!info.pop().isOfType(tType("+")))
+ throw new VerifyException(instr.getDescription());
+ break;
+
+ case opc_ireturn: case opc_lreturn:
+ case opc_freturn: case opc_dreturn: case opc_areturn: {
+ if (((1 << opcode - opc_ireturn) & 0xa) != 0
+ && info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ Type type = info.pop();
+ if (!type.isOfType(types[opcode - opc_ireturn])
+ || !type.isOfType(returnType))
+ throw new VerifyException(instr.getDescription());
+ break;
+ }
+ case opc_jsr:
+ case opc_ret:
+ // handled in main loop
+ break;
+ case opc_return:
+ if (!returnType.typeSig.equals("V"))
+ throw new VerifyException(instr.getDescription());
+ break;
+ case opc_getstatic: {
+ Reference ref = instr.getReference();
+ String type = ref.getType();
+ info.push(tType(type));
+ if (TypeSignature.getTypeSize(type) == 2)
+ info.push(tSecondPart);
+ break;
+ }
+ case opc_getfield: {
+ Reference ref = instr.getReference();
+ Type classType = tType(ref.getClazz());
+ if (!info.pop().isOfType(classType))
+ throw new VerifyException(instr.getDescription());
+ String type = ref.getType();
+ info.push(tType(type));
+ if (TypeSignature.getTypeSize(type) == 2)
+ info.push(tSecondPart);
+ break;
+ }
+ case opc_putstatic: {
+ Reference ref = instr.getReference();
+ String type = ref.getType();
+ if (TypeSignature.getTypeSize(type) == 2
+ && info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(tType(type)))
+ throw new VerifyException(instr.getDescription());
+ break;
+ }
+ case opc_putfield: {
+ Reference ref = instr.getReference();
+ String type = ref.getType();
+ if (TypeSignature.getTypeSize(type) == 2
+ && info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(tType(type)))
+ throw new VerifyException(instr.getDescription());
+ Type classType = tType(ref.getClazz());
+ if (!info.pop().isOfType(classType))
+ throw new VerifyException(instr.getDescription());
+ break;
+ }
+ case opc_invokevirtual:
+ case opc_invokespecial:
+ case opc_invokestatic :
+ case opc_invokeinterface: {
+ Reference ref = instr.getReference();
+ String refmt = ref.getType();
+ String[] paramTypes = TypeSignature.getParameterTypes(refmt);
+ for (int i=paramTypes.length - 1; i >= 0; i--) {
+ if (TypeSignature.getTypeSize(paramTypes[i]) == 2
+ && info.pop() != tSecondPart)
+ throw new VerifyException(instr.getDescription());
+ if (!info.pop().isOfType(tType(paramTypes[i])))
+ throw new VerifyException(instr.getDescription());
+ }
+ if (ref.getName().equals("")) {
+ Type clazz = info.pop();
+ String typeSig = clazz.getTypeSig();
+ String refClazzSig = ref.getClazz();
+ Type refClazz = tType("N" + refClazzSig.substring(1));
+ if (opcode != opc_invokespecial
+ || refClazzSig.charAt(0) != 'L'
+ || !clazz.isOfType(refClazz))
+ throw new VerifyException(instr.getDescription());
+ Type newType = tType("L" + clazz.classInfo.getName()
+ .replace('.','/')+";");
+ for (int i=0; i< info.stackHeight; i++)
+ if (info.stack[i] == clazz)
+ info.stack[i] = newType;
+ for (int i=0; i< info.locals.length; i++)
+ if (info.locals[i] == clazz)
+ info.locals[i] = newType;
+ } else if (opcode != opc_invokestatic) {
+ Type classType = tType(ref.getClazz());
+ if (!info.pop().isOfType(classType))
+ throw new VerifyException(instr.getDescription());
+ }
+ String type = TypeSignature.getReturnType(refmt);
+ if (!type.equals("V")) {
+ info.push(tType(type));
+ if (TypeSignature.getTypeSize(type) == 2)
+ info.push(tSecondPart);
+ }
+ break;
+ }
+ case opc_new: {
+ String clName = instr.getClazzType();
+ info.stack[info.stackHeight++] =
+ tType("N" + clName.substring(1) + instr.hashCode());
+ break;
+ }
+ case opc_arraylength: {
+ if (!info.pop().isOfType(tType("[*")))
+ throw new VerifyException(instr.getDescription());
+ info.push(tInt);
+ break;
+ }
+ case opc_athrow: {
+ if (!info.pop().isOfType(tType("Ljava/lang/Throwable;")))
+ throw new VerifyException(instr.getDescription());
+ break;
+ }
+ case opc_checkcast: {
+ Type classType = tType(instr.getClazzType());
+ if (!info.pop().isOfType(tType("+")))
+ throw new VerifyException(instr.getDescription());
+ info.push(classType);
+ break;
+ }
+ case opc_instanceof: {
+ if (!info.pop().isOfType(tType("Ljava/lang/Object;")))
+ throw new VerifyException(instr.getDescription());
+ info.push(tInt);
+ break;
+ }
+ case opc_monitorenter:
+ case opc_monitorexit:
+ if (!info.pop().isOfType(tType("Ljava/lang/Object;")))
+ throw new VerifyException(instr.getDescription());
+ break;
+ case opc_multianewarray: {
+ int dimension = instr.getDimensions();
+ for (int i=dimension - 1; i >= 0; i--)
+ if (!info.pop().isOfType(tInt))
+ throw new VerifyException(instr.getDescription());
+ Type classType = tType(instr.getClazzType());
+ info.push(classType);
+ break;
+ }
+ default:
+ throw new AssertError("Invalid opcode "+opcode);
+ }
+ }
+
+ /* We manually program a bitset, since the best features are
+ * missing in jdk 1.1.
+ */
+ private class MyBitSet {
+ int[] data;
+ // This is always smaller than the first set bit.
+ int firstBit;
+
+ public MyBitSet(int maxLength) {
+ data = new int[(maxLength + 31) / 32];
+ firstBit = 0;
+ }
+
+ public void set(int bit) {
+ data[bit >> 5] |= 1 << (bit & 0x1f);
+ if (bit < firstBit)
+ firstBit = bit;
+ }
+
+ public void clear(int bit) {
+ data[bit >> 5] &= ~(1 << (bit & 0x1f));
+ }
+
+ public int findFirst() {
+ int first = firstBit >> 5;
+ while (data[first] == 0) {
+ first++;
+ firstBit = first << 5;
+ }
+ int bitmask = data[first] >> (firstBit & 0x1f);
+ while ((bitmask & 1) == 0) {
+ bitmask >>= 1;
+ firstBit++;
+ }
+ return firstBit;
+ }
+
+ public boolean isEmpty() {
+ for (int i = firstBit >> 5; i < data.length; i++) {
+ if (data[i] != 0)
+ return false;
+ }
+ return true;
+ }
+ }
+
+ private void doVerify() throws VerifyException {
+ Block[] blocks = bb.getBlocks();
+ int len = blocks.length;
+ verifyInfos = new VerifyInfo[len];
+ beforeJsrs = new VerifyInfo[len];
+ subInfos = new SubroutineInfo[len];
+
+ MyBitSet todoSet = new MyBitSet(blocks.length);
+ Block firstBlock = bb.getStartBlock();
+ if (firstBlock == null) {
+ /* empty method is okay */
+ return;
+ }
+ verifyInfos[firstBlock.getBlockNr()] = initInfo();
+ todoSet.set(firstBlock.getBlockNr());
+ while (!todoSet.isEmpty()) {
+ int blockNr = todoSet.findFirst();
+ todoSet.clear(blockNr);
+ Block block = blocks[blockNr];
+ VerifyInfo info = (VerifyInfo) verifyInfos[blockNr].clone();
+
+ Handler[] catchers = block.getCatchers();
+ if (catchers.length > 0) {
+ VerifyInfo excInfo = (VerifyInfo) info.clone();
+
+ for (int j = 0; j < info.locals.length; j++) {
+ if (info.locals[j].getTypeSig().charAt(0) == 'N')
+ throw new VerifyException
+ ("Uninitialized local in try block");
+ }
+ excInfo.stackHeight = 1;
+ for (int i=0; i < catchers.length; i++) {
+ String type = catchers[i].getType();
+ if (type != null)
+ excInfo.stack[0] =
+ tType("L" + type.replace('.', '/') + ";");
+ else
+ excInfo.stack[0]
+ = tType("Ljava/lang/Throwable;");
+ Block catcher = catchers[i].getCatcher();
+ if (mergeInfo(catcher, excInfo))
+ todoSet.set(catcher.getBlockNr());
+ }
+ }
+
+
+ Instruction instr = null;
+ Iterator iter = block.getInstructions().iterator();
+ while (iter.hasNext()) {
+ instr = (Instruction) iter.next();
+ modelEffect(instr, info);
+
+ if (catchers.length > 0 && instr.isStore()) {
+ for (int i=0; i < catchers.length; i++) {
+ int slot = instr.getLocalSlot();
+ if (info.locals[slot].getTypeSig().charAt(0) == 'N')
+ throw new VerifyException
+ ("Uninitialized local in try block");
+
+ Block catcher = catchers[i].getCatcher();
+ int catcherNr = catcher.getBlockNr();
+ VerifyInfo oldInfo = verifyInfos[catcherNr];
+ Type newType = oldInfo.locals[slot]
+ .mergeType(this, info.locals[slot]);
+ if (!newType.equals(oldInfo.locals[slot])) {
+ oldInfo.locals[slot] = newType;
+ todoSet.set(catcherNr);
+ }
+ }
+ }
+ }
+
+ int opcode = instr.getOpcode();
+ if (opcode == opc_jsr) {
+ Block jsrTarget = block.getSuccs()[0];
+ Block nextBlock = block.getSuccs()[1];
+
+ if (info.jsrInfo != null) {
+ // Check for recursive jsrs.
+ for (JsrUsedInfo jui = info.jsrInfo;
+ jui != null;
+ jui = subInfos[jui.jsrTarget.getBlockNr()]
+ .prevInfo) {
+ // Don't assume this is recursive, but assume
+ // that the previous rets were left instead.
+ //XXXXXXXXXXXXXXXXX
+ if (jui.jsrTarget == jsrTarget) {
+ // This is a recursive jsr. Or the previous
+ // invocation of the jsr terminated without a
+ // ret. We forbid this! XXX I think this too
+ // harsh, but doing it right is very difficult,
+ // so I stay on secure side.
+ throw new VerifyException("Recursive JSR!");
+ }
+ }
+ }
+
+ // Create the VerifyInfo for the state after the jsr
+ // is performed.
+ VerifyInfo targetInfo = (VerifyInfo) info.clone();
+ targetInfo.push(tType(jsrTarget));
+ targetInfo.jsrInfo
+ = new JsrUsedInfo(jsrTarget, new BitSet());
+ // Merge the target info
+ if (mergeInfo(jsrTarget, targetInfo))
+ todoSet.set(jsrTarget.getBlockNr());
+
+ SubroutineInfo subInfo = subInfos[jsrTarget.getBlockNr()];
+ // Create the subroutine info if it doesn't yet exists.
+ if (subInfo == null) {
+ subInfo = new SubroutineInfo();
+ subInfos[jsrTarget.getBlockNr()] = subInfo;
+ if (info.jsrInfo != null)
+ subInfo.prevInfo = new JsrUsedInfo(info.jsrInfo);
+ } else {
+ boolean changed;
+ if (info.jsrInfo != null) {
+ changed = mergeJsrTarget
+ (subInfo.prevInfo, info.jsrInfo);
+ if (subInfo.prevInfo.jsrTarget == null)
+ subInfo.prevInfo = null;
+ } else {
+ subInfo.prevInfo = null;
+ changed = true;
+ }
+ if (changed
+ && subInfos[jsrTarget.getBlockNr()].retBlock != null)
+ todoSet.set(subInfos[jsrTarget.getBlockNr()]
+ .retBlock.getBlockNr());
+ }
+
+ if (nextBlock != null) {
+ // Add our successor to the successor list.
+ subInfo.jsrSuccessors.set(nextBlock.getBlockNr());
+
+ if (subInfo.retInfo != null) {
+ // The jsr target already knows its return
+ // instruction, we do the ret merging immediately
+ VerifyInfo retInfo = subInfo.retInfo;
+ info.stack = retInfo.stack;
+ info.stackHeight = retInfo.stackHeight;
+ if (subInfo.prevInfo != null)
+ info.jsrInfo = new JsrUsedInfo(subInfo.prevInfo);
+ else
+ info.jsrInfo = null;
+ BitSet usedLocals = subInfo.usedLocals;
+ for (int j = 0; j < bb.getMaxLocals(); j++) {
+ if (usedLocals.get(j))
+ info.locals[j] = retInfo.locals[j];
+ }
+ if (mergeInfo(nextBlock, info))
+ todoSet.set(nextBlock.getBlockNr());
+ } else {
+ beforeJsrs[nextBlock.getBlockNr()] = info;
+ }
+ }
+ } else if (opcode == opc_ret) {
+ Type retVarType = info.locals[instr.getLocalSlot()];
+ if (info.jsrInfo == null || !retVarType.isOfType(tType("R")))
+ throw new VerifyException(instr.getDescription());
+ Block jsrTarget = retVarType.getJsrTarget();
+ BitSet usedLocals = (BitSet) info.jsrInfo.jsrUsed;
+ for (Block lastTarget = info.jsrInfo.jsrTarget;
+ jsrTarget != lastTarget;
+ lastTarget = subInfos[lastTarget.getBlockNr()]
+ .prevInfo.jsrTarget) {
+ if (lastTarget == null)
+ throw new VerifyException("returned to a leaved jsr");
+ usedLocals.or(subInfos[lastTarget.getBlockNr()]
+ .prevInfo.jsrUsed);
+ }
+
+ SubroutineInfo subInfo = subInfos[jsrTarget.getBlockNr()];
+ if (subInfo.retBlock != null && subInfo.retBlock != block)
+ throw new VerifyException
+ ("JsrTarget has more than one ret: " + jsrTarget);
+ subInfo.retInfo = info;
+ subInfo.usedLocals = usedLocals;
+ for (int i=0; i < blocks.length; i++) {
+ if (subInfo.jsrSuccessors.get(i)) {
+ VerifyInfo afterJsrInfo;
+ // If this was the first time, copy the info before
+ // the jsr.
+ if (subInfo.retBlock == null) {
+ afterJsrInfo = beforeJsrs[i];
+ // Check if the infos are mergeable,
+ // i.e. the items on the stack match.
+ // This isn't specified by the virtual
+ // machine specification, but it would be
+ // really bad, if we have to support such
+ // weird jsrs. The decompiler doesn't
+ // like them!
+ if (afterJsrInfo.stackHeight
+ != info.stackHeight)
+ throw new VerifyException
+ ("Stack height differ after jsr to: "
+ + jsrTarget);
+ for (int k = 0; k < info.stackHeight; k++) {
+ if (info.stack[i].mergeType
+ (this, afterJsrInfo.stack[k]) == tNone)
+ throw new VerifyException
+ ("Type error while"+
+ " merging stacks after jsr");
+ }
+ } else
+ afterJsrInfo = (VerifyInfo) verifyInfos[i].clone();
+
+ afterJsrInfo.stack = info.stack;
+ afterJsrInfo.stackHeight = info.stackHeight;
+ afterJsrInfo.jsrInfo = subInfo.prevInfo;
+ if (subInfo.prevInfo != null)
+ afterJsrInfo.jsrInfo
+ = new JsrUsedInfo(subInfo.prevInfo);
+ else
+ afterJsrInfo.jsrInfo = null;
+ for (int j = 0; j < bb.getMaxLocals(); j++) {
+ if (usedLocals.get(j))
+ afterJsrInfo.locals[j] = info.locals[j];
+ }
+ if (mergeInfo(blocks[i], afterJsrInfo))
+ todoSet.set(i);
+ }
+ }
+ subInfo.retBlock = block;
+ } else {
+ Block[] succs = block.getSuccs();
+ for (int i=0; i< succs.length; i++) {
+ Block succ = succs[i];
+ if (succ == null) {
+ if (info.stackHeight != 0)
+ throw new VerifyException();
+ continue;
+ }
+
+ /* We don't need to check for uninitialized objects
+ * in back-branch. The reason is the following:
+ *
+ * An uninitialized object can't merge with anything
+ * else, so if this is really a back-branch to already
+ * analyzed code, the uninitialized object will simply
+ * vanish to unknown on the merge.
+ */
+ if (mergeInfo(succ, info))
+ todoSet.set(succ.getBlockNr());
+ }
+ }
+ }
+
+ if ((GlobalOptions.debuggingFlags
+ & GlobalOptions.DEBUG_VERIFIER) != 0) {
+ dumpInfo(GlobalOptions.err);
+ }
+ }
+
+ public void verify() throws VerifyException {
+ try {
+ doVerify();
+ } catch (VerifyException ex) {
+ dumpInfo(GlobalOptions.err);
+ throw ex;
+ } catch (RuntimeException ex) {
+ dumpInfo(GlobalOptions.err);
+ throw ex;
+ }
+ }
+}
diff --git a/jode/jode/jvm/CodeVerifier.java.in b/jode/jode/jvm/CodeVerifier.java.in
deleted file mode 100644
index 556902f..0000000
--- a/jode/jode/jvm/CodeVerifier.java.in
+++ /dev/null
@@ -1,1127 +0,0 @@
-/* CodeVerifier 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.jvm;
-import jode.AssertError;
-import jode.GlobalOptions;
-import jode.bytecode.BytecodeInfo;
-import jode.bytecode.ClassInfo;
-import jode.bytecode.Handler;
-import jode.bytecode.Instruction;
-import jode.bytecode.MethodInfo;
-import jode.bytecode.Opcodes;
-import jode.bytecode.Reference;
-import jode.bytecode.TypeSignature;
-
-import java.util.BitSet;
-import @COLLECTIONS@.Iterator;
-import @COLLECTIONS@.HashSet;
-import @COLLECTIONS@.List;
-import @COLLECTIONS@.ArrayList;
-
-public class CodeVerifier implements Opcodes {
- ClassInfo ci;
- MethodInfo mi;
- BytecodeInfo bi;
-
- String methodType;
- String returnType;
-
- static Type tNull = Type.tType("0");
- static Type tInt = Type.tType("I");
- static Type tLong = Type.tType("J");
- static Type tFloat = Type.tType("F");
- static Type tDouble = Type.tType("D");
- static Type tString = Type.tType("Ljava/lang/String;");
- static Type tNone = Type.tType("?");
- static Type tSecondPart = new Type("2");
- static Type tObject = new Type("Ljava/lang/Object;");
-
-
- /**
- * We need some more types, than mentioned in jvm.
- */
- private static class Type {
- /* "ZBCSIFJD" are the normal primitive types.
- * "L...;" is normal class type.
- * "[..." is normal array type
- * "?" stands for type error
- * "N...;" stands for new uninitialized type.
- * "0" stands for null type.
- * "R" stands for return address type.
- * "2" stands for second half of a two word type.
- */
- private String typeSig;
-
- /**
- * The dependant instruction. This has two usages:
- * - "N...;"
- * - The new instruction, or null if this is the this param
- * of <init>.
- * - "R"
- The target of the jsr.
- */
- private Instruction instr;
-
- public Type(String typeSig) {
- this.typeSig = typeSig;
- }
-
- public Type(String typeSig, Instruction instr) {
- this.typeSig = typeSig;
- this.instr = instr;
- }
-
- public static Type tType(String typeSig) {
- // unify them?
- return new Type(typeSig);
- }
-
- public static Type tType(String typeSig, Instruction instr) {
- // unify them?
- return new Type(typeSig, instr);
- }
-
- public String getTypeSig() {
- return typeSig;
- }
-
- public Instruction getInstruction() {
- return instr;
- }
-
- /**
- * @param t2 the type signature of the type to check for.
- * This may be one of the special signatures:
- *
- "[*"
- array of something
- * - "+"
- (uninitialized) object/returnvalue type
- * - "2", "R"
- as the typeSig parameter
- *
- * @return true, iff this is castable to t2 by a
- * widening cast. */
- public boolean isOfType(String destSig) {
- String thisSig = typeSig;
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_VERIFIER) != 0)
- GlobalOptions.err.println("isOfType("+thisSig+","+destSig+")");
- if (thisSig.equals(destSig))
- return true;
-
- char c1 = thisSig.charAt(0);
- char c2 = destSig.charAt(0);
- switch (c2) {
- case 'Z': case 'B': case 'C': case 'S': case 'I':
- /* integer type */
- return ("ZBCSI".indexOf(c1) >= 0);
- case '+':
- return ("L[nNR0".indexOf(c1) >= 0);
-
- case '[':
- if (c1 == '0')
- return true;
- while (c1 == '[' && c2 == '[') {
- thisSig = thisSig.substring(1);
- destSig = destSig.substring(1);
- c1 = thisSig.charAt(0);
- c2 = destSig.charAt(0);
- }
-
- if (c2 == '*')
- /* destType is array of unknowns */
- return true;
- /* Note that short[] is only compatible to short[],
- * therefore we only need to handle Object types specially.
- */
-
- if (c2 != 'L')
- return false;
- /* fall through*/
- case 'L':
- if (c1 == '0')
- return true;
- if ("L[".indexOf(c1) < 0)
- return false;
-
- ClassInfo wantedType = TypeSignature.getClassInfo(destSig);
- if (wantedType.isInterface()
- || wantedType == ClassInfo.javaLangObject)
- return true;
- if (c1 == 'L')
- return wantedType.superClassOf(TypeSignature
- .getClassInfo(thisSig));
- }
- return false;
- }
-
- /**
- * @return The common super type of this and type2.
- */
- public Type mergeType(Type type2) {
- String sig1 = typeSig;
- String sig2 = type2.typeSig;
-
- if (this.equals(type2))
- return this;
-
- char c1 = sig1.charAt(0);
- char c2 = sig2.charAt(0);
- if (c1 == '*')
- return type2;
- if (c2 == '*')
- return this;
- if ("ZBCSI".indexOf(c1) >= 0 && "ZBCSI".indexOf(c2) >= 0)
- return this;
-
- if (c1 == '0')
- return ("L[0".indexOf(c2) >= 0) ? type2 : tNone;
- if (c2 == '0')
- return ("L[".indexOf(c1) >= 0) ? this : tNone;
-
-
- int dimensions = 0;
- /* Note that short[] is only compatible to short[],
- * therefore we make the array handling after the primitive
- * type handling. Also note that we don't allow arrays of
- * special types.
- */
- while (c1 == '[' && c2 == '[') {
- sig1 = sig1.substring(1);
- sig2 = sig2.substring(1);
- c1 = sig1.charAt(0);
- c2 = sig2.charAt(0);
- dimensions++;
- }
-
- if (c1 == '[' || c2 == '[') {
- // Only one of them is array now, the other must be an
- // object, the common super is tObject
- if (c1 == 'L' || c2 == 'L') {
- if (dimensions == 0)
- return tObject;
- StringBuffer result = new StringBuffer(dimensions + 18);
- for (int i=0; i< dimensions; i++)
- result.append("[");
- result.append("Ljava/lang/Object;");
- return tType(result.toString());
- }
- return tNone;
- }
-
- if (c1 == 'L' && c2 == 'L') {
- ClassInfo clazz1 = TypeSignature.getClassInfo(sig1);
- ClassInfo clazz2 = TypeSignature.getClassInfo(sig2);
- if (clazz1.superClassOf(clazz2))
- return this;
- if (clazz2.superClassOf(clazz1))
- return type2;
- do {
- clazz1 = clazz1.getSuperclass();
- } while (!clazz1.superClassOf(clazz2));
- StringBuffer result = new StringBuffer
- (dimensions + clazz1.getName().length() + 2);
- for (int i=0; i< dimensions; i++)
- result.append("[");
- result.append("L")
- .append(clazz1.getName().replace('.', '/')).append(";");
- return tType(result.toString());
- }
- return tNone;
- }
-
- public boolean equals(Object other) {
- if (other instanceof Type) {
- Type type2 = (Type) other;
- return typeSig.equals(type2.typeSig)
- && instr == type2.instr;
- }
- return false;
- }
-
- public String toString() {
- if (instr != null)
- return typeSig+"@"+instr.getAddr();
- return typeSig;
- }
- }
-
- /**
- * JLS 4.9.6: Verifying code that contains a finally clause:
- * - Each instruction keeps track of the list of jsr targets.
- * - For each instruction and each jsr needed to reach that instruction
- * a bit vector is maintained of all local vars accessed or modified.
- */
-
- class VerifyInfo implements Cloneable {
- Type[] stack = new Type[bi.getMaxStack()];
- Type[] locals = new Type[bi.getMaxLocals()];
- Instruction[] jsrTargets = null;
- BitSet[] jsrLocals = null;
- int stackHeight = 0;
- int maxHeight = 0;
- /* If this is a jsr target, this field contains the single
- * allowed ret instruction.
- */
- Instruction retInstr = null;
-
- public Object clone() {
- try {
- VerifyInfo result = (VerifyInfo) super.clone();
- result.stack = (Type[]) stack.clone();
- result.locals = (Type[]) locals.clone();
- return result;
- } catch(CloneNotSupportedException ex) {
- throw new AssertError("Clone not supported?");
- }
- }
-
- public final void reserve(int count) throws VerifyException {
- if (stackHeight + count > maxHeight) {
- maxHeight = stackHeight + count;
- if (maxHeight > stack.length)
- throw new VerifyException("stack overflow");
- }
- }
-
- public final void need(int count) throws VerifyException {
- if (stackHeight < count)
- throw new VerifyException("stack underflow");
- }
-
- public final void push(Type type) throws VerifyException {
- reserve(1);
- stack[stackHeight++] = type;
- }
-
- public final Type pop() throws VerifyException {
- need(1);
- return stack[--stackHeight];
- }
-
- public String toString() {
- StringBuffer result = new StringBuffer("locals:[");
- String comma = "";
- for (int i=0; i"))
- info.locals[slot++] = Type.tType("N"+ clazzName+";", null);
- else
- info.locals[slot++] = Type.tType("L"+ clazzName+";");
- }
- while (methodType.charAt(pos) != ')') {
- int start = pos;
- pos = TypeSignature.skipType(methodType, pos);
- String paramType = methodType.substring(start, pos);
- info.locals[slot++] = Type.tType(paramType);
- if (TypeSignature.getTypeSize(paramType) == 2)
- info.locals[slot++] = tSecondPart;
- }
- while (slot < bi.getMaxLocals())
- info.locals[slot++] = tNone;
- return info;
- }
-
- public boolean mergeInfo(Instruction instr, VerifyInfo info)
- throws VerifyException {
- if (instr.getTmpInfo() == null) {
- instr.setTmpInfo(info);
- return true;
- }
- boolean changed = false;
- VerifyInfo oldInfo = (VerifyInfo) instr.getTmpInfo();
- if (oldInfo.stackHeight != info.stackHeight)
- throw new VerifyException("Stack height differ at: "
- + instr.getDescription());
- for (int i=0; i < oldInfo.stackHeight; i++) {
- Type newType = oldInfo.stack[i].mergeType(info.stack[i]);
- if (!newType.equals(oldInfo.stack[i])) {
- if (newType == tNone)
- throw new VerifyException("Type error while merging: "
- + oldInfo.stack[i]
- + " and " + info.stack[i]);
- changed = true;
- oldInfo.stack[i] = newType;
- }
- }
- for (int i=0; i < bi.getMaxLocals(); i++) {
- Type newType = oldInfo.locals[i].mergeType(info.locals[i]);
- if (!newType.equals(oldInfo.locals[i])) {
- changed = true;
- oldInfo.locals[i] = newType;
- }
- }
- if (oldInfo.jsrTargets != null) {
- int jsrDepth;
- if (info.jsrTargets == null)
- jsrDepth = 0;
- else {
- jsrDepth = info.jsrTargets.length;
- int infoPtr = 0;
- oldInfo_loop:
- for (int oldInfoPtr=0;
- oldInfoPtr < oldInfo.jsrTargets.length; oldInfoPtr++) {
- for (int i=infoPtr; i< jsrDepth; i++) {
- if (oldInfo.jsrTargets[oldInfoPtr]
- == info.jsrTargets[i]) {
- System.arraycopy(info.jsrTargets, i,
- info.jsrTargets, infoPtr,
- jsrDepth - i);
- jsrDepth -= (i - infoPtr);
- infoPtr++;
- continue oldInfo_loop;
- }
- }
- }
- jsrDepth = infoPtr;
- }
- if (jsrDepth != oldInfo.jsrTargets.length) {
- if (jsrDepth == 0)
- oldInfo.jsrTargets = null;
- else {
- oldInfo.jsrTargets = new Instruction[jsrDepth];
- System.arraycopy(info.jsrTargets, 0,
- oldInfo.jsrTargets, 0, jsrDepth);
- }
- changed = true;
- }
- }
- return changed;
- }
-
-
- String[] types = {
- "I", "J", "F", "D", "+", "B", "C", "S"
- };
- String[] arrayTypes = {
- "[I", "[J", "[F", "[D", "[Ljava/lang/Object;", "[B", "[C", "[S"
- };
-
- public VerifyInfo modelEffect(Instruction instr, VerifyInfo prevInfo)
- throws VerifyException {
- int jsrLength =
- prevInfo.jsrTargets != null ? prevInfo.jsrTargets.length : 0;
- VerifyInfo result = (VerifyInfo) prevInfo.clone();
- int opcode = instr.getOpcode();
- switch (opcode) {
- case opc_nop:
- case opc_goto:
- break;
- case opc_ldc: {
- Type type;
- Object constant = instr.getConstant();
- if (constant == null)
- type = tNull;
- else if (constant instanceof Integer)
- type = tInt;
- else if (constant instanceof Float)
- type = tFloat;
- else
- type = tString;
- result.push(type);
- break;
- }
- case opc_ldc2_w: {
- Type type;
- Object constant = instr.getConstant();
- if (constant instanceof Long)
- type = tLong;
- else
- type = tDouble;
- result.push(type);
- result.push(tSecondPart);
- break;
- }
- case opc_iload:
- case opc_lload:
- case opc_fload:
- case opc_dload:
- case opc_aload: {
- if (jsrLength > 0
- && (!result.jsrLocals[jsrLength-1].get(instr.getLocalSlot())
- || ((opcode & 0x1) == 0
- && !result.jsrLocals[jsrLength-1]
- .get(instr.getLocalSlot()+1)))) {
- result.jsrLocals = (BitSet[]) result.jsrLocals.clone();
- result.jsrLocals[jsrLength-1]
- = (BitSet) result.jsrLocals[jsrLength-1].clone();
- result.jsrLocals[jsrLength-1].set(instr.getLocalSlot());
- if ((opcode & 0x1) == 0)
- result.jsrLocals[jsrLength-1].set(instr.getLocalSlot() + 1);
- }
- if ((opcode & 0x1) == 0
- && result.locals[instr.getLocalSlot()+1] != tSecondPart)
- throw new VerifyException(instr.getDescription());
- Type type = result.locals[instr.getLocalSlot()];
- if (!type.isOfType(types[opcode - opc_iload]))
- throw new VerifyException(instr.getDescription());
- result.push(type);
- if ((opcode & 0x1) == 0)
- result.push(tSecondPart);
- break;
- }
- case opc_iaload: case opc_laload:
- case opc_faload: case opc_daload: case opc_aaload:
- case opc_baload: case opc_caload: case opc_saload: {
- if (!result.pop().isOfType("I"))
- throw new VerifyException(instr.getDescription());
- Type arrType = result.pop();
- if (!arrType.isOfType(arrayTypes[opcode - opc_iaload])
- && (opcode != opc_baload
- || !arrType.isOfType("[Z")))
- throw new VerifyException(instr.getDescription());
-
- String typeSig = arrType.getTypeSig();
- Type elemType = (typeSig.charAt(0) == '['
- ? Type.tType(typeSig.substring(1))
- : (opcode == opc_aaload ? tNull
- : Type.tType(types[opcode - opc_iaload])));
- result.push(elemType);
- if (((1 << opcode - opc_iaload) & 0xa) != 0)
- result.push(tSecondPart);
- break;
- }
- case opc_istore: case opc_lstore:
- case opc_fstore: case opc_dstore: case opc_astore: {
- if (jsrLength > 0
- && (!result.jsrLocals[jsrLength-1].get(instr.getLocalSlot())
- || ((opcode & 0x1) != 0
- && !result.jsrLocals[jsrLength-1]
- .get(instr.getLocalSlot()+1)))) {
- result.jsrLocals = (BitSet[]) result.jsrLocals.clone();
- result.jsrLocals[jsrLength-1]
- = (BitSet) result.jsrLocals[jsrLength-1].clone();
- result.jsrLocals[jsrLength-1].set(instr.getLocalSlot());
- if ((opcode & 0x1) != 0)
- result.jsrLocals[jsrLength-1].set(instr.getLocalSlot() + 1);
- }
- if ((opcode & 0x1) != 0
- && result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- Type type = result.pop();
- if (!type.isOfType(types[opcode - opc_istore]))
- if (opcode != opc_astore || !type.isOfType("R"))
- throw new VerifyException(instr.getDescription());
- result.locals[instr.getLocalSlot()] = type;
- if ((opcode & 0x1) != 0)
- result.locals[instr.getLocalSlot()+1] = tSecondPart;
- break;
- }
- case opc_iastore: case opc_lastore:
- case opc_fastore: case opc_dastore: case opc_aastore:
- case opc_bastore: case opc_castore: case opc_sastore: {
- if (((1 << opcode - opc_iastore) & 0xa) != 0
- && result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- Type type = result.pop();
- if (!result.pop().isOfType("I"))
- throw new VerifyException(instr.getDescription());
- Type arrType = result.pop();
- if (!arrType.isOfType(arrayTypes[opcode - opc_iastore])
- && (opcode != opc_bastore || !arrType.isOfType("[Z")))
- throw new VerifyException(instr.getDescription());
- String elemType = opcode >= opc_bastore ? "I"
- : types[opcode - opc_iastore];
- if (!type.isOfType(elemType))
- throw new VerifyException(instr.getDescription());
- break;
- }
- case opc_pop: case opc_pop2: {
- int count = opcode - (opc_pop-1);
- result.need(count);
- result.stackHeight -= count;
- break;
- }
- case opc_dup: case opc_dup_x1: case opc_dup_x2: {
- int depth = opcode - opc_dup;
- result.reserve(1);
- result.need(depth+1);
- if (result.stack[result.stackHeight-1] == tSecondPart)
- throw new VerifyException(instr.getDescription());
-
- int stackdepth = result.stackHeight - (depth + 1);
- if (result.stack[stackdepth] == tSecondPart)
- throw new VerifyException(instr.getDescription()
- + " on long or double");
- for (int i=result.stackHeight; i > stackdepth; i--)
- result.stack[i] = result.stack[i-1];
- result.stack[stackdepth] = result.stack[result.stackHeight++];
- break;
- }
- case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: {
- int depth = opcode - opc_dup2;
- result.reserve(2);
- result.need(depth+2);
- if (result.stack[result.stackHeight-2] == tSecondPart)
- throw new VerifyException(instr.getDescription()
- + " on misaligned long or double");
- int stacktop = result.stackHeight;
- int stackdepth = stacktop - (depth + 2);
- if (result.stack[stackdepth] == tSecondPart)
- throw new VerifyException(instr.getDescription()
- + " on long or double");
- for (int i=stacktop; i > stackdepth; i--)
- result.stack[i+1] = result.stack[i-1];
- result.stack[stackdepth+1] = result.stack[stacktop+1];
- result.stack[stackdepth] = result.stack[stacktop];
- result.stackHeight+=2;
- break;
- }
- case opc_swap: {
- result.need(2);
- if (result.stack[result.stackHeight-2] == tSecondPart
- || result.stack[result.stackHeight-1] == tSecondPart)
- throw new VerifyException(instr.getDescription()
- + " on misaligned long or double");
- Type tmp = result.stack[result.stackHeight-1];
- result.stack[result.stackHeight-1] =
- result.stack[result.stackHeight-2];
- result.stack[result.stackHeight-2] = tmp;
- break;
- }
- case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
- case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
- case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
- case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
- case opc_irem: case opc_lrem: case opc_frem: case opc_drem: {
- String type = types[(opcode - opc_iadd) & 3];
- if ((opcode & 1) != 0
- && result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType(type))
- throw new VerifyException(instr.getDescription());
- if ((opcode & 1) != 0) {
- result.need(2);
- if (result.stack[result.stackHeight-1] != tSecondPart
- || !result.stack[result.stackHeight-2].isOfType(type))
- throw new VerifyException(instr.getDescription());
- } else {
- result.need(1);
- if (!result.stack[result.stackHeight-1].isOfType(type))
- throw new VerifyException(instr.getDescription());
- }
- break;
- }
- case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: {
- String type = types[(opcode - opc_ineg) & 3];
- if ((opcode & 1) != 0) {
- result.need(2);
- if (result.stack[result.stackHeight-1] != tSecondPart
- || !result.stack[result.stackHeight-2].isOfType(type))
- throw new VerifyException(instr.getDescription());
- } else {
- result.need(1);
- if (!result.stack[result.stackHeight-1].isOfType(type))
- throw new VerifyException(instr.getDescription());
- }
- break;
- }
- case opc_ishl: case opc_lshl:
- case opc_ishr: case opc_lshr:
- case opc_iushr: case opc_lushr:
- if (!result.pop().isOfType("I"))
- throw new VerifyException(instr.getDescription());
-
- if ((opcode & 1) != 0) {
- result.need(2);
- if (result.stack[result.stackHeight-1] != tSecondPart ||
- !result.stack[result.stackHeight-2].isOfType("J"))
- throw new VerifyException(instr.getDescription());
- } else {
- result.need(1);
- if (!result.stack[result.stackHeight-1].isOfType("I"))
- throw new VerifyException(instr.getDescription());
- }
- break;
-
- case opc_iand: case opc_land:
- case opc_ior : case opc_lor :
- case opc_ixor: case opc_lxor:
- if ((opcode & 1) != 0
- && result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType(types[opcode & 1]))
- throw new VerifyException(instr.getDescription());
- if ((opcode & 1) != 0) {
- result.need(2);
- if (result.stack[result.stackHeight-1] != tSecondPart
- || !result.stack[result.stackHeight-2].isOfType("J"))
- throw new VerifyException(instr.getDescription());
- } else {
- result.need(1);
- if (!result.stack[result.stackHeight-1].isOfType("I"))
- throw new VerifyException(instr.getDescription());
- }
- break;
-
- case opc_iinc:
- if (!result.locals[instr.getLocalSlot()].isOfType("I"))
- throw new VerifyException(instr.getDescription());
- break;
- case opc_i2l: case opc_i2f: case opc_i2d:
- case opc_l2i: case opc_l2f: case opc_l2d:
- case opc_f2i: case opc_f2l: case opc_f2d:
- case opc_d2i: case opc_d2l: case opc_d2f: {
- int from = (opcode-opc_i2l)/3;
- int to = (opcode-opc_i2l)%3;
- if (to >= from)
- to++;
- if ((from & 1) != 0
- && result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType(types[from]))
- throw new VerifyException(instr.getDescription());
-
- result.push(Type.tType(types[to]));
- if ((to & 1) != 0)
- result.push(tSecondPart);
- break;
- }
- case opc_i2b: case opc_i2c: case opc_i2s:
- result.need(1);
- if (!result.stack[result.stackHeight-1].isOfType("I"))
- throw new VerifyException(instr.getDescription());
- break;
-
- case opc_lcmp:
- if (result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType("J"))
- throw new VerifyException(instr.getDescription());
- if (result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType("J"))
- throw new VerifyException(instr.getDescription());
- result.push(tInt);
- break;
- case opc_dcmpl: case opc_dcmpg:
- if (result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType("D"))
- throw new VerifyException(instr.getDescription());
- if (result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType("D"))
- throw new VerifyException(instr.getDescription());
- result.push(tInt);
- break;
- case opc_fcmpl: case opc_fcmpg:
- if (!result.pop().isOfType("F"))
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType("F"))
- throw new VerifyException(instr.getDescription());
- result.push(tInt);
- break;
-
- case opc_ifeq: case opc_ifne:
- case opc_iflt: case opc_ifge:
- case opc_ifgt: case opc_ifle:
- case opc_tableswitch:
- case opc_lookupswitch:
- if (!result.pop().isOfType("I"))
- throw new VerifyException(instr.getDescription());
- break;
-
- case opc_if_icmpeq: case opc_if_icmpne:
- case opc_if_icmplt: case opc_if_icmpge:
- case opc_if_icmpgt: case opc_if_icmple:
- if (!result.pop().isOfType("I"))
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType("I"))
- throw new VerifyException(instr.getDescription());
- break;
- case opc_if_acmpeq: case opc_if_acmpne:
- if (!result.pop().isOfType("+"))
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType("+"))
- throw new VerifyException(instr.getDescription());
- break;
- case opc_ifnull: case opc_ifnonnull:
- if (!result.pop().isOfType("+"))
- throw new VerifyException(instr.getDescription());
- break;
-
- case opc_ireturn: case opc_lreturn:
- case opc_freturn: case opc_dreturn: case opc_areturn: {
- if (((1 << opcode - opc_ireturn) & 0xa) != 0
- && result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- Type type = result.pop();
- if (!type.isOfType(types[opcode - opc_ireturn])
- || !type.isOfType(TypeSignature.getReturnType(methodType)))
- throw new VerifyException(instr.getDescription());
- break;
- }
- case opc_jsr: {
- Instruction jsrTarget = instr.getSingleSucc();
- result.stack[result.stackHeight++] = Type.tType("R", jsrTarget);
- result.jsrTargets = new Instruction[jsrLength+1];
- result.jsrLocals = new BitSet[jsrLength+1];
- if (jsrLength > 0) {
- for (int i=0; i< prevInfo.jsrTargets.length; i++)
- if (prevInfo.jsrTargets[i] == instr.getSingleSucc())
- throw new VerifyException(instr.getDescription()+
- " is recursive");
- System.arraycopy(prevInfo.jsrTargets, 0,
- result.jsrTargets, 0, jsrLength);
- System.arraycopy(prevInfo.jsrLocals, 0,
- result.jsrLocals, 0, jsrLength);
- }
- result.jsrTargets[jsrLength] = instr.getSingleSucc();
- result.jsrLocals[jsrLength] = new BitSet();
- break;
- }
- case opc_return:
- if (!returnType.equals("V"))
- throw new VerifyException(instr.getDescription());
- break;
- case opc_getstatic: {
- Reference ref = instr.getReference();
- String type = ref.getType();
- result.push(Type.tType(type));
- if (TypeSignature.getTypeSize(type) == 2)
- result.push(tSecondPart);
- break;
- }
- case opc_getfield: {
- Reference ref = instr.getReference();
- String classType = ref.getClazz();
- if (!result.pop().isOfType(classType))
- throw new VerifyException(instr.getDescription());
- String type = ref.getType();
- result.push(Type.tType(type));
- if (TypeSignature.getTypeSize(type) == 2)
- result.push(tSecondPart);
- break;
- }
- case opc_putstatic: {
- Reference ref = instr.getReference();
- String type = ref.getType();
- if (TypeSignature.getTypeSize(type) == 2
- && result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType(type))
- throw new VerifyException(instr.getDescription());
- break;
- }
- case opc_putfield: {
- Reference ref = instr.getReference();
- String type = ref.getType();
- if (TypeSignature.getTypeSize(type) == 2
- && result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType(type))
- throw new VerifyException(instr.getDescription());
- String classType = ref.getClazz();
- if (!result.pop().isOfType(classType))
- throw new VerifyException(instr.getDescription());
- break;
- }
- case opc_invokevirtual:
- case opc_invokespecial:
- case opc_invokestatic :
- case opc_invokeinterface: {
- Reference ref = instr.getReference();
- String refmt = ref.getType();
- String[] paramTypes = TypeSignature.getParameterTypes(refmt);
- for (int i=paramTypes.length - 1; i >= 0; i--) {
- if (TypeSignature.getTypeSize(paramTypes[i]) == 2
- && result.pop() != tSecondPart)
- throw new VerifyException(instr.getDescription());
- if (!result.pop().isOfType(paramTypes[i]))
- throw new VerifyException(instr.getDescription());
- }
- if (ref.getName().equals("")) {
- Type clazz = result.pop();
- String typeSig = clazz.getTypeSig();
- String refClazz = ref.getClazz();
- if (opcode != opc_invokespecial
- || typeSig.charAt(0) != 'N'
- || refClazz.charAt(0) != 'L')
- throw new VerifyException(instr.getDescription());
- if (!typeSig.substring(1).equals(refClazz.substring(1))) {
- ClassInfo uci = ClassInfo.forName
- (typeSig.substring(1, typeSig.length()-1)
- .replace('/', '.'));
- if (uci.getSuperclass()
- != TypeSignature.getClassInfo(refClazz)
- || clazz.getInstruction() != null)
- throw new VerifyException(instr.getDescription());
- }
- Type newType = Type.tType("L" + typeSig.substring(1));
- for (int i=0; i< result.stackHeight; i++)
- if (result.stack[i] == clazz)
- result.stack[i] = newType;
- for (int i=0; i< result.locals.length; i++)
- if (result.locals[i] == clazz)
- result.locals[i] = newType;
- } else if (opcode != opc_invokestatic) {
- String classType = ref.getClazz();
- if (!result.pop().isOfType(classType))
- throw new VerifyException(instr.getDescription());
- }
- String type = TypeSignature.getReturnType(refmt);
- if (!type.equals("V")) {
- result.push(Type.tType(type));
- if (TypeSignature.getTypeSize(type) == 2)
- result.push(tSecondPart);
- }
- break;
- }
- case opc_new: {
- String clName = instr.getClazzType();
- result.stack[result.stackHeight++] =
- Type.tType("N" + clName.substring(1), instr);
- break;
- }
- case opc_arraylength: {
- if (!result.pop().isOfType("[*"))
- throw new VerifyException(instr.getDescription());
- result.push(tInt);
- break;
- }
- case opc_athrow: {
- if (!result.pop().isOfType("Ljava/lang/Throwable;"))
- throw new VerifyException(instr.getDescription());
- break;
- }
- case opc_checkcast: {
- String classType = instr.getClazzType();
- if (!result.pop().isOfType("+"))
- throw new VerifyException(instr.getDescription());
- result.push(Type.tType(classType));
- break;
- }
- case opc_instanceof: {
- if (!result.pop().isOfType("Ljava/lang/Object;"))
- throw new VerifyException(instr.getDescription());
- result.push(tInt);
- break;
- }
- case opc_monitorenter:
- case opc_monitorexit:
- if (!result.pop().isOfType("Ljava/lang/Object;"))
- throw new VerifyException(instr.getDescription());
- break;
- case opc_multianewarray: {
- int dimension = instr.getDimensions();
- for (int i=dimension - 1; i >= 0; i--)
- if (!result.pop().isOfType("I"))
- throw new VerifyException(instr.getDescription());
- String classType = instr.getClazzType();
- result.push(Type.tType(classType));
- break;
- }
- default:
- throw new AssertError("Invalid opcode "+opcode);
- }
- return result;
- }
-
- public void doVerify() throws VerifyException {
- HashSet todoSet = new HashSet();
-
- Instruction firstInstr = (Instruction) bi.getInstructions().get(0);
- firstInstr.setTmpInfo(initInfo());
- todoSet.add(firstInstr);
- Handler[] handlers = bi.getExceptionHandlers();
- while (!todoSet.isEmpty()) {
- Iterator iter = todoSet.iterator();
- Instruction instr = (Instruction) iter.next();
- iter.remove();
- if (!instr.doesAlwaysJump() && instr.getNextByAddr() == null)
- throw new VerifyException("Flow can fall off end of method");
-
- VerifyInfo prevInfo = (VerifyInfo) instr.getTmpInfo();
- int opcode = instr.getOpcode();
- if (opcode == opc_ret) {
- Type retVarType = prevInfo.locals[instr.getLocalSlot()];
- if (prevInfo.jsrTargets == null
- || !retVarType.isOfType("R"))
- throw new VerifyException(instr.getDescription());
- int jsrLength = prevInfo.jsrTargets.length - 1;
- Instruction jsrTarget = retVarType.getInstruction();
- while (jsrTarget != prevInfo.jsrTargets[jsrLength])
- if (--jsrLength < 0)
- throw new VerifyException(instr.getDescription());
- VerifyInfo jsrTargetInfo = (VerifyInfo) jsrTarget.getTmpInfo();
- if (jsrTargetInfo.retInstr == null)
- jsrTargetInfo.retInstr = instr;
- else if (jsrTargetInfo.retInstr != instr)
- throw new VerifyException
- ("JsrTarget has more than one ret: "
- + jsrTarget.getDescription());
- Instruction[] nextTargets;
- BitSet[] nextLocals;
- if (jsrLength > 0) {
- nextTargets = new Instruction[jsrLength];
- nextLocals = new BitSet[jsrLength];
- System.arraycopy(prevInfo.jsrTargets, 0,
- nextTargets, 0, jsrLength);
- System.arraycopy(prevInfo.jsrLocals, 0,
- nextLocals, 0, jsrLength);
- } else {
- nextTargets = null;
- nextLocals = null;
- }
- for (int i=0; i < jsrTarget.getPreds().length; i++) {
- Instruction jsrInstr = jsrTarget.getPreds()[i];
- if (jsrInstr.getTmpInfo() != null)
- todoSet.add(jsrInstr);
- }
- } else {
- VerifyInfo info = modelEffect(instr, prevInfo);
- if (!instr.doesAlwaysJump())
- if (mergeInfo(instr.getNextByAddr(), info))
- todoSet.add(instr.getNextByAddr());
- if (opcode == opc_jsr) {
- VerifyInfo targetInfo =
- (VerifyInfo) instr.getSingleSucc().getTmpInfo();
- if (targetInfo != null && targetInfo.retInstr != null) {
- VerifyInfo afterJsrInfo
- = (VerifyInfo) prevInfo.clone();
- VerifyInfo retInfo
- = (VerifyInfo) targetInfo.retInstr.getTmpInfo();
- BitSet usedLocals
- = retInfo.jsrLocals[retInfo.jsrLocals.length-1];
- for (int j = 0; j < bi.getMaxLocals(); j++) {
- if (usedLocals.get(j))
- afterJsrInfo.locals[j] = retInfo.locals[j];
- }
- if (mergeInfo(instr.getNextByAddr(), afterJsrInfo))
- todoSet.add(instr.getNextByAddr());
- }
- }
- if (instr.getSuccs() != null) {
- for (int i=0; i< instr.getSuccs().length; i++) {
- if (instr.getSuccs()[i].getAddr() < instr.getAddr()) {
- /* This is a backwards branch */
- for (int j = 0; j < prevInfo.locals.length; j++) {
- if (prevInfo.locals[j]
- .getTypeSig().charAt(0) == 'N')
- throw new VerifyException
- ("Uninitialized local in back-branch");
- }
- for (int j = 0; j < prevInfo.stackHeight; j++) {
- if (prevInfo.stack[j]
- .getTypeSig().charAt(0) == 'N')
- throw new VerifyException
- ("Uninitialized stack in back-branch");
- }
- }
- if (mergeInfo(instr.getSuccs()[i],
- (VerifyInfo) info.clone()))
- todoSet.add(instr.getSuccs()[i]);
- }
- }
- for (int i=0; i= 0) {
- for (int j = 0; j < prevInfo.locals.length; j++) {
- if (prevInfo.locals[j]
- .getTypeSig().charAt(0) == 'N')
- throw new VerifyException
- ("Uninitialized local in try block");
- }
- VerifyInfo excInfo = (VerifyInfo) prevInfo.clone();
- excInfo.stackHeight = 1;
- if (handlers[i].type != null)
- excInfo.stack[0] =
- Type.tType("L" + handlers[i].type
- .replace('.', '/') + ";");
- else
- excInfo.stack[0]
- = Type.tType("Ljava/lang/Throwable;");
- if (mergeInfo(handlers[i].catcher, excInfo))
- todoSet.add(handlers[i].catcher);
- }
- }
- }
- }
-
- if ((GlobalOptions.debuggingFlags
- & GlobalOptions.DEBUG_VERIFIER) != 0) {
- for (Iterator i = bi.getInstructions().iterator(); i.hasNext(); ) {
- Instruction instr = (Instruction) i.next();
-
- VerifyInfo info = (VerifyInfo) instr.getTmpInfo();
- if (info != null)
- GlobalOptions.err.println(info.toString());
- GlobalOptions.err.println(instr.getDescription());
-
- }
- }
- for (Iterator i = bi.getInstructions().iterator(); i.hasNext(); ) {
- Instruction instr = (Instruction) i.next();
- instr.setTmpInfo(null);
- }
- }
-
-
- public void verify() throws VerifyException {
- try {
- doVerify();
- } catch (VerifyException ex) {
- for (Iterator i = bi.getInstructions().iterator(); i.hasNext(); ) {
- Instruction instr = (Instruction) i.next();
- VerifyInfo info = (VerifyInfo) instr.getTmpInfo();
- if (info != null)
- GlobalOptions.err.println(info.toString());
- GlobalOptions.err.println(instr.getDescription());
-
- instr.setTmpInfo(null);
- }
- throw ex;
- }
- }
-}
diff --git a/jode/jode/jvm/Interpreter.java.in b/jode/jode/jvm/Interpreter.java
similarity index 93%
rename from jode/jode/jvm/Interpreter.java.in
rename to jode/jode/jvm/Interpreter.java
index afdecde..718385c 100644
--- a/jode/jode/jvm/Interpreter.java.in
+++ b/jode/jode/jvm/Interpreter.java
@@ -20,7 +20,8 @@
package jode.jvm;
import jode.AssertError;
import jode.GlobalOptions;
-import jode.bytecode.BytecodeInfo;
+import jode.bytecode.BasicBlocks;
+import jode.bytecode.Block;
import jode.bytecode.Handler;
import jode.bytecode.Instruction;
import jode.bytecode.Opcodes;
@@ -29,7 +30,10 @@ import jode.bytecode.TypeSignature;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
-import @COLLECTIONS@.Arrays;
+///#def COLLECTIONS java.util
+import java.util.Arrays;
+import java.util.Iterator;
+///#enddef
/**
* This class is a java virtual machine written in java :-). Well not
@@ -59,16 +63,16 @@ public class Interpreter implements Opcodes {
this.env = env;
}
- private Value[] fillParameters(BytecodeInfo code,
+ private Value[] fillParameters(BasicBlocks bb,
Object cls, Object[] params) {
- Value[] locals = new Value[code.getMaxLocals()];
+ Value[] locals = new Value[bb.getMaxLocals()];
for (int i=0; i< locals.length; i++)
locals[i] = new Value();
- String myType = code.getMethodInfo().getType();
+ String myType = bb.getMethodInfo().getType();
String[] myParamTypes = TypeSignature.getParameterTypes(myType);
int slot = 0;
- if (!code.getMethodInfo().isStatic())
+ if (!bb.getMethodInfo().isStatic())
locals[slot++].setObject(cls);
for (int i=0; i< myParamTypes.length; i++) {
locals[slot].setObject(params[i]);
@@ -77,24 +81,39 @@ public class Interpreter implements Opcodes {
return locals;
}
- public Object interpretMethod(BytecodeInfo code,
+ public Object interpretMethod(BasicBlocks bb,
Object instance, Object[] myParams)
throws InterpreterException, InvocationTargetException {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_INTERPRT) != 0)
- GlobalOptions.err.println("Interpreting "+code);
+ GlobalOptions.err.println("Interpreting "+bb);
- Value[] locals = fillParameters(code, instance, myParams);
- Value[] stack = new Value[code.getMaxStack()];
+ Value[] locals = fillParameters(bb, instance, myParams);
+ Value[] stack = new Value[bb.getMaxStack()];
for (int i=0; i < stack.length; i++)
stack[i] = new Value();
- Instruction pc = (Instruction) code.getInstructions().get(0);
+ Block[] blocks = bb.getBlocks();
+ Block nextBlock = bb.getStartBlock();
+
int stacktop = 0;
+ Block[] succs = null;
+ Handler[] handlers = null;
+ Iterator iter = null;
+
big_loop:
for(;;) {
+ if (iter == null || !iter.hasNext()) {
+ /* If block is over continue with the next block */
+ if (nextBlock == null)
+ return Void.TYPE;
+ iter = nextBlock.getInstructions().iterator();
+ succs = nextBlock.getSuccs();
+ handlers = nextBlock.getCatchers();
+ nextBlock = succs.length > 0 ? succs[succs.length - 1] : null;
+ }
try {
- Instruction instr = pc;
+ Instruction instr = (Instruction) iter.next();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_INTERPRT) != 0) {
GlobalOptions.err.println(instr.getDescription());
@@ -114,7 +133,6 @@ public class Interpreter implements Opcodes {
GlobalOptions.err.print(locals[i]+",");
GlobalOptions.err.println("]");
}
- pc = instr.getNextByAddr();
int opcode = instr.getOpcode();
switch (opcode) {
case opc_nop:
@@ -572,28 +590,26 @@ public class Interpreter implements Opcodes {
int opc_mask = 1 << opcode;
if (value > 0 && (opc_mask & CMP_GREATER_MASK) != 0
|| value < 0 && (opc_mask & CMP_LESS_MASK) != 0
- || value == 0 && (opc_mask & CMP_EQUAL_MASK) != 0)
- pc = instr.getSingleSucc();
+ || value == 0 && (opc_mask & CMP_EQUAL_MASK) != 0) {
+ nextBlock = succs[0];
+ }
break;
}
case opc_jsr:
case opc_jsr_w:
- stack[stacktop++].setObject(instr);
- /* fall through */
- case opc_goto:
- case opc_goto_w:
- pc = instr.getSingleSucc();
+ stack[stacktop++].setObject(nextBlock);
+ nextBlock = succs[0];
break;
case opc_ret:
- pc = (Instruction)locals[instr.getLocalSlot()].objectValue();
+ nextBlock
+ = (Block) locals[instr.getLocalSlot()].objectValue();
break;
case opc_lookupswitch: {
int value = stack[--stacktop].intValue();
int[] values = instr.getValues();
int pos = Arrays.binarySearch(values, value);
- pc = pos < 0
- ? instr.getSuccs()[values.length]
- : instr.getSuccs()[pos];
+ if (pos >= 0)
+ nextBlock = succs[pos];
break;
}
case opc_ireturn: case opc_freturn: case opc_areturn:
@@ -734,16 +750,14 @@ public class Interpreter implements Opcodes {
throw new AssertError("Invalid opcode "+opcode);
}
} catch (InvocationTargetException ex) {
- Handler[] handlers = code.getExceptionHandlers();
+ iter = null;
Throwable obj = ex.getTargetException();
- for (int i=0; i< handlers.length; i++) {
- if (handlers[i].start.compareTo(pc) <= 0
- && handlers[i].end.compareTo(pc) >= 0
- && (handlers[i].type == null
- || env.instanceOf(obj, handlers[i].type))) {
+ for (int i=0; i < handlers.length; i++) {
+ if (handlers[i].getType() == null
+ || env.instanceOf(obj, handlers[i].getType())) {
stacktop = 0;
stack[stacktop++].setObject(obj);
- pc = handlers[i].catcher;
+ nextBlock = handlers[i].getCatcher();
continue big_loop;
}
}
diff --git a/jode/jode/jvm/Makefile.am b/jode/jode/jvm/Makefile.am
index 2f2372b..f73feab 100644
--- a/jode/jode/jvm/Makefile.am
+++ b/jode/jode/jvm/Makefile.am
@@ -1,10 +1,8 @@
## Input file for automake to generate the Makefile.in used by configure
-JAR = @JAR@
-JAVAC = @JAVAC@
-JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
- -dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir) \
- -depfile=Makefile.dep
+JAVADEP = $(PERL) -w -s $(top_srcdir)/scripts/javaDependencies.pl \
+ -subdir=$(subdir) -dependdir=$(top_builddir) \
+ -classpath=$(top_builddir):$(top_srcdir) -depfile=Makefile.dep
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
diff --git a/jode/jode/jvm/SyntheticAnalyzer.java.in b/jode/jode/jvm/SyntheticAnalyzer.java
similarity index 69%
rename from jode/jode/jvm/SyntheticAnalyzer.java.in
rename to jode/jode/jvm/SyntheticAnalyzer.java
index 4e55ef4..b5c738a 100644
--- a/jode/jode/jvm/SyntheticAnalyzer.java.in
+++ b/jode/jode/jvm/SyntheticAnalyzer.java
@@ -19,7 +19,8 @@
package jode.jvm;
import jode.GlobalOptions;
-import jode.bytecode.BytecodeInfo;
+import jode.bytecode.BasicBlocks;
+import jode.bytecode.Block;
import jode.bytecode.ClassInfo;
import jode.bytecode.FieldInfo;
import jode.bytecode.Handler;
@@ -32,7 +33,9 @@ import jode.type.MethodType;
import java.lang.reflect.Modifier;
-import @COLLECTIONS@.Iterator;
+///#def COLLECTIONS java.util
+import java.util.Iterator;
+///#enddef
public class SyntheticAnalyzer implements Opcodes {
public final static int UNKNOWN = 0;
@@ -47,11 +50,14 @@ public class SyntheticAnalyzer implements Opcodes {
int kind = UNKNOWN;
Reference reference;
+ ClassInfo classInfo;
MethodInfo method;
- public SyntheticAnalyzer(MethodInfo method, boolean checkName) {
+ public SyntheticAnalyzer(ClassInfo classInfo, MethodInfo method,
+ boolean checkName) {
+ this.classInfo = classInfo;
this.method = method;
- if (method.getBytecode() == null)
+ if (method.getBasicBlocks() == null)
return;
if (!checkName || method.getName().equals("class$"))
if (checkGetClass())
@@ -94,37 +100,50 @@ public class SyntheticAnalyzer implements Opcodes {
.equals("(Ljava/lang/String;)Ljava/lang/Class;")))
return false;
- BytecodeInfo bytecode = method.getBytecode();
+ BasicBlocks bb = method.getBasicBlocks();
- Handler[] excHandlers = bytecode.getExceptionHandlers();
- if (excHandlers.length != 1
- || !"java.lang.ClassNotFoundException".equals(excHandlers[0].type))
+ Block[] blocks = bb.getBlocks();
+ Block startBlock = bb.getStartBlock();
+ Handler[] excHandlers = bb.getExceptionHandlers();
+ if (startBlock == null
+ || startBlock.getInstructions().size() != 3
+ || excHandlers.length != 1
+ || excHandlers[0].getStart() != startBlock
+ || excHandlers[0].getEnd() != startBlock
+ || !"java.lang.ClassNotFoundException"
+ .equals(excHandlers[0].getType()))
return false;
- int excSlot = -1;
- int i = 0;
- for (Iterator iter = bytecode.getInstructions().iterator(); iter.hasNext(); i++) {
- Instruction instr = (Instruction) iter.next();
- if (i == getClassOpcodes.length
- || instr.getOpcode() != getClassOpcodes[i])
+ for (int i=0; i< 3; i++) {
+ Instruction instr =
+ (Instruction) startBlock.getInstructions().get(i);
+ if (instr.getOpcode() != getClassOpcodes[i])
return false;
- if (i == 0 && (instr.getLocalSlot() != 0
- || excHandlers[0].start != instr))
+ if (getClassRefs[i] != null
+ && !getClassRefs[i].equals(instr.getReference()))
return false;
- if (i == 2 && excHandlers[0].end != instr)
+ if (i == 0 && instr.getLocalSlot() != 0)
return false;
- if (i == 3) {
- if (excHandlers[0].catcher != instr)
- return false;
+ }
+
+ Block catchBlock = excHandlers[0].getCatcher();
+ if (catchBlock.getInstructions().size() != 7)
+ return false;
+ int excSlot = -1;
+ for (int i=0; i< 7; i++) {
+ Instruction instr = (Instruction)
+ catchBlock.getInstructions().get(i);
+ if (instr.getOpcode() != getClassOpcodes[3+i])
+ return false;
+ if (getClassRefs[3+i] != null
+ && !getClassRefs[3+i].equals(instr.getReference()))
+ return false;
+ if (i == 0)
excSlot = instr.getLocalSlot();
- }
- if (i == 4 && !instr.getClazzType().equals
+ if (i == 1 && !instr.getClazzType().equals
("Ljava/lang/NoClassDefFoundError;"))
return false;
- if (i == 6 && instr.getLocalSlot() != excSlot)
- return false;
- if (getClassRefs[i] != null
- && !getClassRefs[i].equals(instr.getReference()))
+ if (i == 3 && instr.getLocalSlot() != excSlot)
return false;
}
this.kind = GETCLASS;
@@ -135,22 +154,35 @@ public class SyntheticAnalyzer implements Opcodes {
Modifier.PUBLIC | Modifier.STATIC);
public boolean checkStaticAccess() {
- ClassInfo clazzInfo = method.getClazzInfo();
- BytecodeInfo bytecode = method.getBytecode();
- Iterator iter = bytecode.getInstructions().iterator();
-
+ BasicBlocks bb = method.getBasicBlocks();
+ Handler[] excHandlers = bb.getExceptionHandlers();
+ if (excHandlers != null && excHandlers.length != 0)
+ return false;
+ Block[] blocks = bb.getBlocks();
+ Block startBlock = bb.getStartBlock();
+ if (startBlock == null)
+ return false;
+ Block[] succBlocks = startBlock.getSuccs();
+ if (succBlocks.length > 1 ||
+ (succBlocks.length == 1 && succBlocks[0] != null))
+ return false;
+ Iterator iter = startBlock.getInstructions().iterator();
+ if (!iter.hasNext())
+ return false;
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_getstatic) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
- .equals(clazzInfo.getName().replace('.','/'))))
+ .equals(classInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
- = clazzInfo.findField(ref.getName(), ref.getType());
+ = classInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) !=
(Modifier.PRIVATE | Modifier.STATIC))
return false;
+ if (!iter.hasNext())
+ return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
@@ -167,6 +199,8 @@ public class SyntheticAnalyzer implements Opcodes {
params++;
slot += (instr.getOpcode() == opc_lload
|| instr.getOpcode() == opc_dload) ? 2 : 1;
+ if (!iter.hasNext())
+ return false;
instr = (Instruction) iter.next();
}
if (instr.getOpcode() == opc_putstatic) {
@@ -176,13 +210,15 @@ public class SyntheticAnalyzer implements Opcodes {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
- .equals(clazzInfo.getName().replace('.','/'))))
+ .equals(classInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
- = clazzInfo.findField(ref.getName(), ref.getType());
+ = classInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) !=
(Modifier.PRIVATE | Modifier.STATIC))
return false;
+ if (!iter.hasNext())
+ return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_return)
return false;
@@ -194,20 +230,25 @@ public class SyntheticAnalyzer implements Opcodes {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
- .equals(clazzInfo.getName().replace('.','/'))))
+ .equals(classInfo.getName().replace('.','/'))))
return false;
MethodInfo refMethod
- = clazzInfo.findMethod(ref.getName(), ref.getType());
+ = classInfo.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) !=
(Modifier.PRIVATE | Modifier.STATIC)
|| refType.getParameterTypes().length != params)
return false;
+ if (!iter.hasNext())
+ return false;
instr = (Instruction) iter.next();
if (refType.getReturnType() == Type.tVoid) {
- if (instr.getOpcode() != opc_return)
+ if (iter.hasNext())
return false;
} else {
+ if (!iter.hasNext())
+ return false;
+ instr = (Instruction) iter.next();
if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
return false;
@@ -222,33 +263,46 @@ public class SyntheticAnalyzer implements Opcodes {
}
public boolean checkAccess() {
- ClassInfo clazzInfo = method.getClazzInfo();
- BytecodeInfo bytecode = method.getBytecode();
- Handler[] excHandlers = bytecode.getExceptionHandlers();
- if (excHandlers != null && excHandlers.length != 0)
- return false;
-
if (method.isStatic()) {
if (checkStaticAccess())
return true;
}
- Iterator iter = bytecode.getInstructions().iterator();
+ BasicBlocks bb = method.getBasicBlocks();
+ Handler[] excHandlers = bb.getExceptionHandlers();
+ if (excHandlers != null && excHandlers.length != 0)
+ return false;
+ Block[] blocks = bb.getBlocks();
+ Block startBlock = bb.getStartBlock();
+ if (startBlock == null)
+ return false;
+ Block[] succBlocks = startBlock.getSuccs();
+ if (succBlocks.length > 1 ||
+ (succBlocks.length == 1 && succBlocks[0] != null))
+ return false;
+ Iterator iter = startBlock.getInstructions().iterator();
+
+ if (!iter.hasNext())
+ return false;
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_aload || instr.getLocalSlot() != 0)
return false;
+ if (!iter.hasNext())
+ return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_getfield) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
- .equals(clazzInfo.getName().replace('.','/'))))
+ .equals(classInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
- = clazzInfo.findField(ref.getName(), ref.getType());
+ = classInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) != Modifier.PRIVATE)
return false;
+ if (!iter.hasNext())
+ return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
@@ -265,6 +319,8 @@ public class SyntheticAnalyzer implements Opcodes {
params++;
slot += (instr.getOpcode() == opc_lload
|| instr.getOpcode() == opc_dload) ? 2 : 1;
+ if (!iter.hasNext())
+ return false;
instr = (Instruction) iter.next();
}
if (instr.getOpcode() == opc_putfield) {
@@ -274,14 +330,13 @@ public class SyntheticAnalyzer implements Opcodes {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
- .equals(clazzInfo.getName().replace('.','/'))))
+ .equals(classInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
- = clazzInfo.findField(ref.getName(), ref.getType());
+ = classInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) != Modifier.PRIVATE)
return false;
- instr = (Instruction) iter.next();
- if (instr.getOpcode() != opc_return)
+ if (iter.hasNext())
return false;
reference = ref;
kind = ACCESSPUTFIELD;
@@ -291,19 +346,21 @@ public class SyntheticAnalyzer implements Opcodes {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
- .equals(clazzInfo.getName().replace('.','/'))))
+ .equals(classInfo.getName().replace('.','/'))))
return false;
MethodInfo refMethod
- = clazzInfo.findMethod(ref.getName(), ref.getType());
+ = classInfo.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) != Modifier.PRIVATE
|| refType.getParameterTypes().length != params)
return false;
- instr = (Instruction) iter.next();
if (refType.getReturnType() == Type.tVoid) {
- if (instr.getOpcode() != opc_return)
+ if (iter.hasNext())
return false;
} else {
+ if (!iter.hasNext())
+ return false;
+ instr = (Instruction) iter.next();
if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
return false;
@@ -318,16 +375,25 @@ public class SyntheticAnalyzer implements Opcodes {
}
public boolean checkConstructorAccess() {
- ClassInfo clazzInfo = method.getClazzInfo();
- BytecodeInfo bytecode = method.getBytecode();
- Handler[] excHandlers = bytecode.getExceptionHandlers();
+ BasicBlocks bb = method.getBasicBlocks();
+ Handler[] excHandlers = bb.getExceptionHandlers();
if (excHandlers != null && excHandlers.length != 0)
return false;
-
- Iterator iter = bytecode.getInstructions().iterator();
+ Block[] blocks = bb.getBlocks();
+ Block startBlock = bb.getStartBlock();
+ if (startBlock == null)
+ return false;
+ Block[] succBlocks = startBlock.getSuccs();
+ if (succBlocks.length != 1 || succBlocks[0] != null)
+ return false;
+ Iterator iter = startBlock.getInstructions().iterator();
+ if (!iter.hasNext())
+ return false;
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_aload || instr.getLocalSlot() != 0)
return false;
+ if (!iter.hasNext())
+ return false;
instr = (Instruction) iter.next();
// slot begins with 2. Slot 1 contains a dummy value, that
@@ -339,25 +405,25 @@ public class SyntheticAnalyzer implements Opcodes {
params++;
slot += (instr.getOpcode() == opc_lload
|| instr.getOpcode() == opc_dload) ? 2 : 1;
+ if (!iter.hasNext())
+ return false;
instr = (Instruction) iter.next();
}
if (instr.getOpcode() == opc_invokespecial) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
- .equals(clazzInfo.getName().replace('.','/'))))
+ .equals(classInfo.getName().replace('.','/'))))
return false;
MethodInfo refMethod
- = clazzInfo.findMethod(ref.getName(), ref.getType());
+ = classInfo.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) != Modifier.PRIVATE
|| !refMethod.getName().equals("")
|| refType.getParameterTypes().length != params)
return false;
- instr = (Instruction) iter.next();
- if (instr.getOpcode() != opc_return)
+ if (iter.hasNext())
return false;
-
/* For valid bytecode the types matches automatically */
reference = ref;
kind = ACCESSCONSTRUCTOR;