1 /*
  2  * Copyright (c) 2000, 2023, 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   }
 77 
 78   // The format of the stream, after decompression, is a series of
 79   // integers organized like this:
 80   //
 81   //   FieldInfoStream := j=num_java_fields k=num_injected_fields Field[j+k] End
 82   //   Field := name sig offset access flags Optionals(flags)
 83   //   Optionals(i) := initval?[i&is_init]     // ConstantValue attr
 84   //                   gsig?[i&is_generic]     // signature attr
 85   //                   group?[i&is_contended]  // Contended anno (group)
 86   //   End = 0
 87   //
 88 
 89   static FieldInfoValues readFieldInfoValues(CompressedReadStream crs) {
 90     FieldInfoValues fieldInfoValues = new FieldInfoValues();
 91     fieldInfoValues.nameIndex = crs.readInt();                 // read name_index
 92     fieldInfoValues.signatureIndex = crs.readInt();            // read signature index
 93     fieldInfoValues.offset = crs.readInt();                    // read offset
 94     fieldInfoValues.accessFlags = crs.readInt();               // read access flags
 95     fieldInfoValues.fieldFlags = crs.readInt();                // read field flags
 96                                                                // Optional reads:
 97     if (fieldIsInitialized(fieldInfoValues.fieldFlags)) {
 98         fieldInfoValues.initialValueIndex = crs.readInt();     // read initial value index
 99     }
100     if (fieldIsGeneric(fieldInfoValues.fieldFlags)) {
101         fieldInfoValues.genericSignatureIndex = crs.readInt(); // read generic signature index
102     }
103     if (fieldIsContended(fieldInfoValues.fieldFlags)) {
104         fieldInfoValues.contendedGroup = crs.readInt();        // read contended group
105     }
106     return fieldInfoValues;
107   }
108 
109   public static Field[] getFields(InstanceKlass kls) {
110     CompressedReadStream crs = new CompressedReadStream(kls.getFieldInfoStream().getDataStart());
111     int numJavaFields = crs.readInt();     // read num_java_fields
112     int numInjectedFields = crs.readInt(); // read num_injected_fields;
113     int numFields = numJavaFields + numInjectedFields;
114     Field[] fields = new Field[numFields];
115     for (int i = 0; i < numFields; i++) {
116       FieldInfoValues values = readFieldInfoValues(crs);
117       fields[i] = new Field(kls, i, values);
118     }
119     return fields;
120   }
121 
122   FieldInfoValues         values;
123   private Symbol          name;
124   private long            offset;
125   private FieldIdentifier id;
126   private boolean         isVMField;
127   // Java fields only
128   private InstanceKlass   holder;
129   private FieldType       fieldType;
130   private Symbol          signature;
131   private Symbol          genericSignature;
132   private AccessFlags     accessFlags;
133   private int             fieldIndex;
134 
135   /** Returns the byte offset of the field within the object or klass */
136   public long getOffset() { return offset; }
137 
138   /** Returns the identifier of the field */
139   public FieldIdentifier getID() { return id; }
140 
141   public Symbol getName() { return name; }
142   public int getNameIndex() { return values.nameIndex; }
143 
144   /** Indicates whether this is a VM field */
145   public boolean isVMField() { return isVMField; }
146 
147   /** Indicates whether this is a named field */
148   public boolean isNamedField() { return (id instanceof NamedFieldIdentifier); }
149 
150   public void printOn(PrintStream tty) {
151     getID().printOn(tty);
152     tty.print(" {" + getOffset() + "} :");
153   }
154 
155   /** (Named, non-VM fields only) Returns the InstanceKlass containing
156       this (static or non-static) field. */
157   public InstanceKlass getFieldHolder() {
158     return holder;
159   }
160 
161   /** (Named, non-VM fields only) Returns the index in the fields
162       TypeArray for this field. Equivalent to the "index" in the VM's
163       fieldDescriptors. */
164   public int getFieldIndex() {
165     return fieldIndex;
166   }
167 
168   /** (Named, non-VM fields only) Retrieves the access flags. */
169   public long getAccessFlags() { return accessFlags.getValue(); }
170   public AccessFlags getAccessFlagsObj() { return accessFlags; }
171 
172   /** (Named, non-VM fields only) Returns the type of this field. */
173   public FieldType getFieldType() { return fieldType; }
174 
175   /** (Named, non-VM fields only) Returns the signature of this
176       field. */
177   public Symbol getSignature() { return signature; }
178   public int getSignatureIndex() { return values.signatureIndex; }
179   public Symbol getGenericSignature() { return genericSignature; }
180   public int getGenericSignatureIndex() { return values.genericSignatureIndex; }
181 
182   public boolean hasInitialValue()           { return holder.getFieldInitialValueIndex(fieldIndex) != 0;    }
183   public int getInitialValueIndex()        { return values.initialValueIndex; }
184 
185   //
186   // Following accessors are for named, non-VM fields only
187   //
188   public boolean isPublic()                  { return accessFlags.isPublic(); }
189   public boolean isPrivate()                 { return accessFlags.isPrivate(); }
190   public boolean isProtected()               { return accessFlags.isProtected(); }
191   public boolean isPackagePrivate()          { return !isPublic() && !isPrivate() && !isProtected(); }
192 
193   public boolean isStatic()                  { return accessFlags.isStatic(); }
194   public boolean isFinal()                   { return accessFlags.isFinal(); }
195   public boolean isVolatile()                { return accessFlags.isVolatile(); }
196   public boolean isTransient()               { return accessFlags.isTransient(); }
197 
198   public boolean isSynthetic()               { return accessFlags.isSynthetic(); }
199   public boolean isEnumConstant()            { return accessFlags.isEnum();      }
200 
201   private static boolean fieldIsInitialized(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_INITIALIZED) & 1 ) != 0; }
202   private static boolean fieldIsInjected(int flags)    { return ((flags >> InstanceKlass.FIELD_FLAG_IS_INJECTED   ) & 1 ) != 0; }
203   private static boolean fieldIsGeneric(int flags)     { return ((flags >> InstanceKlass.FIELD_FLAG_IS_GENERIC    ) & 1 ) != 0; }
204   private static boolean fieldIsStable(int flags)      { return ((flags >> InstanceKlass.FIELD_FLAG_IS_STABLE     ) & 1 ) != 0; }
205   private static boolean fieldIsContended(int flags)   { return ((flags >> InstanceKlass.FIELD_FLAG_IS_CONTENDED  ) & 1 ) != 0; }
206 
207 
208   public boolean isInitialized()             { return fieldIsInitialized(values.fieldFlags); }
209   public boolean isInjected()                { return fieldIsInjected(values.fieldFlags); }
210   public boolean isGeneric()                 { return fieldIsGeneric(values.fieldFlags); }
211   public boolean isStable()                  { return fieldIsStable(values.fieldFlags); }
212   public boolean isContended()               { return fieldIsContended(values.fieldFlags); }
213 
214   public boolean equals(Object obj) {
215      if (obj == null) {
216         return false;
217      }
218 
219      if (! (obj instanceof Field)) {
220         return false;
221      }
222 
223      Field other = (Field) obj;
224      return this.getFieldHolder().equals(other.getFieldHolder()) &&
225             this.getID().equals(other.getID());
226   }
227 
228   public int hashCode() {
229      return getFieldHolder().hashCode() ^ getID().hashCode();
230   }
231 }