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