2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0.
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package gov.nasa.jpf.vm;
20 import gov.nasa.jpf.Config;
21 import gov.nasa.jpf.JPF;
22 import gov.nasa.jpf.JPFException;
23 import gov.nasa.jpf.util.JPFLogger;
24 import gov.nasa.jpf.util.LocationSpec;
25 import gov.nasa.jpf.vm.bytecode.ReturnInstruction;
26 import java.lang.reflect.Modifier;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.List;
33 * information associated with a method. Each method in JPF
34 * is represented by a MethodInfo object
36 public class MethodInfo extends InfoObject implements GenericSignatureHolder {
38 static JPFLogger logger = JPF.getLogger("gov.nasa.jpf.vm.MethodInfo");
40 static final int INIT_MTH_SIZE = 4096;
41 protected static final ArrayList<MethodInfo> mthTable = new ArrayList<MethodInfo>(INIT_MTH_SIZE);
44 static final int DIRECT_CALL = -1;
46 static final LocalVarInfo[] EMPTY = new LocalVarInfo[0];
48 static final int[] EMPTY_INT = new int[0];
51 * Used to warn about local variable information.
53 protected static boolean warnedLocalInfo = false;
55 //--- various JPF method attributes
56 static final int EXEC_ATOMIC = 0x10000; // method executed atomically
57 static final int EXEC_HIDDEN = 0x20000; // method hidden from path
58 static final int FIREWALL = 0x40000; // firewall any unhandled exceptionHandlers
59 // (turn into UnhandledException throws)
60 static final int IS_CLINIT = 0x80000;
61 static final int IS_INIT = 0x100000;
63 static final int IS_REFLECTION = 0x200000; // this is a reflection direct call
64 static final int IS_DIRECT_CALL = 0x400000;
66 /** a unique int assigned to this method */
67 protected int globalId = -1;
70 * this is a lazy evaluated mangled name consisting of the name and
73 protected String uniqueName;
75 /** Name of the method */
76 protected String name;
78 /** Signature of the method */
79 protected String signature;
81 /** Generic signature of the method */
82 protected String genericSignature;
84 /** Class the method belongs to */
85 protected ClassInfo ci;
87 /** Instructions associated with the method */
88 protected Instruction[] code;
90 /** JPFConfigException handlers */
91 protected ExceptionHandler[] exceptionHandlers;
93 /** classnames of checked exception thrown by the method */
94 protected String[] thrownExceptionClassNames;
96 /** Table used for line numbers
97 * this assigns a line number to every instruction index, instead of
98 * using an array of ranges. Assuming we have 2-3 insns per line on average,
99 * this should still require less memory than a reference array with associated
100 * range objects, and allows faster access of instruction line numbers, which
101 * we might need for location specs
103 protected int[] lineNumbers;
105 /** Local variable information */
106 protected LocalVarInfo localVars[] = null;
108 /** Maximum number of local variables */
109 protected int maxLocals;
111 /** Maximum number of elements on the stack */
112 protected int maxStack;
114 /** null if we don't have any */
115 AnnotationInfo[][] parameterAnnotations;
117 //--- a batch of attributes
119 /** the standard Java modifier attributes */
120 protected int modifiers;
122 /** a batch of execution related JPF attributes */
123 protected int attributes;
126 //--- all the stuff we need for native methods
127 // <2do> pcm - turn this into a derived class
129 /** the number of stack slots for the arguments (incl. 'this'), lazy eval */
130 protected int argSize = -1;
132 /** number of arguments (excl. 'this'), lazy eval */
133 protected int nArgs = -1;
135 /** what return type do we have (again, lazy evaluated) */
136 protected byte returnType = -1;
138 /** number of stack slots for return value */
139 protected int retSize = -1;
141 /** used for native method parameter conversion (lazy evaluated) */
142 protected byte[] argTypes = null;
144 static boolean init (Config config) {
149 public static MethodInfo getMethodInfo (int globalId){
150 if (globalId >=0 && globalId <mthTable.size()){
151 return mthTable.get(globalId);
157 public static MethodInfo create (String name, String signature, int modifiers){
158 return new MethodInfo( name, signature, modifiers);
161 public static MethodInfo create (ClassInfo ci, String name, String signature, int modifiers){
162 return new MethodInfo( ci, name, signature, modifiers);
165 static MethodInfo create (ClassInfo ci, String name, String signature, int modifiers, int maxLocals, int maxStack){
166 return new MethodInfo( ci, name, signature, modifiers, maxLocals, maxStack);
170 * for direct call construction
171 * Note: this is only a partial initialization, the code still has to be created/installed by the caller
173 public MethodInfo (MethodInfo callee, int nLocals, int nOperands) {
174 globalId = DIRECT_CALL;
175 // we don't want direct call methods in the mthTable (would be a memory leak) so don't register
178 name = "[" + callee.name + ']'; // it doesn't allocate anything, so we don't have to be unique
180 genericSignature = "";
182 maxStack = nOperands; // <2do> cache for optimization
185 exceptionHandlers = null;
186 thrownExceptionClassNames = null;
189 // we need to preserve the ClassInfo so that class resolution for static method calls works
192 attributes |= IS_DIRECT_CALL;
193 modifiers = Modifier.STATIC; // always treated as static
195 // code still has to be installed by caller
199 * This is used to create synthetic methods of function object types
201 public MethodInfo(String name, String signature, int modifiers, int nLocals, int nOperands) {
202 this( name, signature, modifiers);
204 maxStack = nOperands;
209 * for NativeMethodInfo creation
211 public MethodInfo (MethodInfo mi) {
212 globalId = mi.globalId;
213 uniqueName = mi.uniqueName;
215 signature = mi.signature;
216 genericSignature = mi.genericSignature;
218 modifiers = mi.modifiers;
219 attributes = mi.attributes;
220 thrownExceptionClassNames = mi.thrownExceptionClassNames;
221 parameterAnnotations = mi.parameterAnnotations;
223 annotations = mi.annotations;
225 localVars = null; // there are no StackFrame localVarInfos, this is native
226 // code still has to be installed by caller
229 // <2do> this is going away
230 public MethodInfo (ClassInfo ci, String name, String signature, int modifiers, int maxLocals, int maxStack){
233 this.signature = signature;
234 this.uniqueName = getUniqueName(name, signature);
235 this.genericSignature = "";
236 this.maxLocals = maxLocals;
237 this.maxStack = maxStack;
238 this.modifiers = modifiers;
240 this.lineNumbers = null;
241 this.exceptionHandlers = null;
242 this.thrownExceptionClassNames = null;
244 // set attributes we can deduce from the name and the ClassInfo
246 if (name.equals("<init>")) {
247 attributes |= IS_INIT;
248 } else if (name.equals("<clinit>")) {
249 this.modifiers |= Modifier.SYNCHRONIZED;
250 attributes |= IS_CLINIT | FIREWALL;
252 if (ci.isInterface()) { // all interface methods are public
253 this.modifiers |= Modifier.PUBLIC;
257 this.globalId = mthTable.size();
262 public MethodInfo (String name, String signature, int modifiers){
264 this.signature = signature;
265 this.modifiers = modifiers;
266 this.uniqueName = getUniqueName(name, signature);
267 this.genericSignature = "";
269 if (name.equals("<init>")) {
270 attributes |= IS_INIT;
271 } else if (name.equals("<clinit>")) {
272 // for some reason clinits don't have the synchronized modifier, but they are synchronized
273 // we keep it consistent so that we don't have to implement special lock acquisition/release for clinits
274 this.modifiers |= Modifier.SYNCHRONIZED;
275 attributes |= IS_CLINIT | FIREWALL;
278 this.globalId = mthTable.size();
282 public MethodInfo (ClassInfo ci, String name, String signature, int modifiers){
283 this(name, signature, modifiers);
288 //--- setters used during construction
290 public void linkToClass (ClassInfo ci){
293 if (ci.isInterface()) { // all interface methods are public
294 this.modifiers |= Modifier.PUBLIC;
298 public void setMaxLocals(int maxLocals){
299 this.maxLocals = maxLocals;
302 public void setMaxStack(int maxStack){
303 this.maxStack = maxStack;
306 public void setCode (Instruction[] code){
307 for (int i=0; i<code.length; i++){
308 code[i].setMethodInfo(this);
314 public boolean hasParameterAnnotations() {
315 return (parameterAnnotations != null);
318 // since some listeners might call this on every method invocation, we should do a little optimization
319 static AnnotationInfo[][] NO_PARAMETER_ANNOTATIONS_0 = new AnnotationInfo[0][];
320 static AnnotationInfo[][] NO_PARAMETER_ANNOTATIONS_1 = { new AnnotationInfo[0] };
321 static AnnotationInfo[][] NO_PARAMETER_ANNOTATIONS_2 = { new AnnotationInfo[0], new AnnotationInfo[0] };
322 static AnnotationInfo[][] NO_PARAMETER_ANNOTATIONS_3 = { new AnnotationInfo[0], new AnnotationInfo[0], new AnnotationInfo[0] };
324 public AnnotationInfo[][] getParameterAnnotations() {
325 if (parameterAnnotations == null){ // keep this similar to getAnnotations()
326 int n = getNumberOfArguments();
328 case 0: return NO_PARAMETER_ANNOTATIONS_0;
329 case 1: return NO_PARAMETER_ANNOTATIONS_1;
330 case 2: return NO_PARAMETER_ANNOTATIONS_2;
331 case 3: return NO_PARAMETER_ANNOTATIONS_3;
333 AnnotationInfo[][] pai = new AnnotationInfo[n][];
334 for (int i=0; i<n; i++){
335 pai[i] = new AnnotationInfo[0];
341 return parameterAnnotations;
346 * return annotations for parameterIndex
348 public AnnotationInfo[] getParameterAnnotations(int parameterIndex){
349 if (parameterAnnotations == null){
352 if (parameterIndex >= getNumberOfArguments()){
355 return parameterAnnotations[parameterIndex];
362 public static int getNumberOfLoadedMethods () {
363 return mthTable.size();
366 void setAtomic (boolean isAtomic) {
368 attributes |= EXEC_ATOMIC;
370 attributes &= ~EXEC_ATOMIC;
373 public boolean isAtomic () {
374 return ((attributes & EXEC_ATOMIC) != 0);
377 void setHidden (boolean isHidden) {
379 attributes |= EXEC_HIDDEN;
381 attributes &= ~EXEC_HIDDEN;
384 public boolean isHidden () {
385 return ((attributes & EXEC_HIDDEN) != 0);
389 * turn unhandled exceptionHandlers at the JPF execution level
390 * into UnhandledException throws at the host VM level
391 * this is useful to implement firewalls for direct calls
392 * which should not let exceptionHandlers permeate into bytecode/
395 public void setFirewall (boolean isFirewalled) {
397 attributes |= FIREWALL;
399 attributes &= ~FIREWALL;
402 public boolean isFirewall () {
403 return ((attributes & FIREWALL) != 0);
409 public Object clone() {
411 return super.clone();
412 } catch (CloneNotSupportedException cnx) {
417 public int getGlobalId() {
421 public DirectCallStackFrame createRunStartStackFrame (ThreadInfo ti){
422 return ci.createRunStartStackFrame( ti, this);
425 public DirectCallStackFrame createDirectCallStackFrame (ThreadInfo ti, int nLocals){
426 return ci.createDirectCallStackFrame(ti, this, nLocals);
429 public boolean isSyncRelevant () {
430 return (name.charAt(0) != '<');
433 public boolean isInitOrClinit (){
434 return ((attributes & (IS_CLINIT | IS_INIT)) != 0);
437 public boolean isClinit () {
438 return ((attributes & IS_CLINIT) != 0);
441 public boolean isClinit (ClassInfo ci) {
442 return (((attributes & IS_CLINIT) != 0) && (this.ci == ci));
445 public boolean isInit() {
446 return ((attributes & IS_INIT) != 0);
449 public boolean isDirectCallStub(){
450 return ((attributes & IS_DIRECT_CALL) != 0);
454 * yet another name - this time with a non-mangled, but abbreviated signature
455 * and without return type (e.g. like "main(String[])"
457 public String getLongName () {
458 StringBuilder sb = new StringBuilder();
462 String[] argTypeNames = getArgumentTypeNames();
463 for (int i=0; i<argTypeNames.length; i++) {
464 String a = argTypeNames[i];
465 int idx = a.lastIndexOf('.');
467 a = a.substring(idx+1);
476 return sb.toString();
480 * return the minimal name that has to be unique for overloading
481 * used as a lookup key
482 * NOTE: with the silent introduction of covariant return types
483 * in Java 5.0, we have to use the full signature to be unique
485 public static String getUniqueName (String mname, String signature) {
486 return (mname + signature);
489 public String getStackTraceSource() {
490 return getSourceFileName();
493 public byte[] getArgumentTypes () {
494 if (argTypes == null) {
495 argTypes = Types.getArgumentTypes(signature);
496 nArgs = argTypes.length;
502 public String[] getArgumentTypeNames () {
503 return Types.getArgumentTypeNames(signature);
506 // TODO: Fix for Groovy's model-checking
507 public String[] getArgumentGenericTypeNames () {
508 // TODO: We need to double check but for some reason Groovy has a type of generic signature with "<*>"
509 // TODO: in the class file.
510 if (genericSignature == null || genericSignature.equals("") || genericSignature.contains("<*>"))
511 return getArgumentTypeNames();
512 if (!genericSignature.contains(":"))
513 return new String[0];
514 return Types.getArgumentTypeNames(genericSignature);
517 public int getArgumentsSize () {
519 argSize = Types.getArgumentsSize(signature);
530 * return only the LocalVarInfos for arguments, in order of definition
531 * or null if there are no localVarInfos.
532 * throw a JPFException if there are more immediately in scope vars than args
534 * NOTE - it is perfectly legal for a method to have arguments but no LocalVarInfos,
535 * which are code attributes, clients have to check for a non-null return value
536 * even if the method has arguments.
537 * Note also that abstract / interface methods don't have code and hence no
540 public LocalVarInfo[] getArgumentLocalVars(){
541 if (localVars == null){ // shortcut in case we don't have args or localVars;
545 int nArgs = getNumberOfStackArguments(); // we want 'this'
547 return new LocalVarInfo[0]; // rare enough so that we don't use a static
550 LocalVarInfo[] argLvis = new LocalVarInfo[nArgs];
551 int n = 0; // how many args we've got so far
553 for (LocalVarInfo lvi : localVars){
554 // arguments are the only ones that are immediately in scope
555 if (lvi.getStartPC() == 0){
556 if (n == nArgs){ // ARGH - more in-scope vars than args
557 throw new JPFException("inconsistent localVar table for method " + getFullName());
560 // order with respect to slot index - since this might get called
561 // frequently, we don't use java.util.Arrays.sort() but sort in
562 // on-the-fly. Note that we can have several localVar entries for the
563 // same name, but only one can be immediately in scope
564 int slotIdx = lvi.getSlotIndex();
567 for (i = 0; i < n; i++) {
568 if (slotIdx < argLvis[i].getSlotIndex()) {
569 for (int j=n; j>i; j--){
570 argLvis[j] = argLvis[j-1];
577 if (i == n) { // append
586 public String getReturnType () {
587 return Types.getReturnTypeSignature(signature);
590 public String getReturnTypeName () {
591 return Types.getReturnTypeName(signature);
594 public String getGenericReturnTypeName () {
595 // TODO: We need to double check but for some reason Groovy has a type of generic signature with "<*>"
596 // TODO: in the class file.
597 if (genericSignature == null || genericSignature.equals("") || genericSignature.contains("<*>"))
598 return Types.getReturnTypeName(signature);
599 if (!genericSignature.contains(":"))
600 return Types.getReturnTypeName(signature);
601 return Types.getGenericReturnTypeName(genericSignature);
604 public String getSourceFileName () {
606 return ci.getSourceFileName();
612 public String getClassName () {
621 * Returns the class the method belongs to.
623 public ClassInfo getClassInfo () {
628 * @deprecated - use getFullName
631 public String getCompleteName () {
632 return getFullName();
636 * return classname.name (but w/o signature)
638 public String getBaseName() {
639 return getClassName() + '.' + name;
642 public boolean isCtor () {
643 return (name.equals("<init>"));
646 public boolean isInternalMethod () {
647 // <2do> pcm - should turn this into an attribute for efficiency reasons
648 return (name.equals("<clinit>") || uniqueName.equals("finalize()V"));
651 public boolean isThreadEntry (ThreadInfo ti) {
652 return (uniqueName.equals("run()V") && (ti.countStackFrames() == 1));
656 * Returns the full classname (if any) + name + signature.
658 public String getFullName () {
660 return ci.getName() + '.' + getUniqueName();
662 return getUniqueName();
667 * returns stack trace name: classname (if any) + name
669 public String getStackTraceName(){
671 return ci.getName() + '.' + name;
678 * return number of instructions
680 public int getNumberOfInstructions() {
689 * Returns a specific instruction.
691 public Instruction getInstruction (int i) {
696 if ((i < 0) || (i >= code.length)) {
704 * Returns the instruction at a certain position.
706 public Instruction getInstructionAt (int position) {
711 for (int i = 0, l = code.length; i < l; i++) {
712 if ((code[i] != null) && (code[i].getPosition() == position)) {
717 throw new JPFException("instruction not found");
721 * Returns the instructions of the method.
723 public Instruction[] getInstructions () {
727 public boolean includesLine (int line){
728 int len = code.length;
729 return (code[0].getLineNumber() <= line) && (code[len].getLineNumber() >= line);
732 public Instruction[] getInstructionsForLine (int line){
733 return getInstructionsForLineInterval(line,line);
736 public Instruction[] getInstructionsForLineInterval (int l1, int l2){
737 Instruction[] c = code;
739 // instruction line numbers don't have to be monotonic (they can decrease for loops)
740 // hence we cannot easily check for overlapping ranges
743 ArrayList<Instruction> matchingInsns = null;
745 for (int i = 0; i < c.length; i++) {
746 Instruction insn = c[i];
747 int line = insn.getLineNumber();
748 if (line == l1 || line == l2 || (line > l1 && line < l2)) {
749 if (matchingInsns == null) {
750 matchingInsns = new ArrayList<Instruction>();
752 matchingInsns.add(insn);
756 if (matchingInsns == null) {
759 return matchingInsns.toArray(new Instruction[matchingInsns.size()]);
767 public Instruction[] getMatchingInstructions (LocationSpec lspec){
768 return getInstructionsForLineInterval(lspec.getFromLine(), lspec.getToLine());
773 * Returns the line number for a given position.
775 public int getLineNumber (Instruction pc) {
776 if (lineNumbers == null) {
780 return pc.getPosition();
784 int idx = pc.getInstructionIndex();
785 if (idx < 0) idx = 0;
786 return lineNumbers[idx];
793 * Returns a table to translate positions into line numbers.
795 public int[] getLineNumbers () {
799 public boolean containsLineNumber (int n){
800 if (lineNumbers != null){
801 return (lineNumbers[0] <= n) && (lineNumbers[lineNumbers.length-1] <= n);
807 public boolean intersectsLineNumbers( int first, int last){
808 if (lineNumbers != null){
809 if ((last < lineNumbers[0]) || (first > lineNumbers[lineNumbers.length-1])){
818 public ExceptionHandler getHandlerFor (ClassInfo ciException, Instruction insn){
819 if (exceptionHandlers != null){
820 int position = insn.getPosition();
821 for (int i=0; i<exceptionHandlers.length; i++){
822 ExceptionHandler handler = exceptionHandlers[i];
823 if ((position >= handler.getBegin()) && (position < handler.getEnd())) {
824 // checks if this type of exception is caught here (null means 'any')
825 String handledType = handler.getName();
826 if ((handledType == null) // a catch-all handler
827 || ciException.isInstanceOf(handledType)) {
837 public boolean isMJI () {
841 public int getMaxLocals () {
845 public int getMaxStack () {
849 public ExceptionHandler[] getExceptions () {
850 return exceptionHandlers;
853 public String[] getThrownExceptionClassNames () {
854 return thrownExceptionClassNames;
858 public LocalVarInfo getLocalVar(String name, int pc){
859 LocalVarInfo[] vars = localVars;
861 for (int i = 0; i < vars.length; i++) {
862 LocalVarInfo lv = vars[i];
863 if (lv.matches(name, pc)) {
873 public LocalVarInfo getLocalVar (int slotIdx, int pc){
874 LocalVarInfo[] vars = localVars;
877 for (int i = 0; i < vars.length; i++) {
878 LocalVarInfo lv = vars[i];
879 if (lv.matches(slotIdx, pc)) {
888 public LocalVarInfo[] getLocalVars() {
894 * note that this might contain duplicates for variables with multiple
897 public String[] getLocalVariableNames() {
898 String[] names = new String[localVars.length];
900 for (int i=0; i<localVars.length; i++){
901 names[i] = localVars[i].getName();
908 public MethodInfo getOverriddenMethodInfo(){
909 MethodInfo smi = null;
912 ClassInfo sci = ci.getSuperClass();
914 smi = sci.getMethod(getUniqueName(), true);
922 * Returns the name of the method.
924 public String getName () {
928 public String getJNIName () {
929 return Types.getJNIMangledMethodName(null, name, signature);
932 public int getModifiers () {
937 * Returns true if the method is native
939 public boolean isNative () {
940 return ((modifiers & Modifier.NATIVE) != 0);
943 public boolean isAbstract () {
944 return ((modifiers & Modifier.ABSTRACT) != 0);
947 // overridden by NativeMethodInfo
948 public boolean isUnresolvedNativeMethod(){
949 return ((modifiers & Modifier.NATIVE) != 0);
952 // overridden by NativeMethodInfo
953 public boolean isJPFExecutable (){
954 return !hasAttr(NoJPFExec.class);
957 public int getNumberOfArguments () {
959 nArgs = Types.getNumberOfArguments(signature);
966 * Returns the size of the arguments.
967 * This returns the number of parameters passed on the stack, incl. 'this'
969 public int getNumberOfStackArguments () {
970 int n = getNumberOfArguments();
972 return isStatic() ? n : n + 1;
975 public int getNumberOfCallerStackSlots () {
976 return Types.getNumberOfStackSlots(signature, isStatic()); // includes return type
979 public Instruction getFirstInsn(){
986 public Instruction getLastInsn() {
988 return code[code.length-1];
994 * do we return Object references?
996 public boolean isReferenceReturnType () {
997 int r = getReturnTypeCode();
999 return ((r == Types.T_REFERENCE) || (r == Types.T_ARRAY));
1002 public byte getReturnTypeCode () {
1003 if (returnType < 0) {
1004 returnType = Types.getReturnBuiltinType(signature);
1011 * what is the slot size of the return value
1013 public int getReturnSize() {
1015 switch (getReturnTypeCode()) {
1021 case Types.T_DOUBLE:
1034 public Class<? extends ChoiceGenerator<?>> getReturnChoiceGeneratorType (){
1035 switch (getReturnTypeCode()){
1036 case Types.T_BOOLEAN:
1037 return BooleanChoiceGenerator.class;
1043 return IntChoiceGenerator.class;
1046 return LongChoiceGenerator.class;
1049 return FloatChoiceGenerator.class;
1051 case Types.T_DOUBLE:
1052 return DoubleChoiceGenerator.class;
1055 case Types.T_REFERENCE:
1057 return ReferenceChoiceGenerator.class;
1064 * Returns the signature of the method.
1066 public String getSignature () {
1071 public String getGenericSignature() {
1072 return genericSignature;
1076 public void setGenericSignature(String sig){
1077 genericSignature = sig;
1081 * Returns true if the method is static.
1083 public boolean isStatic () {
1084 return ((modifiers & Modifier.STATIC) != 0);
1088 * is this a public method
1090 public boolean isPublic() {
1091 return ((modifiers & Modifier.PUBLIC) != 0);
1094 public boolean isPrivate() {
1095 return ((modifiers & Modifier.PRIVATE) != 0);
1098 public boolean isProtected() {
1099 return ((modifiers & Modifier.PROTECTED) != 0);
1103 * Returns true if the method is synchronized.
1105 public boolean isSynchronized () {
1106 return ((modifiers & Modifier.SYNCHRONIZED) != 0);
1109 // <2do> these modifiers are still java.lang.reflect internal and not
1110 // supported by public Modifier methods, but since we want to keep this
1111 // similar to the Method reflection and we get the modifiers from the
1112 // classfile we implement this with explicit values
1114 public boolean isSynthetic(){
1115 return ((modifiers & 0x00001000) != 0);
1117 public boolean isVarargs(){
1118 return ((modifiers & 0x00000080) != 0);
1122 * is this from a classfile or was it created by JPF (and hence should not
1123 * be visible in stacktraces etc)
1125 public boolean isJPFInternal(){
1126 // note this has a different meaning than Method.isSynthetic(), which
1127 // is defined in VM spec 4.7.8. What we mean here is that this MethodInfo
1128 // is not associated with any class (such as direct call MethodInfos), but
1129 // there might be more in the future
1130 return (ci == null);
1133 public String getUniqueName () {
1137 public boolean hasCode(){
1138 return (code != null);
1141 public boolean hasEmptyBody (){
1142 // only instruction is a return
1143 return (code.length == 1 && (code[0] instanceof ReturnInstruction));
1147 //--- parameter annotations
1148 //<2do> these are going away
1149 protected void startParameterAnnotations(int annotationCount){
1150 parameterAnnotations = new AnnotationInfo[annotationCount][];
1152 protected void setParameterAnnotations(int index, AnnotationInfo[] ai){
1153 parameterAnnotations[index] = ai;
1155 protected void finishParameterAnnotations(){
1159 public void setParameterAnnotations (AnnotationInfo[][] parameterAnnotations){
1160 this.parameterAnnotations = parameterAnnotations;
1163 //--- thrown exceptions
1164 //<2do> these are going away
1165 protected void startTrownExceptions (int exceptionCount){
1166 thrownExceptionClassNames = new String[exceptionCount];
1168 protected void setException (int index, String exceptionType){
1169 thrownExceptionClassNames[index] = Types.getClassNameFromTypeName(exceptionType);
1171 protected void finishThrownExceptions(){
1175 public void setThrownExceptions (String[] exceptions){
1176 thrownExceptionClassNames = exceptions;
1180 //--- exception handler table initialization
1181 //<2do> these are going away
1182 protected void startExceptionHandlerTable (int handlerCount){
1183 exceptionHandlers = new ExceptionHandler[handlerCount];
1185 protected void setExceptionHandler (int index, int startPc, int endPc, int handlerPc, String catchType){
1186 exceptionHandlers[index] = new ExceptionHandler(catchType, startPc, endPc, handlerPc);
1188 protected void finishExceptionHandlerTable(){
1192 public void setExceptionHandlers (ExceptionHandler[] handlers){
1193 exceptionHandlers = handlers;
1196 //--- local var table initialization
1197 // <2do> these are going away
1198 protected void startLocalVarTable (int localVarCount){
1199 localVars = new LocalVarInfo[localVarCount];
1201 protected void setLocalVar(int index, String varName, String descriptor, int scopeStartPc, int scopeEndPc, int slotIndex){
1202 localVars[index] = new LocalVarInfo(varName, descriptor, "", scopeStartPc, scopeEndPc, slotIndex);
1204 protected void finishLocalVarTable(){
1208 public void setLocalVarTable (LocalVarInfo[] locals){
1212 public void setLocalVarAnnotations (){
1213 if (localVars != null){
1214 for (VariableAnnotationInfo ai : getTargetTypeAnnotations(VariableAnnotationInfo.class)){
1215 for (int i = 0; i < ai.getNumberOfScopeEntries(); i++) {
1216 for (LocalVarInfo lv : localVars) {
1217 if (lv.getStartPC() == ai.getStartPC(i) && lv.getSlotIndex() == ai.getSlotIndex(i)) {
1218 lv.addTypeAnnotation(ai);
1226 public boolean hasTypeAnnotatedLocalVars (){
1227 if (localVars != null){
1228 for (LocalVarInfo lv : localVars){
1229 if (lv.hasTypeAnnotations()){
1238 public List<LocalVarInfo> getTypeAnnotatedLocalVars (){
1239 List<LocalVarInfo> list = null;
1241 if (localVars != null){
1242 for (LocalVarInfo lv : localVars){
1243 if (lv.hasTypeAnnotations()){
1245 list = new ArrayList<LocalVarInfo>();
1253 list = Collections.emptyList();
1259 public List<LocalVarInfo> getTypeAnnotatedLocalVars (String annotationClsName){
1260 List<LocalVarInfo> list = null;
1262 if (localVars != null){
1263 for (LocalVarInfo lv : localVars){
1264 AbstractTypeAnnotationInfo tai = lv.getTypeAnnotation(annotationClsName);
1267 list = new ArrayList<LocalVarInfo>();
1275 list = Collections.emptyList();
1282 //--- line number table initialization
1283 // <2do> these are going away
1284 protected void startLineNumberTable(int lineNumberCount){
1285 int len = code.length;
1286 int[] ln = new int[len];
1290 protected void setLineNumber(int index, int lineNumber, int startPc){
1291 int len = code.length;
1292 int[] ln = lineNumbers;
1294 for (int i=0; i<len; i++){
1295 Instruction insn = code[i];
1296 int pc = insn.getPosition();
1298 if (pc == startPc){ // this is the first insn with this line number
1304 protected void finishLineNumberTable (){
1305 int len = code.length;
1306 int[] ln = lineNumbers;
1307 int lastLine = ln[0];
1309 for (int i=1; i<len; i++){
1319 * note - this depends on that we already have a code array
1320 * and that the lines/startPcs are sorted (monotonic increasing)
1322 public void setLineNumbers (int[] lines, int[] startPcs){
1326 int len = code.length;
1327 int[] ln = new int[len];
1329 for (int i=0; i<len; i++){
1330 Instruction insn = code[i];
1331 int pc = insn.getPosition();
1333 if ((j < startPcs.length) && pc == startPcs[j]){
1334 lastLine = lines[j];
1345 * this version takes an already expanded line number array which has to be of
1346 * the same size as the code array
1348 public void setLineNumbers (int[] lines){
1349 if (lines.length != code.length){
1350 throw new JPFException("inconsitent code/line number size");
1352 lineNumbers = lines;
1356 public String toString() {
1357 return "MethodInfo[" + getFullName() + ']';
1360 // for debugging purposes
1362 System.out.println("--- " + this);
1363 for (int i = 0; i < code.length; i++) {
1364 System.out.printf("%2d [%d]: %s\n", i, code[i].getPosition(), code[i].toString());
1369 * Creates a method for a given class, by cloning this MethodInfo
1370 * and all the instructions belong to the method
1372 public MethodInfo getInstanceFor(ClassInfo ci) {
1376 clone = (MethodInfo)super.clone();
1379 clone.globalId = mthTable.size();
1385 clone.code = new Instruction[code.length];
1387 for(int i=0; i<code.length; i++) {
1388 clone.code[i] = code[i].typeSafeClone(clone);
1392 } catch (CloneNotSupportedException cnsx){
1393 cnsx.printStackTrace();