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 reference?
159       */
160      public boolean isReferenceType() {
161        return reference;
162      }
163    
164      /**
165       * Shared among all instances of this class?
166       */
167      @Uninterruptible
168      public boolean isStatic() {
169        return (modifiers & ACC_STATIC) != 0;
170      }
171    
172      /**
173       * May only be assigned once?
174       */
175      @Uninterruptible
176      public boolean isFinal() {
177        return (modifiers & ACC_FINAL) != 0;
178      }
179    
180      /**
181       * Value not to be cached in a register?
182       */
183      @Uninterruptible
184      public boolean isVolatile() {
185        return (modifiers & ACC_VOLATILE) != 0;
186      }
187    
188      /**
189       * Value not to be written/read by persistent object manager?
190       */
191      @Uninterruptible
192      public boolean isTransient() {
193        return (modifiers & ACC_TRANSIENT) != 0;
194      }
195    
196      /**
197       * Not present in source code file?
198       */
199      public boolean isSynthetic() {
200        return (modifiers & ACC_SYNTHETIC) != 0;
201      }
202    
203      /**
204       * Enum constant
205       */
206      public boolean isEnumConstant() {
207        return (modifiers & ACC_ENUM) != 0;
208      }
209    
210      /**
211       * Is the field RuntimeFinal? That is can the annotation value be used in
212       * place a reading the field.
213       * @return whether the method has a pure annotation
214       */
215      public boolean isRuntimeFinal() {
216       return hasRuntimeFinalAnnotation();
217      }
218    
219      /**
220       * Is this field invisible to the memory management system.
221       */
222      public boolean isUntraced() {
223        return hasUntracedAnnotation();
224      }
225    
226      /**
227       * Make this field a traced field by garbage collection. Affects all
228       * subclasses of the class in which this field is defined.
229       */
230      public void makeTraced() {
231        madeTraced = true;
232        getDeclaringClass().makeFieldTraced(this);
233      }
234    
235      /**
236       * Get the value from the runtime final field
237       * @return whether the method has a pure annotation
238       */
239      public boolean getRuntimeFinalValue() {
240        org.vmmagic.pragma.RuntimeFinal ann;
241        if (VM.runningVM) {
242          ann = getAnnotation(org.vmmagic.pragma.RuntimeFinal.class);
243        } else {
244          try {
245          ann = getDeclaringClass().getClassForType().getField(getName().toString())
246          .getAnnotation(org.vmmagic.pragma.RuntimeFinal.class);
247          } catch (NoSuchFieldException e) {
248            throw new Error(e);
249          }
250        }
251        return ann.value();
252      }
253    
254      /**
255       * Get index of constant pool entry containing this
256       * "static final constant" field's value.
257       * @return constant pool index (0 --> field is not a "static final constant")
258       */
259      @Uninterruptible
260      int getConstantValueIndex() {
261        return constantValueIndex;
262      }
263    
264      //-------------------------------------------------------------------//
265      // Low level support for various reflective operations               //
266      // Because different clients have different error checking           //
267      // requirements, these operations are completely unsafe and we       //
268      // assume that the client has done the required error checking.      //
269      //-------------------------------------------------------------------//
270    
271      /**
272       * Read the contents of the field.
273       * If the contents of this field is an object, return that object.
274       * If the contents of this field is a primitive, get the value and wrap it in an object.
275       */
276      public Object getObjectUnchecked(Object obj) {
277        if (isReferenceType()) {
278          return getObjectValueUnchecked(obj);
279        } else {
280          TypeReference type = getType();
281          if (type.isCharType()) return getCharValueUnchecked(obj);
282          if (type.isDoubleType()) return getDoubleValueUnchecked(obj);
283          if (type.isFloatType()) return getFloatValueUnchecked(obj);
284          if (type.isLongType()) return getLongValueUnchecked(obj);
285          if (type.isIntType()) return getIntValueUnchecked(obj);
286          if (type.isShortType()) return getShortValueUnchecked(obj);
287          if (type.isByteType()) return getByteValueUnchecked(obj);
288          if (type.isBooleanType()) return getBooleanValueUnchecked(obj);
289          return null;
290        }
291      }
292    
293      /**
294       * Read one object ref from heap using RVM object model, GC safe.
295       * @param obj the object whose field is to be read,
296       * or null if the field is static.
297       * @return the reference described by this RVMField from the given object.
298       */
299      public Object getObjectValueUnchecked(Object obj) {
300        if (isStatic()) {
301          if (NEEDS_OBJECT_GETSTATIC_BARRIER && !isUntraced()) {
302            return Barriers.objectStaticRead(getOffset(), getId());
303          } else {
304            return Statics.getSlotContentsAsObject(getOffset());
305          }
306        } else {
307          if (NEEDS_OBJECT_GETFIELD_BARRIER && !isUntraced()) {
308            return Barriers.objectFieldRead(obj, getOffset(), getId());
309          } else {
310            return Magic.getObjectAtOffset(obj, getOffset());
311          }
312        }
313      }
314    
315      public Word getWordValueUnchecked(Object obj) {
316        if (isStatic()) {
317          return Statics.getSlotContentsAsAddress(getOffset()).toWord();
318        } else {
319          return Magic.getWordAtOffset(obj, getOffset());
320        }
321      }
322    
323      public Address getAddressValueUnchecked(Object obj) {
324        if (isStatic()) {
325          return Statics.getSlotContentsAsAddress(getOffset()).toWord().toAddress();
326        } else {
327          return Magic.getAddressAtOffset(obj, getOffset());
328        }
329      }
330    
331      public Offset getOffsetValueUnchecked(Object obj) {
332        if (isStatic()) {
333          return Statics.getSlotContentsAsAddress(getOffset()).toWord().toOffset();
334        } else {
335          return Magic.getOffsetAtOffset(obj, getOffset());
336        }
337      }
338    
339      public Extent getExtentValueUnchecked(Object obj) {
340        if (isStatic()) {
341          return Statics.getSlotContentsAsAddress(getOffset()).toWord().toExtent();
342        } else {
343          return Magic.getExtentAtOffset(obj, getOffset());
344        }
345      }
346    
347      public boolean getBooleanValueUnchecked(Object obj) {
348        byte bits;
349        if (isStatic()) {
350          bits = (byte) Statics.getSlotContentsAsInt(getOffset());
351        } else {
352          bits = Magic.getUnsignedByteAtOffset(obj, getOffset());
353        }
354        return (bits != 0);
355      }
356    
357      public byte getByteValueUnchecked(Object obj) {
358        if (isStatic()) {
359          return (byte) Statics.getSlotContentsAsInt(getOffset());
360        } else {
361          return Magic.getByteAtOffset(obj, getOffset());
362        }
363      }
364    
365      public char getCharValueUnchecked(Object obj) {
366        if (isStatic()) {
367          return (char) Statics.getSlotContentsAsInt(getOffset());
368        } else {
369          return Magic.getCharAtOffset(obj, getOffset());
370        }
371      }
372    
373      public short getShortValueUnchecked(Object obj) {
374        if (isStatic()) {
375          return (short) Statics.getSlotContentsAsInt(getOffset());
376        } else {
377          return Magic.getShortAtOffset(obj, getOffset());
378        }
379      }
380    
381      public int getIntValueUnchecked(Object obj) {
382        return get32Bits(obj);
383      }
384    
385      public long getLongValueUnchecked(Object obj) {
386        return get64Bits(obj);
387      }
388    
389      public float getFloatValueUnchecked(Object obj) {
390        return Magic.intBitsAsFloat(get32Bits(obj));
391      }
392    
393      public double getDoubleValueUnchecked(Object obj) {
394        return Magic.longBitsAsDouble(get64Bits(obj));
395      }
396    
397      private int get32Bits(Object obj) {
398        if (isStatic()) {
399          return Statics.getSlotContentsAsInt(getOffset());
400        } else {
401          return Magic.getIntAtOffset(obj, getOffset());
402        }
403      }
404    
405      private long get64Bits(Object obj) {
406        if (isStatic()) {
407          return Statics.getSlotContentsAsLong(getOffset());
408        } else {
409          return Magic.getLongAtOffset(obj, getOffset());
410        }
411      }
412    
413      /**
414       * assign one object ref from heap using RVM object model, GC safe.
415       * @param obj the object whose field is to be modified, or null if the field is static.
416       * @param ref the object reference to be assigned.
417       */
418      public void setObjectValueUnchecked(Object obj, Object ref) {
419        if (isStatic()) {
420          if (NEEDS_OBJECT_PUTSTATIC_BARRIER && !isUntraced()) {
421            Barriers.objectStaticWrite(ref, getOffset(), getId());
422          } else {
423            Statics.setSlotContents(getOffset(), ref);
424          }
425        } else {
426          if (NEEDS_OBJECT_PUTFIELD_BARRIER && !isUntraced()) {
427            Barriers.objectFieldWrite(obj, ref, getOffset(), getId());
428          } else {
429            Magic.setObjectAtOffset(obj, getOffset(), ref);
430          }
431        }
432      }
433    
434      /**
435       * assign one object ref from heap using RVM object model, GC safe.
436       * @param obj the object whose field is to be modified, or null if the field is static.
437       * @param ref the object reference to be assigned.
438       */
439      public void setWordValueUnchecked(Object obj, Word ref) {
440        if (isStatic()) {
441          Statics.setSlotContents(getOffset(), ref);
442        } else {
443          if (Barriers.NEEDS_WORD_PUTFIELD_BARRIER) {
444            Barriers.wordFieldWrite(obj, ref, getOffset(), getId());
445          } else {
446            Magic.setWordAtOffset(obj, getOffset(), ref);
447          }
448        }
449      }
450    
451      public void setAddressValueUnchecked(Object obj, Address ref) {
452        if (isStatic()) {
453          Statics.setSlotContents(getOffset(), ref);
454        } else {
455          if (Barriers.NEEDS_ADDRESS_PUTFIELD_BARRIER) {
456            Barriers.addressFieldWrite(obj, ref, getOffset(), getId());
457          } else {
458            Magic.setAddressAtOffset(obj, getOffset(), ref);
459          }
460        }
461      }
462    
463      public void setExtentValueUnchecked(Object obj, Extent ref) {
464        if (isStatic()) {
465          Statics.setSlotContents(getOffset(), ref);
466        } else {
467          if (Barriers.NEEDS_EXTENT_PUTFIELD_BARRIER) {
468            Barriers.extentFieldWrite(obj, ref, getOffset(), getId());
469          } else {
470            Magic.setExtentAtOffset(obj, getOffset(), ref);
471          }
472        }
473      }
474    
475      public void setOffsetValueUnchecked(Object obj, Offset ref) {
476        if (isStatic()) {
477          Statics.setSlotContents(getOffset(), ref);
478        } else {
479          if (Barriers.NEEDS_OFFSET_PUTFIELD_BARRIER) {
480            Barriers.offsetFieldWrite(obj, ref, getOffset(), getId());
481          } else {
482            Magic.setOffsetAtOffset(obj, getOffset(), ref);
483          }
484        }
485      }
486    
487      public void setBooleanValueUnchecked(Object obj, boolean b) {
488        if (isStatic()) {
489          Statics.setSlotContents(getOffset(), b ? 1 : 0);
490        } else {
491          if (Barriers.NEEDS_BOOLEAN_PUTFIELD_BARRIER) {
492            Barriers.booleanFieldWrite(obj, b, getOffset(), getId());
493          } else {
494            Magic.setBooleanAtOffset(obj, getOffset(), b);
495          }
496        }
497      }
498    
499      public void setByteValueUnchecked(Object obj, byte b) {
500        if (isStatic()) {
501          Statics.setSlotContents(getOffset(), b);
502        } else {
503          if (Barriers.NEEDS_BYTE_PUTFIELD_BARRIER) {
504            Barriers.byteFieldWrite(obj, b, getOffset(), getId());
505          } else {
506            Magic.setByteAtOffset(obj, getOffset(), b);
507          }
508        }
509      }
510    
511      public void setCharValueUnchecked(Object obj, char c) {
512        if (isStatic()) {
513          Statics.setSlotContents(getOffset(), c);
514        } else {
515          if (Barriers.NEEDS_CHAR_PUTFIELD_BARRIER) {
516            Barriers.charFieldWrite(obj, c, getOffset(), getId());
517          } else {
518            Magic.setCharAtOffset(obj, getOffset(), c);
519          }
520        }
521      }
522    
523      public void setShortValueUnchecked(Object obj, short i) {
524        if (isStatic()) {
525          Statics.setSlotContents(getOffset(), i);
526        } else {
527          if (Barriers.NEEDS_SHORT_PUTFIELD_BARRIER) {
528            Barriers.shortFieldWrite(obj, i, getOffset(), getId());
529          } else {
530            Magic.setShortAtOffset(obj, getOffset(), i);
531          }
532        }
533      }
534    
535      public void setIntValueUnchecked(Object obj, int i) {
536        if (isStatic()) {
537          Statics.setSlotContents(getOffset(), i);
538        } else {
539          if (Barriers.NEEDS_INT_PUTFIELD_BARRIER) {
540            Barriers.intFieldWrite(obj, i, getOffset(), getId());
541          } else {
542            Magic.setIntAtOffset(obj, getOffset(), i);
543          }
544        }
545      }
546    
547      public void setFloatValueUnchecked(Object obj, float f) {
548        if (isStatic()) {
549          Statics.setSlotContents(getOffset(), f);
550        } else {
551          if (Barriers.NEEDS_FLOAT_PUTFIELD_BARRIER) {
552            Barriers.floatFieldWrite(obj, f, getOffset(), getId());
553          } else {
554            Magic.setFloatAtOffset(obj, getOffset(), f);
555          }
556        }
557      }
558    
559      public void setLongValueUnchecked(Object obj, long l) {
560        if (isStatic()) {
561          Statics.setSlotContents(getOffset(), l);
562        } else {
563          if (Barriers.NEEDS_LONG_PUTFIELD_BARRIER) {
564            Barriers.longFieldWrite(obj, l, getOffset(), getId());
565          } else {
566            Magic.setLongAtOffset(obj, getOffset(), l);
567          }
568        }
569      }
570    
571      public void setDoubleValueUnchecked(Object obj, double d) {
572        if (isStatic()) {
573          Statics.setSlotContents(getOffset(), d);
574        } else {
575          if (Barriers.NEEDS_DOUBLE_PUTFIELD_BARRIER) {
576            Barriers.doubleFieldWrite(obj, d, getOffset(), getId());
577          } else {
578            Magic.setDoubleAtOffset(obj, getOffset(), d);
579          }
580        }
581      }
582    }