// // Copyright (C) 2006 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.vm; import java.lang.reflect.Modifier; import java.util.ArrayList; import de.fosd.typechef.featureexpr.FeatureExpr; import gov.nasa.jpf.Config; import gov.nasa.jpf.JPF; import gov.nasa.jpf.JPFException; import gov.nasa.jpf.util.JPFLogger; import gov.nasa.jpf.util.LocationSpec; /** * information associated with a method. Each method in JPF * is represented by a MethodInfo object */ public class MethodInfo extends InfoObject implements GenericSignatureHolder { static JPFLogger logger = JPF.getLogger("gov.nasa.jpf.vm.MethodInfo"); static final int INIT_MTH_SIZE = 4096; protected static final ArrayList<MethodInfo> mthTable = new ArrayList<MethodInfo>(INIT_MTH_SIZE); // special globalIds static final int DIRECT_CALL = -1; static final LocalVarInfo[] EMPTY = new LocalVarInfo[0]; static final int[] EMPTY_INT = new int[0]; /** * Used to warn about local variable information. */ protected static boolean warnedLocalInfo = false; //--- various JPF method attributes static final int EXEC_ATOMIC = 0x10000; // method executed atomically static final int EXEC_HIDDEN = 0x20000; // method hidden from path static final int FIREWALL = 0x40000; // firewall any unhandled exceptionHandlers // (turn into UnhandledException throws) static final int IS_CLINIT = 0x80000; static final int IS_INIT = 0x100000; static final int IS_REFLECTION = 0x200000; // this is a reflection direct call static final int IS_DIRECT_CALL = 0x400000; /** a unique int assigned to this method */ protected int globalId = -1; /** * this is a lazy evaluated mangled name consisting of the name and * arg type signature */ protected String uniqueName; /** Name of the method */ protected String name; /** Signature of the method */ protected String signature; /** Generic signature of the method */ protected String genericSignature; /** Class the method belongs to */ protected ClassInfo ci; /** Instructions associated with the method */ protected Instruction[] code; /** JPFConfigException handlers */ protected ExceptionHandler[] exceptionHandlers; /** classnames of checked exception thrown by the method */ protected String[] thrownExceptionClassNames; /** Table used for line numbers * this assigns a line number to every instruction index, instead of * using an array of ranges. Assuming we have 2-3 insns per line on average, * this should still require less memory than a reference array with associated * range objects, and allows faster access of instruction line numbers, which * we might need for location specs */ protected int[] lineNumbers; /** Local variable information */ protected LocalVarInfo localVars[] = null; /** Maximum number of local variables */ protected int maxLocals; /** Maximum number of elements on the stack */ protected int maxStack; /** null if we don't have any */ AnnotationInfo[][] parameterAnnotations; //--- a batch of attributes /** the standard Java modifier attributes */ protected int modifiers; /** a batch of execution related JPF attributes */ protected int attributes; //--- all the stuff we need for native methods // <2do> pcm - turn this into a derived class /** the number of stack slots for the arguments (incl. 'this'), lazy eval */ protected int argSize = -1; /** number of arguments (excl. 'this'), lazy eval */ protected int nArgs = -1; /** what return type do we have (again, lazy evaluated) */ protected byte returnType = -1; /** number of stack slots for return value */ protected int retSize = -1; /** used for native method parameter conversion (lazy evaluated) */ protected byte[] argTypes = null; static boolean init (Config config) { mthTable.clear(); return true; } public static MethodInfo getMethodInfo (int globalId){ if (globalId >=0 && globalId <mthTable.size()){ return mthTable.get(globalId); } else { return null; } } public static MethodInfo create (String name, String signature, int modifiers){ return new MethodInfo( name, signature, modifiers); } public static MethodInfo create (ClassInfo ci, String name, String signature, int modifiers){ return new MethodInfo( ci, name, signature, modifiers); } static MethodInfo create (ClassInfo ci, String name, String signature, int modifiers, int maxLocals, int maxStack){ return new MethodInfo( ci, name, signature, modifiers, maxLocals, maxStack); } /** * for direct call construction * Note: this is only a partial initialization, the code still has to be created/installed by the caller */ public MethodInfo (MethodInfo callee, int nLocals, int nOperands) { globalId = DIRECT_CALL; // we don't want direct call methods in the mthTable (would be a memory leak) so don't register ci = callee.ci; name = "[" + callee.name + ']'; // it doesn't allocate anything, so we don't have to be unique signature = "()V"; genericSignature = ""; maxLocals = nLocals; maxStack = nOperands; // <2do> cache for optimization localVars = EMPTY; lineNumbers = null; exceptionHandlers = null; thrownExceptionClassNames = null; uniqueName = name; // we need to preserve the ClassInfo so that class resolution for static method calls works ci = callee.ci; attributes |= IS_DIRECT_CALL; modifiers = Modifier.STATIC; // always treated as static // code still has to be installed by caller } /** * This is used to create synthetic methods of function object types */ public MethodInfo(String name, String signature, int modifiers, int nLocals, int nOperands) { this( name, signature, modifiers); maxLocals = nLocals; maxStack = nOperands; localVars = EMPTY; } /** * for NativeMethodInfo creation */ public MethodInfo (MethodInfo mi) { globalId = mi.globalId; uniqueName = mi.uniqueName; name = mi.name; signature = mi.signature; genericSignature = mi.genericSignature; ci = mi.ci; modifiers = mi.modifiers; attributes = mi.attributes; thrownExceptionClassNames = mi.thrownExceptionClassNames; parameterAnnotations = mi.parameterAnnotations; annotations = mi.annotations; localVars = null; // there are no StackFrame localVarInfos, this is native // code still has to be installed by caller } // <2do> this is going away public MethodInfo (ClassInfo ci, String name, String signature, int modifiers, int maxLocals, int maxStack){ this.ci = ci; this.name = name; this.signature = signature; this.uniqueName = getUniqueName(name, signature); this.genericSignature = ""; this.maxLocals = maxLocals; this.maxStack = maxStack; this.modifiers = modifiers; this.lineNumbers = null; this.exceptionHandlers = null; this.thrownExceptionClassNames = null; // set attributes we can deduce from the name and the ClassInfo if (ci != null){ if (name.equals("<init>")) { attributes |= IS_INIT; } else if (name.equals("<clinit>")) { this.modifiers |= Modifier.SYNCHRONIZED; attributes |= IS_CLINIT | FIREWALL; } if (ci.isInterface()) { // all interface methods are public this.modifiers |= Modifier.PUBLIC; } } this.globalId = mthTable.size(); mthTable.add(this); } public MethodInfo (String name, String signature, int modifiers){ this.name = name; this.signature = signature; this.modifiers = modifiers; this.uniqueName = getUniqueName(name, signature); this.genericSignature = ""; if (name.equals("<init>")) { attributes |= IS_INIT; } else if (name.equals("<clinit>")) { this.modifiers |= Modifier.SYNCHRONIZED; attributes |= IS_CLINIT | FIREWALL; } this.globalId = mthTable.size(); mthTable.add(this); } public MethodInfo (ClassInfo ci, String name, String signature, int modifiers){ this(name, signature, modifiers); this.ci = ci; } //--- setters used during construction public void linkToClass (ClassInfo ci){ this.ci = ci; if (ci.isInterface()) { // all interface methods are public this.modifiers |= Modifier.PUBLIC; } } public void setMaxLocals(int maxLocals){ this.maxLocals = maxLocals; } public void setMaxStack(int maxStack){ this.maxStack = maxStack; } public void setCode (Instruction[] code){ for (int i=0; i<code.length; i++){ code[i].setMethodInfo(this); } this.code = code; } public boolean hasParameterAnnotations() { return (parameterAnnotations != null); } // since some listeners might call this on every method invocation, we should do a little optimization static AnnotationInfo[][] NO_PARAMETER_ANNOTATIONS_0 = new AnnotationInfo[0][]; static AnnotationInfo[][] NO_PARAMETER_ANNOTATIONS_1 = { new AnnotationInfo[0] }; static AnnotationInfo[][] NO_PARAMETER_ANNOTATIONS_2 = { new AnnotationInfo[0], new AnnotationInfo[0] }; static AnnotationInfo[][] NO_PARAMETER_ANNOTATIONS_3 = { new AnnotationInfo[0], new AnnotationInfo[0], new AnnotationInfo[0] }; public AnnotationInfo[][] getParameterAnnotations() { if (parameterAnnotations == null){ // keep this similar to getAnnotations() int n = getNumberOfArguments(); switch (n){ case 0: return NO_PARAMETER_ANNOTATIONS_0; case 1: return NO_PARAMETER_ANNOTATIONS_1; case 2: return NO_PARAMETER_ANNOTATIONS_2; case 3: return NO_PARAMETER_ANNOTATIONS_3; default: AnnotationInfo[][] pai = new AnnotationInfo[n][]; for (int i=0; i<n; i++){ pai[i] = new AnnotationInfo[0]; } return pai; } } else { return parameterAnnotations; } } /** * return annotations for parameterIndex */ public AnnotationInfo[] getParameterAnnotations(int parameterIndex){ if (parameterAnnotations == null){ return null; } else { if (parameterIndex >= getNumberOfArguments()){ return null; } else { return parameterAnnotations[parameterIndex]; } } } public static int getNumberOfLoadedMethods () { return mthTable.size(); } void setAtomic (boolean isAtomic) { if (isAtomic) { attributes |= EXEC_ATOMIC; } else { attributes &= ~EXEC_ATOMIC; } } public boolean isAtomic () { return ((attributes & EXEC_ATOMIC) != 0); } void setHidden (boolean isHidden) { if (isHidden) { attributes |= EXEC_HIDDEN; } else { attributes &= ~EXEC_HIDDEN; } } public boolean isHidden () { return ((attributes & EXEC_HIDDEN) != 0); } /** * turn unhandled exceptionHandlers at the JPF execution level * into UnhandledException throws at the host VM level * this is useful to implement firewalls for direct calls * which should not let exceptionHandlers permeate into bytecode/ * application code */ public void setFirewall (boolean isFirewalled) { if (isFirewalled) { attributes |= FIREWALL; } else { attributes &= ~FIREWALL; } } public boolean isFirewall () { return ((attributes & FIREWALL) != 0); } public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException cnx) { return null; } } public int getGlobalId() { return globalId; } public DirectCallStackFrame createRunStartStackFrame (FeatureExpr ctx, ThreadInfo ti){ return ci.createRunStartStackFrame( ctx, ti, this); } public DirectCallStackFrame createDirectCallStackFrame (FeatureExpr ctx, ThreadInfo ti, int nLocals){ return ci.createDirectCallStackFrame(ctx, ti, this, nLocals); } public boolean isSyncRelevant () { return (name.charAt(0) != '<'); } public boolean isInitOrClinit (){ return ((attributes & (IS_CLINIT | IS_INIT)) != 0); } public boolean isClinit () { return ((attributes & IS_CLINIT) != 0); } public boolean isClinit (ClassInfo ci) { return (((attributes & IS_CLINIT) != 0) && (this.ci == ci)); } public boolean isInit() { return ((attributes & IS_INIT) != 0); } public boolean isDirectCallStub(){ return ((attributes & IS_DIRECT_CALL) != 0); } /** * yet another name - this time with a non-mangled, but abbreviated signature * and without return type (e.g. like "main(String[])" */ public String getLongName () { StringBuilder sb = new StringBuilder(); sb.append(name); sb.append('('); String[] argTypeNames = getArgumentTypeNames(); for (int i=0; i<argTypeNames.length; i++) { String a = argTypeNames[i]; int idx = a.lastIndexOf('.'); if (idx > 0) { a = a.substring(idx+1); } if (i>0) { sb.append(','); } sb.append(a); } sb.append(')'); return sb.toString(); } /** * return the minimal name that has to be unique for overloading * used as a lookup key * NOTE: with the silent introduction of covariant return types * in Java 5.0, we have to use the full signature to be unique */ public static String getUniqueName (String mname, String signature) { return (mname + signature); } public String getStackTraceSource() { return getSourceFileName(); } public byte[] getArgumentTypes () { if (argTypes == null) { argTypes = Types.getArgumentTypes(signature); nArgs = argTypes.length; } return argTypes; } public String[] getArgumentTypeNames () { return Types.getArgumentTypeNames(signature); } public int getArgumentsSize () { if (argSize < 0) { argSize = Types.getArgumentsSize(signature); if (!isStatic()) { argSize++; } } return argSize; } /** * return only the LocalVarInfos for arguments, in order of definition * or null if there are no localVarInfos. * throw a JPFException if there are more immediately in scope vars than args * * NOTE - it is perfectly legal for a method to have arguments but no LocalVarInfos, * which are code attributes, clients have to check for a non-null return value * even if the method has arguments. * Note also that abstract / interface methods don't have code and hence no * LocalVarInfos */ public LocalVarInfo[] getArgumentLocalVars(){ if (localVars == null){ // shortcut in case we don't have args or localVars; return null; } int nArgs = getNumberOfStackArguments(); // we want 'this' if (nArgs == 0){ return new LocalVarInfo[0]; // rare enough so that we don't use a static } LocalVarInfo[] argLvis = new LocalVarInfo[nArgs]; int n = 0; // how many args we've got so far for (LocalVarInfo lvi : localVars){ // arguments are the only ones that are immediately in scope if (lvi.getStartPC() == 0){ if (n == nArgs){ // ARGH - more in-scope vars than args throw new JPFException("inconsistent localVar table for method " + getFullName()); } // order with respect to slot index - since this might get called // frequently, we don't use java.util.Arrays.sort() but sort in // on-the-fly. Note that we can have several localVar entries for the // same name, but only one can be immediately in scope int slotIdx = lvi.getSlotIndex(); int i; for (i = 0; i < n; i++) { if (slotIdx < argLvis[i].getSlotIndex()) { for (int j=n; j>i; j--){ argLvis[j] = argLvis[j-1]; } argLvis[i] = lvi; n++; break; } } if (i == n) { // append argLvis[n++] = lvi; } } } return argLvis; } public String getReturnType () { return Types.getReturnTypeSignature(signature); } public String getReturnTypeName () { return Types.getReturnTypeName(signature); } public String getSourceFileName () { if (ci != null) { return ci.getSourceFileName(); } else { return "[VM]"; } } public String getClassName () { if (ci != null) { return ci.getName(); } else { return "[VM]"; } } /** * Returns the class the method belongs to. */ public ClassInfo getClassInfo () { return ci; } /** * @deprecated - use getFullName */ public String getCompleteName () { return getFullName(); } /** * return classname.name (but w/o signature) */ public String getBaseName() { return getClassName() + '.' + name; } public boolean isCtor () { return (name.equals("<init>")); } public boolean isInternalMethod () { // <2do> pcm - should turn this into an attribute for efficiency reasons return (name.equals("<clinit>") || uniqueName.equals("finalize()V")); } public boolean isThreadEntry (ThreadInfo ti) { return (uniqueName.equals("run()V") && (ti.countStackFrames() == 1)); } /** * Returns the full classname (if any) + name + signature. */ public String getFullName () { if (ci != null) { return ci.getName() + '.' + getUniqueName(); } else { return getUniqueName(); } } /** * returns stack trace name: classname (if any) + name */ public String getStackTraceName(){ if (ci != null) { return ci.getName() + '.' + name; } else { return name; } } /** * return number of instructions */ public int getNumberOfInstructions() { if (code == null){ return 0; } return code.length; } /** * Returns a specific instruction. */ public Instruction getInstruction (int i) { if (code == null) { return null; } if ((i < 0) || (i >= code.length)) { return null; } return code[i]; } /** * Returns the instruction at a certain position. */ public Instruction getInstructionAt (int position) { if (code == null) { return null; } for (int i = 0, l = code.length; i < l; i++) { if ((code[i] != null) && (code[i].getPosition() == position)) { return code[i]; } } throw new JPFException("instruction not found"); } /** * Returns the instructions of the method. */ public Instruction[] getInstructions () { return code; } public boolean includesLine (int line){ int len = code.length; return (code[0].getLineNumber() <= line) && (code[len].getLineNumber() >= line); } public Instruction[] getInstructionsForLine (int line){ return getInstructionsForLineInterval(line,line); } public Instruction[] getInstructionsForLineInterval (int l1, int l2){ Instruction[] c = code; // instruction line numbers don't have to be monotonic (they can decrease for loops) // hence we cannot easily check for overlapping ranges if (c != null){ ArrayList<Instruction> matchingInsns = null; for (int i = 0; i < c.length; i++) { Instruction insn = c[i]; int line = insn.getLineNumber(); if (line == l1 || line == l2 || (line > l1 && line < l2)) { if (matchingInsns == null) { matchingInsns = new ArrayList<Instruction>(); } matchingInsns.add(insn); } } if (matchingInsns == null) { return null; } else { return matchingInsns.toArray(new Instruction[matchingInsns.size()]); } } else { return null; } } public Instruction[] getMatchingInstructions (LocationSpec lspec){ return getInstructionsForLineInterval(lspec.getFromLine(), lspec.getToLine()); } /** * Returns the line number for a given position. */ public int getLineNumber (Instruction pc) { if (lineNumbers == null) { if (pc == null) return -1; else return pc.getPosition(); } if (pc != null) { int idx = pc.getInstructionIndex(); if (idx < 0) idx = 0; return lineNumbers[idx]; } else { return -1; } } /** * Returns a table to translate positions into line numbers. */ public int[] getLineNumbers () { return lineNumbers; } public boolean containsLineNumber (int n){ if (lineNumbers != null){ return (lineNumbers[0] <= n) && (lineNumbers[lineNumbers.length-1] <= n); } return false; } public boolean intersectsLineNumbers( int first, int last){ if (lineNumbers != null){ if ((last < lineNumbers[0]) || (first > lineNumbers[lineNumbers.length-1])){ return false; } return true; } return false; } public ExceptionHandler getHandlerFor (ClassInfo ciException, Instruction insn){ if (exceptionHandlers != null){ int position = insn.getPosition(); for (int i=0; i<exceptionHandlers.length; i++){ ExceptionHandler handler = exceptionHandlers[i]; if ((position >= handler.getBegin()) && (position < handler.getEnd())) { // checks if this type of exception is caught here (null means 'any') String handledType = handler.getName(); if ((handledType == null) // a catch-all handler || ciException.isInstanceOf(handledType)) { return handler; } } } } return null; } public boolean isMJI () { return false; } public int getMaxLocals () { return maxLocals; } public int getMaxStack () { return maxStack; } public ExceptionHandler[] getExceptions () { return exceptionHandlers; } public String[] getThrownExceptionClassNames () { return thrownExceptionClassNames; } public LocalVarInfo getLocalVar(String name, int pc){ LocalVarInfo[] vars = localVars; if (vars != null){ for (int i = 0; i < vars.length; i++) { LocalVarInfo lv = vars[i]; if (lv.matches(name, pc)) { return lv; } } } return null; } public LocalVarInfo getLocalVar (int slotIdx, int pc){ LocalVarInfo[] vars = localVars; if (vars != null){ for (int i = 0; i < vars.length; i++) { LocalVarInfo lv = vars[i]; if (lv.matches(slotIdx, pc)) { return lv; } } } return null; } public LocalVarInfo[] getLocalVars() { return localVars; } /** * note that this might contain duplicates for variables with multiple * scope entries */ public String[] getLocalVariableNames() { String[] names = new String[localVars.length]; for (int i=0; i<localVars.length; i++){ names[i] = localVars[i].getName(); } return names; } public MethodInfo getOverriddenMethodInfo(){ MethodInfo smi = null; if (ci != null) { ClassInfo sci = ci.getSuperClass(); if (sci != null){ smi = sci.getMethod(getUniqueName(), true); } } return smi; } /** * Returns the name of the method. */ public String getName () { return name; } public String getJNIName () { return Types.getJNIMangledMethodName(null, name, signature); } public int getModifiers () { return modifiers; } /** * Returns true if the method is native */ public boolean isNative () { return ((modifiers & Modifier.NATIVE) != 0); } public boolean isAbstract () { return ((modifiers & Modifier.ABSTRACT) != 0); } // overridden by NativeMethodInfo public boolean isUnresolvedNativeMethod(){ return ((modifiers & Modifier.NATIVE) != 0); } public int getNumberOfArguments () { if (nArgs < 0) { nArgs = Types.getNumberOfArguments(signature); } return nArgs; } /** * Returns the size of the arguments. * This returns the number of parameters passed on the stack, incl. 'this' */ public int getNumberOfStackArguments () { int n = getNumberOfArguments(); return isStatic() ? n : n + 1; } public int getNumberOfCallerStackSlots () { return Types.getNumberOfStackSlots(signature, isStatic()); // includes return type } public Instruction getFirstInsn(){ if (code != null){ return code[0]; } return null; } public Instruction getLastInsn() { if (code != null){ return code[code.length-1]; } return null; } /** * do we return Object references? */ public boolean isReferenceReturnType () { int r = getReturnTypeCode(); return ((r == Types.T_REFERENCE) || (r == Types.T_ARRAY)); } public byte getReturnTypeCode () { if (returnType < 0) { returnType = Types.getReturnBuiltinType(signature); } return returnType; } /** * what is the slot size of the return value */ public int getReturnSize() { if (retSize == -1){ switch (getReturnTypeCode()) { case Types.T_VOID: retSize = 0; break; case Types.T_LONG: case Types.T_DOUBLE: retSize = 2; break; default: retSize = 1; break; } } return retSize; } public Class<? extends ChoiceGenerator<?>> getReturnChoiceGeneratorType (){ switch (getReturnTypeCode()){ case Types.T_BOOLEAN: return BooleanChoiceGenerator.class; case Types.T_BYTE: case Types.T_CHAR: case Types.T_SHORT: case Types.T_INT: return IntChoiceGenerator.class; case Types.T_LONG: return LongChoiceGenerator.class; case Types.T_FLOAT: return FloatChoiceGenerator.class; case Types.T_DOUBLE: return DoubleChoiceGenerator.class; case Types.T_ARRAY: case Types.T_REFERENCE: case Types.T_VOID: return ReferenceChoiceGenerator.class; } return null; } /** * Returns the signature of the method. */ public String getSignature () { return signature; } public String getGenericSignature() { return genericSignature; } public void setGenericSignature(String sig){ genericSignature = sig; } /** * Returns true if the method is static. */ public boolean isStatic () { return ((modifiers & Modifier.STATIC) != 0); } /** * is this a public method */ public boolean isPublic() { return ((modifiers & Modifier.PUBLIC) != 0); } public boolean isPrivate() { return ((modifiers & Modifier.PRIVATE) != 0); } public boolean isProtected() { return ((modifiers & Modifier.PROTECTED) != 0); } /** * Returns true if the method is synchronized. */ public boolean isSynchronized () { return ((modifiers & Modifier.SYNCHRONIZED) != 0); } // <2do> these modifiers are still java.lang.reflect internal and not // supported by public Modifier methods, but since we want to keep this // similar to the Method reflection and we get the modifiers from the // classfile we implement this with explicit values public boolean isSynthetic(){ return ((modifiers & 0x00001000) != 0); } public boolean isVarargs(){ return ((modifiers & 0x00000080) != 0); } /* * is this from a classfile or was it created by JPF (and hence should not * be visible in stacktraces etc) */ public boolean isJPFInternal(){ // note this has a different meaning than Method.isSynthetic(), which // is defined in VM spec 4.7.8. What we mean here is that this MethodInfo // is not associated with any class (such as direct call MethodInfos), but // there might be more in the future return (ci == null); } public String getUniqueName () { return uniqueName; } public boolean hasCode(){ return (code != null); } public boolean hasEmptyBody (){ // only instruction is a return return (code.length == 1 && (code[0] instanceof ReturnInstruction)); } //--- parameter annotations //<2do> these are going away protected void startParameterAnnotations(int annotationCount){ parameterAnnotations = new AnnotationInfo[annotationCount][]; } protected void setParameterAnnotations(int index, AnnotationInfo[] ai){ parameterAnnotations[index] = ai; } protected void finishParameterAnnotations(){ // nothing } public void setParameterAnnotations (AnnotationInfo[][] parameterAnnotations){ this.parameterAnnotations = parameterAnnotations; } //--- thrown exceptions //<2do> these are going away protected void startTrownExceptions (int exceptionCount){ thrownExceptionClassNames = new String[exceptionCount]; } protected void setException (int index, String exceptionType){ thrownExceptionClassNames[index] = Types.getClassNameFromTypeName(exceptionType); } protected void finishThrownExceptions(){ // nothing } public void setThrownExceptions (String[] exceptions){ thrownExceptionClassNames = exceptions; } //--- exception handler table initialization //<2do> these are going away protected void startExceptionHandlerTable (int handlerCount){ exceptionHandlers = new ExceptionHandler[handlerCount]; } protected void setExceptionHandler (int index, int startPc, int endPc, int handlerPc, String catchType){ exceptionHandlers[index] = new ExceptionHandler(catchType, startPc, endPc, handlerPc); } protected void finishExceptionHandlerTable(){ // nothing } public void setExceptionHandlers (ExceptionHandler[] handlers){ exceptionHandlers = handlers; } //--- local var table initialization // <2do> these are going away protected void startLocalVarTable (int localVarCount){ localVars = new LocalVarInfo[localVarCount]; } protected void setLocalVar(int index, String varName, String descriptor, int scopeStartPc, int scopeEndPc, int slotIndex){ localVars[index] = new LocalVarInfo(varName, descriptor, "", scopeStartPc, scopeEndPc, slotIndex); } protected void finishLocalVarTable(){ // nothing to do } public void setLocalVarTable (LocalVarInfo[] locals){ localVars = locals; } //--- line number table initialization // <2do> these are going away protected void startLineNumberTable(int lineNumberCount){ int len = code.length; int[] ln = new int[len]; lineNumbers = ln; } protected void setLineNumber(int index, int lineNumber, int startPc){ int len = code.length; int[] ln = lineNumbers; for (int i=0; i<len; i++){ Instruction insn = code[i]; int pc = insn.getPosition(); if (pc == startPc){ // this is the first insn with this line number ln[i] = lineNumber; return; } } } protected void finishLineNumberTable (){ int len = code.length; int[] ln = lineNumbers; int lastLine = ln[0]; for (int i=1; i<len; i++){ if (ln[i] == 0){ ln[i] = lastLine; } else { lastLine = ln[i]; } } } /** * note - this depends on that we already have a code array * and that the lines/startPcs are sorted (monotonic increasing) */ public void setLineNumbers (int[] lines, int[] startPcs){ int j=0; int lastLine = -1; int len = code.length; int[] ln = new int[len]; for (int i=0; i<len; i++){ Instruction insn = code[i]; int pc = insn.getPosition(); if ((j < startPcs.length) && pc == startPcs[j]){ lastLine = lines[j]; j++; } ln[i] = lastLine; } lineNumbers = ln; } /** * this version takes an already expanded line number array which has to be of * the same size as the code array */ public void setLineNumbers (int[] lines){ if (lines.length != code.length){ throw new JPFException("inconsitent code/line number size"); } lineNumbers = lines; } public String toString() { return "MethodInfo[" + getFullName() + ']'; } // for debugging purposes public void dump(){ System.out.println("--- " + this); for (int i = 0; i < code.length; i++) { System.out.printf("%2d [%d]: %s\n", i, code[i].getPosition(), code[i].toString()); } } /** * Creates a method for a given class, by cloning this MethodInfo * and all the instructions belong to the method */ public MethodInfo getInstanceFor(ClassInfo ci) { MethodInfo clone; try { clone = (MethodInfo)super.clone(); clone.ci = ci; clone.globalId = mthTable.size(); mthTable.add(this); if(code == null) { clone.code = null; } else { clone.code = new Instruction[code.length]; for(int i=0; i<code.length; i++) { clone.code[i] = code[i].typeSafeClone(clone); } } } catch (CloneNotSupportedException cnsx){ cnsx.printStackTrace(); return null; } return clone; } }