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 }