1 /*
  2  * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 package sun.jvm.hotspot.oops;
 26 
 27 import java.io.*;
 28 
 29 import sun.jvm.hotspot.code.CompressedReadStream;
 30 import sun.jvm.hotspot.runtime.*;
 31 import sun.jvm.hotspot.utilities.*;
 32 
 33 // Super class for all fields in an object
 34 public class Field {
 35 
 36   Field(FieldIdentifier id, long offset, boolean isVMField) {
 37     this.offset    = offset;
 38     this.id        = id;
 39     this.isVMField = isVMField;
 40   }
 41 
 42   /** Constructor for fields that are named in an InstanceKlass's
 43       fields array (i.e., named, non-VM fields) */
 44   private Field(InstanceKlass holder, int fieldIndex, FieldInfoValues values) {
 45     this.holder = holder;
 46     this.fieldIndex = fieldIndex;
 47     this.values = values;
 48     offset = values.offset;
 49 
 50     name = holder.getSymbolFromIndex(values.nameIndex, isInjected());
 51     signature = holder.getSymbolFromIndex(values.signatureIndex, isInjected());
 52     id          = new NamedFieldIdentifier(name.asString());
 53     fieldType   = new FieldType(signature);
 54     accessFlags = new AccessFlags(values.accessFlags);
 55 
 56     if (isGeneric()) {
 57       genericSignature = holder.getSymbolFromIndex(values.genericSignatureIndex, isInjected());
 58     }
 59   }
 60 
 61   /** Constructor for cloning an existing Field object */
 62   Field(InstanceKlass holder, int fieldIndex) {
 63       this(holder, fieldIndex, holder.getField(fieldIndex).values);
 64   }
 65 
 66 
 67   static class FieldInfoValues {
 68     int nameIndex;
 69     int signatureIndex;
 70     int offset;
 71     int accessFlags;
 72     int fieldFlags;
 73     int initialValueIndex;
 74     int genericSignatureIndex;
 75     int contendedGroup;
 76     int layoutKind;
 77     int nullMarkerOffset;
 78   }
 79 
 80   // The format of the stream, after decompression, is a series of
 81   // integers organized like this:
 82   //
 83   //   FieldInfoStream := j=num_java_fields k=num_injected_fields Field[j+k] End
 84   //   Field := name sig offset access flags Optionals(flags)
 85   //   Optionals(i) := initval?[i&is_init]     // ConstantValue attr
 86   //                   gsig?[i&is_generic]     // signature attr
 87   //                   group?[i&is_contended]  // Contended anno (group)
 88   //   End = 0
 89   //
 90 
 91   static FieldInfoValues readFieldInfoValues(CompressedReadStream crs) {
 92     FieldInfoValues fieldInfoValues = new FieldInfoValues();
 93     fieldInfoValues.nameIndex = crs.readInt();                 // read name_index
 94     fieldInfoValues.signatureIndex = crs.readInt();            // read signature index
 95     fieldInfoValues.offset = crs.readInt();                    // read offset
 96     fieldInfoValues.accessFlags = crs.readInt();               // read access flags
 97     fieldInfoValues.fieldFlags = crs.readInt();                // read field flags
 98                                                                // Optional reads:
 99     if (fieldIsInitialized(fieldInfoValues.fieldFlags)) {
100         fieldInfoValues.initialValueIndex = crs.readInt();     // read initial value index
101     }
102     if (fieldIsGeneric(fieldInfoValues.fieldFlags)) {
103         fieldInfoValues.genericSignatureIndex = crs.readInt(); // read generic signature index
104     }
105     if (fieldIsContended(fieldInfoValues.fieldFlags)) {
106         fieldInfoValues.contendedGroup = crs.readInt();        // read contended group
107     }
108     if (fieldIsFlat(fieldInfoValues.fieldFlags)) {
109         fieldInfoValues.layoutKind = crs.readInt();            // read LayoutKind as int
110     }
111     if (fieldHasNullMarker(fieldInfoValues.fieldFlags)) {
112         fieldInfoValues.nullMarkerOffset = crs.readInt();      // read null marker offset
113     }
114     return fieldInfoValues;
115   }
116 
117   public static Field[] getFields(InstanceKlass kls) {
118     CompressedReadStream crs = new CompressedReadStream(kls.getFieldInfoStream().getDataStart());
119     int numJavaFields = crs.readInt();     // read num_java_fields
120     int numInjectedFields = crs.readInt(); // read num_injected_fields;
121     int numFields = numJavaFields + numInjectedFields;
122     Field[] fields = new Field[numFields];
123     for (int i = 0; i < numFields; i++) {
124       FieldInfoValues values = readFieldInfoValues(crs);
125       fields[i] = new Field(kls, i, values);
126     }
127     return fields;
128   }
129 
130   FieldInfoValues         values;
131   private Symbol          name;
132   private long            offset;
133   private FieldIdentifier id;
134   private boolean         isVMField;
135   // Java fields only
136   private InstanceKlass   holder;
137   private FieldType       fieldType;
138   private Symbol          signature;
139   private Symbol          genericSignature;
140   private AccessFlags     accessFlags;
141   private int             fieldIndex;
142 
143   /** Returns the byte offset of the field within the object or klass */
144   public long getOffset() { return offset; }
145 
146   /** Returns the identifier of the field */
147   public FieldIdentifier getID() { return id; }
148 
149   public Symbol getName() { return name; }
150   public int getNameIndex() { return values.nameIndex; }
151 
152   /** Indicates whether this is a VM field */
153   public boolean isVMField() { return isVMField; }
154 
155   /** Indicates whether this is a named field */
156   public boolean isNamedField() { return (id instanceof NamedFieldIdentifier); }
157 
158   public void printOn(PrintStream tty) {
159     getID().printOn(tty);
160     tty.print(" {" + getOffset() + "} :");
161   }
162 
163   /** (Named, non-VM fields only) Returns the InstanceKlass containing
164       this (static or non-static) field. */
165   public InstanceKlass getFieldHolder() {
166     return holder;
167   }
168 
169   /** (Named, non-VM fields only) Returns the index in the fields
170       TypeArray for this field. Equivalent to the "index" in the VM's
171       fieldDescriptors. */
172   public int getFieldIndex() {
173     return fieldIndex;
174   }
175 
176   /** (Named, non-VM fields only) Retrieves the access flags. */
177   public long getAccessFlags() { return accessFlags.getValue(); }
178   public AccessFlags getAccessFlagsObj() { return accessFlags; }
179 
180   /** (Named, non-VM fields only) Returns the type of this field. */
181   public FieldType getFieldType() { return fieldType; }
182 
183   /** (Named, non-VM fields only) Returns the signature of this
184       field. */
185   public Symbol getSignature() { return signature; }
186   public int getSignatureIndex() { return values.signatureIndex; }
187   public Symbol getGenericSignature() { return genericSignature; }
188   public int getGenericSignatureIndex() { return values.genericSignatureIndex; }
189 
190   public boolean hasInitialValue()           { return holder.getFieldInitialValueIndex(fieldIndex) != 0;    }
191   public int getInitialValueIndex()        { return values.initialValueIndex; }
192 
193   //
194   // Following accessors are for named, non-VM fields only
195   //
196   public boolean isPublic()                  { return accessFlags.isPublic(); }
197   public boolean isPrivate()                 { return accessFlags.isPrivate(); }
198   public boolean isProtected()               { return accessFlags.isProtected(); }
199   public boolean isPackagePrivate()          { return !isPublic() && !isPrivate() && !isProtected(); }
200 
201   public boolean isStatic()                  { return accessFlags.isStatic(); }
202   public boolean isFinal()                   { return accessFlags.isFinal(); }
203   public boolean isVolatile()                { return accessFlags.isVolatile(); }
204   public boolean isTransient()               { return accessFlags.isTransient(); }
205 
206   public boolean isSynthetic()               { return accessFlags.isSynthetic(); }
207   public boolean isEnumConstant()            { return accessFlags.isEnum();      }
208 
209   private static boolean fieldIsInitialized(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_INITIALIZED) & 1 ) != 0; }
210   private static boolean fieldIsInjected(int flags)    { return ((flags >> InstanceKlass.FIELD_FLAG_IS_INJECTED   ) & 1 ) != 0; }
211   private static boolean fieldIsGeneric(int flags)     { return ((flags >> InstanceKlass.FIELD_FLAG_IS_GENERIC    ) & 1 ) != 0; }
212   private static boolean fieldIsStable(int flags)      { return ((flags >> InstanceKlass.FIELD_FLAG_IS_STABLE     ) & 1 ) != 0; }
213   private static boolean fieldIsContended(int flags)   { return ((flags >> InstanceKlass.FIELD_FLAG_IS_CONTENDED  ) & 1 ) != 0; }
214   private static boolean fieldIsNullFreeInlineType(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_NULL_FREE_INLINE) & 1 ) != 0; }
215   private static boolean fieldIsFlat(int flags)               { return ((flags >> InstanceKlass.FIELD_FLAG_IS_FLAT) & 1 ) != 0; }
216   private static boolean fieldHasNullMarker(int flags)         { return ((flags >> InstanceKlass.FIELD_FLAG_IS_NULL_MARKER) & 1 ) != 0; }
217 
218   public boolean isInitialized()             { return fieldIsInitialized(values.fieldFlags); }
219   public boolean isInjected()                { return fieldIsInjected(values.fieldFlags); }
220   public boolean isGeneric()                 { return fieldIsGeneric(values.fieldFlags); }
221   public boolean isStable()                  { return fieldIsStable(values.fieldFlags); }
222   public boolean isContended()               { return fieldIsContended(values.fieldFlags); }
223 
224   public boolean equals(Object obj) {
225      if (obj == null) {
226         return false;
227      }
228 
229      if (! (obj instanceof Field)) {
230         return false;
231      }
232 
233      Field other = (Field) obj;
234      return this.getFieldHolder().equals(other.getFieldHolder()) &&
235             this.getID().equals(other.getID());
236   }
237 
238   public int hashCode() {
239      return getFieldHolder().hashCode() ^ getID().hashCode();
240   }
241 }