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 }