Initial import
[jpf-core.git] / src / peers / gov / nasa / jpf / vm / JPF_java_lang_reflect_Field.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18 package gov.nasa.jpf.vm;
19
20 import gov.nasa.jpf.Config;
21 import gov.nasa.jpf.annotation.MJI;
22
23 import java.lang.reflect.Modifier;
24
25 /**
26  * native peer for java.lang.reflect.Field
27  */
28 public class JPF_java_lang_reflect_Field extends NativePeer {
29
30   // <2do> using Fields is fine, but creating them is not efficient until we get rid of the registry
31   
32   static final int NREG = 64;
33   static FieldInfo[] registered;
34   static int nRegistered;
35   
36   public static boolean init (Config conf){
37     registered = new FieldInfo[NREG];
38     nRegistered = 0;
39     return true;
40   }
41   
42   static int registerFieldInfo (FieldInfo fi) {
43     int idx;
44     
45     for (idx=0; idx < nRegistered; idx++) {
46       if (registered[idx] == fi) {
47         return idx;
48       }
49     }
50     
51     if (idx == registered.length) {
52       FieldInfo[] newReg = new FieldInfo[registered.length+NREG];
53       System.arraycopy(registered, 0, newReg, 0, registered.length);
54       registered = newReg;
55     }
56     
57     registered[idx] = fi;
58     nRegistered++;
59     return idx;
60   }
61   
62   static FieldInfo getRegisteredFieldInfo (int idx) {
63     return registered[idx];
64   }
65   
66   /**
67    * <2do> that doesn't take care of class init yet
68    */
69   @MJI
70   public int getType____Ljava_lang_Class_2 (MJIEnv env, int objRef) {
71     ThreadInfo ti = env.getThreadInfo();
72     FieldInfo fi = getFieldInfo(env, objRef);
73
74     ClassInfo ci = fi.getTypeClassInfo();
75     if (!ci.isRegistered()) {
76       ci.registerClass(ti);
77     }
78
79     return ci.getClassObjectRef();
80   }
81   
82   @MJI
83   public int getModifiers____I (MJIEnv env, int objRef){
84     FieldInfo fi = getFieldInfo(env, objRef);
85     return fi.getModifiers();
86   }
87
88   protected StackFrame getCallerFrame (MJIEnv env){
89     ThreadInfo ti = env.getThreadInfo();
90     StackFrame frame = ti.getTopFrame(); // this is the Field.get/setX(), so we still have to get down
91     return frame.getPrevious();
92   }
93   
94   protected boolean isAccessible (MJIEnv env, FieldInfo fi, int fieldRef, int ownerRef){
95     
96     // note that setAccessible() even overrides final
97     ElementInfo fei = env.getElementInfo(fieldRef);
98     if (fei.getBooleanField("isAccessible")){
99       return true;
100     }
101     
102     if (fi.isFinal()){
103       return false;
104     }
105     
106     if (fi.isPublic()){
107       return true;
108     }
109     
110     // otherwise we have to check object identities and access modifier of the executing method
111     ClassInfo ciDecl = fi.getClassInfo();
112     String declPackage = ciDecl.getPackageName();
113     
114     StackFrame frame = getCallerFrame(env);    
115     MethodInfo mi = frame.getMethodInfo();
116     ClassInfo ciMethod = mi.getClassInfo();
117     String mthPackage = ciMethod.getPackageName();
118
119     if (!fi.isPrivate() && declPackage.equals(mthPackage)) {
120       return true;
121     }
122     
123     if (fi.isStatic()){
124       if (ciDecl == ciMethod){
125         return true;
126       }
127       
128     } else {
129       int thisRef = frame.getCalleeThis(mi);
130       if (thisRef == ownerRef) { // same object
131         return true;
132       }
133     }
134     
135     // <2do> lots of more checks here
136     
137     return false;
138   }
139   
140   protected ElementInfo getCheckedElementInfo (MJIEnv env, FieldInfo fi, int objRef, int ownerRef, boolean isWrite){
141     ElementInfo ei;
142
143     if (!isAvailable(env, fi, ownerRef)){
144       return null;
145     }
146
147     if (fi.isStatic()){
148       ClassInfo fci = fi.getClassInfo();
149       ei = isWrite ? fci.getModifiableStaticElementInfo() : fci.getStaticElementInfo();
150     } else { // instance field
151       ei = isWrite ? env.getModifiableElementInfo(ownerRef) : env.getElementInfo(ownerRef);
152     }
153
154     if (ei == null) {
155       env.throwException("java.lang.NullPointerException");
156       return null;
157     }
158
159     if ( !isAccessible(env, fi, objRef, ownerRef)){
160       env.throwException("java.lang.IllegalAccessException", "field not accessible: " + fi);
161       return null;
162     }
163     
164     return ei;
165   }
166   
167   protected boolean checkFieldType (MJIEnv env, FieldInfo fi, Class<?> fiType){
168     if (!fiType.isInstance(fi)) {
169       env.throwException("java.lang.IllegalArgumentException", "incompatible field type: " + fi);
170       return false;
171     }
172     
173     return true;
174   }
175   
176   protected ElementInfo checkSharedFieldAccess (ThreadInfo ti, ElementInfo ei, FieldInfo fi){    
177     Instruction insn = ti.getPC();
178     Scheduler scheduler = ti.getScheduler();
179     
180     if (fi.isStatic()){      
181       if (scheduler.canHaveSharedClassCG(ti, insn, ei, fi)){
182         ei = scheduler.updateClassSharedness(ti, ei, fi);
183         scheduler.setsSharedClassCG(ti, insn, ei, fi);
184       }
185       
186     } else {
187       if (scheduler.canHaveSharedObjectCG(ti, insn, ei, fi)){
188         ei = scheduler.updateObjectSharedness(ti, ei, fi);
189         scheduler.setsSharedObjectCG(ti, insn, ei, fi);
190       }
191     }
192     
193     return ei;
194   }
195   
196   @MJI
197   public boolean getBoolean__Ljava_lang_Object_2__Z (MJIEnv env, int objRef, int ownerRef) {
198     ThreadInfo ti = env.getThreadInfo();
199     FieldInfo fi = getFieldInfo(env, objRef);    
200     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, false);
201     if (ei != null){
202       if (checkFieldType(env, fi, BooleanFieldInfo.class)){
203         ei = checkSharedFieldAccess(ti, ei, fi);
204         if (ti.hasNextChoiceGenerator()) {
205           env.repeatInvocation();
206           return false;
207         }
208         
209         return ei.getBooleanField(fi);
210       }
211     }
212     return false;
213   }
214
215   @MJI
216   public byte getByte__Ljava_lang_Object_2__B (MJIEnv env, int objRef, int ownerRef) {
217     ThreadInfo ti = env.getThreadInfo();
218     FieldInfo fi = getFieldInfo(env, objRef);
219     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, false);
220     if (ei != null) {
221       if (checkFieldType(env, fi, BooleanFieldInfo.class)) {
222         ei = checkSharedFieldAccess(ti, ei, fi);
223         if (ti.hasNextChoiceGenerator()) {
224           env.repeatInvocation();
225           return 0;
226         }
227         return ei.getByteField(fi);
228       }
229     }
230     return 0;
231   }
232
233   @MJI
234   public char getChar__Ljava_lang_Object_2__C (MJIEnv env, int objRef, int ownerRef) {
235     ThreadInfo ti = env.getThreadInfo();
236     FieldInfo fi = getFieldInfo(env, objRef);
237     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, false);
238     if (ei != null){
239       if (checkFieldType(env, fi, CharFieldInfo.class)) {
240         ei = checkSharedFieldAccess(ti, ei, fi);
241         if (ti.hasNextChoiceGenerator()) {
242           env.repeatInvocation();
243           return 0;
244         }
245         return ei.getCharField(fi);
246       }
247     }
248     return 0;
249   }
250
251   @MJI
252   public short getShort__Ljava_lang_Object_2__S (MJIEnv env, int objRef, int ownerRef) {
253     ThreadInfo ti = env.getThreadInfo();
254     FieldInfo fi = getFieldInfo(env, objRef);
255     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, false);
256     if (ei != null){
257       if (checkFieldType(env, fi, ShortFieldInfo.class)){
258         ei = checkSharedFieldAccess(ti, ei, fi);
259         if (ti.hasNextChoiceGenerator()) {
260           env.repeatInvocation();
261           return 0;
262         }
263         return ei.getShortField(fi);
264       }
265     }
266     return 0;
267   }
268
269   @MJI
270   public int getInt__Ljava_lang_Object_2__I (MJIEnv env, int objRef, int ownerRef) {
271     ThreadInfo ti = env.getThreadInfo();
272     FieldInfo fi = getFieldInfo(env, objRef);
273     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, false);
274     if (ei != null){
275       if (checkFieldType(env, fi, IntegerFieldInfo.class)){
276         ei = checkSharedFieldAccess(ti, ei, fi);
277         if (ti.hasNextChoiceGenerator()) {
278           env.repeatInvocation();
279           return 0;
280         }
281         return ei.getIntField(fi);
282       }
283     }
284     return 0;
285   }
286
287   @MJI
288   public long getLong__Ljava_lang_Object_2__J (MJIEnv env, int objRef, int ownerRef) {
289     ThreadInfo ti = env.getThreadInfo();
290     FieldInfo fi = getFieldInfo(env, objRef);
291     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, false);
292     if (ei != null){
293       if (checkFieldType(env, fi, LongFieldInfo.class)){
294         ei = checkSharedFieldAccess(ti, ei, fi);
295         if (ti.hasNextChoiceGenerator()) {
296           env.repeatInvocation();
297           return 0;
298         }
299         return ei.getLongField(fi);
300       }
301     }
302     return 0;
303   }
304
305   @MJI
306   public float getFloat__Ljava_lang_Object_2__F (MJIEnv env, int objRef, int ownerRef) {
307     ThreadInfo ti = env.getThreadInfo();
308     FieldInfo fi = getFieldInfo(env, objRef);
309     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, false);
310     if (ei != null){
311       if (checkFieldType(env, fi, FloatFieldInfo.class)){
312         ei = checkSharedFieldAccess(ti, ei, fi);
313         if (ti.hasNextChoiceGenerator()) {
314           env.repeatInvocation();
315           return 0;
316         }
317         return ei.getFloatField(fi);
318       }
319     }
320     return 0;
321   }
322
323   @MJI
324   public double getDouble__Ljava_lang_Object_2__D (MJIEnv env, int objRef, int ownerRef) {
325     ThreadInfo ti = env.getThreadInfo();
326     FieldInfo fi = getFieldInfo(env, objRef);
327     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, false);
328     if (ei != null){
329       if (checkFieldType(env, fi, DoubleFieldInfo.class)){
330         ei = checkSharedFieldAccess(ti, ei, fi);
331         if (ti.hasNextChoiceGenerator()) {
332           env.repeatInvocation();
333           return 0;
334         }
335         return ei.getDoubleField(fi);
336       }
337     }
338     return 0;
339   }
340
341   @MJI
342   public int getAnnotation__Ljava_lang_Class_2__Ljava_lang_annotation_Annotation_2 (MJIEnv env, int objRef, int annotationClsRef) {
343     FieldInfo fi = getFieldInfo(env,objRef);
344     ClassInfo aci = env.getReferredClassInfo(annotationClsRef);
345     
346     AnnotationInfo ai = fi.getAnnotation(aci.getName());
347     if (ai != null){
348       ClassInfo aciProxy = aci.getAnnotationProxy();
349       try {
350         return env.newAnnotationProxy(aciProxy, ai);
351       } catch (ClinitRequired x){
352         env.handleClinitRequest(x.getRequiredClassInfo());
353         return MJIEnv.NULL;
354       }
355     }
356     
357     return MJIEnv.NULL;
358   }
359
360   @MJI
361   public int getAnnotations_____3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int objRef){
362     FieldInfo fi = getFieldInfo(env,objRef);
363     AnnotationInfo[] ai = fi.getAnnotations();
364     
365     try {
366       return env.newAnnotationProxies(ai);
367     } catch (ClinitRequired x){
368       env.handleClinitRequest(x.getRequiredClassInfo());
369       return MJIEnv.NULL;
370     }
371   }
372
373   @MJI
374   public void setBoolean__Ljava_lang_Object_2Z__V (MJIEnv env, int objRef, int ownerRef,
375                                                           boolean val) {
376     ThreadInfo ti = env.getThreadInfo();
377     FieldInfo fi = getFieldInfo(env, objRef);
378     if (!isAvailable(env, fi, ownerRef)){
379       return;
380     }
381     
382     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, true);
383     if (ei != null){
384       if (checkFieldType(env, fi, BooleanFieldInfo.class)){
385         ei = checkSharedFieldAccess(ti, ei, fi);
386         if (ti.getVM().hasNextChoiceGenerator()) {
387           env.repeatInvocation();
388           return;
389         }
390         ei.setBooleanField(fi, val);
391       }
392     }
393   }
394
395   @MJI
396   public void setByte__Ljava_lang_Object_2B__V (MJIEnv env, int objRef, int ownerRef, byte val) {
397     ThreadInfo ti = env.getThreadInfo();
398     FieldInfo fi = getFieldInfo(env, objRef);
399     if (!isAvailable(env, fi, ownerRef)){
400       return;
401     }
402     
403     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, true);
404     if (ei != null){
405       if (checkFieldType(env, fi, ByteFieldInfo.class)){
406         ei = checkSharedFieldAccess(ti, ei, fi);
407         if (ti.getVM().hasNextChoiceGenerator()) {
408           env.repeatInvocation();
409           return;
410         }
411         ei.setByteField(fi, val);
412       }
413     }
414   }
415
416   @MJI
417   public void setChar__Ljava_lang_Object_2C__V (MJIEnv env, int objRef, int ownerRef, char val) {
418     ThreadInfo ti = env.getThreadInfo();
419     FieldInfo fi = getFieldInfo(env, objRef);
420     if (!isAvailable(env, fi, ownerRef)){
421       return;
422     }
423     
424     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, true);
425     if (ei != null){
426       if (checkFieldType(env, fi, CharFieldInfo.class)){
427         ei = checkSharedFieldAccess(ti, ei, fi);
428         if (ti.getVM().hasNextChoiceGenerator()) {
429           env.repeatInvocation();
430           return;
431         }
432         ei.setCharField(fi, val);
433       }
434     }
435   }
436
437   @MJI
438   public void setShort__Ljava_lang_Object_2S__V (MJIEnv env, int objRef, int ownerRef,  short val) {
439     ThreadInfo ti = env.getThreadInfo();
440     FieldInfo fi = getFieldInfo(env, objRef);
441     if (!isAvailable(env, fi, ownerRef)){
442       return;
443     }
444     
445     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, true);
446     if (ei != null){
447       if (checkFieldType(env, fi, ShortFieldInfo.class)){
448         ei = checkSharedFieldAccess(ti, ei, fi);
449         if (ti.getVM().hasNextChoiceGenerator()) {
450           env.repeatInvocation();
451           return;
452         }
453         ei.setShortField(fi, val);
454       }
455     }
456   }  
457
458   @MJI
459   public void setInt__Ljava_lang_Object_2I__V (MJIEnv env, int objRef, int ownerRef, int val) {
460     ThreadInfo ti = env.getThreadInfo();
461     FieldInfo fi = getFieldInfo(env, objRef);
462     if (!isAvailable(env, fi, ownerRef)){
463       return;
464     }
465     
466     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, true);
467     if (ei != null){
468       if (checkFieldType(env, fi, IntegerFieldInfo.class)){
469         ei = checkSharedFieldAccess(ti, ei, fi);
470         if (ti.getVM().hasNextChoiceGenerator()) {
471           env.repeatInvocation();
472           return;
473         }
474         ei.setIntField(fi, val);
475       }
476     }
477   }
478
479   @MJI
480   public void setLong__Ljava_lang_Object_2J__V (MJIEnv env, int objRef, int ownerRef, long val) {
481     ThreadInfo ti = env.getThreadInfo();
482     FieldInfo fi = getFieldInfo(env, objRef);
483     if (!isAvailable(env, fi, ownerRef)){
484       return;
485     }
486     
487     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, true);
488     if (ei != null){
489       if (checkFieldType(env, fi, LongFieldInfo.class)){
490         ei = checkSharedFieldAccess(ti, ei, fi);
491         if (ti.getVM().hasNextChoiceGenerator()) {
492           env.repeatInvocation();
493           return;
494         }
495         ei.setLongField(fi, val);
496       }
497     }
498   }
499
500   @MJI
501   public void setFloat__Ljava_lang_Object_2F__V (MJIEnv env, int objRef, int ownerRef, float val) {
502     ThreadInfo ti = env.getThreadInfo();
503     FieldInfo fi = getFieldInfo(env, objRef);
504     if (!isAvailable(env, fi, ownerRef)){
505       return;
506     }
507     
508     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, true);
509     if (ei != null){
510       if (checkFieldType(env, fi, FloatFieldInfo.class)){
511         ei = checkSharedFieldAccess(ti, ei, fi);
512         if (ti.getVM().hasNextChoiceGenerator()) {
513           env.repeatInvocation();
514           return;
515         }
516         ei.setFloatField(fi, val);
517       }
518     }
519   }
520
521   @MJI
522   public void setDouble__Ljava_lang_Object_2D__V (MJIEnv env, int objRef, int ownerRef, double val) {
523     ThreadInfo ti = env.getThreadInfo();
524     FieldInfo fi = getFieldInfo(env, objRef);
525     if (!isAvailable(env, fi, ownerRef)){
526       return;
527     }
528     
529     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, true);
530     if (ei != null){
531       if (checkFieldType(env, fi, DoubleFieldInfo.class)){
532         ei = checkSharedFieldAccess(ti, ei, fi);
533         if (ti.getVM().hasNextChoiceGenerator()) {
534           env.repeatInvocation();
535           return;
536         }
537         ei.setDoubleField(fi, val);
538       }
539     }
540   }
541
542   @MJI
543   public int get__Ljava_lang_Object_2__Ljava_lang_Object_2 (MJIEnv env, int objRef, int ownerRef) {
544     ThreadInfo ti = env.getThreadInfo();
545     FieldInfo fi = getFieldInfo(env, objRef);
546     
547     ElementInfo ei = getCheckedElementInfo( env, fi, objRef, ownerRef, false); // no type check here
548     if (ei == null){
549       // just return, NPE already thrown by getCheckedElementInfo()
550       return 0;
551     }
552      
553     ei = checkSharedFieldAccess(ti, ei, fi);
554     if (ti.getVM().hasNextChoiceGenerator()) {
555       env.repeatInvocation();
556       return 0;
557     }
558     
559     if (!(fi instanceof ReferenceFieldInfo)) { // primitive type, we need to box it
560       if (fi instanceof DoubleFieldInfo){
561         double d = ei.getDoubleField(fi);
562         return env.newDouble(d);
563       } else if (fi instanceof FloatFieldInfo){
564         float f = ei.getFloatField(fi);
565         return env.newFloat(f);
566       } else if (fi instanceof LongFieldInfo){
567         long l = ei.getLongField(fi);
568         return env.newLong(l);
569       } else if (fi instanceof IntegerFieldInfo){
570         // this might actually represent a plethora of types
571         int i = ei.getIntField(fi);
572         return env.newInteger(i);
573       } else if (fi instanceof BooleanFieldInfo){
574         boolean b = ei.getBooleanField(fi);
575         return env.newBoolean(b);
576       } else if (fi instanceof ByteFieldInfo){
577         byte z = ei.getByteField(fi);
578         return env.newByte(z);
579       } else if (fi instanceof CharFieldInfo){
580         char c = ei.getCharField(fi);
581         return env.newCharacter(c);
582       } else if (fi instanceof ShortFieldInfo){
583         short s = ei.getShortField(fi);
584         return env.newShort(s);
585       }
586       
587     } else { // it's a reference
588       int ref = ei.getReferenceField(fi); // we internally store it as int
589       return ref;
590     }
591     
592     env.throwException("java.lang.IllegalArgumentException", "unknown field type");
593     return MJIEnv.NULL;
594   }
595
596   @MJI
597   public int getDeclaringClass____Ljava_lang_Class_2 (MJIEnv env, int objref){
598     FieldInfo fi = getFieldInfo(env, objref);
599     ClassInfo ci = fi.getClassInfo();
600     return ci.getClassObjectRef();
601   }
602
603   @MJI
604   public boolean isSynthetic____Z (MJIEnv env, int objref){
605     FieldInfo fi = getFieldInfo(env, objref);
606     String fn = fi.getName();
607     return (fn.startsWith("this$") || fn.startsWith("val$"));
608   }
609
610   @MJI
611   public int getName____Ljava_lang_String_2 (MJIEnv env, int objRef) {
612     FieldInfo fi = getFieldInfo(env, objRef);
613     
614     int nameRef = env.getReferenceField( objRef, "name");
615     if (nameRef == MJIEnv.NULL) {
616       nameRef = env.newString(fi.getName());
617       env.setReferenceField(objRef, "name", nameRef);
618     }
619    
620     return nameRef;
621   }
622
623   static FieldInfo getFieldInfo (MJIEnv env, int objRef) {
624     int fidx = env.getIntField( objRef, "regIdx");
625     assert ((fidx >= 0) || (fidx < nRegistered)) : "illegal FieldInfo request: " + fidx + ", " + nRegistered;
626     
627     return registered[fidx];
628   }
629   
630   static boolean isAvailable (MJIEnv env, FieldInfo fi, int ownerRef){
631     if (fi.isStatic()){
632       ClassInfo fci = fi.getClassInfo();
633       if (fci.initializeClass(env.getThreadInfo())){
634         env.repeatInvocation();
635         return false;
636       }
637       
638     } else {
639       if (ownerRef == MJIEnv.NULL){
640         env.throwException("java.lang.NullPointerException");
641         return false;        
642       }
643       // class had obviously been initialized, otherwise we won't have an instance of it
644     }
645
646     return true;
647   }
648   
649   
650   /**
651    * Peer method for the <code>java.lang.reflect.Field.set</code> method.
652    * 
653    * <2do> refactor to make boxed type handling more efficient
654    */
655   @MJI
656   public void set__Ljava_lang_Object_2Ljava_lang_Object_2__V (MJIEnv env, int objRef, int ownerRef, int val) {
657     ThreadInfo ti = env.getThreadInfo();
658     FieldInfo fi = getFieldInfo(env, objRef);
659
660     if (!isAvailable(env, fi, ownerRef)){
661       return;
662     }
663         
664     ClassInfo ci = fi.getClassInfo();
665     ClassInfo cio = env.getClassInfo(ownerRef);
666
667     if (!fi.isStatic() && !cio.isInstanceOf(ci)) {
668       env.throwException("java.lang.IllegalArgumentException", 
669                          fi.getType() + "field " + fi.getName() + " does not belong to this object");
670       return;
671     }
672     
673     Object[] attrs = env.getArgAttributes();
674     Object attr = (attrs==null)? null: attrs[2];
675     
676     String type = getValueType(env, val);
677     
678     if (!isAssignmentCompatible(env, fi, val)){
679       env.throwException("java.lang.IllegalArgumentException", 
680                          "field of type " + fi.getType() + " not assignment compatible with " + type + " object");      
681     }
682     
683     ElementInfo ei = getCheckedElementInfo(env, fi, objRef, ownerRef, true);
684     if (ei != null){
685       // <2do> what about exposure?
686       ei = checkSharedFieldAccess(ti, ei, fi);
687       if (ti.getVM().hasNextChoiceGenerator()) {
688         env.repeatInvocation();
689         return;
690       }
691
692       if (!setValue(env, fi, ownerRef, val, attr)) {
693         env.throwException("java.lang.IllegalArgumentException",
694                 "Can not set " + fi.getType() + " field " + fi.getFullName() + " to " + ((MJIEnv.NULL != val) ? env.getClassInfo(val).getName() + " object " : "null"));
695       }
696     }
697   }
698
699   protected String getValueType (MJIEnv env, int ref){
700     if (ref != MJIEnv.NULL){
701       ElementInfo eiVal = env.getElementInfo(ref);
702       return eiVal.getType();
703     } else {
704       return null;
705     }
706   }
707   
708   protected boolean isAssignmentCompatible (MJIEnv env, FieldInfo fi, int refVal){
709     if (refVal == MJIEnv.NULL){
710       return true;
711       
712     } else {
713       ElementInfo eiVal = env.getElementInfo(refVal);
714       ClassInfo ciVal = eiVal.getClassInfo();
715       String valClsName = ciVal.getName();
716       
717       if (fi.isBooleanField() && valClsName.equals("java.lang.Boolean")) return true;
718       else if (fi.isByteField() && valClsName.equals("java.lang.Byte")) return true;
719       else if (fi.isCharField() && valClsName.equals("java.lang.Char")) return true;
720       else if (fi.isShortField() && valClsName.equals("java.lang.Short")) return true;
721       else if (fi.isIntField() && valClsName.equals("java.lang.Integer")) return true;
722       else if (fi.isLongField() && valClsName.equals("java.lang.Long")) return true;
723       else if (fi.isFloatField() && valClsName.equals("java.lang.Float")) return true;
724       else if (fi.isDoubleField() && valClsName.equals("java.lang.Double")) return true;
725       else {
726         return ciVal.isInstanceOf(fi.getTypeClassInfo());
727       }
728     }
729   }
730   
731   protected static boolean setValue(MJIEnv env, FieldInfo fi, int obj, int value, Object attr) {
732     ClassInfo fieldClassInfo = fi.getClassInfo();
733     String className = fieldClassInfo.getName();
734     String fieldType = fi.getType();
735     ClassInfo tci = fi.getTypeClassInfo();
736     
737     ElementInfo ei = null;
738     if (fi.isStatic()) {
739       ei = fi.getClassInfo().getModifiableStaticElementInfo();
740     } else {
741       ei = env.getModifiableElementInfo(obj);
742     }
743
744     if (tci.isPrimitive()) {
745       if (value == MJIEnv.NULL) {
746         return false;
747       }
748
749       // checks whether unboxing can be done by accessing the field "value"
750       final String fieldName = "value";
751       FieldInfo finfo = env.getElementInfo(value).getFieldInfo(fieldName);
752       if (finfo == null) {
753         return false;
754       }
755       
756       ei.setFieldAttr(fi, attr);
757
758       if ("boolean".equals(fieldType)){
759         boolean val = env.getBooleanField(value, fieldName);
760         ei.setBooleanField(fi, val);
761         return true;
762       } else if ("byte".equals(fieldType)){
763         byte val = env.getByteField(value, fieldName);
764         ei.setByteField(fi, val);
765         return true;
766       } else if ("char".equals(fieldType)){
767         char val = env.getCharField(value, fieldName);
768         ei.setCharField(fi, val);
769         return true;
770       } else if ("short".equals(fieldType)){
771         short val = env.getShortField(value, fieldName);
772         ei.setShortField(fi, val);
773         return true;
774       } else if ("int".equals(fieldType)){
775         int val = env.getIntField(value, fieldName);
776         ei.setIntField(fi, val);
777         return true;
778       } else if ("long".equals(fieldType)){
779         long val = env.getLongField(value, fieldName);
780         ei.setLongField(fi, val);
781         return true;
782       } else if ("float".equals(fieldType)){
783         float val = env.getFloatField(value, fieldName);
784         ei.setFloatField(fi, val);
785         return true;
786       } else if ("double".equals(fieldType)){
787         double val = env.getDoubleField(value, fieldName);
788         ei.setDoubleField(fi, val);
789         return true;
790       } else {
791         return false;
792       }
793
794     } else { // it's a reference
795       if (value != MJIEnv.NULL) {
796         ClassInfo ciValue = env.getClassInfo(value);
797         if (!ciValue.isInstanceOf(tci)) {
798           return false;
799         }
800       }
801
802       ei.setFieldAttr(fi, attr);
803
804       if (fi.isStatic()) {
805         env.setStaticReferenceField(className, fi.getName(), value);
806       } else {
807         env.setReferenceField(obj, fi.getName(), value);
808       }
809       return true;
810     }
811   }
812
813   @MJI
814   public boolean equals__Ljava_lang_Object_2__Z (MJIEnv env, int objRef, int ownerRef){
815     int fidx = env.getIntField(ownerRef, "regIdx");
816     if (fidx >= 0 && fidx < nRegistered){
817       FieldInfo fi1 = getFieldInfo(env, objRef);
818       FieldInfo fi2 = getFieldInfo(env, ownerRef);
819       return ((fi1.getClassInfo() == fi2.getClassInfo()) && fi1.getName().equals(fi2.getName()) && fi1.getType().equals(fi2.getType()));
820     }
821     return false;
822   }
823
824   @MJI
825   public int toString____Ljava_lang_String_2 (MJIEnv env, int objRef){
826     StringBuilder sb = new StringBuilder();
827     FieldInfo fi = getFieldInfo(env, objRef);
828     sb.append(Modifier.toString(fi.getModifiers()));
829     sb.append(' ');
830     sb.append(fi.getType());
831     sb.append(' ');
832     sb.append(fi.getFullName());
833     int sref = env.newString(sb.toString());
834     return sref;
835   }
836
837   @MJI
838   public int hashCode____I (MJIEnv env, int objRef){
839     FieldInfo fi = getFieldInfo(env, objRef);
840     return fi.getClassInfo().getName().hashCode() ^ fi.getName().hashCode();
841   }
842
843   @MJI
844   public int getDeclaredAnnotations_____3Ljava_lang_annotation_Annotation_2 (MJIEnv env, int objRef){
845     return getAnnotations_____3Ljava_lang_annotation_Annotation_2(env, objRef);
846   }
847 }