1 /*
2 * Copyright (c) 2011, 2025, 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 #ifndef SHARE_OOPS_FIELDSTREAMS_HPP
26 #define SHARE_OOPS_FIELDSTREAMS_HPP
27
28 #include "oops/fieldInfo.hpp"
29 #include "oops/instanceKlass.hpp"
30 #include "runtime/fieldDescriptor.hpp"
31
32 // The is the base class for iteration over the fields array
33 // describing the declared fields in the class. Several subclasses
34 // are provided depending on the kind of iteration required. The
35 // JavaFieldStream is for iterating over regular Java fields and it
36 // generally the preferred iterator. InternalFieldStream only
37 // iterates over fields that have been injected by the JVM.
38 // AllFieldStream exposes all fields and should only be used in rare
39 // cases.
40 // HierarchicalFieldStream allows to also iterate over fields of supertypes.
41 class FieldStreamBase : public StackObj {
42 protected:
43 const Array<u1>* _fieldinfo_stream;
44 FieldInfoReader _reader;
45 constantPoolHandle _constants;
46 int _index;
47 int _limit;
48
49 FieldInfo _fi_buf;
50 fieldDescriptor _fd_buf;
51
52 FieldInfo const * field() const {
53 assert(!done(), "no more fields");
54 return &_fi_buf;
55 }
56
57 inline FieldStreamBase(const Array<u1>* fieldinfo_stream, ConstantPool* constants, int start, int limit);
58
59 inline FieldStreamBase(const Array<u1>* fieldinfo_stream, ConstantPool* constants);
60
61 private:
62 void initialize() {
63 int java_fields_count;
64 int injected_fields_count;
65 _reader.read_field_counts(&java_fields_count, &injected_fields_count);
66 if (_limit < _index) {
67 _limit = java_fields_count + injected_fields_count;
68 } else {
69 assert( _limit <= java_fields_count + injected_fields_count, "Safety check");
70 }
71 if (_limit != 0) {
72 _reader.read_field_info(_fi_buf);
73 }
74 }
75
76 public:
77 inline FieldStreamBase(InstanceKlass* klass);
78
79 // accessors
80 int index() const { return _index; }
81 InstanceKlass* field_holder() const { return _constants->pool_holder(); }
82
83 void next() {
84 _index += 1;
85 if (done()) return;
86 _reader.read_field_info(_fi_buf);
87 }
88 bool done() const { return _index >= _limit; }
89
90 // Accessors for current field
91 AccessFlags access_flags() const {
92 return field()->access_flags();
93 }
94
95 FieldInfo::FieldFlags field_flags() const {
96 return field()->field_flags();
97 }
98
99 Symbol* name() const {
100 return field()->name(_constants());
101 }
102
103 Symbol* signature() const {
104 return field()->signature(_constants());
105 }
106
107 Symbol* generic_signature() const {
108 if (field()->field_flags().is_generic()) {
109 return _constants->symbol_at(field()->generic_signature_index());
110 } else {
111 return nullptr;
112 }
113 }
114
115 int offset() const {
116 return field()->offset();
117 }
118
119 bool is_contended() const {
120 return field()->is_contended();
121 }
122
123 int contended_group() const {
124 return field()->contended_group();
125 }
126
127 // Convenient methods
128
129 const FieldInfo& to_FieldInfo() const {
130 return _fi_buf;
131 }
132
133 int num_total_fields() const {
134 return FieldInfoStream::num_total_fields(_fieldinfo_stream);
135 }
136
137 // bridge to a heavier API:
138 fieldDescriptor& field_descriptor() const {
139 fieldDescriptor& field = const_cast<fieldDescriptor&>(_fd_buf);
140 field.reinitialize(field_holder(), to_FieldInfo());
141 return field;
142 }
143 };
144
145 // Iterate over only the Java fields
146 class JavaFieldStream : public FieldStreamBase {
147 Array<u1>* _search_table;
148
149 public:
150 JavaFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), 0, k->java_fields_count()),
151 _search_table(k->fieldinfo_search_table()) {}
152
153 u2 name_index() const {
154 assert(!field()->field_flags().is_injected(), "regular only");
155 return field()->name_index();
156 }
157
158 u2 signature_index() const {
159 assert(!field()->field_flags().is_injected(), "regular only");
160 return field()->signature_index();
161 }
162
163 u2 generic_signature_index() const {
164 assert(!field()->field_flags().is_injected(), "regular only");
165 if (field()->field_flags().is_generic()) {
166 return field()->generic_signature_index();
167 }
168 return 0;
169 }
170
171 u2 initval_index() const {
172 assert(!field()->field_flags().is_injected(), "regular only");
173 return field()->initializer_index();
174 }
175
176 // Performs either a linear search or binary search through the stream
177 // looking for a matching name/signature combo
178 bool lookup(const Symbol* name, const Symbol* signature);
179 };
180
181
182 // Iterate over only the internal fields
183 class InternalFieldStream : public FieldStreamBase {
184 public:
185 InternalFieldStream(InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), k->java_fields_count(), 0) {}
186 };
187
188
189 class AllFieldStream : public FieldStreamBase {
190 public:
191 AllFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants()) {}
192 };
193
194 // Iterate over fields including the ones declared in supertypes
195 template<typename FieldStreamType>
196 class HierarchicalFieldStream : public StackObj {
197 private:
198 const Array<InstanceKlass*>* _interfaces;
199 InstanceKlass* _next_klass; // null indicates no more type to visit
200 FieldStreamType _current_stream;
201 int _interface_index;
202
203 void prepare() {
204 _next_klass = next_klass_with_fields();
205 // special case: the initial klass has no fields. If any supertype has any fields, use that directly.
206 // if no such supertype exists, done() will return false already.
207 next_stream_if_done();
208 }
209
210 InstanceKlass* next_klass_with_fields() {
211 assert(_next_klass != nullptr, "reached end of types already");
212 InstanceKlass* result = _next_klass;
213 do {
214 if (!result->is_interface() && result->super() != nullptr) {
215 result = result->super();
216 } else if (_interface_index > 0) {
217 result = _interfaces->at(--_interface_index);
218 } else {
219 return nullptr; // we did not find any more supertypes with fields
220 }
221 } while (FieldStreamType(result).done());
222 return result;
223 }
224
225 // sets _current_stream to the next if the current is done and any more is available
226 void next_stream_if_done() {
227 if (_next_klass != nullptr && _current_stream.done()) {
228 _current_stream = FieldStreamType(_next_klass);
229 assert(!_current_stream.done(), "created empty stream");
230 _next_klass = next_klass_with_fields();
231 }
232 }
233
234 public:
235 HierarchicalFieldStream(InstanceKlass* klass) :
236 _interfaces(klass->transitive_interfaces()),
237 _next_klass(klass),
238 _current_stream(FieldStreamType(klass)),
239 _interface_index(_interfaces->length()) {
240 prepare();
241 }
242
243 void next() {
244 _current_stream.next();
245 next_stream_if_done();
246 }
247
248 bool done() const { return _next_klass == nullptr && _current_stream.done(); }
249
250 // bridge functions from FieldStreamBase
251
252 AccessFlags access_flags() const {
253 return _current_stream.access_flags();
254 }
255
256 FieldInfo::FieldFlags field_flags() const {
257 return _current_stream.field_flags();
258 }
259
260 Symbol* name() const {
261 return _current_stream.name();
262 }
263
264 Symbol* signature() const {
265 return _current_stream.signature();
266 }
267
268 Symbol* generic_signature() const {
269 return _current_stream.generic_signature();
270 }
271
272 int offset() const {
273 return _current_stream.offset();
274 }
275
276 bool is_contended() const {
277 return _current_stream.is_contended();
278 }
279
280 int contended_group() const {
281 return _current_stream.contended_group();
282 }
283
284 FieldInfo to_FieldInfo() {
285 return _current_stream.to_FieldInfo();
286 }
287
288 fieldDescriptor& field_descriptor() const {
289 return _current_stream.field_descriptor();
290 }
291
292 };
293
294 #endif // SHARE_OOPS_FIELDSTREAMS_HPP