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