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