1 /*
2 * Copyright (c) 2011, 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 #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 }
69 assert(_limit <= java_fields_count + injected_fields_count, "Safety check");
70 if (_index < _limit) {
71 if (_index != 0) {
72 _reader.skip_to_field_info(_index);
73 }
74 _reader.read_field_info(_fi_buf);
75 }
76 }
77
78 public:
79 inline FieldStreamBase(InstanceKlass* klass);
80
81 // accessors
82 int index() const { return _index; }
83 InstanceKlass* field_holder() const { return _constants->pool_holder(); }
84
85 void next() {
86 _index += 1;
87 if (done()) return;
88 _reader.read_field_info(_fi_buf);
89 }
90 bool done() const { return _index >= _limit; }
91
92 // Accessors for current field
93 AccessFlags access_flags() const {
94 return field()->access_flags();
95 }
96
97 FieldInfo::FieldFlags field_flags() const {
98 return field()->field_flags();
99 }
100
101 Symbol* name() const {
102 return field()->name(_constants());
103 }
104
105 Symbol* signature() const {
106 return field()->signature(_constants());
107 }
108
109 Symbol* generic_signature() const {
110 if (field()->field_flags().is_generic()) {
111 return _constants->symbol_at(field()->generic_signature_index());
112 } else {
113 return nullptr;
114 }
115 }
116
117 int offset() const {
118 return field()->offset();
119 }
120
121 bool is_null_free_inline_type() {122 return field()->field_flags().is_null_free_inline_type();123 }124 125 bool is_flat() const {126 return field()->field_flags().is_flat();127 }128
129 bool is_contended() const {
130 return field()->is_contended();
131 }
132
133 int contended_group() const {
134 return field()->contended_group();
135 }
136
137 int null_marker_offset() const {138 return field()->null_marker_offset();139 }140
141 // Convenient methods
142
143 const FieldInfo& to_FieldInfo() const {
144 return _fi_buf;
145 }
146
147 int num_total_fields() const {
148 return FieldInfoStream::num_total_fields(_fieldinfo_stream);
149 }
150
151 // bridge to a heavier API:
152 fieldDescriptor& field_descriptor() const {
153 fieldDescriptor& field = const_cast<fieldDescriptor&>(_fd_buf);
154 field.reinitialize(field_holder(), to_FieldInfo());
155 return field;
156 }
157 };
158
159 // Iterate over only the Java fields
160 class JavaFieldStream : public FieldStreamBase {
161 Array<u1>* _search_table;
162
163 public:
164 JavaFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), 0, k->java_fields_count()),
165 _search_table(k->fieldinfo_search_table()) {}
166
167 u2 name_index() const {
168 assert(!field()->field_flags().is_injected(), "regular only");
169 return field()->name_index();
170 }
171
172 u2 signature_index() const {
173 assert(!field()->field_flags().is_injected(), "regular only");
174 return field()->signature_index();
175 }
176
177 u2 generic_signature_index() const {
178 assert(!field()->field_flags().is_injected(), "regular only");
179 if (field()->field_flags().is_generic()) {
180 return field()->generic_signature_index();
181 }
182 return 0;
183 }
184
185 u2 initval_index() const {
186 assert(!field()->field_flags().is_injected(), "regular only");
187 return field()->initializer_index();
188 }
189
190 // Performs either a linear search or binary search through the stream
191 // looking for a matching name/signature combo
192 bool lookup(const Symbol* name, const Symbol* signature);
193 };
194
195
196 // Iterate over only the internal fields
197 class InternalFieldStream : public FieldStreamBase {
198 public:
199 InternalFieldStream(InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), k->java_fields_count(), -1) {}
200 };
201
202
203 class AllFieldStream : public FieldStreamBase {
204 public:
205 AllFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants()) {}
206 };
207
208 // Very generally, a base class for a stream adapter, a subclass just implements209 // current_stream that returns a FieldStreamType, and this adapter takes care of providing210 // the methods of FieldStreamBase.211 //212 // In practice, this is used to provide a stream over the fields of a class and its superclasses213 // and interfaces. The subclass of HierarchicalFieldStreamBase decides in which order we iterate214 // on the superclasses (and interfaces), and the template parameter FieldStreamType is the underlying215 // stream we use to iterate over the fields each class. Methods such as done and next are still up to216 // the subclasses, allowing them to iterate over the class hierarchy, but also skip elements that217 // the underlying FieldStreamType would otherwise include.218 219 template<typename FieldStreamType>220 class HierarchicalFieldStreamBase : public StackObj {221 virtual FieldStreamType& current_stream() = 0;222 virtual const FieldStreamType& current_stream() const = 0;223 224 public:225 // bridge functions from FieldStreamBase226 int index() const {227 return current_stream().index();228 }229 230 AccessFlags access_flags() const {231 return current_stream().access_flags();232 }233 234 FieldInfo::FieldFlags field_flags() const {235 return current_stream().field_flags();236 }237 238 Symbol* name() const {239 return current_stream().name();240 }241 242 Symbol* signature() const {243 return current_stream().signature();244 }245 246 Symbol* generic_signature() const {247 return current_stream().generic_signature();248 }249 250 int offset() const {251 return current_stream().offset();252 }253 254 bool is_contended() const {255 return current_stream().is_contended();256 }257 258 int contended_group() const {259 return current_stream().contended_group();260 }261 262 FieldInfo to_FieldInfo() {263 return current_stream().to_FieldInfo();264 }265 266 fieldDescriptor& field_descriptor() const {267 return current_stream().field_descriptor();268 }269 270 bool is_flat() const {271 return current_stream().is_flat();272 }273 274 bool is_null_free_inline_type() {275 return current_stream().is_null_free_inline_type();276 }277 278 int null_marker_offset() {279 return current_stream().null_marker_offset();280 }281 };282 283 // Iterate over fields including the ones declared in supertypes.284 // Subclasses are traversed before base classes, and interfaces285 // at the end.
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 sense347 // Let's decide when or if the need arises. Since we are not traversing interfaces, we348 // wouldn't get all the static fields, and since the current use-case of this stream does not349 // 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 up353 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_nonstatic() {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_nonstatic();
396 }
397
398 void next() {399 raw_next();400 closest_nonstatic();
401 }
402
403 bool done() const { return _current_stream_index < 0; }
404 };
405
406 #endif // SHARE_OOPS_FIELDSTREAMS_HPP
--- EOF ---