c76ecb8d139cc5281bfd54752d59f527202b5c46
[jpf-core.git] / src / peers / gov / nasa / jpf / vm / JPF_java_lang_Class.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 java.io.IOException;
21 import java.io.InputStream;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.Set;
25
26 import gov.nasa.jpf.Config;
27 import gov.nasa.jpf.annotation.MJI;
28
29
30 /**
31  * MJI NativePeer class for java.lang.Class library abstraction
32  */
33 public class JPF_java_lang_Class extends NativePeer {
34   
35   static final String FIELD_CLASSNAME = "java.lang.reflect.Field";
36   static final String METHOD_CLASSNAME = "java.lang.reflect.Method";
37   static final String CONSTRUCTOR_CLASSNAME = "java.lang.reflect.Constructor";
38   
39   public static boolean init (Config conf){
40     // we create Method and Constructor objects, so we better make sure these
41     // classes are initialized (they already might be)
42     JPF_java_lang_reflect_Method.init(conf);
43     JPF_java_lang_reflect_Constructor.init(conf);
44     return true;
45   }
46   
47   @MJI
48   public boolean isArray____Z (MJIEnv env, int robj) {
49     ClassInfo ci = env.getReferredClassInfo( robj);
50     return ci.isArray();
51   }
52
53   @MJI
54   public int getComponentType____Ljava_lang_Class_2 (MJIEnv env, int robj) {
55     if (isArray____Z(env, robj)) {
56       ThreadInfo ti = env.getThreadInfo();
57       Instruction insn = ti.getPC();
58       ClassInfo ci = env.getReferredClassInfo( robj).getComponentClassInfo();
59
60     if (ci.initializeClass(ti)){
61         env.repeatInvocation();
62         return MJIEnv.NULL;
63       }
64
65       return ci.getClassObjectRef();
66     }
67
68     return MJIEnv.NULL;
69   }
70
71   @MJI
72   public boolean isInstance__Ljava_lang_Object_2__Z (MJIEnv env, int robj,
73                                                          int r1) {
74     ElementInfo sei = env.getStaticElementInfo(robj);
75     ClassInfo   ci = sei.getClassInfo();
76     ClassInfo   ciOther = env.getClassInfo(r1);
77     return (ciOther.isInstanceOf(ci));
78   }
79
80   @MJI
81   public boolean isInterface____Z (MJIEnv env, int robj){
82     ClassInfo ci = env.getReferredClassInfo( robj);
83     return ci.isInterface();
84   }
85   
86   @MJI
87   public boolean isAssignableFrom__Ljava_lang_Class_2__Z (MJIEnv env, int rcls,
88                                                               int r1) {
89     ElementInfo sei1 = env.getStaticElementInfo(rcls);
90     ClassInfo   ci1 = sei1.getClassInfo();
91
92     ElementInfo sei2 = env.getStaticElementInfo(r1);
93     ClassInfo   ci2 = sei2.getClassInfo();
94
95     return ci2.isInstanceOf( ci1);
96   }
97   
98   @MJI
99   public int getAnnotations_____3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int robj){    
100     ClassInfo ci = env.getReferredClassInfo( robj);
101     AnnotationInfo[] ai = ci.getAnnotations();
102
103     try {
104       return env.newAnnotationProxies(ai);
105     } catch (ClinitRequired x){
106       env.handleClinitRequest(x.getRequiredClassInfo());
107       return MJIEnv.NULL;
108     }
109   }
110   
111   @MJI
112   public int getAnnotation__Ljava_lang_Class_2__Ljava_lang_annotation_Annotation_2 (MJIEnv env, int robj,
113                                                                                 int annoClsRef){
114     ClassInfo ci = env.getReferredClassInfo( robj);
115     ClassInfo aci = env.getReferredClassInfo(annoClsRef);
116     
117     AnnotationInfo ai = ci.getAnnotation(aci.getName());
118     if (ai != null){
119       ClassInfo aciProxy = aci.getAnnotationProxy();
120       
121       try {
122         return env.newAnnotationProxy(aciProxy, ai);
123       } catch (ClinitRequired x){
124         env.handleClinitRequest(x.getRequiredClassInfo());
125         return MJIEnv.NULL;
126       }
127     } else {
128       return MJIEnv.NULL;
129     }
130   }
131   
132   @MJI
133   public int getPrimitiveClass__Ljava_lang_String_2__Ljava_lang_Class_2 (MJIEnv env,
134                                                             int rcls, int stringRef) {
135     // we don't really have to check for a valid class name here, since
136     // this is a package default method that just gets called from
137     // the clinit of box classes
138     // note this does NOT return the box class (e.g. java.lang.Integer), which
139     // is a normal, functional class, but a primitive class (e.g. 'int') that
140     // is rather a strange beast (not even Object derived)
141     
142     ClassLoaderInfo scli = env.getSystemClassLoaderInfo(); // this is the one responsible for builtin classes
143     String primClsName = env.getStringObject(stringRef); // always initialized
144     
145     ClassInfo ci = scli.getResolvedClassInfo(primClsName);
146     return ci.getClassObjectRef();
147   }
148
149   @MJI
150   public boolean desiredAssertionStatus____Z (MJIEnv env, int robj) {
151     ClassInfo ci = env.getReferredClassInfo(robj);
152     return ci.desiredAssertionStatus();
153   }
154
155   public static int getClassObject (MJIEnv env, ClassInfo ci){
156     ThreadInfo ti = env.getThreadInfo();
157     Instruction insn = ti.getPC();
158
159     if (ci.initializeClass(ti)){
160       env.repeatInvocation();
161       return MJIEnv.NULL;
162     }
163
164     StaticElementInfo ei = ci.getStaticElementInfo();
165     int ref = ei.getClassObjectRef();
166
167     return ref;
168   }
169   
170   @MJI
171   public int forName__Ljava_lang_String_2__Ljava_lang_Class_2 (MJIEnv env,
172                                                                        int rcls,
173                                                                        int clsNameRef) {
174     if (clsNameRef == MJIEnv.NULL){
175       env.throwException("java.lang.NullPointerException", "no class name provided");
176       return MJIEnv.NULL;
177     }
178     
179     String clsName = env.getStringObject(clsNameRef);
180     
181     if (clsName.isEmpty()){
182       env.throwException("java.lang.ClassNotFoundException", "empty class name");
183       return MJIEnv.NULL;  
184     }
185     
186     ThreadInfo ti = env.getThreadInfo();
187     MethodInfo mi = ti.getTopFrame().getPrevious().getMethodInfo();
188     // class of the method that includes the invocation of Class.forName() 
189     ClassInfo cls = mi.getClassInfo();
190
191     String name;
192     // for array type, the component terminal must be resolved
193     if(clsName.charAt(0)=='[') {
194       name = Types.getComponentTerminal(clsName);
195     } else{
196       name = clsName;
197     }
198
199     // make the classloader of the class including the invocation of 
200     // Class.forName() resolve the class with the given name
201     try {
202       cls.resolveReferencedClass(name);
203     } catch(LoadOnJPFRequired lre) {
204       env.repeatInvocation();
205       return MJIEnv.NULL;
206     }
207
208     // The class obtained here is the same as the resolved one, except
209     // if it represents an array type
210     ClassInfo ci = cls.getClassLoaderInfo().getResolvedClassInfo(clsName);
211
212     return getClassObject(env, ci);
213   }
214
215   /**
216    * this is an example of a native method issuing direct calls - otherwise known
217    * as a round trip.
218    * We don't have to deal with class init here anymore, since this is called
219    * via the class object of the class to instantiate
220    */
221   @MJI
222   public int newInstance____Ljava_lang_Object_2 (MJIEnv env, int robj) {
223     ThreadInfo ti = env.getThreadInfo();
224     DirectCallStackFrame frame = ti.getReturnedDirectCall();
225     
226     ClassInfo ci = env.getReferredClassInfo(robj);   // what are we
227     MethodInfo miCtor = ci.getMethod("<init>()V", true); // note there always is one since something needs to call Object()
228
229     if (frame == null){ // first time around
230       if(ci.isAbstract()){ // not allowed to instantiate
231         env.throwException("java.lang.InstantiationException");
232         return MJIEnv.NULL;
233       }
234
235       // <2do> - still need to handle protected
236       if (miCtor.isPrivate()) {
237         env.throwException("java.lang.IllegalAccessException", "cannot access non-public member of class " + ci.getName());
238         return MJIEnv.NULL;
239       }
240
241       int objRef = env.newObjectOfUncheckedClass(ci);  // create the thing
242
243       frame = miCtor.createDirectCallStackFrame(ti, 1);
244       // note that we don't set this as a reflection call since it is supposed to propagate exceptions
245       frame.setReferenceArgument(0, objRef, null);
246       frame.setLocalReferenceVariable(0, objRef);        // (1) store ref for retrieval during re-exec
247       ti.pushFrame(frame);
248       
249       // check if we have to push clinits
250       ci.initializeClass(ti);
251       
252       env.repeatInvocation();
253       return MJIEnv.NULL;
254       
255     } else { // re-execution
256       int objRef = frame.getLocalVariable(0); // that's the object ref we set in (1)
257       return objRef;
258     }      
259   }
260   
261   @MJI
262   public int getSuperclass____Ljava_lang_Class_2 (MJIEnv env, int robj) {
263     ClassInfo ci = env.getReferredClassInfo( robj);
264     ClassInfo sci = ci.getSuperClass();
265     if (sci != null) {
266       return sci.getClassObjectRef();
267     } else {
268       return MJIEnv.NULL;
269     }
270   }
271
272   int getMethod (MJIEnv env, int clsRef, ClassInfo ciMethod, String mname, int argTypesRef,
273                         boolean isRecursiveLookup, boolean publicOnly) {
274
275     ClassInfo ci = env.getReferredClassInfo( clsRef);
276     
277     StringBuilder sb = new StringBuilder(mname);
278     sb.append('(');
279     int nParams = argTypesRef != MJIEnv.NULL ? env.getArrayLength(argTypesRef) : 0;
280     for (int i=0; i<nParams; i++) {
281       int cRef = env.getReferenceArrayElement(argTypesRef, i);
282       ClassInfo cit = env.getReferredClassInfo( cRef);
283       String tname = cit.getName();
284       String tcode = tname;
285       tcode = Types.getTypeSignature(tcode, false);
286       sb.append(tcode);
287     }
288     sb.append(')');
289     String fullMthName = sb.toString();
290
291     MethodInfo mi = ci.getReflectionMethod(fullMthName, isRecursiveLookup);
292     if (mi == null || (publicOnly && !mi.isPublic())) {
293       env.throwException("java.lang.NoSuchMethodException", ci.getName() + '.' + fullMthName);
294       return MJIEnv.NULL;
295       
296     } else {
297       return createMethodObject(env, ciMethod, mi);      
298     }
299   }
300
301   int createMethodObject (MJIEnv env, ClassInfo objectCi, MethodInfo mi) {
302     // NOTE - we rely on Constructor and Method peers being initialized
303     if (mi.isCtor()){
304       return JPF_java_lang_reflect_Constructor.createConstructorObject(env, objectCi, mi);
305     } else {
306       return JPF_java_lang_reflect_Method.createMethodObject(env, objectCi, mi);      
307     }
308   }
309   
310   @MJI
311   public int getDeclaredMethod__Ljava_lang_String_2_3Ljava_lang_Class_2__Ljava_lang_reflect_Method_2 (MJIEnv env, int clsRef,
312                                                                                                      int nameRef, int argTypesRef) {
313     ClassInfo mci = getInitializedClassInfo(env, METHOD_CLASSNAME);
314     if (mci == null) {
315       env.repeatInvocation();
316       return MJIEnv.NULL;
317     }
318     
319     String mname = env.getStringObject(nameRef);
320     return getMethod(env, clsRef, mci, mname, argTypesRef, false, false);
321   }
322
323   @MJI
324   public int getDeclaredConstructor___3Ljava_lang_Class_2__Ljava_lang_reflect_Constructor_2 (MJIEnv env,
325                                                                                                int clsRef,
326                                                                                                int argTypesRef){
327     ClassInfo mci = getInitializedClassInfo(env, CONSTRUCTOR_CLASSNAME);
328     if (mci == null) {
329       env.repeatInvocation();
330       return MJIEnv.NULL;
331     }
332     
333     int ctorRef =  getMethod(env,clsRef, mci, "<init>",argTypesRef,false, false);
334     return ctorRef;
335   }
336   
337   @MJI
338   public int getMethod__Ljava_lang_String_2_3Ljava_lang_Class_2__Ljava_lang_reflect_Method_2 (MJIEnv env, int clsRef,
339                                                                                                      int nameRef, int argTypesRef) {
340     ClassInfo mci = getInitializedClassInfo(env, METHOD_CLASSNAME);
341     if (mci == null) {
342       env.repeatInvocation();
343       return MJIEnv.NULL;
344     }
345     
346     String mname = env.getStringObject(nameRef);
347     return getMethod( env, clsRef, mci, mname, argTypesRef, true, true);
348   }
349
350   private void addDeclaredMethodsRec (boolean includeSuperClasses, HashMap<String,MethodInfo>methods, ClassInfo ci){
351     
352     if (includeSuperClasses){ // do NOT include Object methods for interfaces
353       ClassInfo sci = ci.getSuperClass();
354       if (sci != null){
355         addDeclaredMethodsRec( includeSuperClasses, methods,sci);
356       }
357     }
358
359     ClassLoaderInfo cl = ci.getClassLoaderInfo();
360     for (String ifcName : ci.getDirectInterfaceNames()){
361       ClassInfo ici = cl.getResolvedClassInfo(ifcName); // has to be already defined, so no exception
362       addDeclaredMethodsRec( includeSuperClasses, methods,ici);
363     }
364
365     for (MethodInfo mi : ci.getDeclaredMethodInfos()) {
366       // filter out non-public, <clinit> and <init>
367       if (mi.isPublic() && (mi.getName().charAt(0) != '<')) {
368         String mname = mi.getUniqueName();
369
370         if (!(ci.isInterface() && methods.containsKey(mname))){
371           methods.put(mname, mi);
372         }
373       }
374     }
375   }
376
377   @MJI
378   public int getMethods_____3Ljava_lang_reflect_Method_2 (MJIEnv env, int objref) {
379     ClassInfo mci = getInitializedClassInfo(env, METHOD_CLASSNAME);
380     if (mci == null) {
381       env.repeatInvocation();
382       return MJIEnv.NULL;
383     }
384     
385     ClassInfo ci = env.getReferredClassInfo(objref);
386
387     // collect all the public, non-ctor instance methods
388     if (!ci.isPrimitive()) {
389       HashMap<String,MethodInfo> methods = new HashMap<String,MethodInfo>();
390       addDeclaredMethodsRec( !ci.isInterface(), methods,ci);
391       
392       int n = methods.size();
393       int aref = env.newObjectArray("Ljava/lang/reflect/Method;", n);
394       int i=0;
395
396       for (MethodInfo mi : methods.values()){
397         int mref = createMethodObject(env, mci, mi);
398         env.setReferenceArrayElement(aref,i++,mref);
399       }
400
401       return aref;
402
403     } else {
404       return env.newObjectArray("Ljava/lang/reflect/Method;", 0);
405     }
406   }
407   
408   @MJI
409   public int getDeclaredMethods_____3Ljava_lang_reflect_Method_2 (MJIEnv env, int objref) {
410     ClassInfo mci = getInitializedClassInfo(env, METHOD_CLASSNAME);
411     if (mci == null) {
412       env.repeatInvocation();
413       return MJIEnv.NULL;
414     }
415     
416     ClassInfo ci = env.getReferredClassInfo(objref);
417     MethodInfo[] methodInfos = ci.getDeclaredMethodInfos();
418     
419     // we have to filter out the ctors and the static init
420     int nMth = methodInfos.length;
421     for (int i=0; i<methodInfos.length; i++){
422       if (methodInfos[i].getName().charAt(0) == '<'){
423         methodInfos[i] = null;
424         nMth--;
425       }
426     }
427     
428     int aref = env.newObjectArray("Ljava/lang/reflect/Method;", nMth);
429     
430     for (int i=0, j=0; i<methodInfos.length; i++) {
431       if (methodInfos[i] != null){
432         int mref = createMethodObject(env, mci, methodInfos[i]);
433         env.setReferenceArrayElement(aref,j++,mref);
434       }
435     }
436     
437     return aref;
438   }
439   
440   int getConstructors (MJIEnv env, int objref, boolean publicOnly){
441     ClassInfo mci = getInitializedClassInfo(env, CONSTRUCTOR_CLASSNAME);
442     if (mci == null) {
443       env.repeatInvocation();
444       return MJIEnv.NULL;
445     }
446     
447     ClassInfo ci = env.getReferredClassInfo(objref);
448     ArrayList<MethodInfo> ctors = new ArrayList<MethodInfo>();
449     
450     // we have to filter out the ctors and the static init
451     for (MethodInfo mi : ci.getDeclaredMethodInfos()){
452       if (mi.getName().equals("<init>")){
453         if (!publicOnly || mi.isPublic()) {
454           ctors.add(mi);
455         }
456       }
457     }
458     
459     int nCtors = ctors.size();
460     int aref = env.newObjectArray("Ljava/lang/reflect/Constructor;", nCtors);
461     
462     for (int i=0; i<nCtors; i++){
463       env.setReferenceArrayElement(aref, i, createMethodObject(env, mci, ctors.get(i)));
464     }
465     
466     return aref;
467   }
468   
469   @MJI
470   public int getConstructors_____3Ljava_lang_reflect_Constructor_2 (MJIEnv env, int objref){
471     return getConstructors(env, objref, true);
472   }  
473   
474   @MJI
475   public int getDeclaredConstructors_____3Ljava_lang_reflect_Constructor_2 (MJIEnv env, int objref){
476     return getConstructors(env, objref, false);
477   }
478   
479   @MJI
480   public int getConstructor___3Ljava_lang_Class_2__Ljava_lang_reflect_Constructor_2 (MJIEnv env, int clsRef,
481                                                                                        int argTypesRef){
482     ClassInfo mci = getInitializedClassInfo(env, CONSTRUCTOR_CLASSNAME);
483     if (mci == null) {
484       env.repeatInvocation();
485       return MJIEnv.NULL;
486     }
487     
488     // <2do> should only return a public ctor 
489     return getMethod(env,clsRef, mci, "<init>",argTypesRef,false,true);
490   }
491   
492   // this is only used for system classes such as java.lang.reflect.Method
493   ClassInfo getInitializedClassInfo (MJIEnv env, String clsName){
494     ThreadInfo ti = env.getThreadInfo();
495     Instruction insn = ti.getPC();
496     ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo( clsName);
497     
498     if (ci.initializeClass(ti)){
499       return null;
500     } else {
501       return ci;
502     }    
503   }
504   
505   @MJI
506   public void initialize0____V (MJIEnv env, int clsObjRef){
507     ClassInfo ci = env.getReferredClassInfo( clsObjRef);
508     ci.initializeClass(ThreadInfo.currentThread);
509   }
510
511   Set<ClassInfo> getInitializedInterfaces (MJIEnv env, ClassInfo ci){
512     ThreadInfo ti = env.getThreadInfo();
513     Instruction insn = ti.getPC();
514
515     Set<ClassInfo> ifcs = ci.getAllInterfaceClassInfos();
516     for (ClassInfo ciIfc : ifcs){
517     if (ciIfc.initializeClass(ti)){
518         return null;
519       } 
520     }
521
522     return ifcs;
523   }
524   
525   static int createFieldObject (MJIEnv env, FieldInfo fi, ClassInfo fci){
526     int regIdx = JPF_java_lang_reflect_Field.registerFieldInfo(fi);
527     
528     int eidx = env.newObject(fci);
529     ElementInfo ei = env.getModifiableElementInfo(eidx);    
530     ei.setIntField("regIdx", regIdx);
531     
532     return eidx;
533   }
534   
535   @MJI
536   public int getDeclaredFields_____3Ljava_lang_reflect_Field_2 (MJIEnv env, int objRef) {
537     ClassInfo fci = getInitializedClassInfo(env, FIELD_CLASSNAME);
538     if (fci == null) {
539       env.repeatInvocation();
540       return MJIEnv.NULL;
541     }
542
543     ClassInfo ci = env.getReferredClassInfo(objRef);
544     int nInstance = ci.getNumberOfDeclaredInstanceFields();
545     int nStatic = ci.getNumberOfStaticFields();
546     int aref = env.newObjectArray("Ljava/lang/reflect/Field;", nInstance + nStatic);
547     int i, j=0;
548     
549     for (i=0; i<nStatic; i++) {
550       FieldInfo fi = ci.getStaticField(i);
551       env.setReferenceArrayElement(aref, j++, createFieldObject(env, fi, fci));
552     }    
553     
554     for (i=0; i<nInstance; i++) {
555       FieldInfo fi = ci.getDeclaredInstanceField(i);
556       env.setReferenceArrayElement(aref, j++, createFieldObject(env, fi, fci));
557     }
558     
559     return aref;
560   }
561   
562   @MJI
563   public int getFields_____3Ljava_lang_reflect_Field_2 (MJIEnv env, int clsRef){
564     ClassInfo fci = getInitializedClassInfo(env, FIELD_CLASSNAME);
565     if (fci == null) {
566       env.repeatInvocation();
567       return MJIEnv.NULL;
568     }
569         
570     ClassInfo ci = env.getReferredClassInfo(clsRef);
571     // interfaces might not be initialized yet, so we have to check first
572     Set<ClassInfo> ifcs = getInitializedInterfaces( env, ci);
573     if (ifcs == null) {
574       env.repeatInvocation();
575       return MJIEnv.NULL;
576     }
577     
578     ArrayList<FieldInfo> fiList = new ArrayList<FieldInfo>();
579     for (; ci != null; ci = ci.getSuperClass()){
580       // the host VM returns them in order of declaration, but the spec says there is no guaranteed order so we keep it simple
581       for (FieldInfo fi : ci.getDeclaredInstanceFields()){
582         if (fi.isPublic()){
583           fiList.add(fi);
584         }
585       }
586       for (FieldInfo fi : ci.getDeclaredStaticFields()){
587         if (fi.isPublic()){
588           fiList.add(fi);
589         }
590       }
591     }
592     
593     for (ClassInfo ciIfc : ifcs){
594       for (FieldInfo fi : ciIfc.getDeclaredStaticFields()){
595         fiList.add(fi); // there are no non-public fields in interfaces
596       }      
597     }
598
599     int aref = env.newObjectArray("Ljava/lang/reflect/Field;", fiList.size());
600     int j=0;
601     for (FieldInfo fi : fiList){
602       env.setReferenceArrayElement(aref, j++, createFieldObject(env, fi, fci));
603     }
604     
605     return aref;
606   }
607     
608   int getField (MJIEnv env, int clsRef, int nameRef, boolean isRecursiveLookup) {    
609     ClassInfo ci = env.getReferredClassInfo( clsRef);
610     String fname = env.getStringObject(nameRef);
611     FieldInfo fi = null;
612     
613     if (isRecursiveLookup) {
614       fi = ci.getInstanceField(fname);
615       if (fi == null) {
616         fi = ci.getStaticField(fname);
617       }      
618     } else {
619         fi = ci.getDeclaredInstanceField(fname);
620         if (fi == null) {
621           fi = ci.getDeclaredStaticField(fname);
622         }
623     }
624     
625     if (fi == null) {      
626       env.throwException("java.lang.NoSuchFieldException", fname);
627       return MJIEnv.NULL;
628       
629     } else {
630       // don't do a Field clinit before we know there is such a field
631       ClassInfo fci = getInitializedClassInfo( env, FIELD_CLASSNAME);
632       if (fci == null) {
633         env.repeatInvocation();
634         return MJIEnv.NULL;
635       }
636       
637       return createFieldObject( env, fi, fci);
638     }
639   }
640   
641   @MJI
642   public int getDeclaredField__Ljava_lang_String_2__Ljava_lang_reflect_Field_2 (MJIEnv env, int clsRef, int nameRef) {
643     return getField(env,clsRef,nameRef, false);
644   }  
645  
646   @MJI
647   public int getField__Ljava_lang_String_2__Ljava_lang_reflect_Field_2 (MJIEnv env, int clsRef, int nameRef) {
648     return getField(env,clsRef,nameRef, true);    
649   }
650
651   @MJI
652   public int getModifiers____I (MJIEnv env, int clsRef){
653     ClassInfo ci = env.getReferredClassInfo(clsRef);
654     return ci.getModifiers();
655   }
656
657   @MJI
658   public int getEnumConstants_____3Ljava_lang_Object_2 (MJIEnv env, int clsRef){
659     ClassInfo ci = env.getReferredClassInfo(clsRef);
660     
661     if (env.requiresClinitExecution(ci)){
662       env.repeatInvocation();
663       return 0;
664     }
665
666     if (ci.getSuperClass().getName().equals("java.lang.Enum")) {      
667       ArrayList<FieldInfo> list = new ArrayList<FieldInfo>();
668       String cName = ci.getName();
669       
670       for (FieldInfo fi : ci.getDeclaredStaticFields()) {
671         if (fi.isFinal() && cName.equals(fi.getType())){
672           list.add(fi);
673         }
674       }
675       
676       int aRef = env.newObjectArray(cName, list.size());      
677       StaticElementInfo sei = ci.getStaticElementInfo();
678       int i=0;
679       for (FieldInfo fi : list){
680         env.setReferenceArrayElement( aRef, i++, sei.getReferenceField(fi));
681       }
682       return aRef;
683     }
684     
685     return MJIEnv.NULL;
686   }
687     
688   @MJI
689   public int getInterfaces_____3Ljava_lang_Class_2 (MJIEnv env, int clsRef){
690     ClassInfo ci = env.getReferredClassInfo(clsRef);
691     int aref = MJIEnv.NULL;
692     ThreadInfo ti = env.getThreadInfo();
693     
694     // contrary to the API doc, this only returns the interfaces directly
695     // implemented by this class, not it's bases
696     // <2do> this is not exactly correct, since the interfaces should be ordered
697     Set<ClassInfo> interfaces = ci.getInterfaceClassInfos();
698     aref = env.newObjectArray("Ljava/lang/Class;", interfaces.size());
699
700     int i=0;
701     for (ClassInfo ifc: interfaces){
702       env.setReferenceArrayElement(aref, i++, ifc.getClassObjectRef());
703     }
704     
705     return aref;
706   }
707
708
709   /**
710    * <2do> needs to load from the classfile location, NOT the MJIEnv (native) class
711    *
712    * @author Sebastian Gfeller (sebastian.gfeller@gmail.com)
713    * @author Tihomir Gvero (tihomir.gvero@gmail.com)
714    */
715   @MJI
716   public int getByteArrayFromResourceStream__Ljava_lang_String_2___3B(MJIEnv env, int clsRef, int nameRef) {
717     String name = env.getStringObject(nameRef);
718
719     // <2do> this is not loading from the classfile location! fix it
720     InputStream is = env.getClass().getResourceAsStream(name);
721     if (is == null){
722       return MJIEnv.NULL;
723     }
724     // We assume that the entire input stream can be read at the moment,
725     // although this could break.
726     byte[] content = null;
727     try {
728       content = new byte[is.available()];
729       is.read(content);
730     } catch (IOException e) {
731       throw new RuntimeException(e);
732     }
733     // Now if everything worked, the content should be in the byte buffer.
734     // We put this buffer into the JPF VM.
735     return env.newByteArray(content);
736   }
737
738   @MJI
739   public int getEnclosingClass____Ljava_lang_Class_2 (MJIEnv env, int clsRef) {
740     ClassInfo ciEncl = env.getReferredClassInfo( clsRef).getEnclosingClassInfo();
741     
742     if (ciEncl == null){
743       return MJIEnv.NULL;
744     }
745
746     if (ciEncl.initializeClass(env.getThreadInfo())) {
747       env.repeatInvocation();
748       return 0;
749     }
750
751     return ciEncl.getClassObjectRef();
752   }
753
754   @MJI
755   public int getDeclaredClasses_____3Ljava_lang_Class_2 (MJIEnv env, int clsRef){
756     ClassInfo ci = env.getReferredClassInfo(clsRef);
757     String[] innerClassNames =  ci.getInnerClasses();
758     int aref = MJIEnv.NULL;
759     ThreadInfo ti = env.getThreadInfo();
760     
761     MethodInfo mi = ti.getTopFrame().getPrevious().getMethodInfo();
762     // class of the method that includes the invocation of Class.getDeclaredClasses 
763     ClassInfo cls = mi.getClassInfo();
764
765     // first resolve all the inner classes
766     int length = innerClassNames.length;
767     ClassInfo[] resolvedInnerClass = new ClassInfo[length];
768     for(int i=0; i<length; i++) {
769       try {
770         resolvedInnerClass[i] = cls.resolveReferencedClass(innerClassNames[i]);
771       } catch(LoadOnJPFRequired lre) {
772         env.repeatInvocation();
773         return MJIEnv.NULL;
774       }
775     }
776
777     aref = env.newObjectArray("Ljava/lang/Class;", innerClassNames.length);
778     for (int i=0; i<length; i++){
779       ClassInfo ici = resolvedInnerClass[i];
780       if (!ici.isRegistered()) {
781         ici.registerClass(ti);
782       }
783       env.setReferenceArrayElement(aref, i, ici.getClassObjectRef());
784     }
785     
786     return aref;
787   }
788
789   private String getCanonicalName (ClassInfo ci){
790     if (ci.isArray()){
791       String canonicalName = getCanonicalName(ci.getComponentClassInfo());
792       if (canonicalName != null){
793         return canonicalName + "[]";
794       } else{
795         return null;
796       }
797     }
798     if (isLocalOrAnonymousClass(ci)) {
799       return null;
800     }
801     if (ci.getEnclosingClassInfo() == null){
802       return ci.getName();
803     } else{
804       String enclosingName = getCanonicalName(ci.getEnclosingClassInfo());
805       if (enclosingName == null){ return null; }
806       return enclosingName + "." + ci.getSimpleName();
807     }
808   }
809
810   @MJI
811   public int getCanonicalName____Ljava_lang_String_2 (MJIEnv env, int clsRef){
812     ClassInfo ci = env.getReferredClassInfo(clsRef);
813     return env.newString(getCanonicalName(ci));
814   }
815
816   @MJI
817   public boolean isAnnotation____Z (MJIEnv env, int clsObjRef){
818     ClassInfo ci = env.getReferredClassInfo(clsObjRef);
819     return (ci.getModifiers() & 0x2000) != 0;
820   }
821   
822   @MJI
823   public boolean isAnnotationPresent__Ljava_lang_Class_2__Z (MJIEnv env, int clsObjRef, int annoClsObjRef){
824     ClassInfo ci = env.getReferredClassInfo(clsObjRef);
825     ClassInfo ciAnno = env.getReferredClassInfo(annoClsObjRef);
826     
827     return ci.getAnnotation( ciAnno.getName()) != null;    
828   }
829   
830   @MJI
831   public int getDeclaredAnnotations_____3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int robj){
832     ClassInfo ci = env.getReferredClassInfo(robj);
833
834     try{
835       return env.newAnnotationProxies(ci.getDeclaredAnnotations());
836     } catch (ClinitRequired x){
837       env.handleClinitRequest(x.getRequiredClassInfo());
838       return MJIEnv.NULL;
839     }
840   }
841
842   @MJI
843   public int getEnclosingConstructor____Ljava_lang_reflect_Constructor_2 (MJIEnv env, int robj){
844     ClassInfo mci = getInitializedClassInfo(env, CONSTRUCTOR_CLASSNAME);
845     if (mci == null){
846       env.repeatInvocation();
847       return MJIEnv.NULL;
848     }
849     ClassInfo ci = env.getReferredClassInfo(robj);
850     MethodInfo enclosingMethod = ci.getEnclosingMethodInfo();
851
852     if ((enclosingMethod != null) && enclosingMethod.isCtor()){ 
853       return createMethodObject(env, mci, enclosingMethod); 
854     }
855     return MJIEnv.NULL;
856   }
857
858   @MJI
859   public int getEnclosingMethod____Ljava_lang_reflect_Method_2 (MJIEnv env, int robj){
860     ClassInfo mci = getInitializedClassInfo(env, METHOD_CLASSNAME);
861     if (mci == null){
862       env.repeatInvocation();
863       return MJIEnv.NULL;
864     }
865     ClassInfo ci = env.getReferredClassInfo(robj);
866     MethodInfo enclosingMethod = ci.getEnclosingMethodInfo();
867
868     if ((enclosingMethod != null) && !enclosingMethod.isCtor()){ 
869       return createMethodObject(env, mci, enclosingMethod); 
870     }
871     return MJIEnv.NULL;
872   }
873
874   @MJI
875   public boolean isAnonymousClass____Z (MJIEnv env, int robj){
876     ClassInfo ci = env.getReferredClassInfo(robj);
877     String cname = null;
878     if (ci.getName().contains("$")){
879       cname = ci.getName().substring(ci.getName().lastIndexOf('$') + 1);
880     }
881     return (cname == null) ? false : cname.matches("\\d+?");
882   }
883
884   @MJI
885   public boolean isEnum____Z (MJIEnv env, int robj){
886     ClassInfo ci = env.getReferredClassInfo(robj);
887     return ci.isEnum();
888   }
889
890   // Similar to getEnclosingClass() except it returns null for the case of
891   // anonymous class.
892   @MJI
893   public int getDeclaringClass____Ljava_lang_Class_2 (MJIEnv env, int clsRef){
894     ClassInfo ci = env.getReferredClassInfo(clsRef);
895     if (isLocalOrAnonymousClass(ci)){
896       return MJIEnv.NULL;
897     } else{
898       return getEnclosingClass____Ljava_lang_Class_2(env, clsRef);
899     }
900   }
901
902   @MJI
903   public boolean isLocalClass____Z (MJIEnv env, int robj){
904     ClassInfo ci = env.getReferredClassInfo(robj);
905     return isLocalOrAnonymousClass(ci) && !isAnonymousClass____Z(env, robj);
906   }
907
908   private boolean isLocalOrAnonymousClass (ClassInfo ci){
909     return (ci.getEnclosingMethodInfo() != null);
910   }
911
912   @MJI
913   public boolean isMemberClass____Z (MJIEnv env, int robj){
914     ClassInfo ci = env.getReferredClassInfo(robj);
915     return (ci.getEnclosingClassInfo() != null) && !isLocalOrAnonymousClass(ci);
916   }
917
918   /**
919    * Append the package name prefix of the class represented by robj, if the name is not 
920    * absolute. OW, remove leading "/". 
921    */
922   @MJI
923   public int getResolvedName__Ljava_lang_String_2__Ljava_lang_String_2 (MJIEnv env, int robj, int resRef){
924     String rname = env.getStringObject(resRef);
925     ClassInfo ci = env.getReferredClassInfo(robj);
926     if (rname == null) {
927       return MJIEnv.NULL;
928     }
929     if (!rname.startsWith("/")) {
930       ClassInfo c = ci;
931       while (c.isArray()) {
932           c = c.getComponentClassInfo();
933       }
934       String baseName = c.getName();
935       int index = baseName.lastIndexOf('.');
936       if (index != -1) {
937         rname = baseName.substring(0, index).replace('.', '/')
938             +"/"+rname;
939       }
940     } else {
941         rname = rname.substring(1);
942     }
943
944     return env.newString(rname);
945   }
946 }