2bac12a33b7b2b237f60669666e4da76cf9d2160
[jpf-core.git] / src / main / gov / nasa / jpf / vm / MJIEnv.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 com.sun.org.apache.bcel.internal.generic.InstructionConstants;
21 import gov.nasa.jpf.Config;
22 import gov.nasa.jpf.JPF;
23 import gov.nasa.jpf.JPFException;
24 import gov.nasa.jpf.JPFListener;
25 import gov.nasa.jpf.vm.serialize.UnknownJPFClass;
26
27 import java.util.Date;
28 import java.util.Locale;
29
30
31 /**
32  * MJIEnv is the call environment for "native" methods, i.e. code that
33  * is executed by the VM, not by JPF.
34  *
35  * Since library abstractions are supposed to be "user code", we provide
36  * this class as a (little bit of) insulation towards the inner JPF workings.
37  *
38  * There are two APIs exported by this class. The public methods (like
39  * getStringObject) don't expose JPF internals, and can be used from non
40  * gov.nasa.jpf.vm NativePeer classes). The rest is package-default
41  * and can be used to fiddle around as much as you like to (if you are in
42  * the ..jvm package)
43  *
44  * Note that MJIEnv objects are now per-ThreadInfo (i.e. the variable
45  * call envionment only includes MethodInfo and ClassInfo), which means
46  * MJIEnv can be used in non-native methods (but only carefully, if you
47  * don't need mi or ciMth).
48  *
49  * Note also this only works because we are not getting recursive in
50  * native method calls. In fact, the whole DirectCallStackFrame / repeatTopInstruction
51  * mechanism is there to turn logial recursion (JPF calling native, calling
52  * JPF, calling native,..) into iteration. Otherwise we couldn't backtrack
53  */
54 public class MJIEnv {
55   public static final int NULL = 0;
56
57   VM                     vm;
58   ClassInfo               ciMth;  // the ClassInfo of the method this is called from
59   MethodInfo              mi;
60   ThreadInfo              ti;
61   Heap                    heap;
62
63   // those are various attributes set by the execution. note that
64   // NativePeer.invoke never gets recursive in a roundtrip (at least if
65   // used correctly, so we don't have to be afraid to overwrite any of these
66   boolean                 repeat;
67   Object                  returnAttr;
68
69   // exception to be thrown upon return from native method
70   // NOTE: this is only transient - don't expect this to be preserved over
71   // transition boundaries
72   int                     exceptionRef;
73
74   MJIEnv (ThreadInfo ti) {
75     this.ti = ti;
76
77     // set those here so that we don't have an inconsistent state between
78     // creation of an MJI object and the first native method call in
79     // this thread (where any access to the heap or sa would bomb)
80     vm = ti.getVM();
81     heap = vm.getHeap();
82
83     exceptionRef = NULL;
84   }
85
86   public VM getVM () {
87     return vm;
88   }
89
90   public JPF getJPF () {
91     return vm.getJPF();
92   }
93
94   public boolean isBigEndianPlatform(){
95     return vm.isBigEndianPlatform();
96   }
97   
98   public void addListener (JPFListener l){
99     vm.getJPF().addListener(l);
100   }
101
102   public void removeListener (JPFListener l){
103     vm.getJPF().removeListener(l);
104   }
105
106   public Config getConfig() {
107     return vm.getConfig();
108   }
109
110   public void gc() {
111     heap.gc();
112   }
113
114   public void forceState (){
115     getSystemState().setForced(true);
116   }
117
118   public void ignoreTransition () {
119     getSystemState().setIgnored(true);
120   }
121
122   public boolean isArray (int objref) {
123     return heap.get(objref).isArray();
124   }
125
126   public int getArrayLength (int objref) {
127     if (isArray(objref)) {
128       return heap.get(objref).arrayLength();
129     } else {
130       throwException("java.lang.IllegalArgumentException");
131
132       return 0;
133     }
134   }
135
136   public String getArrayType (int objref) {
137     return heap.get(objref).getArrayType();
138   }
139
140   public int getArrayTypeSize (int objref) {
141     return Types.getTypeSize(getArrayType(objref));
142   }
143
144   //=== various attribute accessors ============================================
145   // we only support some attribute APIs here, since MJIEnv adds little value
146   // other than hiding the ElementInfo access. If the client already has
147   // an ElementInfo reference, it should use that one to retrieve/enumerate/set
148   // attributes since this avoids repeated Heap.get() calls
149   
150   //--- object attributes
151
152   public boolean hasObjectAttr (int objref){
153     if (objref != NULL){
154       ElementInfo ei = heap.get(objref);
155       return ei.hasObjectAttr();
156     }
157
158     return false;
159   }
160
161   public boolean hasObjectAttr (int objref, Class<?> type){
162     if (objref != NULL){
163       ElementInfo ei = heap.get(objref);
164       return ei.hasObjectAttr(type);
165     }
166
167     return false;    
168   }
169   
170   /**
171    * this returns all of them - use either if you know there will be only
172    * one attribute at a time, or check/process result with ObjectList
173    */  
174   public Object getObjectAttr (int objref){
175     if (objref != NULL){
176       ElementInfo ei = heap.get(objref);
177       return ei.getObjectAttr();
178     }
179     return null;
180   }
181   
182   /**
183    * this replaces all of them - use only if you know 
184    *  - there will be only one attribute at a time
185    *  - you obtained the value you set by a previous getXAttr()
186    *  - you constructed a multi value list with ObjectList.createList()
187    */
188   public void setObjectAttr (int objref, Object a){
189     if (objref != NULL){
190       ElementInfo ei = heap.get(objref);
191       ei.setObjectAttr(a);
192     }
193   }
194
195   public void addObjectAttr (int objref, Object a){
196     if (objref != NULL){
197       ElementInfo ei = heap.getModifiable(objref);
198       ei.addObjectAttr(a);
199     }
200   }
201
202   
203   /**
204    * this only returns the first attr of this type, there can be more
205    * if you don't use client private types or the provided type is too general
206    */
207   public <T> T getObjectAttr (int objref, Class<T> attrType){
208     ElementInfo ei = heap.get(objref);
209     return ei.getObjectAttr(attrType);
210   }
211   
212   //--- field attributes
213
214   public boolean hasFieldAttr (int objref){
215     if (objref != NULL){
216       ElementInfo ei = heap.get(objref);
217       return ei.hasFieldAttr();
218     }
219
220     return false;
221   }
222   
223   public boolean hasFieldAttr (int objref, Class<?> type){
224     if (objref != NULL){
225       ElementInfo ei = heap.get(objref);
226       return ei.hasFieldAttr(type);
227     }
228
229     return false;    
230   }
231   
232   /**
233    * this returns all of them - use either if you know there will be only
234    * one attribute at a time, or check/process result with ObjectList
235    */  
236   public Object getFieldAttr (int objref, String fname){
237     ElementInfo ei = heap.get(objref);
238     FieldInfo fi = ei.getFieldInfo(fname);
239     if (fi != null){
240       return ei.getFieldAttr(fi);
241     } else {
242       throw new JPFException("no such field: " + fname);
243     }
244   }
245   
246   /**
247    * this replaces all of them - use only if you know 
248    *  - there will be only one attribute at a time
249    *  - you obtained the value you set by a previous getXAttr()
250    *  - you constructed a multi value list with ObjectList.createList()
251    */
252   public void setFieldAttr (int objref, String fname, Object a){
253     if (objref != NULL){
254       ElementInfo ei = heap.get(objref);
255       FieldInfo fi = ei.getFieldInfo(fname);
256       ei.setFieldAttr(fi, a);
257     }
258   }
259
260   public void addFieldAttr (int objref, String fname, Object a){
261     if (objref != NULL){
262       ElementInfo ei = heap.getModifiable(objref);
263       FieldInfo fi = ei.getFieldInfo(fname);
264       ei.addFieldAttr(fi, a);
265     }
266   }
267
268   
269   /**
270    * this only returns the first attr of this type, there can be more
271    * if you don't use client private types or the provided type is too general
272    */
273   public <T> T getFieldAttr (int objref, String fname, Class<T> attrType){
274     ElementInfo ei = heap.get(objref);
275     FieldInfo fi = ei.getFieldInfo(fname);
276     if (fi != null){
277       return ei.getFieldAttr(fi, attrType);
278     } else {
279       throw new JPFException("no such field: " + fname);
280     }
281   }
282
283   
284   //--- element attrs
285
286   public boolean hasElementdAttr (int objref){
287     if (objref != NULL){
288       ElementInfo ei = heap.get(objref);
289       return ei.hasElementAttr();
290     }
291
292     return false;
293   }
294   
295   public boolean hasElementAttr (int objref, Class<?> type){
296     if (objref != NULL){
297       ElementInfo ei = heap.get(objref);
298       return ei.hasElementAttr(type);
299     }
300
301     return false;    
302   }
303
304   /**
305    * this returns all of them - use either if you know there will be only
306    * one attribute at a time, or check/process result with ObjectList
307    */  
308   public Object getElementAttr (int objref, int idx){
309     ElementInfo ei = heap.get(objref);
310     return ei.getElementAttr(idx);
311   }
312   
313   /**
314    * this replaces all of them - use only if you know 
315    *  - there will be only one attribute at a time
316    *  - you obtained the value you set by a previous getXAttr()
317    *  - you constructed a multi value list with ObjectList.createList()
318    */
319   public void setElementAttr (int objref, int idx, Object a){
320     ElementInfo ei = heap.get(objref);
321     ei.setElementAttr(idx, a);
322   }
323
324   public void addElementAttr (int objref, int idx, Object a){
325     ElementInfo ei = heap.getModifiable(objref);
326     ei.addElementAttr(idx, a);
327   }
328
329   
330   /**
331    * this only returns the first attr of this type, there can be more
332    * if you don't use client private types or the provided type is too general
333    */
334   public <T> T getElementAttr (int objref, int idx, Class<T> attrType){
335     if (objref != NULL){
336       ElementInfo ei = heap.get(objref);
337       return ei.getElementAttr(idx, attrType);
338     }
339     return null;
340   }
341
342   
343
344   // == end attrs ==  
345
346
347   
348   // the instance field setters
349   public void setBooleanField (int objref, String fname, boolean val) {
350     heap.getModifiable(objref).setBooleanField(fname, val);
351   }
352
353   public boolean getBooleanField (int objref, String fname) {
354     return heap.get(objref).getBooleanField(fname);
355   }
356
357   public boolean getBooleanArrayElement (int objref, int index) {
358     return heap.get(objref).getBooleanElement(index);
359   }
360
361   public void setBooleanArrayElement (int objref, int index, boolean value) {
362     heap.getModifiable(objref).setBooleanElement(index, value);
363   }
364
365
366   public void setByteField (int objref, String fname, byte val) {
367     heap.getModifiable(objref).setByteField(fname, val);
368   }
369
370   public byte getByteField (int objref, String fname) {
371     return heap.get(objref).getByteField(fname);
372   }
373
374   public void setCharField (int objref, String fname, char val) {
375     heap.getModifiable(objref).setCharField(fname, val);
376   }
377
378   public char getCharField (int objref, String fname) {
379     return heap.get(objref).getCharField(fname);
380   }
381
382   public void setDoubleField (int objref, String fname, double val) {
383     heap.getModifiable(objref).setDoubleField(fname, val);
384   }
385
386   public double getDoubleField (int objref, String fname) {
387     return heap.get(objref).getDoubleField(fname);
388   }
389
390   public void setFloatField (int objref, String fname, float val) {
391     heap.getModifiable(objref).setFloatField(fname, val);
392   }
393
394   public float getFloatField (int objref, String fname) {
395     return heap.get(objref).getFloatField(fname);
396   }
397
398
399   public void setByteArrayElement (int objref, int index, byte value) {
400     heap.getModifiable(objref).setByteElement(index, value);
401   }
402
403   public byte getByteArrayElement (int objref, int index) {
404     return heap.get(objref).getByteElement(index);
405   }
406
407   public void setCharArrayElement (int objref, int index, char value) {
408     heap.getModifiable(objref).setCharElement(index, value);
409   }
410
411   public void setIntArrayElement (int objref, int index, int value) {
412     heap.getModifiable(objref).setIntElement(index, value);
413   }
414
415   public void setShortArrayElement (int objref, int index, short value) {
416     heap.getModifiable(objref).setShortElement(index, value);
417   }
418
419   public void setFloatArrayElement (int objref, int index, float value) {
420     heap.getModifiable(objref).setFloatElement(index, value);
421   }
422
423   public float getFloatArrayElement (int objref, int index) {
424     return heap.get(objref).getFloatElement(index);
425   }
426
427   public double getDoubleArrayElement (int objref, int index) {
428     return heap.get(objref).getDoubleElement(index);
429   }
430   public void setDoubleArrayElement (int objref, int index, double value) {
431     heap.getModifiable(objref).setDoubleElement(index, value);
432   }
433
434   public short getShortArrayElement (int objref, int index) {
435     return heap.get(objref).getShortElement(index);
436   }
437
438   public int getIntArrayElement (int objref, int index) {
439     return heap.get(objref).getIntElement(index);
440   }
441
442   public char getCharArrayElement (int objref, int index) {
443     return heap.get(objref).getCharElement(index);
444   }
445
446   public void setIntField (int objref, String fname, int val) {
447     ElementInfo ei = heap.getModifiable(objref);
448     ei.setIntField(fname, val);
449   }
450
451   // these two are the workhorses
452   public void setDeclaredIntField (int objref, String refType, String fname, int val) {
453     ElementInfo ei = heap.getModifiable(objref);
454     ei.setDeclaredIntField(fname, refType, val);
455   }
456
457   public int getIntField (int objref, String fname) {
458     ElementInfo ei = heap.get(objref);
459     return ei.getIntField(fname);
460   }
461
462   public int getDeclaredIntField (int objref, String refType, String fname) {
463     ElementInfo ei = heap.get(objref);
464     return ei.getDeclaredIntField(fname, refType);
465   }
466
467   // these two are the workhorses
468   public void setDeclaredReferenceField (int objref, String refType, String fname, int val) {
469     ElementInfo ei = heap.getModifiable(objref);
470     ei.setDeclaredReferenceField(fname, refType, val);
471   }
472
473   public void setReferenceField (int objref, String fname, int ref) {
474      ElementInfo ei = heap.getModifiable(objref);
475      ei.setReferenceField(fname, ref);
476   }
477
478   public int getReferenceField (int objref, String fname) {
479     ElementInfo ei = heap.get(objref);
480     return ei.getReferenceField(fname);
481   }
482
483   // we need this in case of a masked field
484   public int getReferenceField (int objref, FieldInfo fi) {
485     ElementInfo ei = heap.get(objref);
486     return ei.getReferenceField(fi);
487   }
488
489   public String getStringField (int objref, String fname){
490     int ref = getReferenceField(objref, fname);
491     return getStringObject(ref);
492   }
493
494   // the box object accessors (should probably test for the appropriate class)
495   public boolean getBooleanValue (int objref) {
496     return getBooleanField(objref, "value");
497   }
498
499   public byte getByteValue (int objref) {
500     return getByteField(objref, "value");
501   }
502
503   public char getCharValue (int objref) {
504     return getCharField(objref, "value");
505   }
506
507   public short getShortValue (int objref) {
508     return getShortField(objref, "value");
509   }
510
511   public int getIntValue (int objref) {
512     return getIntField(objref, "value");
513   }
514
515   public long getLongValue (int objref) {
516     return getLongField(objref, "value");
517   }
518
519   public float getFloatValue (int objref) {
520     return getFloatField(objref, "value");
521   }
522
523   public double getDoubleValue (int objref) {
524     return getDoubleField(objref, "value");
525   }
526
527
528   public void setLongArrayElement (int objref, int index, long value) {
529     heap.getModifiable(objref).setLongElement(index, value);
530   }
531
532   public long getLongArrayElement (int objref, int index) {
533     return heap.get(objref).getLongElement(index);
534   }
535
536   public void setLongField (int objref, String fname, long val) {
537     ElementInfo ei = heap.getModifiable(objref);
538     ei.setLongField(fname, val);
539   }
540
541 //  public void setLongField (int objref, String refType, String fname, long val) {
542 //    ElementInfo ei = heap.get(objref);
543 //    ei.setLongField(fname, refType, val);
544 //  }
545
546   public long getLongField (int objref, String fname) {
547     ElementInfo ei = heap.get(objref);
548     return ei.getLongField(fname);
549   }
550
551 //  public long getLongField (int objref, String refType, String fname) {
552 //    ElementInfo ei = heap.get(objref);
553 //    return ei.getLongField(fname, refType);
554 //  }
555
556   public void setReferenceArrayElement (int objref, int index, int eRef) {
557     heap.getModifiable(objref).setReferenceElement(index, eRef);
558   }
559
560   public int getReferenceArrayElement (int objref, int index) {
561     return heap.get(objref).getReferenceElement(index);
562   }
563
564   public void setShortField (int objref, String fname, short val) {
565     setIntField(objref, fname, /*(int)*/ val);
566   }
567
568   public short getShortField (int objref, String fname) {
569     return (short) getIntField(objref, fname);
570   }
571
572   /**
573    * NOTE - this doesn't support element type checks or overlapping in-array copy 
574    */
575   public void arrayCopy (int srcRef, int srcPos, int dstRef, int dstPos, int len){
576     ElementInfo eiSrc = heap.get(srcRef);
577     ElementInfo eiDst = heap.get(dstRef);
578     
579     eiDst.arrayCopy(eiSrc, srcPos, dstPos, len);
580   }
581   
582   public String getTypeName (int objref) {
583     return heap.get(objref).getType();
584   }
585
586   public boolean isInstanceOf (int objref, String clsName) {
587     ClassInfo ci = getClassInfo(objref);
588     return ci.isInstanceOf(clsName);
589   }
590   
591   public boolean isInstanceOf (int objref, ClassInfo cls) {
592     ClassInfo ci = getClassInfo(objref);
593     return ci.isInstanceOf(cls);
594   }
595
596   //--- the static field accessors
597   // NOTE - it is the callers responsibility to ensure the class is
598   // properly initialized, since calling <clinit> requires a roundtrip
599   // (i.e. cannot be done synchronously from one of the following methods)
600   
601   // <2do> this uses the current system CL, we should probably use an explicit CL argument
602   
603   public void setStaticBooleanField (String clsName, String fname,
604                                      boolean value) {
605     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
606     ci.getStaticElementInfo().setBooleanField(fname, value);
607   }
608   public void setStaticBooleanField (int clsObjRef, String fname, boolean val) {
609     ElementInfo cei = getStaticElementInfo(clsObjRef);
610     cei.setBooleanField(fname, val);
611   }
612   
613   public boolean getStaticBooleanField (String clsName, String fname) {
614     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
615     return ci.getStaticElementInfo().getBooleanField(fname);
616   }
617
618   public void setStaticByteField (String clsName, String fname, byte value) {
619     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
620     ci.getStaticElementInfo().setByteField(fname, value);  }
621
622   public byte getStaticByteField (String clsName, String fname) {
623     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
624     return ci.getStaticElementInfo().getByteField(fname);
625   }
626
627   public void setStaticCharField (String clsName, String fname, char value) {
628     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
629     ci.getStaticElementInfo().setCharField(fname, value);  }
630
631   public char getStaticCharField (String clsName, String fname) {
632     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
633     return ci.getStaticElementInfo().getCharField(fname);
634   }
635
636   public void setStaticDoubleField (String clsName, String fname, double val) {
637     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
638     ci.getStaticElementInfo().setDoubleField(fname, val);
639   }
640
641   public double getStaticDoubleField (String clsName, String fname) {
642     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
643     return ci.getStaticElementInfo().getDoubleField(fname);
644   }
645   
646   public double getStaticDoubleField (int clsObjRef, String fname) {
647     ElementInfo cei = getStaticElementInfo(clsObjRef);
648     return cei.getDoubleField(fname);
649   }
650
651   public double getStaticDoubleField (ClassInfo ci, String fname) {
652     ElementInfo ei = ci.getStaticElementInfo();
653     return ei.getDoubleField(fname);
654   }
655   
656   public void setStaticFloatField (String clsName, String fname, float val) {
657     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
658     ci.getStaticElementInfo().setFloatField(fname, val);
659   }
660
661   public float getStaticFloatField (String clsName, String fname) {
662     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
663     return ci.getStaticElementInfo().getFloatField(fname);
664   }
665
666   public void setStaticIntField (String clsName, String fname, int val) {
667     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
668     ci.getStaticElementInfo().setIntField(fname, val);
669   }
670
671   public void setStaticIntField (int clsObjRef, String fname, int val) {
672     ElementInfo cei = getStaticElementInfo(clsObjRef);
673     cei.setIntField(fname, val);
674   }
675
676   public int getStaticIntField (String clsName, String fname) {
677     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
678     return ci.getStaticElementInfo().getIntField(fname);
679   }
680   
681   public int getStaticIntField (int clsObjRef, String fname) {
682     ElementInfo cei = getStaticElementInfo(clsObjRef);
683     return cei.getIntField(fname);
684   }
685
686   public int getStaticIntField (ClassInfo ci, String fname) {
687     ElementInfo ei = ci.getStaticElementInfo();
688     return ei.getIntField(fname);
689   }
690
691   public void setStaticLongField (String clsName, String fname, long value) {
692     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
693     ci.getStaticElementInfo().setLongField(fname, value);
694   }
695
696   public void setStaticLongField (int clsObjRef, String fname, long val) {
697     ElementInfo cei = getModifiableStaticElementInfo(clsObjRef);
698     cei.setLongField(fname, val);
699   }
700
701   public long getStaticLongField (int clsRef, String fname) {
702     ClassInfo ci = getReferredClassInfo(clsRef);
703     return getStaticLongField(ci, fname);
704   }
705
706   public long getStaticLongField (String clsName, String fname) {
707     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
708     return getStaticLongField(ci, fname);
709   }
710
711   public long getStaticLongField (ClassInfo ci, String fname){
712     ElementInfo ei = ci.getStaticElementInfo();
713     return ei.getLongField(fname);
714   }
715
716   public void setStaticReferenceField (String clsName, String fname, int objref) {
717     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
718
719     // <2do> - we should REALLY check for type compatibility here
720     ci.getModifiableStaticElementInfo().setReferenceField(fname, objref);
721   }
722
723   public void setStaticReferenceField (int clsObjRef, String fname, int objref) {
724     ElementInfo cei = getModifiableStaticElementInfo(clsObjRef);
725
726     // <2do> - we should REALLY check for type compatibility here
727     cei.setReferenceField(fname, objref);
728   }
729
730   public int getStaticReferenceField (String clsName, String fname) {
731     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
732     return ci.getStaticElementInfo().getReferenceField(fname);
733   }
734
735   public int getStaticReferenceField (int clsObjRef, String fname) {
736     ElementInfo cei = getStaticElementInfo(clsObjRef);
737     return cei.getReferenceField(fname);
738   }
739
740   public int getStaticReferenceField (ClassInfo ci, String fname){
741     return ci.getStaticElementInfo().getReferenceField(fname);
742   }
743
744   public short getStaticShortField (String clsName, String fname) {
745     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
746     return ci.getStaticElementInfo().getShortField(fname);
747   }
748
749   public char[] getStringChars (int objRef){
750     if (objRef != MJIEnv.NULL) {
751       ElementInfo ei = getElementInfo(objRef);
752       return ei.getStringChars();
753       
754     } else {
755       return null;
756     }
757     
758   }
759   
760   /**
761    * turn JPF String object into a VM String object
762    * (this is a method available for non gov..jvm NativePeer classes)
763    */
764   public String getStringObject (int objRef) {
765     if (objRef != MJIEnv.NULL) {
766       ElementInfo ei = getElementInfo(objRef);
767       return ei.asString();
768       
769     } else {
770       return null;
771     }
772   }
773
774   public String[] getStringArrayObject (int aRef){
775     String[] sa = null;
776      
777     if (aRef == NULL) return sa;
778
779     ClassInfo aci = getClassInfo(aRef);
780     if (aci.isArray()){
781       ClassInfo eci = aci.getComponentClassInfo();
782       if (eci.getName().equals("java.lang.String")){
783         int len = getArrayLength(aRef);
784         sa = new String[len];
785
786         for (int i=0; i<len; i++){
787           int sRef = getReferenceArrayElement(aRef,i);
788           sa[i] = getStringObject(sRef);
789         }
790
791         return sa;
792         
793       } else {
794         throw new IllegalArgumentException("not a String[] array: " + aci.getName());
795       }
796     } else {
797       throw new IllegalArgumentException("not an array reference: " + aci.getName());
798     }
799   }
800   
801   public Date getDateObject (int objref) {
802     if (objref != MJIEnv.NULL) {
803       ElementInfo ei = getElementInfo(objref);
804       if (ei.getClassInfo().getName().equals("java.util.Date")) {
805         // <2do> this is not complete yet
806         long fastTime = ei.getLongField("fastTime");
807         Date d = new Date(fastTime);
808         return d;
809       } else {
810         throw new JPFException("not a Date object reference: " + ei);
811       }
812     } else {
813       return null;
814     }
815     
816   }
817
818   public Object[] getArgumentArray (int argRef) {
819     Object[] args = null;
820     if (argRef == NULL) return args;
821
822     int nArgs = getArrayLength(argRef);
823     args = new Object[nArgs];
824
825     for (int i=0; i<nArgs; i++){
826       int aref = getReferenceArrayElement(argRef,i);
827       ClassInfo ci = getClassInfo(aref);
828       String clsName = ci.getName();
829       if (clsName.equals("java.lang.Boolean")){
830         args[i] = Boolean.valueOf(getBooleanField(aref,"value"));
831       } else if (clsName.equals("java.lang.Integer")){
832         args[i] = Integer.valueOf(getIntField(aref,"value"));
833       } else if (clsName.equals("java.lang.Double")){
834         args[i] = Double.valueOf(getDoubleField(aref,"value"));
835       } else if (clsName.equals("java.lang.String")){
836         args[i] = getStringObject(aref);
837       }
838     }
839
840     return args;
841   }
842
843   public Boolean getBooleanObject (int objref){
844     return Boolean.valueOf(getBooleanField(objref, "value"));
845   }
846
847   public Byte getByteObject (int objref){
848     return new Byte(getByteField(objref, "value"));
849   }
850
851   public Character getCharObject (int objref){
852     return new Character(getCharField(objref, "value"));
853   }
854
855   public Short getShortObject (int objref){
856     return new Short(getShortField(objref, "value"));
857   }
858
859   public Integer getIntegerObject (int objref){
860     return new Integer(getIntField(objref, "value"));
861   }
862
863   public Long getLongObject (int objref){
864     return new Long(getLongField(objref, "value"));
865   }
866
867   public Float getFloatObject (int objref){
868     return new Float(getFloatField(objref, "value"));
869   }
870
871   public Double getDoubleObject (int objref){
872     return new Double(getDoubleField(objref, "value"));
873   }
874
875   // danger - the returned arrays could be used to modify contents of stored objects
876
877   public byte[] getByteArrayObject (int objref) {
878     ElementInfo ei = getElementInfo(objref);
879     byte[] a = ei.asByteArray();
880
881     return a;
882   }
883
884   public char[] getCharArrayObject (int objref) {
885     ElementInfo ei = getElementInfo(objref);
886     char[] a = ei.asCharArray();
887
888     return a;
889   }
890
891   public short[] getShortArrayObject (int objref) {
892     ElementInfo ei = getElementInfo(objref);
893     short[] a = ei.asShortArray();
894
895     return a;
896   }
897
898   public int[] getIntArrayObject (int objref) {
899     ElementInfo ei = getElementInfo(objref);
900     int[] a = ei.asIntArray();
901
902     return a;
903   }
904
905   public long[] getLongArrayObject (int objref) {
906     ElementInfo ei = getElementInfo(objref);
907     long[] a = ei.asLongArray();
908
909     return a;
910   }
911
912   public float[] getFloatArrayObject (int objref) {
913     ElementInfo ei = getElementInfo(objref);
914     float[] a = ei.asFloatArray();
915
916     return a;
917   }
918
919   public double[] getDoubleArrayObject (int objref) {
920     ElementInfo ei = getElementInfo(objref);
921     double[] a = ei.asDoubleArray();
922
923     return a;
924   }
925
926   public boolean[] getBooleanArrayObject (int objref) {
927     ElementInfo ei = getElementInfo(objref);
928     boolean[] a = ei.asBooleanArray();
929
930     return a;
931   }
932   
933   public int[] getReferenceArrayObject (int objref){
934     ElementInfo ei = getElementInfo(objref);
935     int[] a = ei.asReferenceArray();
936
937     return a;    
938   }
939
940   public boolean canLock (int objref) {
941     ElementInfo ei = getElementInfo(objref);
942
943     return ei.canLock(ti);
944   }
945
946   public int newBooleanArray (int size) {
947     return heap.newArray("Z", size, ti).getObjectRef();
948   }
949
950   public int newByteArray (int size) {
951     return heap.newArray("B", size, ti).getObjectRef();
952   }
953
954   public int newByteArray (byte[] buf){
955     ElementInfo eiArray = heap.newArray("B", buf.length, ti);
956     for (int i=0; i<buf.length; i++){
957       eiArray.setByteElement( i, buf[i]);
958     }
959     return eiArray.getObjectRef();
960   }
961
962   public int newCharArray (int size) {
963     return heap.newArray("C", size, ti).getObjectRef();
964   }
965
966   public int newCharArray (char[] buf){
967     ElementInfo eiArray = heap.newArray("C", buf.length, ti);
968     for (int i=0; i<buf.length; i++){
969       eiArray.setCharElement( i, buf[i]);
970     }
971     return eiArray.getObjectRef();
972   }
973
974   public int newShortArray (int size) {
975     return heap.newArray("S", size, ti).getObjectRef();
976   }
977   
978   public int newShortArray (short[] buf){
979     ElementInfo eiArray = heap.newArray("S", buf.length, ti);
980     for (int i=0; i<buf.length; i++){
981       eiArray.setShortElement(i, buf[i]);
982     }
983     return eiArray.getObjectRef();
984   }
985
986   public int newDoubleArray (int size) {
987     return heap.newArray("D", size, ti).getObjectRef();
988   }
989
990   public int newDoubleArray (double[] buf){
991     ElementInfo eiArray =  heap.newArray("D", buf.length, ti);
992     for (int i=0; i<buf.length; i++){
993       eiArray.setDoubleElement(i, buf[i]);
994     }
995     return eiArray.getObjectRef();
996   }
997
998   public int newFloatArray (int size) {
999     return heap.newArray("F", size, ti).getObjectRef();
1000   }
1001   
1002   public int newFloatArray (float[] buf){
1003     ElementInfo eiArray =  heap.newArray("F", buf.length, ti);
1004     for (int i=0; i<buf.length; i++){
1005       eiArray.setFloatElement( i, buf[i]);
1006     }
1007     return eiArray.getObjectRef();
1008   }
1009
1010   public int newIntArray (int size) {
1011     return heap.newArray("I", size, ti).getObjectRef();
1012   }
1013
1014   public int newIntArray (int[] buf){
1015     ElementInfo eiArray = heap.newArray("I", buf.length, ti);
1016     for (int i=0; i<buf.length; i++){
1017       eiArray.setIntElement( i, buf[i]);
1018     }
1019     return eiArray.getObjectRef();
1020   }
1021
1022   public int newLongArray (int size) {
1023     return heap.newArray("J", size, ti).getObjectRef();
1024   }
1025
1026   public int newLongArray (long[] buf){
1027     ElementInfo eiArray = heap.newArray("J", buf.length, ti);
1028     for (int i=0; i<buf.length; i++){
1029       eiArray.setLongElement( i, buf[i]);
1030     }
1031     return eiArray.getObjectRef();
1032   }
1033
1034   public int newObjectArray (String elementClsName, int size) {
1035     if (!elementClsName.endsWith(";")) {
1036       elementClsName = Types.getTypeSignature(elementClsName, false);
1037     }
1038
1039     return heap.newArray(elementClsName, size, ti).getObjectRef();
1040   }
1041
1042   public ElementInfo newElementInfo (ClassInfo ci) throws ClinitRequired {
1043     if (ci.initializeClass(ti)){
1044       throw new ClinitRequired(ci);
1045     }
1046
1047     return heap.newObject(ci, ti);
1048   }
1049   
1050   /**
1051    * check if the ClassInfo is properly initialized
1052    * if yes, create a new instance of it but don't call any ctor
1053    * if no, throw a ClinitRequired exception
1054    */
1055   public int newObject (ClassInfo ci)  throws ClinitRequired {
1056     ElementInfo ei = newElementInfo(ci);
1057     return ei.getObjectRef();
1058   }
1059
1060   /**
1061    * this creates a new object without checking if the ClassInfo needs
1062    * initialization. This is useful in a context that already
1063    * is aware and handles re-execution
1064    */
1065   public int newObjectOfUncheckedClass (ClassInfo ci){
1066     ElementInfo ei = heap.newObject(ci, ti);
1067     return ei.getObjectRef();    
1068   }
1069   
1070   public ElementInfo newElementInfo (String clsName)  throws ClinitRequired, UnknownJPFClass {
1071     ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
1072     if (ci != null){
1073       return newElementInfo(ci);
1074     } else {
1075       throw new UnknownJPFClass(clsName);
1076     }
1077   }
1078   
1079   public int newObject (String clsName)   throws ClinitRequired, UnknownJPFClass {
1080     ElementInfo ei = newElementInfo(clsName);
1081     return (ei != null) ? ei.getObjectRef() : NULL;
1082   }
1083   
1084   public int newString (String s) {
1085     if (s == null){
1086       return NULL;
1087     } else {
1088       return heap.newString(s, ti).getObjectRef();
1089     }
1090   }
1091
1092   public int newStringArray (String[] a){
1093     int aref = newObjectArray("Ljava/lang/String;", a.length);
1094
1095     for (int i=0; i<a.length; i++){
1096       setReferenceArrayElement(aref, i, newString(a[i]));
1097     }
1098
1099     return aref;
1100   }
1101
1102   public int newString (int arrayRef) {
1103     String t = getArrayType(arrayRef);
1104     String s = null;
1105
1106     if ("C".equals(t)) {          // character array
1107       char[] ca = getCharArrayObject(arrayRef);
1108       s = new String(ca);
1109     } else if ("B".equals(t)) {   // byte array
1110       byte[] ba = getByteArrayObject(arrayRef);
1111       s = new String(ba);
1112     }
1113
1114     if (s == null) {
1115       return NULL;
1116     }
1117
1118     return newString(s);
1119   }
1120   
1121   public String format (int fmtRef, int argRef){
1122     String format = getStringObject(fmtRef);
1123     int len = getArrayLength(argRef);
1124     Object[] arg = new Object[len];
1125
1126     for (int i=0; i<len; i++){
1127       int ref = getReferenceArrayElement(argRef,i);
1128       if (ref != NULL) {
1129         String clsName = getClassName(ref);
1130         if (clsName.equals("java.lang.String")) {
1131           arg[i] = getStringObject(ref);
1132         } else if (clsName.equals("java.lang.Boolean")){
1133           arg[i] = getBooleanObject(ref);
1134         } else if (clsName.equals("java.lang.Byte")) {
1135           arg[i] = getByteObject(ref);
1136         } else if (clsName.equals("java.lang.Char")) {
1137           arg[i] = getCharObject(ref);
1138         } else if (clsName.equals("java.lang.Short")) {
1139           arg[i] = getShortObject(ref);
1140         } else if (clsName.equals("java.lang.Integer")) {
1141           arg[i] = getIntegerObject(ref);
1142         } else if (clsName.equals("java.lang.Long")) {
1143           arg[i] = getLongObject(ref);
1144         } else if (clsName.equals("java.lang.Float")) {
1145           arg[i] = getFloatObject(ref);
1146         } else if (clsName.equals("java.lang.Double")) {
1147           arg[i] = getDoubleObject(ref);
1148         } else {
1149           // need a toString() here
1150           arg[i] = "??";
1151         }
1152       }
1153     }
1154
1155     return String.format(format,arg);
1156   }
1157
1158   public String format (Locale l,int fmtRef, int argRef){
1159             String format = getStringObject(fmtRef);
1160             int len = getArrayLength(argRef);
1161             Object[] arg = new Object[len];
1162
1163             for (int i=0; i<len; i++){
1164               int ref = getReferenceArrayElement(argRef,i);
1165               if (ref != NULL) {
1166                 String clsName = getClassName(ref);
1167                 if (clsName.equals("java.lang.String")) {
1168                   arg[i] = getStringObject(ref);
1169                 } else if (clsName.equals("java.lang.Byte")) {
1170                   arg[i] = getByteObject(ref);
1171                 } else if (clsName.equals("java.lang.Char")) {
1172                   arg[i] = getCharObject(ref);
1173                 } else if (clsName.equals("java.lang.Short")) {
1174                   arg[i] = getShortObject(ref);
1175                 } else if (clsName.equals("java.lang.Integer")) {
1176                   arg[i] = getIntegerObject(ref);
1177                 } else if (clsName.equals("java.lang.Long")) {
1178                   arg[i] = getLongObject(ref);
1179                 } else if (clsName.equals("java.lang.Float")) {
1180                   arg[i] = getFloatObject(ref);
1181                 } else if (clsName.equals("java.lang.Double")) {
1182                   arg[i] = getDoubleObject(ref);
1183                 } else {
1184                   // need a toString() here
1185                   arg[i] = "??";
1186                 }
1187               }
1188             }
1189
1190             return String.format(l,format,arg);
1191           }
1192
1193
1194   public int newBoolean (boolean b){
1195     return getStaticReferenceField("java.lang.Boolean", b ? "TRUE" : "FALSE");
1196   }
1197
1198   public int newInteger (int n){
1199     ElementInfo ei = heap.newObject(ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Integer"), ti);
1200     ei.setIntField("value",n);
1201     return ei.getObjectRef();
1202   }
1203
1204   public int newLong (long l){
1205     ElementInfo ei = heap.newObject(ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Long"), ti);
1206     ei.setLongField("value",l);
1207     return ei.getObjectRef();
1208   }
1209
1210   public int newDouble (double d){
1211     ElementInfo ei = heap.newObject(ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Double"), ti);
1212     ei.setDoubleField("value",d);
1213     return ei.getObjectRef();
1214   }
1215
1216   public int newFloat (float f){
1217     ElementInfo ei = heap.newObject(ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Float"), ti);
1218     ei.setFloatField("value",f);
1219     return ei.getObjectRef();
1220   }
1221
1222   public int newByte (byte b){
1223     ElementInfo ei = heap.newObject(ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Byte"), ti);
1224     ei.setByteField("value",b);
1225     return ei.getObjectRef();
1226   }
1227
1228   public int newShort (short s){
1229     ElementInfo ei = heap.newObject(ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Short"), ti);
1230     ei.setShortField("value",s);
1231     return ei.getObjectRef();
1232   }
1233
1234   public int newCharacter (char c){
1235     ElementInfo ei =  heap.newObject(ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.Character"), ti);
1236     ei.setCharField("value",c);
1237     return ei.getObjectRef();
1238   }
1239
1240
1241   public boolean notify (int objref) {
1242     // objref can't be NULL since the corresponding INVOKE would have failed
1243     ElementInfo ei = getModifiableElementInfo(objref);
1244     return notify(ei);
1245   }
1246
1247   public boolean notify (ElementInfo ei) {
1248     if (!ei.isLockedBy(ti)){
1249       throwException("java.lang.IllegalMonitorStateException",
1250                                  "un-synchronized notify");
1251       return false;
1252     }
1253
1254     return ei.notifies(getSystemState(), ti); 
1255   }
1256   
1257   public boolean notifyAll (int objref) {
1258     // objref can't be NULL since the corresponding INVOKE would have failed
1259     ElementInfo ei = getElementInfo(objref);
1260     return notifyAll(ei);
1261   }
1262
1263   public boolean notifyAll (ElementInfo ei) {
1264     if (!ei.isLockedBy(ti)){
1265       throwException("java.lang.IllegalMonitorStateException",
1266                                  "un-synchronized notifyAll");
1267       return false;
1268     }
1269
1270     return ei.notifiesAll();    
1271   }
1272   
1273   public void registerPinDown(int objref){
1274     heap.registerPinDown(objref);
1275   }
1276   public void registerPinDown (ElementInfo ei){
1277     registerPinDown(ei.getObjectRef());
1278   }
1279   
1280   public void releasePinDown(int objref){
1281     heap.releasePinDown(objref);
1282   }
1283   public void releasePinDown (ElementInfo ei){
1284     releasePinDown(ei.getObjectRef());
1285   }
1286   
1287   /**
1288    *  use this whenever a peer performs an operation on a class that might not be initialized yet
1289    *  Do a repeatInvocation() in this case 
1290    */
1291   public boolean requiresClinitExecution(ClassInfo ci) {
1292     return ci.initializeClass(ti);
1293   }
1294   
1295   /**
1296    * repeat execution of the instruction that caused a native method call
1297    * NOTE - this does NOT mean it's the NEXT executed insn, since the native method
1298    * might have pushed direct call frames on the stack before asking us to repeat it.
1299    */
1300   public void repeatInvocation () {
1301     repeat = true;
1302   }
1303
1304   public boolean isInvocationRepeated() {
1305     return repeat;
1306   }
1307
1308
1309   public boolean setNextChoiceGenerator (ChoiceGenerator<?> cg){
1310     return vm.getSystemState().setNextChoiceGenerator(cg);
1311   }
1312
1313   public void setMandatoryNextChoiceGenerator(ChoiceGenerator<?> cg, String failMsg){
1314     vm.getSystemState().setMandatoryNextChoiceGenerator(cg, failMsg);
1315   }
1316
1317   public ChoiceGenerator<?> getChoiceGenerator () {
1318     return vm.getSystemState().getChoiceGenerator();
1319   }
1320
1321   // note this only makes sense if we actually do return something
1322   public void setReturnAttribute (Object attr) {
1323     returnAttr = attr;
1324   }
1325
1326   /**
1327    * return attr list of all arguments. Use ObjectList to retrieve values
1328    * from this list
1329    * 
1330    * NOTE - this can only be called from a native method context, since
1331    * otherwise the top frame is the callee
1332    */
1333   public Object[] getArgAttributes () {
1334     StackFrame caller = getCallerStackFrame();
1335     return caller.getArgumentAttrs(mi);
1336   }
1337
1338   public Object getReturnAttribute() {
1339     return returnAttr;
1340   }
1341
1342   // if any of the next methods is called from the bottom
1343   // half of a CG method, you might want to check if another thread
1344   // or a listener has already set an exception you don't want to override
1345   // (this is for instance used in Thread.stop())
1346
1347   public void throwException (int xRef){
1348     assert isInstanceOf(xRef, "java.lang.Throwable");
1349     exceptionRef = xRef;
1350   }
1351
1352   public void throwException (String clsName) {
1353     ClassInfo ciX = ClassInfo.getInitializedClassInfo(clsName, ti);
1354     assert ciX.isInstanceOf("java.lang.Throwable");
1355     exceptionRef = ti.createException(ciX, null, NULL);
1356   }
1357
1358   public void throwException (String clsName, String details) {
1359     ClassInfo ciX = ClassInfo.getInitializedClassInfo(clsName, ti);
1360     assert ciX.isInstanceOf("java.lang.Throwable");
1361     exceptionRef = ti.createException(ciX, details, NULL);
1362   }
1363
1364   public void throwAssertion (String details) {
1365     throwException("java.lang.AssertionError", details);
1366   }
1367
1368   public void throwInterrupt(){
1369     throwException("java.lang.InterruptedException");
1370   }
1371
1372   public void stopThread(){
1373     stopThreadWithException(MJIEnv.NULL);
1374   }
1375
1376   public void stopThreadWithException (int xRef){
1377     // this will call throwException(xRef) with the proper Throwable
1378     ti.setStopped(xRef);
1379   }
1380
1381   void setCallEnvironment (MethodInfo mi) {
1382     this.mi = mi;
1383
1384     if (mi != null){
1385       ciMth = mi.getClassInfo();
1386     } else {
1387       //ciMth = null;
1388       //mi = null;
1389     }
1390
1391     repeat = false;
1392     returnAttr = null;
1393
1394     // we should NOT reset exceptionRef here because it might have been set
1395     // at the beginning of the transition. It gets reset upon return from the
1396     // native method
1397     //exceptionRef = NULL;
1398   }
1399
1400   void clearCallEnvironment () {
1401     setCallEnvironment(null);
1402   }
1403
1404   ElementInfo getStaticElementInfo (int clsObjRef) {
1405     ClassInfo ci = getReferredClassInfo( clsObjRef);
1406     if (ci != null) {
1407       return ci.getStaticElementInfo();
1408     }
1409     
1410     return null;
1411   }
1412   
1413   ElementInfo getModifiableStaticElementInfo (int clsObjRef) {
1414     ClassInfo ci = getReferredClassInfo( clsObjRef);
1415     if (ci != null) {
1416       return ci.getModifiableStaticElementInfo();
1417     }
1418     
1419     return null;
1420   }
1421   
1422
1423   ClassInfo getClassInfo () {
1424     return ciMth;
1425   }
1426
1427   public ClassInfo getReferredClassInfo (int clsObjRef) {
1428     ElementInfo ei = getElementInfo(clsObjRef);
1429     if (ei.getClassInfo().getName().equals("java.lang.Class")) {
1430       int ciId = ei.getIntField( ClassInfo.ID_FIELD);
1431       int clref = ei.getReferenceField("classLoader");
1432       
1433       ElementInfo eiCl = getElementInfo(clref);
1434       int cliId = eiCl.getIntField(ClassLoaderInfo.ID_FIELD);
1435       
1436       ClassLoaderInfo cli = getVM().getClassLoader(cliId);
1437       ClassInfo referredCi = cli.getClassInfo(ciId);
1438       
1439       return referredCi;
1440       
1441     } else {
1442       throw new JPFException("not a java.lang.Class object: " + ei);
1443     }
1444   }
1445
1446   public ClassInfo getClassInfo (int objref) {
1447     ElementInfo ei = getElementInfo(objref);
1448     if (ei != null){
1449       return ei.getClassInfo();
1450     } else {
1451       return null;
1452     }
1453   }
1454
1455   public String getClassName (int objref) {
1456     return getClassInfo(objref).getName();
1457   }
1458
1459   public Heap getHeap () {
1460     return vm.getHeap();
1461   }
1462
1463   public ElementInfo getElementInfo (int objref) {
1464     return heap.get(objref);
1465   }
1466
1467   public ElementInfo getModifiableElementInfo (int objref) {
1468     return heap.getModifiable(objref);
1469   }
1470
1471   
1472   public int getStateId () {
1473     return VM.getVM().getStateId();
1474   }
1475
1476   void clearException(){
1477     exceptionRef = MJIEnv.NULL;
1478   }
1479
1480   public int peekException () {
1481     return exceptionRef;
1482   }
1483
1484   public int popException () {
1485     int ret = exceptionRef;
1486     exceptionRef = NULL;
1487     return ret;
1488   }
1489
1490   public boolean hasException(){
1491     return (exceptionRef != NULL);
1492   }
1493
1494   public boolean hasPendingInterrupt(){
1495     return (exceptionRef != NULL && isInstanceOf(exceptionRef, "java.lang.InterruptedException"));
1496   }
1497
1498   //-- time is managed by the VM
1499   public long currentTimeMillis(){
1500     return vm.currentTimeMillis();
1501   }
1502   
1503   public long nanoTime(){
1504     return vm.nanoTime();
1505   }
1506   
1507   //--- those are not public since they refer to JPF internals
1508   public KernelState getKernelState () {
1509     return VM.getVM().getKernelState();
1510   }
1511
1512   public MethodInfo getMethodInfo () {
1513     return mi;
1514   }
1515
1516   public Instruction getInstruction () {
1517     return ti.getPC();
1518   }
1519
1520   /**
1521    * It returns the ClassLoaderInfo corresponding to the given classloader object
1522    * reference
1523    */
1524   public ClassLoaderInfo getClassLoaderInfo(int clObjRef) {
1525     if(clObjRef == MJIEnv.NULL) {
1526       return null;
1527     }
1528
1529     int cliId = heap.get(clObjRef).getIntField(ClassLoaderInfo.ID_FIELD);
1530     return getVM().getClassLoader(cliId);
1531   }
1532
1533   // <2do> that's not correct - it should return the current SystemClassLoader, NOT the startup SystemClassLoader
1534   // (we can instantiate them explicitly)
1535   public ClassLoaderInfo getSystemClassLoaderInfo() {
1536     return ti.getSystemClassLoaderInfo();
1537   }
1538   
1539   public SystemState getSystemState () {
1540     return ti.getVM().getSystemState();
1541   }
1542   
1543   public ApplicationContext getApplicationContext (){
1544     return ti.getApplicationContext();
1545   }
1546
1547   public ThreadInfo getThreadInfo () {
1548     return ti;
1549   }
1550
1551   /**
1552    * NOTE - callers have to be prepared this might return null in case
1553    * the thread got already terminated
1554    */
1555   public ThreadInfo getThreadInfoForId (int id){
1556     return vm.getThreadList().getThreadInfoForId(id);
1557   }
1558
1559   public ThreadInfo getLiveThreadInfoForId (int id){
1560     ThreadInfo ti = vm.getThreadList().getThreadInfoForId(id);
1561     if (ti != null && ti.isAlive()){
1562       return ti;
1563     }
1564     
1565     return null;
1566   }
1567   
1568   /**
1569    * NOTE - callers have to be prepared this might return null in case
1570    * the thread got already terminated
1571    */
1572   public ThreadInfo getThreadInfoForObjRef (int id){
1573     return vm.getThreadList().getThreadInfoForObjRef(id);
1574   }
1575   
1576   public ThreadInfo getLiveThreadInfoForObjRef (int id){
1577     ThreadInfo ti = vm.getThreadList().getThreadInfoForObjRef(id);
1578     if (ti != null && ti.isAlive()){
1579       return ti;
1580     }
1581     
1582     return null;
1583   }
1584
1585   
1586   
1587   public ThreadInfo[] getLiveThreads(){
1588     return getVM().getLiveThreads();
1589   }
1590   
1591   // <2do> - naming? not very intuitive
1592   void lockNotified (int objref) {
1593     ElementInfo ei = getModifiableElementInfo(objref);
1594     ei.lockNotified(ti);
1595   }
1596
1597   void initAnnotationProxyField (int proxyRef, FieldInfo fi, Object v) throws ClinitRequired {
1598     String fname = fi.getName();
1599     String ftype = fi.getType();
1600
1601     if (v instanceof String){
1602       setReferenceField(proxyRef, fname, newString((String)v));
1603     } else if (v instanceof Boolean){
1604       setBooleanField(proxyRef, fname, ((Boolean)v).booleanValue());
1605     } else if (v instanceof Integer){
1606       setIntField(proxyRef, fname, ((Integer)v).intValue());
1607     } else if (v instanceof Long){
1608       setLongField(proxyRef, fname, ((Long)v).longValue());
1609     } else if (v instanceof Float){
1610       setFloatField(proxyRef, fname, ((Float)v).floatValue());
1611     } else if (v instanceof Short){
1612       setShortField(proxyRef, fname, ((Short)v).shortValue());
1613     } else if (v instanceof Character){
1614       setCharField(proxyRef, fname, ((Character)v).charValue());
1615     } else if (v instanceof Byte){
1616       setByteField(proxyRef, fname, ((Byte)v).byteValue());
1617     } else if (v instanceof Double){
1618       setDoubleField(proxyRef, fname, ((Double)v).doubleValue());
1619
1620     } else if (v instanceof AnnotationInfo.EnumValue){ // an enum constant
1621       AnnotationInfo.EnumValue ev = (AnnotationInfo.EnumValue)v;
1622       String eCls = ev.getEnumClassName();
1623       String eConst = ev.getEnumConstName();
1624
1625       ClassInfo eci = ClassLoaderInfo.getCurrentResolvedClassInfo(eCls);
1626       if (!eci.isInitialized()){
1627         throw new ClinitRequired(eci);
1628       }
1629
1630       StaticElementInfo sei = eci.getStaticElementInfo();
1631       int eref = sei.getReferenceField(eConst);
1632       setReferenceField(proxyRef, fname, eref);
1633
1634     } else if (v instanceof AnnotationInfo.ClassValue){ // a class
1635       String clsName = v.toString();
1636       ClassInfo cci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
1637       // <2do> should throw ClassNotFoundError here if cci is null
1638
1639       if (!cci.isInitialized()){
1640         throw new ClinitRequired(cci);
1641       }
1642
1643       int cref = cci.getClassObjectRef();
1644       setReferenceField(proxyRef, fname, cref);
1645
1646     } else if (v.getClass().isArray()){ // ..or arrays thereof
1647       Object[] a = (Object[])v;
1648       int aref = NULL;
1649
1650       if (ftype.equals("java.lang.String[]")){
1651         aref = newObjectArray("Ljava/lang/String;", a.length);
1652         for (int i=0; i<a.length; i++){
1653           setReferenceArrayElement(aref,i,newString(a[i].toString()));
1654         }
1655       } else if (ftype.equals("int[]")){
1656         aref = newIntArray(a.length);
1657         for (int i=0; i<a.length; i++){
1658           setIntArrayElement(aref,i,((Number)a[i]).intValue());
1659         }
1660       } else if (ftype.equals("boolean[]")){
1661         aref = newBooleanArray(a.length);
1662         for (int i=0; i<a.length; i++){
1663           setBooleanArrayElement(aref,i,((Boolean)a[i]).booleanValue());
1664         }
1665       } else if (ftype.equals("long[]")){
1666         aref = newLongArray(a.length);
1667         for (int i=0; i<a.length; i++){
1668           setLongArrayElement(aref,i,((Number)a[i]).longValue());
1669         }
1670       } else if (ftype.equals("double[]")){
1671         aref = newDoubleArray(a.length);
1672         for (int i=0; i<a.length; i++){
1673           setDoubleArrayElement(aref,i,((Number)a[i]).doubleValue());
1674         }
1675       } else if (ftype.equals("java.lang.Class[]")){
1676         aref = newObjectArray("java.lang.Class", a.length);
1677         for (int i=0; i<a.length; i++){
1678           String clsName = ((AnnotationInfo.ClassValue)a[i]).getName();
1679           ClassInfo cci = ClassLoaderInfo.getCurrentResolvedClassInfo(clsName);
1680           if (!cci.isInitialized()){
1681             throw new ClinitRequired(cci);
1682           }
1683           int cref = cci.getClassObjectRef();
1684           setReferenceArrayElement(aref,i,cref);
1685         }
1686       }
1687
1688       if (aref != NULL){
1689         setReferenceField(proxyRef, fname, aref);
1690       } else {
1691         throwException("AnnotationElement type not supported: " + ftype);
1692       }
1693
1694     } else {
1695       throwException("AnnotationElement type not supported: " + ftype);
1696     }
1697   }
1698
1699   int newAnnotationProxy (ClassInfo aciProxy, AnnotationInfo ai) throws ClinitRequired {
1700
1701     int proxyRef = newObject(aciProxy);
1702
1703     // init fields of the new object from the AnnotationInfo
1704     for (AnnotationInfo.Entry e : ai.getEntries()){
1705       Object v = e.getValue();
1706       String fname = e.getKey();
1707       FieldInfo fi = aciProxy.getInstanceField(fname);
1708
1709       initAnnotationProxyField(proxyRef, fi, v);
1710     }
1711
1712     return proxyRef;
1713   }
1714
1715   int newAnnotationProxies (AnnotationInfo[] ai) throws ClinitRequired {
1716
1717     if ((ai != null) && (ai.length > 0)){
1718       int aref = newObjectArray("Ljava/lang/annotation/Annotation;", ai.length);
1719       for (int i=0; i<ai.length; i++){
1720         ClassInfo aci = ClassLoaderInfo.getCurrentResolvedClassInfo(ai[i].getName());
1721         ClassInfo aciProxy = aci.getAnnotationProxy();
1722
1723         int ar = newAnnotationProxy(aciProxy, ai[i]);
1724         setReferenceArrayElement(aref, i, ar);
1725       }
1726       return aref;
1727
1728     } else {
1729       // on demand init (not too many programs use annotation reflection)
1730       int aref = getStaticReferenceField("java.lang.Class", "emptyAnnotations");
1731       if (aref == NULL) {
1732         aref = newObjectArray("Ljava/lang/annotation/Annotation;", 0);
1733         setStaticReferenceField("java.lang.Class", "emptyAnnotations", aref);
1734       }
1735       return aref;
1736     }
1737   }
1738
1739   public void handleClinitRequest (ClassInfo ci) {
1740     ThreadInfo ti = getThreadInfo();
1741
1742     // NOTE: we have to repeat no matter what, since this is called from
1743     // a handler context (if we only had to create a class object w/o
1744     // calling clinit, we can't just go on)
1745     ci.initializeClass(ti);
1746     repeatInvocation();
1747   }
1748
1749   public StackFrame getCallerStackFrame() {
1750     // since native methods are now executed within their own stack frames
1751     // we provide a little helper to get the caller
1752     return ti.getLastNonSyntheticStackFrame();
1753   }
1754
1755   public StackFrame getModifiableCallerStackFrame() {
1756     // since native methods are now executed within their own stack frames
1757     // we provide a little helper to get the caller
1758     return ti.getModifiableLastNonSyntheticStackFrame();
1759   }
1760
1761   
1762   public int valueOfBoolean(boolean b) {
1763     return BoxObjectCacheManager.valueOfBoolean(ti, b);
1764   }
1765
1766   public int valueOfByte(byte b) {
1767     return BoxObjectCacheManager.valueOfByte(ti, b);
1768   }
1769
1770   public int valueOfCharacter(char c) {
1771     return BoxObjectCacheManager.valueOfCharacter(ti, c);
1772   }
1773
1774   public int valueOfShort(short s) {
1775     return BoxObjectCacheManager.valueOfShort(ti, s);
1776   }
1777
1778   public int valueOfInteger(int i) {
1779     return BoxObjectCacheManager.valueOfInteger(ti, i);
1780   }
1781
1782   public int valueOfLong(long l) {
1783     return BoxObjectCacheManager.valueOfLong(ti, l);
1784   }
1785 }