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