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
43 protected:
44 const Array<u1>* _fieldinfo_stream;
45 FieldInfoReader _reader;
46 constantPoolHandle _constants;
47 int _index;
48 int _limit;
49
50 FieldInfo _fi_buf;
51 fieldDescriptor _fd_buf;
52
53 FieldInfo const * field() const {
54 assert(!done(), "no more fields");
55 return &_fi_buf;
56 }
57
58 inline FieldStreamBase(const Array<u1>* fieldinfo_stream, ConstantPool* constants, int start, int limit);
59
60 inline FieldStreamBase(const Array<u1>* fieldinfo_stream, ConstantPool* constants);
61
62 private:
63 void initialize() {
64 int java_fields_count;
65 int injected_fields_count;
66 _reader.read_field_counts(&java_fields_count, &injected_fields_count);
67 if (_limit < _index) {
68 _limit = java_fields_count + injected_fields_count;
69 } else {
70 assert( _limit <= java_fields_count + injected_fields_count, "Safety check");
71 }
72 if (_limit != 0) {
73 _reader.read_field_info(_fi_buf);
74 }
75 }
76
77 public:
78 inline FieldStreamBase(InstanceKlass* klass);
79
80 // accessors
81 int index() const { return _index; }
82 InstanceKlass* field_holder() const { return _constants->pool_holder(); }
83
84 void next() {
85 _index += 1;
86 if (done()) return;
87 _reader.read_field_info(_fi_buf);
88 }
89 bool done() const { return _index >= _limit; }
90
91 // Accessors for current field
92 AccessFlags access_flags() const {
93 return field()->access_flags();
94 }
95
96 FieldInfo::FieldFlags field_flags() const {
97 return field()->field_flags();
98 }
99
100 Symbol* name() const {
101 return field()->name(_constants());
102 }
103
104 Symbol* signature() const {
105 return field()->signature(_constants());
106 }
107
108 Symbol* generic_signature() const {
109 if (field()->field_flags().is_generic()) {
110 return _constants->symbol_at(field()->generic_signature_index());
111 } else {
112 return nullptr;
113 }
114 }
115
116 int offset() const {
117 return field()->offset();
118 }
119
120 bool is_null_free_inline_type() {
121 return field()->field_flags().is_null_free_inline_type();
122 }
123
124 bool is_flat() const {
125 return field()->field_flags().is_flat();
126 }
127
128 bool is_contended() const {
129 return field()->is_contended();
130 }
131
132 int contended_group() const {
133 return field()->contended_group();
134 }
135
136 int null_marker_offset() const {
137 return field()->null_marker_offset();
138 }
139
140 // Convenient methods
141
142 const FieldInfo& to_FieldInfo() const {
143 return _fi_buf;
144 }
145
146 int num_total_fields() const {
147 return FieldInfoStream::num_total_fields(_fieldinfo_stream);
148 }
149
150 // bridge to a heavier API:
151 fieldDescriptor& field_descriptor() const {
152 fieldDescriptor& field = const_cast<fieldDescriptor&>(_fd_buf);
153 field.reinitialize(field_holder(), to_FieldInfo());
154 return field;
155 }
156 };
157
158 // Iterate over only the Java fields
159 class JavaFieldStream : public FieldStreamBase {
160 Array<u1>* _search_table;
161
162 public:
163 JavaFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), 0, k->java_fields_count()),
164 _search_table(k->fieldinfo_search_table()) {}
165
166 u2 name_index() const {
167 assert(!field()->field_flags().is_injected(), "regular only");
168 return field()->name_index();
169 }
170
171 u2 signature_index() const {
172 assert(!field()->field_flags().is_injected(), "regular only");
173 return field()->signature_index();
174 }
175
176 u2 generic_signature_index() const {
177 assert(!field()->field_flags().is_injected(), "regular only");
178 if (field()->field_flags().is_generic()) {
179 return field()->generic_signature_index();
180 }
181 return 0;
182 }
183
184 u2 initval_index() const {
185 assert(!field()->field_flags().is_injected(), "regular only");
186 return field()->initializer_index();
187 }
188
189 // Performs either a linear search or binary search through the stream
190 // looking for a matching name/signature combo
191 bool lookup(const Symbol* name, const Symbol* signature);
192 };
193
194
195 // Iterate over only the internal fields
196 class InternalFieldStream : public FieldStreamBase {
197 public:
198 InternalFieldStream(InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), k->java_fields_count(), 0) {}
199 };
200
201
202 class AllFieldStream : public FieldStreamBase {
203 public:
204 AllFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants()) {}
205 };
206
207 /* Very generally, a base class for a stream adapter, a derived class just implements
208 * current_stream that returns a FieldStreamType, and this adapter takes care of providing
209 * the methods of FieldStreamBase.
210 *
211 * In practice, this is used to provide a stream over the fields of a class and its superclasses
212 * and interfaces. The derived class of HierarchicalFieldStreamBase decides in which order we iterate
213 * on the superclasses (and interfaces), and the template parameter FieldStreamType is the underlying
214 * stream we use to iterate over the fields each class. Methods such as done and next are still up to
215 * the derived classes, allowing them to iterate over the class hierarchy, but also skip elements that
216 * the underlying FieldStreamType would otherwise include.
217 */
218 template<typename FieldStreamType>
219 class HierarchicalFieldStreamBase : public StackObj {
220 virtual FieldStreamType& current_stream() = 0;
221 virtual const FieldStreamType& current_stream() const = 0;
222
223 public:
224 // bridge functions from FieldStreamBase
225 int index() const {
226 return current_stream().index();
227 }
228
229 AccessFlags access_flags() const {
230 return current_stream().access_flags();
231 }
232
233 FieldInfo::FieldFlags field_flags() const {
234 return current_stream().field_flags();
235 }
236
237 Symbol* name() const {
238 return current_stream().name();
239 }
240
241 Symbol* signature() const {
242 return current_stream().signature();
243 }
244
245 Symbol* generic_signature() const {
246 return current_stream().generic_signature();
247 }
248
249 int offset() const {
250 return current_stream().offset();
251 }
252
253 bool is_contended() const {
254 return current_stream().is_contended();
255 }
256
257 int contended_group() const {
258 return current_stream().contended_group();
259 }
260
261 FieldInfo to_FieldInfo() {
262 return current_stream().to_FieldInfo();
263 }
264
265 fieldDescriptor& field_descriptor() const {
266 return current_stream().field_descriptor();
267 }
268
269 bool is_flat() const {
270 return current_stream().is_flat();
271 }
272
273 bool is_null_free_inline_type() {
274 return current_stream().is_null_free_inline_type();
275 }
276
277 int null_marker_offset() {
278 return current_stream().null_marker_offset();
279 }
280 };
281
282 /* Iterate over fields including the ones declared in supertypes.
283 * Derived classes are traversed before base classes, and interfaces
284 * at the end.
285 */
286 template<typename FieldStreamType>
287 class HierarchicalFieldStream final : public HierarchicalFieldStreamBase<FieldStreamType> {
288 private:
289 const Array<InstanceKlass*>* _interfaces;
290 InstanceKlass* _next_klass; // null indicates no more type to visit
291 FieldStreamType _current_stream;
292 int _interface_index;
293
294 void prepare() {
295 _next_klass = next_klass_with_fields();
296 // special case: the initial klass has no fields. If any supertype has any fields, use that directly.
297 // if no such supertype exists, done() will return false already.
298 next_stream_if_done();
299 }
300
301 InstanceKlass* next_klass_with_fields() {
302 assert(_next_klass != nullptr, "reached end of types already");
303 InstanceKlass* result = _next_klass;
304 do {
305 if (!result->is_interface() && result->super() != nullptr) {
306 result = result->super();
307 } else if (_interface_index > 0) {
308 result = _interfaces->at(--_interface_index);
309 } else {
310 return nullptr; // we did not find any more supertypes with fields
311 }
312 } while (FieldStreamType(result).done());
313 return result;
314 }
315
316 // sets _current_stream to the next if the current is done and any more is available
317 void next_stream_if_done() {
318 if (_next_klass != nullptr && _current_stream.done()) {
319 _current_stream = FieldStreamType(_next_klass);
320 assert(!_current_stream.done(), "created empty stream");
321 _next_klass = next_klass_with_fields();
322 }
323 }
324
325 FieldStreamType& current_stream() override { return _current_stream; }
326 const FieldStreamType& current_stream() const override { return _current_stream; }
327
328 public:
329 explicit HierarchicalFieldStream(InstanceKlass* klass) :
330 _interfaces(klass->transitive_interfaces()),
331 _next_klass(klass),
332 _current_stream(FieldStreamType(klass)),
333 _interface_index(_interfaces->length()) {
334 prepare();
335 }
336
337 void next() {
338 _current_stream.next();
339 next_stream_if_done();
340 }
341
342 bool done() const { return _next_klass == nullptr && _current_stream.done(); }
343 };
344
345 /* Iterates on the fields of a class and its super-class top-down (java.lang.Object first)
346 * Doesn't traverse interfaces for now, because it's not clear which order would make sense
347 * Let's decide when or if the need arises. Since we are not traversing interfaces, we
348 * wouldn't get all the static fields, and since the current use-case of this stream does not
349 * care about static fields, we restrict it to regular non-static fields.
350 */
351 class TopDownHierarchicalNonStaticFieldStreamBase final : public HierarchicalFieldStreamBase<JavaFieldStream> {
352 GrowableArray<InstanceKlass*>* _super_types; // Self and super type, bottom up
353 int _current_stream_index;
354 JavaFieldStream _current_stream;
355
356 void next_stream_if_needed() {
357 precond(_current_stream_index >= 0);
358 while (_current_stream.done()) {
359 _current_stream_index--;
360 if (_current_stream_index < 0) {
361 return;
362 }
363 _current_stream = JavaFieldStream(_super_types->at(_current_stream_index));
364 }
365 }
366
367 GrowableArray<InstanceKlass*>* get_super_types(InstanceKlass* klass) {
368 auto super_types = new GrowableArray<InstanceKlass*>();
369 do {
370 super_types->push(klass);
371 } while ((klass = klass->java_super()) != nullptr);
372 return super_types;
373 }
374
375 void raw_next() {
376 _current_stream.next();
377 next_stream_if_needed();
378 }
379
380 void closest_non_static() {
381 while (!done() && access_flags().is_static()) {
382 raw_next();
383 }
384 }
385
386 JavaFieldStream& current_stream() override { return _current_stream; }
387 const JavaFieldStream& current_stream() const override { return _current_stream; }
388
389 public:
390 explicit TopDownHierarchicalNonStaticFieldStreamBase(InstanceKlass* klass) :
391 _super_types(get_super_types(klass)),
392 _current_stream_index(_super_types->length() - 1),
393 _current_stream(JavaFieldStream(_super_types->at(_current_stream_index))) {
394 next_stream_if_needed();
395 closest_non_static();
396 }
397
398 void next() {
399 raw_next();
400 closest_non_static();
401 }
402
403 bool done() const { return _current_stream_index < 0; }
404 };
405
406 #endif // SHARE_OOPS_FIELDSTREAMS_HPP