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