Testing for all 3 new method implementations.
[jpf-core.git] / src / peers / gov / nasa / jpf / vm / JPF_java_lang_reflect_Method.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
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
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
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.
17  */
18 package gov.nasa.jpf.vm;
19
20 import gov.nasa.jpf.Config;
21 import gov.nasa.jpf.annotation.MJI;
22 import gov.nasa.jpf.util.MethodInfoRegistry;
23 import gov.nasa.jpf.util.RunListener;
24 import gov.nasa.jpf.util.RunRegistry;
25
26 import java.lang.reflect.Modifier;
27 import java.util.ArrayList;
28
29 public class JPF_java_lang_reflect_Method extends NativePeer {
30
31   static MethodInfoRegistry registry;
32
33   // class init - this is called automatically from the NativePeer ctor
34   public static boolean init (Config conf) {
35     // this is an example of how to handle cross-initialization between
36     // native peers - this might also get explicitly called by the java.lang.Class
37     // peer, since it creates Method objects. Here we have to make sure
38     // we only reset between JPF runs
39
40     if (registry == null){
41       registry = new MethodInfoRegistry();
42       
43       RunRegistry.getDefaultRegistry().addListener( new RunListener() {
44         @Override
45                 public void reset (RunRegistry reg){
46           registry = null;
47         }
48       });
49     }
50     return true;
51   }
52
53   static int createMethodObject (MJIEnv env, ClassInfo ciMth, MethodInfo mi){
54     // note - it is the callers responsibility to ensure Method is properly initialized    
55     int regIdx = registry.registerMethodInfo(mi);
56     int eidx = env.newObject( ciMth);
57     ElementInfo ei = env.getModifiableElementInfo(eidx);
58     
59     ei.setIntField("regIdx", regIdx);
60     ei.setBooleanField("isAccessible", mi.isPublic());
61     
62     return eidx;
63   }
64   
65   // this is NOT an MJI method, but it is used outside this package, so
66   // we have to add 'final'
67   public static final MethodInfo getMethodInfo (MJIEnv env, int objRef){
68     return registry.getMethodInfo(env,objRef, "regIdx");
69   }
70   
71   @MJI
72   public int getName____Ljava_lang_String_2 (MJIEnv env, int objRef) {
73     MethodInfo mi = getMethodInfo(env, objRef);
74     
75     int nameRef = env.getReferenceField( objRef, "name");
76     if (nameRef == MJIEnv.NULL) {
77       nameRef = env.newString(mi.getName());
78       env.setReferenceField(objRef, "name", nameRef);
79     }
80    
81     return nameRef;
82   }
83
84   @MJI
85   public int getModifiers____I (MJIEnv env, int objRef){
86     MethodInfo mi = getMethodInfo(env, objRef);
87     return mi.getModifiers();
88   }
89
90   static int getParameterTypes( MJIEnv env, MethodInfo mi) {
91     ThreadInfo ti = env.getThreadInfo();
92     String[] argTypeNames = mi.getArgumentTypeNames();
93     int[] ar = new int[argTypeNames.length];
94
95     for (int i = 0; i < argTypeNames.length; i++) {
96       ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(argTypeNames[i]);
97       if (!ci.isRegistered()) {
98         ci.registerClass(ti);
99       }
100
101       ar[i] = ci.getClassObjectRef();
102     }
103
104     int aRef = env.newObjectArray("Ljava/lang/Class;", argTypeNames.length);
105     for (int i = 0; i < argTypeNames.length; i++) {
106       env.setReferenceArrayElement(aRef, i, ar[i]);
107     }
108
109     return aRef;
110   }
111
112   @MJI
113   public int getParameterTypes_____3Ljava_lang_Class_2 (MJIEnv env, int objRef){
114     return getParameterTypes(env, getMethodInfo(env, objRef));
115   }
116
117   // TODO: Fix for Groovy's model-checking
118   private static int getParameterizedTypeImplObj(String signature, MJIEnv env) {
119
120     ThreadInfo ti = env.getThreadInfo();
121     ClassLoaderInfo cli = env.getSystemClassLoaderInfo();
122     ClassInfo ci = cli.getResolvedClassInfo("sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl");
123     // Create a new object of type ParameterizedTypeImpl
124     int paramTypeRef = env.newObject(ci);
125     ElementInfo ei = env.getModifiableElementInfo(paramTypeRef);
126     // Get field information and fill out the fields
127     // rawType field
128     String className = Types.getGenericClassName(signature);
129     ClassInfo gci = cli.getResolvedClassInfo(className);
130     if (!gci.isRegistered()) {
131         gci.registerClass(ti);
132     }
133     ei.setReferenceField("rawType", gci.getClassObjectRef());
134
135     // actualTypeArguments
136     String[] parameterizedTypes = Types.getParameterizedTypesFromArgumentTypeNames(signature);
137     int[] types = new int[parameterizedTypes.length];
138     for(int j = 0; j < parameterizedTypes.length; j++) {
139       ClassInfo pci = cli.getResolvedClassInfo(parameterizedTypes[j]);
140       if (!pci.isRegistered()) {
141         pci.registerClass(ti);
142       }
143       types[j] = pci.getClassObjectRef();
144     }
145     int aRef = env.newObjectArray("Ljava/lang/reflect/Type;", parameterizedTypes.length);
146     // Set references for every array element
147     for (int j = 0; j < parameterizedTypes.length; j++) {
148       env.setReferenceArrayElement(aRef, j, types[j]);
149     }
150     ei.setReferenceField("actualTypeArguments", aRef);
151
152     // ownerType
153     String ownerType = Types.getOwnerClassName(signature);
154     if (ownerType != null) {
155       ClassInfo oci = ClassLoaderInfo.getCurrentResolvedClassInfo(ownerType);
156       if (!oci.isRegistered()) {
157         oci.registerClass(ti);
158       }
159       ei.setReferenceField("ownerType", oci.getClassObjectRef());
160     } else {
161       ei.setReferenceField("ownerType", MJIEnv.NULL);
162     }
163
164     return paramTypeRef;
165   }
166
167   static int getGenericParameterTypes( MJIEnv env, int objRef, MethodInfo mi) {
168     ThreadInfo ti = env.getThreadInfo();
169     String[] argTypeNames = mi.getArgumentGenericTypeNames();
170     int[] ar = new int[argTypeNames.length];
171
172     for (int i = 0; i < argTypeNames.length; i++) {
173       // Change this into just the generic class type if it is a generic class
174       if (Types.isGenericSignature(argTypeNames[i])) {
175         ar[i] = getParameterizedTypeImplObj(argTypeNames[i], env);
176       } else {
177         ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(argTypeNames[i]);
178         if (!ci.isRegistered()) {
179           ci.registerClass(ti);
180         }
181         ar[i] = ci.getClassObjectRef();
182       }
183     }
184     int aRef = env.newObjectArray("Ljava/lang/reflect/Type;", argTypeNames.length);
185     for (int i = 0; i < argTypeNames.length; i++) {
186       env.setReferenceArrayElement(aRef, i, ar[i]);
187     }
188
189     return aRef;
190   }
191
192   @MJI
193   public int getGenericParameterTypes_____3Ljava_lang_reflect_Type_2 (MJIEnv env, int objRef){
194     return getGenericParameterTypes(env, objRef, getMethodInfo(env, objRef));
195   }
196
197   @MJI
198   public int getGenericReturnType____Ljava_lang_reflect_Type_2 (MJIEnv env, int objRef){
199     MethodInfo mi = getMethodInfo(env, objRef);
200     ThreadInfo ti = env.getThreadInfo();
201
202     int retRef;
203     if (Types.isGenericSignature(mi.getGenericReturnTypeName())) {
204       retRef = getParameterizedTypeImplObj(mi.getGenericReturnTypeName(), env);
205     } else {
206       ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(mi.getReturnTypeName());
207       if (!ci.isRegistered()) {
208         ci.registerClass(ti);
209       }
210       retRef = ci.getClassObjectRef();
211     }
212
213     return retRef;
214   }
215   // TODO: Fix for Groovy's model-checking
216   // TODO: We have been able to only register the generic class and not yet the parameterized types
217
218   int getExceptionTypes(MJIEnv env, MethodInfo mi) {
219     ThreadInfo ti = env.getThreadInfo();
220     String[] exceptionNames = mi.getThrownExceptionClassNames();
221      
222     if (exceptionNames == null) {
223       exceptionNames = new String[0];
224     }
225      
226     int[] ar = new int[exceptionNames.length];
227      
228     for (int i = 0; i < exceptionNames.length; i++) {
229       ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(exceptionNames[i]);
230       if (!ci.isRegistered()) {
231         ci.registerClass(ti);
232       }
233        
234       ar[i] = ci.getClassObjectRef();
235     }
236      
237     int aRef = env.newObjectArray("Ljava/lang/Class;", exceptionNames.length);
238     for (int i = 0; i < exceptionNames.length; i++) {
239       env.setReferenceArrayElement(aRef, i, ar[i]);
240     }
241      
242     return aRef;
243   }
244   
245   @MJI
246   public int getExceptionTypes_____3Ljava_lang_Class_2 (MJIEnv env, int objRef) {
247     return getExceptionTypes(env, getMethodInfo(env, objRef));
248   }
249   
250   @MJI
251   public int getDefaultValue____Ljava_lang_Object_2(MJIEnv env, int objRef) {
252     MethodInfo mi = getMethodInfo(env, objRef);
253     ClassInfo ci = mi.getClassInfo();
254     if(!ci.isInterface() || ci.getDirectInterfaceNames() == null || ci.getDirectInterfaceNames().length != 1 || !ci.getDirectInterfaceNames()[0].equals("java.lang.annotation.Annotation")) {
255       return MJIEnv.NULL;
256     }
257     String annotationName = ci.getName();
258     AnnotationInfo ai = ci.getClassLoaderInfo().getResolvedAnnotationInfo(annotationName);
259     Object o = ai.getValue(mi.getName());
260     if(o == null) {
261       return MJIEnv.NULL;
262     }
263     try {
264       return env.liftNativeAnnotationValue(Types.getTypeName(mi.getReturnType()), o);
265     } catch(ClinitRequired e) {
266       env.handleClinitRequest(e.getRequiredClassInfo());
267       return -1;
268     }
269   }
270   
271   @MJI
272   public int getReturnType____Ljava_lang_Class_2 (MJIEnv env, int objRef){
273     MethodInfo mi = getMethodInfo(env, objRef);
274     ThreadInfo ti = env.getThreadInfo();
275
276     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(mi.getReturnTypeName());
277     if (!ci.isRegistered()) {
278       ci.registerClass(ti);
279     }
280
281     return ci.getClassObjectRef();
282   }
283   
284   @MJI
285   public int getDeclaringClass____Ljava_lang_Class_2 (MJIEnv env, int objRef){
286     MethodInfo mi = getMethodInfo(env, objRef);    
287     ClassInfo ci = mi.getClassInfo();
288     // it's got to be registered, otherwise we wouldn't be able to acquire the Method object
289     return ci.getClassObjectRef();
290   }
291     
292   static int createBoxedReturnValueObject (MJIEnv env, MethodInfo mi, DirectCallStackFrame frame) {
293     byte rt = mi.getReturnTypeCode();
294     int ret = MJIEnv.NULL;
295     ElementInfo rei;
296     Object attr = null;
297
298     if (rt == Types.T_DOUBLE) {
299       attr = frame.getLongResultAttr();
300       double v = frame.getDoubleResult();
301       ret = env.newObject(ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Double"));
302       rei = env.getModifiableElementInfo(ret);
303       rei.setDoubleField("value", v);
304     } else if (rt == Types.T_FLOAT) {
305       attr = frame.getResultAttr();
306       float v = frame.getFloatResult();
307       ret = env.newObject(ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Float"));
308       rei = env.getModifiableElementInfo(ret);
309       rei.setFloatField("value", v);
310     } else if (rt == Types.T_LONG) {
311       attr = frame.getLongResultAttr();
312       long v = frame.getLongResult();
313       ret = env.valueOfLong(v);
314     } else if (rt == Types.T_BYTE) {
315       attr = frame.getResultAttr();
316       int v = frame.getResult(); 
317       ret = env.valueOfByte((byte)v);
318     } else if (rt == Types.T_CHAR) {
319       attr = frame.getResultAttr();
320       int v = frame.getResult(); 
321       ret = env.valueOfCharacter((char)v);
322     } else if (rt == Types.T_SHORT) {
323       attr = frame.getResultAttr();
324       int v = frame.getResult(); 
325       ret = env.valueOfShort((short)v);
326     } else if (rt == Types.T_INT) {
327       attr = frame.getResultAttr();
328       int v = frame.getResult(); 
329       ret = env.valueOfInteger(v);
330     } else if (rt == Types.T_BOOLEAN) {
331       attr = frame.getResultAttr();
332       int v = frame.getResult();
333       ret = env.valueOfBoolean((v == 1)? true: false);
334     } else if (mi.isReferenceReturnType()){ 
335       attr = frame.getResultAttr();
336       ret = frame.getReferenceResult();
337     }
338
339     env.setReturnAttribute(attr);
340     return ret;
341   }
342
343   static boolean pushUnboxedArguments (MJIEnv env, MethodInfo mi, DirectCallStackFrame frame, int argIdx, int argsRef) {
344     ElementInfo source;
345     ClassInfo sourceClass;
346     String destTypeNames[];
347     int nArgs, passedCount, sourceRef;
348     byte sourceType, destTypes[];
349
350     destTypes     = mi.getArgumentTypes();
351     destTypeNames = mi.getArgumentTypeNames();
352     nArgs         = destTypeNames.length;
353     
354     // according to the API docs, passing null instead of an empty array is allowed for no args
355     passedCount   = (argsRef != MJIEnv.NULL) ? env.getArrayLength(argsRef) : 0;
356     
357     if (nArgs != passedCount) {
358       env.throwException(IllegalArgumentException.class.getName(), "Wrong number of arguments passed.  Actual = " + passedCount + ".  Expected = " + nArgs);
359       return false;
360     }
361     
362     for (int i = 0; i < nArgs; i++) {
363       sourceRef = env.getReferenceArrayElement(argsRef, i);
364
365       // we have to handle null references explicitly
366       if (sourceRef == MJIEnv.NULL) {
367         if ((destTypes[i] != Types.T_REFERENCE) && (destTypes[i] != Types.T_ARRAY)) {
368           env.throwException(IllegalArgumentException.class.getName(), "Wrong argument type at index " + i + ".  Actual = (null).  Expected = " + destTypeNames[i]);
369           return false;
370         } 
371          
372         frame.pushRef(MJIEnv.NULL);
373         continue;
374       }
375
376       source      = env.getElementInfo(sourceRef);
377       sourceClass = source.getClassInfo();   
378       sourceType = getSourceType( sourceClass, destTypes[i], destTypeNames[i]);
379
380       Object attr = env.getElementInfo(argsRef).getFields().getFieldAttr(i);
381       if ((argIdx = pushArg( argIdx, frame, source, sourceType, destTypes[i], attr)) < 0 ){
382         env.throwException(IllegalArgumentException.class.getName(), "Wrong argument type at index " + i + ".  Source Class = " + sourceClass.getName() + ".  Dest Class = " + destTypeNames[i]);
383         return false;        
384       }
385     }
386     
387     return true;
388   }
389
390   // this returns the primitive type in case we have to unbox, and otherwise checks reference type compatibility
391   private static byte getSourceType (ClassInfo ciArgVal, byte destType, String destTypeName){
392     switch (destType){
393     // the primitives
394     case Types.T_BOOLEAN:
395     case Types.T_BYTE:
396     case Types.T_CHAR:
397     case Types.T_SHORT:
398     case Types.T_INT:
399     case Types.T_LONG:
400     case Types.T_FLOAT:
401     case Types.T_DOUBLE:
402       return Types.getUnboxedType(ciArgVal.getName());
403       
404     case Types.T_ARRAY:
405     case Types.T_REFERENCE: // check if the source type is assignment compatible with the destType
406       if (ciArgVal.isInstanceOf(destTypeName)){
407         return destType;
408       }
409     }
410     
411     return Types.T_NONE;
412   }
413   
414   // do the proper type conversion - Java is pretty forgiving here and does
415   // not throw exceptions upon value truncation
416   private static int pushArg( int argIdx, DirectCallStackFrame frame, ElementInfo eiArg, byte srcType, byte destType, Object attr){    
417     switch (srcType) {
418     case Types.T_DOUBLE:
419     {
420       double v = eiArg.getDoubleField("value");
421       if (destType == Types.T_DOUBLE){
422         return frame.setDoubleArgument( argIdx, v, attr);
423       }
424       return -1;
425     }
426     case Types.T_FLOAT: // covers float, double
427     {
428       float v = eiArg.getFloatField("value");
429       switch (destType){
430       case Types.T_FLOAT:
431         return frame.setFloatArgument( argIdx, v, attr);
432       case Types.T_DOUBLE:
433         return frame.setDoubleArgument( argIdx, v, attr);
434       }
435       return -1;
436     }
437     case Types.T_LONG:
438     {
439       long v = eiArg.getLongField("value");
440       switch (destType){
441       case Types.T_LONG:
442         return frame.setLongArgument(argIdx, v, attr);
443       case Types.T_FLOAT:
444         return frame.setFloatArgument(argIdx, v, attr);
445       case Types.T_DOUBLE:
446         return frame.setDoubleArgument( argIdx, v, attr);
447       }
448       return -1;
449     }
450     case Types.T_INT:
451     { 
452       int v = eiArg.getIntField("value");
453       switch (destType){
454       case Types.T_INT:
455         return frame.setArgument( argIdx, v, attr);
456       case Types.T_LONG:
457         return frame.setLongArgument( argIdx, v, attr);
458       case Types.T_FLOAT:
459         return frame.setFloatArgument(argIdx, v, attr);
460       case Types.T_DOUBLE:
461         return frame.setDoubleArgument( argIdx, v, attr);
462       }
463       return -1;
464     }
465     case Types.T_SHORT:
466     { 
467       int v = eiArg.getShortField("value");
468       switch (destType){
469       case Types.T_SHORT:
470       case Types.T_INT:
471         return frame.setArgument( argIdx, v, attr);
472       case Types.T_LONG:
473         return frame.setLongArgument( argIdx, v, attr);
474       case Types.T_FLOAT:
475         return frame.setFloatArgument(argIdx, v, attr);
476       case Types.T_DOUBLE:
477         return frame.setDoubleArgument( argIdx, v, attr);
478       }
479       return -1;
480     }
481     case Types.T_BYTE:
482     { 
483       byte v = eiArg.getByteField("value");
484       switch (destType){
485       case Types.T_BYTE:
486       case Types.T_SHORT:
487       case Types.T_INT:
488         return frame.setArgument( argIdx, v, attr);
489       case Types.T_LONG:
490         return frame.setLongArgument( argIdx, v, attr);
491       case Types.T_FLOAT:
492         return frame.setFloatArgument(argIdx, v, attr);
493       case Types.T_DOUBLE:
494         return frame.setDoubleArgument( argIdx, v, attr);
495       }
496       return -1;
497     }
498     case Types.T_CHAR:
499     {
500       char v = eiArg.getCharField("value");
501       switch (destType){
502       case Types.T_CHAR:
503       case Types.T_INT:
504         return frame.setArgument( argIdx, v, attr);
505       case Types.T_LONG:
506         return frame.setLongArgument( argIdx, v, attr);
507       case Types.T_FLOAT:
508         return frame.setFloatArgument(argIdx, v, attr);
509       case Types.T_DOUBLE:
510         return frame.setDoubleArgument( argIdx, v, attr);
511       }
512       return -1;
513     }
514     case Types.T_BOOLEAN:
515     {
516       boolean v = eiArg.getBooleanField("value");
517       if (destType == Types.T_BOOLEAN){
518         return frame.setArgument( argIdx, v ? 1 : 0, attr);
519       }
520       return -1;
521     }
522     case Types.T_ARRAY:
523     {
524       int ref =  eiArg.getObjectRef();
525       if (destType == Types.T_ARRAY){
526         return frame.setReferenceArgument( argIdx, ref, attr);
527       }
528       return -1;
529     }
530     case Types.T_REFERENCE:
531     {
532       int ref =  eiArg.getObjectRef();
533       if (destType == Types.T_REFERENCE){
534         return frame.setReferenceArgument( argIdx, ref, attr);
535       }
536       return -1;
537     }
538     default:
539       // T_VOID, T_NONE
540       return -1;
541     }
542   }
543
544   @MJI
545   public int invoke__Ljava_lang_Object_2_3Ljava_lang_Object_2__Ljava_lang_Object_2 (MJIEnv env, int mthRef, int objRef, int argsRef) {
546     ThreadInfo ti = env.getThreadInfo();
547     MethodInfo miCallee = getMethodInfo(env, mthRef);
548     ClassInfo calleeClass = miCallee.getClassInfo();
549     DirectCallStackFrame frame = ti.getReturnedDirectCall();
550     
551     if (frame == null){ // first time
552
553       //--- check the instance we are calling on
554       if (!miCallee.isStatic()) {
555         if (objRef == MJIEnv.NULL){
556           env.throwException("java.lang.NullPointerException");
557           return MJIEnv.NULL;
558           
559         } else {
560           ElementInfo eiObj = ti.getElementInfo(objRef);
561           ClassInfo objClass = eiObj.getClassInfo();
562         
563           if (!objClass.isInstanceOf(calleeClass)) {
564             env.throwException(IllegalArgumentException.class.getName(), "Object is not an instance of declaring class.  Actual = " + objClass + ".  Expected = " + calleeClass);
565             return MJIEnv.NULL;
566           }
567         }
568       }
569
570       //--- check accessibility
571       ElementInfo eiMth = ti.getElementInfo(mthRef);
572       if (! (Boolean) eiMth.getFieldValueObject("isAccessible")) {
573         StackFrame caller = ti.getTopFrame().getPrevious();
574         ClassInfo callerClass = caller.getClassInfo();
575
576         if (callerClass != calleeClass) {
577           env.throwException(IllegalAccessException.class.getName(), "Class " + callerClass.getName() +
578                   " can not access a member of class " + calleeClass.getName()
579                   + " with modifiers \"" + Modifier.toString(miCallee.getModifiers()));
580           return MJIEnv.NULL;
581         }
582       }
583       
584       //--- push the direct call
585       frame = miCallee.createDirectCallStackFrame(ti, 0);
586       frame.setReflection();
587       
588       int argOffset = 0;
589       if (!miCallee.isStatic()) {
590         frame.setReferenceArgument( argOffset++, objRef, null);
591       }
592       if (!pushUnboxedArguments( env, miCallee, frame, argOffset, argsRef)) {
593         // we've got a IllegalArgumentException
594         return MJIEnv.NULL;  
595       }
596       ti.pushFrame(frame);
597       
598       
599       //--- check for and push required clinits
600       if (miCallee.isStatic()){
601         calleeClass.initializeClass(ti);
602       }
603       
604       return MJIEnv.NULL; // reexecute
605       
606     } else { // we have returned from the direct call
607       return createBoxedReturnValueObject( env, miCallee, frame);
608     }
609   }
610   
611
612   // this one has to collect annotations upwards in the inheritance chain
613   static int getAnnotations (MJIEnv env, MethodInfo mi){
614     String mname = mi.getName();
615     String msig = mi.genericSignature;
616     ArrayList<AnnotationInfo> aiList = new ArrayList<AnnotationInfo>();
617     
618     // our own annotations
619     ClassInfo ci = mi.getClassInfo();
620     for (AnnotationInfo ai : mi.getAnnotations()) {
621       aiList.add(ai);
622     }
623     
624     // our superclass annotations
625     for (ci = ci.getSuperClass(); ci != null; ci = ci.getSuperClass()){
626       mi = ci.getMethod(mname, msig, false);
627       if (mi != null){
628         for (AnnotationInfo ai: mi.getAnnotations()){
629           aiList.add(ai);
630         }        
631       }
632     }
633
634     try {
635       return env.newAnnotationProxies(aiList.toArray(new AnnotationInfo[aiList.size()]));
636     } catch (ClinitRequired x){
637       env.handleClinitRequest(x.getRequiredClassInfo());
638       return MJIEnv.NULL;
639     }    
640   }
641
642   @MJI
643   public int getAnnotations_____3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int mthRef){
644     return getAnnotations( env, getMethodInfo(env,mthRef));
645   }
646   
647   // the following ones consist of a package default implementation that is shared with
648   // the constructor peer, and a public model method
649   static int getAnnotation (MJIEnv env, MethodInfo mi, int annotationClsRef){
650     ClassInfo aci = env.getReferredClassInfo(annotationClsRef);
651     
652     AnnotationInfo ai = mi.getAnnotation(aci.getName());
653     if (ai != null){
654       ClassInfo aciProxy = aci.getAnnotationProxy();
655       try {
656         return env.newAnnotationProxy(aciProxy, ai);
657       } catch (ClinitRequired x){
658         env.handleClinitRequest(x.getRequiredClassInfo());
659         return MJIEnv.NULL;
660       }
661     }
662     
663     return MJIEnv.NULL;
664   }  
665
666   @MJI
667   public int getAnnotation__Ljava_lang_Class_2__Ljava_lang_annotation_Annotation_2 (MJIEnv env, int mthRef, int annotationClsRef) {
668     return getAnnotation(env, getMethodInfo(env,mthRef), annotationClsRef);
669   }
670   
671   static int getDeclaredAnnotations (MJIEnv env, MethodInfo mi){
672     AnnotationInfo[] ai = mi.getAnnotations();
673
674     try {
675       return env.newAnnotationProxies(ai);
676     } catch (ClinitRequired x){
677       env.handleClinitRequest(x.getRequiredClassInfo());
678       return MJIEnv.NULL;
679     }    
680   }
681
682   @MJI
683   public int getDeclaredAnnotations_____3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int mthRef){
684     return getDeclaredAnnotations( env, getMethodInfo(env,mthRef));
685   }
686   
687   static int getParameterAnnotations (MJIEnv env, MethodInfo mi){
688     AnnotationInfo[][] pa = mi.getParameterAnnotations();
689     // this should always return an array object, even if the method has no arguments
690     
691     try {
692       int paRef = env.newObjectArray("[Ljava/lang/annotation/Annotation;", pa.length);
693       
694       for (int i=0; i<pa.length; i++){
695         int eRef = env.newAnnotationProxies(pa[i]);
696         env.setReferenceArrayElement(paRef, i, eRef);
697       }
698
699       return paRef;
700       
701     } catch (ClinitRequired x){ // be prepared that we might have to initialize respective annotation classes
702       env.handleClinitRequest(x.getRequiredClassInfo());
703       return MJIEnv.NULL;
704     }    
705   }
706
707   @MJI
708   public int getParameterAnnotations_____3_3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int mthRef){
709     return getParameterAnnotations( env, getMethodInfo(env,mthRef));
710   }
711
712   @MJI
713   public int toString____Ljava_lang_String_2 (MJIEnv env, int objRef){
714     StringBuilder sb = new StringBuilder();
715     
716     MethodInfo mi = getMethodInfo(env, objRef);
717
718     sb.append(Modifier.toString(mi.getModifiers()));
719     sb.append(' ');
720
721     sb.append(mi.getReturnTypeName());
722     sb.append(' ');
723
724     sb.append(mi.getClassName());
725     sb.append('.');
726
727     sb.append(mi.getName());
728
729     sb.append('(');
730     
731     String[] at = mi.getArgumentTypeNames();
732     for (int i=0; i<at.length; i++){
733       if (i>0) sb.append(',');
734       sb.append(at[i]);
735     }
736     
737     sb.append(')');
738     
739     int sref = env.newString(sb.toString());
740     return sref;
741   }
742
743   @MJI
744   public boolean equals__Ljava_lang_Object_2__Z (MJIEnv env, int objRef, int mthRef){
745     ElementInfo ei = env.getElementInfo(mthRef);
746     ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo(JPF_java_lang_Class.METHOD_CLASSNAME);
747
748     if (ei.getClassInfo() == ci){
749       MethodInfo mi1 = getMethodInfo(env, objRef);
750       MethodInfo mi2 = getMethodInfo(env, mthRef);
751       if (mi1.getClassInfo() == mi2.getClassInfo()){
752         if (mi1.getName().equals(mi2.getName())){
753           if (mi1.getReturnType().equals(mi2.getReturnType())){
754             byte[] params1 = mi1.getArgumentTypes();
755             byte[] params2 = mi2.getArgumentTypes();
756             if (params1.length == params2.length){
757               for (int i = 0; i < params1.length; i++){
758                 if (params1[i] != params2[i]){
759                   return false;
760                 }
761               }
762               return true;
763             }
764           }
765         }
766       }
767     }
768     return false;
769   }
770
771   @MJI
772   public int hashCode____I (MJIEnv env, int objRef){
773     MethodInfo mi = getMethodInfo(env, objRef);
774     return mi.getClassName().hashCode() ^ mi.getName().hashCode();
775   }
776 }