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 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->java_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