/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.classloader; import java.io.DataInputStream; import java.io.IOException; import org.jikesrvm.VM; import org.jikesrvm.memorymanagers.mminterface.MM_Constants; import org.jikesrvm.memorymanagers.mminterface.MM_Interface; import org.jikesrvm.runtime.VM_Magic; import org.jikesrvm.runtime.VM_Statics; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Word; /** * A field of a java class. */ public final class VM_Field extends VM_Member { /** * constant pool index of field's value (0 --> not a "static final constant") */ private final int constantValueIndex; /** * Create a field. * * @param declaringClass the VM_TypeReference object of the class * that declared this field * @param memRef the canonical memberReference for this member. * @param modifiers modifiers associated with this field. * @param signature generic type of this field. * @param constantValueIndex constant pool index of constant value * @param annotations array of runtime visible annotations */ private VM_Field(VM_TypeReference declaringClass, VM_MemberReference memRef, short modifiers, short annoModifiers, VM_Atom signature, int constantValueIndex, VM_Annotation[] annotations) { super(declaringClass, memRef, modifiers, annoModifiers, signature, annotations); this.constantValueIndex = constantValueIndex; } /** * Read and create a field. NB only {@link VM_Class} is allowed to * create an instance of a VM_Field. * * @param declaringClass the VM_TypeReference object of the class * that declared this field * @param constantPool the constant pool of the class loading this field * @param memRef the canonical memberReference for this member. * @param modifiers modifiers associated with this member. * @param input the DataInputStream to read the field's attributed from */ static VM_Field readField(VM_TypeReference declaringClass, int[] constantPool, VM_MemberReference memRef, short modifiers, DataInputStream input) throws IOException { // Read the attributes, processing the "non-boring" ones int cvi = 0; VM_Atom signature = null; VM_Annotation[] annotations = null; for (int i = 0, n = input.readUnsignedShort(); i < n; ++i) { VM_Atom attName = VM_Class.getUtf(constantPool, input.readUnsignedShort()); int attLength = input.readInt(); if (attName == VM_ClassLoader.constantValueAttributeName) { cvi = input.readUnsignedShort(); } else if (attName == VM_ClassLoader.syntheticAttributeName) { modifiers |= ACC_SYNTHETIC; } else if (attName == VM_ClassLoader.signatureAttributeName) { signature = VM_Class.getUtf(constantPool, input.readUnsignedShort()); } else if (attName == VM_ClassLoader.runtimeVisibleAnnotationsAttributeName) { annotations = VM_AnnotatedElement.readAnnotations(constantPool, input, 2, declaringClass.getClassLoader()); } else { // all other attributes are boring... input.skipBytes(attLength); } } short annoModifiers = createAnnoModifer (annotations); return new VM_Field(declaringClass, memRef, (short) (modifiers & APPLICABLE_TO_FIELDS), annoModifiers, signature, cvi, annotations); } /** * Create a field for a synthetic annotation class */ static VM_Field createAnnotationField(VM_TypeReference annotationClass, VM_MemberReference memRef) { return new VM_Field(annotationClass, memRef, (short) (ACC_PRIVATE | ACC_SYNTHETIC), (short)0, null, 0, null); } /** * Get type of this field's value. */ @Uninterruptible public VM_TypeReference getType() { return memRef.asFieldReference().getFieldContentsType(); } /** * How many stackslots do value of this type take? */ public int getNumberOfStackSlots() { return getType().getStackWords(); } /** * How many bytes of memory words do value of this type take? */ public int getSize() { return getType().getMemoryBytes(); } /** * Shared among all instances of this class? */ @Uninterruptible public boolean isStatic() { return (modifiers & ACC_STATIC) != 0; } /** * May only be assigned once? */ @Uninterruptible public boolean isFinal() { return (modifiers & ACC_FINAL) != 0; } /** * Value not to be cached in a register? */ @Uninterruptible public boolean isVolatile() { return (modifiers & ACC_VOLATILE) != 0; } /** * Value not to be written/read by persistent object manager? */ @Uninterruptible public boolean isTransient() { return (modifiers & ACC_TRANSIENT) != 0; } /** * Not present in source code file? */ public boolean isSynthetic() { return (modifiers & ACC_SYNTHETIC) != 0; } /** * Enum constant */ public boolean isEnumConstant() { return (modifiers & ACC_ENUM) != 0; } /** * Is the field RuntimeFinal? That is can the annotation value be used in * place a reading the field. * @return whether the method has a pure annotation */ public boolean isRuntimeFinal() { return hasRuntimeFinalAnnotation(); } /** * Get the value from the runtime final field * @return whether the method has a pure annotation */ public boolean getRuntimeFinalValue() { org.vmmagic.pragma.RuntimeFinal ann; if (VM.runningVM) { ann = getAnnotation(org.vmmagic.pragma.RuntimeFinal.class); } else { try { ann = getDeclaringClass().getClassForType().getField(getName().toString()) .getAnnotation(org.vmmagic.pragma.RuntimeFinal.class); } catch (NoSuchFieldException e) { throw new Error(e); } } return ann.value(); } /** * Get index of constant pool entry containing this * "static final constant" field's value. * @return constant pool index (0 --> field is not a "static final constant") */ @Uninterruptible public int getConstantValueIndex() { return constantValueIndex; } //-------------------------------------------------------------------// // Low level support for various reflective operations // // Because different clients have different error checking // // requirements, these operations are completely unsafe and we // // assume that the client has done the required error checking. // //-------------------------------------------------------------------// /** * Read the contents of the field. * If the contents of this field is an object, return that object. * If the contents of this field is a primitive, get the value and wrap it in an object. */ public Object getObjectUnchecked(Object obj) { VM_TypeReference type = getType(); if (type.isReferenceType()) { return getObjectValueUnchecked(obj); } else { if (type.isCharType()) return getCharValueUnchecked(obj); if (type.isDoubleType()) return getDoubleValueUnchecked(obj); if (type.isFloatType()) return getFloatValueUnchecked(obj); if (type.isLongType()) return getLongValueUnchecked(obj); if (type.isIntType()) return getIntValueUnchecked(obj); if (type.isShortType()) return getShortValueUnchecked(obj); if (type.isByteType()) return getByteValueUnchecked(obj); if (type.isBooleanType()) return getBooleanValueUnchecked(obj); return null; } } /** * Read one object ref from heap using RVM object model, GC safe. * @param obj the object whose field is to be read, * or null if the field is static. * @return the reference described by this VM_Field from the given object. */ public Object getObjectValueUnchecked(Object obj) { if (isStatic()) { return VM_Statics.getSlotContentsAsObject(getOffset()); } else { return VM_Magic.getObjectAtOffset(obj, getOffset()); } } public Word getWordValueUnchecked(Object obj) { if (isStatic()) { return VM_Statics.getSlotContentsAsAddress(getOffset()).toWord(); } else { return VM_Magic.getWordAtOffset(obj, getOffset()); } } public boolean getBooleanValueUnchecked(Object obj) { byte bits; if (isStatic()) { bits = (byte) VM_Statics.getSlotContentsAsInt(getOffset()); } else { bits = VM_Magic.getUnsignedByteAtOffset(obj, getOffset()); } return (bits != 0); } public byte getByteValueUnchecked(Object obj) { if (isStatic()) { return (byte) VM_Statics.getSlotContentsAsInt(getOffset()); } else { return VM_Magic.getByteAtOffset(obj, getOffset()); } } public char getCharValueUnchecked(Object obj) { if (isStatic()) { return (char) VM_Statics.getSlotContentsAsInt(getOffset()); } else { return VM_Magic.getCharAtOffset(obj, getOffset()); } } public short getShortValueUnchecked(Object obj) { if (isStatic()) { return (short) VM_Statics.getSlotContentsAsInt(getOffset()); } else { return VM_Magic.getShortAtOffset(obj, getOffset()); } } public int getIntValueUnchecked(Object obj) { return get32Bits(obj); } public long getLongValueUnchecked(Object obj) { return get64Bits(obj); } public float getFloatValueUnchecked(Object obj) { return VM_Magic.intBitsAsFloat(get32Bits(obj)); } public double getDoubleValueUnchecked(Object obj) { return VM_Magic.longBitsAsDouble(get64Bits(obj)); } private int get32Bits(Object obj) { if (isStatic()) { return VM_Statics.getSlotContentsAsInt(getOffset()); } else { return VM_Magic.getIntAtOffset(obj, getOffset()); } } private long get64Bits(Object obj) { if (isStatic()) { return VM_Statics.getSlotContentsAsLong(getOffset()); } else { return VM_Magic.getLongAtOffset(obj, getOffset()); } } /** * assign one object ref from heap using RVM object model, GC safe. * @param obj the object whose field is to be modified, or null if the field is static. * @param ref the object reference to be assigned. */ public void setObjectValueUnchecked(Object obj, Object ref) { if (isStatic()) { if (MM_Constants.NEEDS_PUTSTATIC_WRITE_BARRIER) { MM_Interface.putstaticWriteBarrier(getOffset(), ref, getId()); } else { VM_Statics.setSlotContents(getOffset(), ref); } } else { if (MM_Constants.NEEDS_WRITE_BARRIER) { MM_Interface.putfieldWriteBarrier(obj, getOffset(), ref, getId()); } else { VM_Magic.setObjectAtOffset(obj, getOffset(), ref); } } } /** * assign one object ref from heap using RVM object model, GC safe. * @param obj the object whose field is to be modified, or null if the field is static. * @param ref the object reference to be assigned. */ public void setWordValueUnchecked(Object obj, Word ref) { if (isStatic()) { VM_Statics.setSlotContents(getOffset(), ref); } else { VM_Magic.setWordAtOffset(obj, getOffset(), ref); } } public void setBooleanValueUnchecked(Object obj, boolean b) { if (isStatic()) { VM_Statics.setSlotContents(getOffset(), b ? 1 : 0); } else { VM_Magic.setByteAtOffset(obj, getOffset(), b ? (byte) 1 : (byte) 0); } } public void setByteValueUnchecked(Object obj, byte b) { if (isStatic()) { VM_Statics.setSlotContents(getOffset(), b); } else { VM_Magic.setByteAtOffset(obj, getOffset(), b); } } public void setCharValueUnchecked(Object obj, char c) { if (isStatic()) { VM_Statics.setSlotContents(getOffset(), c); } else { VM_Magic.setCharAtOffset(obj, getOffset(), c); } } public void setShortValueUnchecked(Object obj, short i) { if (isStatic()) { VM_Statics.setSlotContents(getOffset(), i); } else { VM_Magic.setCharAtOffset(obj, getOffset(), (char) i); } } public void setIntValueUnchecked(Object obj, int i) { put32(obj, i); } public void setFloatValueUnchecked(Object obj, float f) { put32(obj, VM_Magic.floatAsIntBits(f)); } public void setLongValueUnchecked(Object obj, long l) { put64(obj, l); } public void setDoubleValueUnchecked(Object obj, double d) { put64(obj, VM_Magic.doubleAsLongBits(d)); } private void put32(Object obj, int value) { if (isStatic()) { VM_Statics.setSlotContents(getOffset(), value); } else { VM_Magic.setIntAtOffset(obj, getOffset(), value); } } private void put64(Object obj, long value) { if (isStatic()) { VM_Statics.setSlotContents(getOffset(), value); } else { VM_Magic.setLongAtOffset(obj, getOffset(), value); } } }