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