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/instanceKlass.hpp"
 29 #include "oops/fieldInfo.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->java_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