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