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