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