001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.classloader;
014    
015    import java.io.DataInputStream;
016    import java.io.IOException;
017    import org.jikesrvm.VM;
018    import org.jikesrvm.mm.mminterface.Barriers;
019    import org.jikesrvm.runtime.Magic;
020    import org.jikesrvm.runtime.Statics;
021    import org.vmmagic.pragma.Uninterruptible;
022    import org.vmmagic.unboxed.Address;
023    import org.vmmagic.unboxed.Extent;
024    import org.vmmagic.unboxed.Offset;
025    import org.vmmagic.unboxed.Word;
026    import static org.jikesrvm.mm.mminterface.Barriers.*;
027    
028    /**
029     * A field of a java class.
030     */
031    public final class RVMField extends RVMMember {
032    
033      /**
034       * constant pool index of field's value (0 --> not a "static final constant")
035       */
036      private final int constantValueIndex;
037    
038      /**
039       * The size of the field in bytes
040       */
041      private final byte size;
042    
043      /**
044       * Does the field hold a reference value?
045       */
046      private final boolean reference;
047    
048      /**
049       * Has the field been made traced?
050       */
051      private boolean madeTraced;
052    
053      /**
054       * Create a field.
055       *
056       * @param declaringClass the TypeReference object of the class
057       * that declared this field
058       * @param memRef the canonical memberReference for this member.
059       * @param modifiers modifiers associated with this field.
060       * @param signature generic type of this field.
061       * @param constantValueIndex constant pool index of constant value
062       * @param annotations array of runtime visible annotations
063       */
064      private RVMField(TypeReference declaringClass, MemberReference memRef, short modifiers, Atom signature,
065                       int constantValueIndex, RVMAnnotation[] annotations) {
066        super(declaringClass, memRef, modifiers, signature, annotations);
067        this.constantValueIndex = constantValueIndex;
068        TypeReference typeRef = memRef.asFieldReference().getFieldContentsType();
069        this.size = (byte)typeRef.getMemoryBytes();
070        this.reference = typeRef.isReferenceType();
071        this.madeTraced = false;
072        if (VM.runningVM && isUntraced()) {
073          VM.sysFail("Untraced field " + toString() + " created at runtime!");
074        }
075      }
076    
077      /**
078       * Read and create a field. NB only {@link RVMClass} is allowed to
079       * create an instance of a RVMField.
080       *
081       * @param declaringClass the TypeReference object of the class
082       * that declared this field
083       * @param constantPool the constant pool of the class loading this field
084       * @param memRef the canonical memberReference for this member.
085       * @param modifiers modifiers associated with this member.
086       * @param input the DataInputStream to read the field's attributed from
087       */
088      static RVMField readField(TypeReference declaringClass, int[] constantPool, MemberReference memRef,
089                                short modifiers, DataInputStream input) throws IOException {
090        // Read the attributes, processing the "non-boring" ones
091        int cvi = 0;
092        Atom signature = null;
093        RVMAnnotation[] annotations = null;
094        for (int i = 0, n = input.readUnsignedShort(); i < n; ++i) {
095          Atom attName = ClassFileReader.getUtf(constantPool, input.readUnsignedShort());
096          int attLength = input.readInt();
097          if (attName == RVMClassLoader.constantValueAttributeName) {
098            cvi = input.readUnsignedShort();
099          } else if (attName == RVMClassLoader.syntheticAttributeName) {
100            modifiers |= ACC_SYNTHETIC;
101          } else if (attName == RVMClassLoader.signatureAttributeName) {
102            signature = ClassFileReader.getUtf(constantPool, input.readUnsignedShort());
103          } else if (attName == RVMClassLoader.runtimeVisibleAnnotationsAttributeName) {
104            annotations = AnnotatedElement.readAnnotations(constantPool, input, declaringClass.getClassLoader());
105          } else {
106            // all other attributes are boring...
107            int skippedAmount = input.skipBytes(attLength);
108            if (skippedAmount != attLength) {
109              throw new IOException("Unexpected short skip");
110            }
111          }
112        }
113        return new RVMField(declaringClass,
114                            memRef,
115                            (short) (modifiers & APPLICABLE_TO_FIELDS),
116                            signature,
117                            cvi,
118                            annotations);
119      }
120    
121      /**
122       * Create a field for a synthetic annotation class
123       */
124      static RVMField createAnnotationField(TypeReference annotationClass, MemberReference memRef) {
125        return new RVMField(annotationClass, memRef, (short) (ACC_PRIVATE | ACC_SYNTHETIC), null, 0, null);
126      }
127    
128      /**
129       * Get type of this field's value.
130       */
131      @Uninterruptible
132      public TypeReference getType() {
133        return memRef.asFieldReference().getFieldContentsType();
134      }
135    
136      /**
137       * How many stackslots do value of this type take?
138       */
139      public int getNumberOfStackSlots() {
140        return getType().getStackWords();
141      }
142    
143      /**
144       * How many bytes of memory words do value of this type take?
145       */
146      public int getSize() {
147        return size;
148      }
149    
150      /**
151       * Does the field hold a reference?
152       */
153      public boolean isTraced() {
154        return (reference && !isUntraced()) || madeTraced;
155      }
156    
157      /**
158       * Does the field hold a made-traced reference?
159       */
160      @Uninterruptible
161      public boolean madeTraced() {
162        return madeTraced;
163      }
164    
165    
166      /**
167       * Does the field hold a reference?
168       */
169      public boolean isReferenceType() {
170        return reference;
171      }
172    
173      /**
174       * Shared among all instances of this class?
175       */
176      @Uninterruptible
177      public boolean isStatic() {
178        return (modifiers & ACC_STATIC) != 0;
179      }
180    
181      /**
182       * May only be assigned once?
183       */
184      @Uninterruptible
185      public boolean isFinal() {
186        return (modifiers & ACC_FINAL) != 0;
187      }
188    
189      /**
190       * Value not to be cached in a register?
191       */
192      @Uninterruptible
193      public boolean isVolatile() {
194        return (modifiers & ACC_VOLATILE) != 0;
195      }
196    
197      /**
198       * Value not to be written/read by persistent object manager?
199       */
200      @Uninterruptible
201      public boolean isTransient() {
202        return (modifiers & ACC_TRANSIENT) != 0;
203      }
204    
205      /**
206       * Not present in source code file?
207       */
208      public boolean isSynthetic() {
209        return (modifiers & ACC_SYNTHETIC) != 0;
210      }
211    
212      /**
213       * Enum constant
214       */
215      public boolean isEnumConstant() {
216        return (modifiers & ACC_ENUM) != 0;
217      }
218    
219      /**
220       * Is the field RuntimeFinal? That is can the annotation value be used in
221       * place a reading the field.
222       * @return whether the method has a pure annotation
223       */
224      public boolean isRuntimeFinal() {
225       return hasRuntimeFinalAnnotation();
226      }
227    
228      /**
229       * Is this field invisible to the memory management system.
230       */
231      public boolean isUntraced() {
232        return hasUntracedAnnotation();
233      }
234    
235      /**
236       * Make this field a traced field by garbage collection. Affects all
237       * subclasses of the class in which this field is defined.
238       */
239      public void makeTraced() {
240        madeTraced = true;
241        getDeclaringClass().makeFieldTraced(this);
242      }
243    
244      /**
245       * Get the value from the runtime final field
246       * @return whether the method has a pure annotation
247       */
248      public boolean getRuntimeFinalValue() {
249        org.vmmagic.pragma.RuntimeFinal ann;
250        if (VM.runningVM) {
251          ann = getAnnotation(org.vmmagic.pragma.RuntimeFinal.class);
252        } else {
253          try {
254          ann = getDeclaringClass().getClassForType().getField(getName().toString())
255          .getAnnotation(org.vmmagic.pragma.RuntimeFinal.class);
256          } catch (NoSuchFieldException e) {
257            throw new Error(e);
258          }
259        }
260        return ann.value();
261      }
262    
263      /**
264       * Get index of constant pool entry containing this
265       * "static final constant" field's value.
266       * @return constant pool index (0 --> field is not a "static final constant")
267       */
268      @Uninterruptible
269      int getConstantValueIndex() {
270        return constantValueIndex;
271      }
272    
273      //-------------------------------------------------------------------//
274      // Low level support for various reflective operations               //
275      // Because different clients have different error checking           //
276      // requirements, these operations are completely unsafe and we       //
277      // assume that the client has done the required error checking.      //
278      //-------------------------------------------------------------------//
279    
280      /**
281       * Read the contents of the field.
282       * If the contents of this field is an object, return that object.
283       * If the contents of this field is a primitive, get the value and wrap it in an object.
284       */
285      public Object getObjectUnchecked(Object obj) {
286        if (isReferenceType()) {
287          return getObjectValueUnchecked(obj);
288        } else {
289          TypeReference type = getType();
290          if (type.isCharType()) return getCharValueUnchecked(obj);
291          if (type.isDoubleType()) return getDoubleValueUnchecked(obj);
292          if (type.isFloatType()) return getFloatValueUnchecked(obj);
293          if (type.isLongType()) return getLongValueUnchecked(obj);
294          if (type.isIntType()) return getIntValueUnchecked(obj);
295          if (type.isShortType()) return getShortValueUnchecked(obj);
296          if (type.isByteType()) return getByteValueUnchecked(obj);
297          if (type.isBooleanType()) return getBooleanValueUnchecked(obj);
298          return null;
299        }
300      }
301    
302      /**
303       * Read one object ref from heap using RVM object model, GC safe.
304       * @param obj the object whose field is to be read,
305       * or null if the field is static.
306       * @return the reference described by this RVMField from the given object.
307       */
308      public Object getObjectValueUnchecked(Object obj) {
309        if (isStatic()) {
310          if (NEEDS_OBJECT_GETSTATIC_BARRIER && !isUntraced()) {
311            return Barriers.objectStaticRead(getOffset(), getId());
312          } else {
313            return Statics.getSlotContentsAsObject(getOffset());
314          }
315        } else {
316          if (NEEDS_OBJECT_GETFIELD_BARRIER && !isUntraced()) {
317            return Barriers.objectFieldRead(obj, getOffset(), getId());
318          } else {
319            return Magic.getObjectAtOffset(obj, getOffset());
320          }
321        }
322      }
323    
324      public Word getWordValueUnchecked(Object obj) {
325        if (isStatic()) {
326          return Statics.getSlotContentsAsAddress(getOffset()).toWord();
327        } else {
328          return Magic.getWordAtOffset(obj, getOffset());
329        }
330      }
331    
332      public Address getAddressValueUnchecked(Object obj) {
333        if (isStatic()) {
334          return Statics.getSlotContentsAsAddress(getOffset()).toWord().toAddress();
335        } else {
336          return Magic.getAddressAtOffset(obj, getOffset());
337        }
338      }
339    
340      public Offset getOffsetValueUnchecked(Object obj) {
341        if (isStatic()) {
342          return Statics.getSlotContentsAsAddress(getOffset()).toWord().toOffset();
343        } else {
344          return Magic.getOffsetAtOffset(obj, getOffset());
345        }
346      }
347    
348      public Extent getExtentValueUnchecked(Object obj) {
349        if (isStatic()) {
350          return Statics.getSlotContentsAsAddress(getOffset()).toWord().toExtent();
351        } else {
352          return Magic.getExtentAtOffset(obj, getOffset());
353        }
354      }
355    
356      public boolean getBooleanValueUnchecked(Object obj) {
357        byte bits;
358        if (isStatic()) {
359          bits = (byte) Statics.getSlotContentsAsInt(getOffset());
360        } else {
361          bits = Magic.getUnsignedByteAtOffset(obj, getOffset());
362        }
363        return (bits != 0);
364      }
365    
366      public byte getByteValueUnchecked(Object obj) {
367        if (isStatic()) {
368          return (byte) Statics.getSlotContentsAsInt(getOffset());
369        } else {
370          return Magic.getByteAtOffset(obj, getOffset());
371        }
372      }
373    
374      public char getCharValueUnchecked(Object obj) {
375        if (isStatic()) {
376          return (char) Statics.getSlotContentsAsInt(getOffset());
377        } else {
378          return Magic.getCharAtOffset(obj, getOffset());
379        }
380      }
381    
382      public short getShortValueUnchecked(Object obj) {
383        if (isStatic()) {
384          return (short) Statics.getSlotContentsAsInt(getOffset());
385        } else {
386          return Magic.getShortAtOffset(obj, getOffset());
387        }
388      }
389    
390      public int getIntValueUnchecked(Object obj) {
391        return get32Bits(obj);
392      }
393    
394      public long getLongValueUnchecked(Object obj) {
395        return get64Bits(obj);
396      }
397    
398      public float getFloatValueUnchecked(Object obj) {
399        return Magic.intBitsAsFloat(get32Bits(obj));
400      }
401    
402      public double getDoubleValueUnchecked(Object obj) {
403        return Magic.longBitsAsDouble(get64Bits(obj));
404      }
405    
406      private int get32Bits(Object obj) {
407        if (isStatic()) {
408          return Statics.getSlotContentsAsInt(getOffset());
409        } else {
410          return Magic.getIntAtOffset(obj, getOffset());
411        }
412      }
413    
414      private long get64Bits(Object obj) {
415        if (isStatic()) {
416          return Statics.getSlotContentsAsLong(getOffset());
417        } else {
418          return Magic.getLongAtOffset(obj, getOffset());
419        }
420      }
421    
422      /**
423       * assign one object ref from heap using RVM object model, GC safe.
424       * @param obj the object whose field is to be modified, or null if the field is static.
425       * @param ref the object reference to be assigned.
426       */
427      public void setObjectValueUnchecked(Object obj, Object ref) {
428        if (isStatic()) {
429          if (NEEDS_OBJECT_PUTSTATIC_BARRIER && !isUntraced()) {
430            Barriers.objectStaticWrite(ref, getOffset(), getId());
431          } else {
432            Statics.setSlotContents(getOffset(), ref);
433          }
434        } else {
435          if (NEEDS_OBJECT_PUTFIELD_BARRIER && !isUntraced()) {
436            Barriers.objectFieldWrite(obj, ref, getOffset(), getId());
437          } else {
438            Magic.setObjectAtOffset(obj, getOffset(), ref);
439          }
440        }
441      }
442    
443      /**
444       * assign one object ref from heap using RVM object model, GC safe.
445       * @param obj the object whose field is to be modified, or null if the field is static.
446       * @param ref the object reference to be assigned.
447       */
448      public void setWordValueUnchecked(Object obj, Word ref) {
449        if (isStatic()) {
450          Statics.setSlotContents(getOffset(), ref);
451        } else {
452          if (Barriers.NEEDS_WORD_PUTFIELD_BARRIER) {
453            Barriers.wordFieldWrite(obj, ref, getOffset(), getId());
454          } else {
455            Magic.setWordAtOffset(obj, getOffset(), ref);
456          }
457        }
458      }
459    
460      public void setAddressValueUnchecked(Object obj, Address ref) {
461        if (isStatic()) {
462          Statics.setSlotContents(getOffset(), ref);
463        } else {
464          if (Barriers.NEEDS_ADDRESS_PUTFIELD_BARRIER) {
465            Barriers.addressFieldWrite(obj, ref, getOffset(), getId());
466          } else {
467            Magic.setAddressAtOffset(obj, getOffset(), ref);
468          }
469        }
470      }
471    
472      public void setExtentValueUnchecked(Object obj, Extent ref) {
473        if (isStatic()) {
474          Statics.setSlotContents(getOffset(), ref);
475        } else {
476          if (Barriers.NEEDS_EXTENT_PUTFIELD_BARRIER) {
477            Barriers.extentFieldWrite(obj, ref, getOffset(), getId());
478          } else {
479            Magic.setExtentAtOffset(obj, getOffset(), ref);
480          }
481        }
482      }
483    
484      public void setOffsetValueUnchecked(Object obj, Offset ref) {
485        if (isStatic()) {
486          Statics.setSlotContents(getOffset(), ref);
487        } else {
488          if (Barriers.NEEDS_OFFSET_PUTFIELD_BARRIER) {
489            Barriers.offsetFieldWrite(obj, ref, getOffset(), getId());
490          } else {
491            Magic.setOffsetAtOffset(obj, getOffset(), ref);
492          }
493        }
494      }
495    
496      public void setBooleanValueUnchecked(Object obj, boolean b) {
497        if (isStatic()) {
498          Statics.setSlotContents(getOffset(), b ? 1 : 0);
499        } else {
500          if (Barriers.NEEDS_BOOLEAN_PUTFIELD_BARRIER) {
501            Barriers.booleanFieldWrite(obj, b, getOffset(), getId());
502          } else {
503            Magic.setBooleanAtOffset(obj, getOffset(), b);
504          }
505        }
506      }
507    
508      public void setByteValueUnchecked(Object obj, byte b) {
509        if (isStatic()) {
510          Statics.setSlotContents(getOffset(), b);
511        } else {
512          if (Barriers.NEEDS_BYTE_PUTFIELD_BARRIER) {
513            Barriers.byteFieldWrite(obj, b, getOffset(), getId());
514          } else {
515            Magic.setByteAtOffset(obj, getOffset(), b);
516          }
517        }
518      }
519    
520      public void setCharValueUnchecked(Object obj, char c) {
521        if (isStatic()) {
522          Statics.setSlotContents(getOffset(), c);
523        } else {
524          if (Barriers.NEEDS_CHAR_PUTFIELD_BARRIER) {
525            Barriers.charFieldWrite(obj, c, getOffset(), getId());
526          } else {
527            Magic.setCharAtOffset(obj, getOffset(), c);
528          }
529        }
530      }
531    
532      public void setShortValueUnchecked(Object obj, short i) {
533        if (isStatic()) {
534          Statics.setSlotContents(getOffset(), i);
535        } else {
536          if (Barriers.NEEDS_SHORT_PUTFIELD_BARRIER) {
537            Barriers.shortFieldWrite(obj, i, getOffset(), getId());
538          } else {
539            Magic.setShortAtOffset(obj, getOffset(), i);
540          }
541        }
542      }
543    
544      public void setIntValueUnchecked(Object obj, int i) {
545        if (isStatic()) {
546          Statics.setSlotContents(getOffset(), i);
547        } else {
548          if (Barriers.NEEDS_INT_PUTFIELD_BARRIER) {
549            Barriers.intFieldWrite(obj, i, getOffset(), getId());
550          } else {
551            Magic.setIntAtOffset(obj, getOffset(), i);
552          }
553        }
554      }
555    
556      public void setFloatValueUnchecked(Object obj, float f) {
557        if (isStatic()) {
558          Statics.setSlotContents(getOffset(), f);
559        } else {
560          if (Barriers.NEEDS_FLOAT_PUTFIELD_BARRIER) {
561            Barriers.floatFieldWrite(obj, f, getOffset(), getId());
562          } else {
563            Magic.setFloatAtOffset(obj, getOffset(), f);
564          }
565        }
566      }
567    
568      public void setLongValueUnchecked(Object obj, long l) {
569        if (isStatic()) {
570          Statics.setSlotContents(getOffset(), l);
571        } else {
572          if (Barriers.NEEDS_LONG_PUTFIELD_BARRIER) {
573            Barriers.longFieldWrite(obj, l, getOffset(), getId());
574          } else {
575            Magic.setLongAtOffset(obj, getOffset(), l);
576          }
577        }
578      }
579    
580      public void setDoubleValueUnchecked(Object obj, double d) {
581        if (isStatic()) {
582          Statics.setSlotContents(getOffset(), d);
583        } else {
584          if (Barriers.NEEDS_DOUBLE_PUTFIELD_BARRIER) {
585            Barriers.doubleFieldWrite(obj, d, getOffset(), getId());
586          } else {
587            Magic.setDoubleAtOffset(obj, getOffset(), d);
588          }
589        }
590      }
591    }