| /* | |
| * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| * | |
| */ | |
| #ifndef SHARE_OOPS_FIELDSTREAMS_HPP | |
| #define SHARE_OOPS_FIELDSTREAMS_HPP | |
| #include "oops/instanceKlass.hpp" | |
| #include "oops/fieldInfo.hpp" | |
| #include "runtime/fieldDescriptor.hpp" | |
| // The is the base class for iteration over the fields array | |
| // describing the declared fields in the class. Several subclasses | |
| // are provided depending on the kind of iteration required. The | |
| // JavaFieldStream is for iterating over regular Java fields and it | |
| // generally the preferred iterator. InternalFieldStream only | |
| // iterates over fields that have been injected by the JVM. | |
| // AllFieldStream exposes all fields and should only be used in rare | |
| // cases. | |
| // HierarchicalFieldStream allows to also iterate over fields of supertypes. | |
| class FieldStreamBase : public StackObj { | |
| protected: | |
| const Array<u1>* _fieldinfo_stream; | |
| FieldInfoReader _reader; | |
| constantPoolHandle _constants; | |
| int _index; | |
| int _limit; | |
| FieldInfo _fi_buf; | |
| fieldDescriptor _fd_buf; | |
| FieldInfo const * field() const { | |
| assert(!done(), "no more fields"); | |
| return &_fi_buf; | |
| } | |
| inline FieldStreamBase(const Array<u1>* fieldinfo_stream, ConstantPool* constants, int start, int limit); | |
| inline FieldStreamBase(const Array<u1>* fieldinfo_stream, ConstantPool* constants); | |
| private: | |
| void initialize() { | |
| int java_fields_count; | |
| int injected_fields_count; | |
| _reader.read_field_counts(&java_fields_count, &injected_fields_count); | |
| if (_limit < _index) { | |
| _limit = java_fields_count + injected_fields_count; | |
| } else { | |
| assert( _limit <= java_fields_count + injected_fields_count, "Safety check"); | |
| } | |
| if (_limit != 0) { | |
| _reader.read_field_info(_fi_buf); | |
| } | |
| } | |
| public: | |
| inline FieldStreamBase(InstanceKlass* klass); | |
| // accessors | |
| int index() const { return _index; } | |
| InstanceKlass* field_holder() const { return _constants->pool_holder(); } | |
| void next() { | |
| _index += 1; | |
| if (done()) return; | |
| _reader.read_field_info(_fi_buf); | |
| } | |
| bool done() const { return _index >= _limit; } | |
| // Accessors for current field | |
| AccessFlags access_flags() const { | |
| return field()->access_flags(); | |
| } | |
| FieldInfo::FieldFlags field_flags() const { | |
| return field()->field_flags(); | |
| } | |
| Symbol* name() const { | |
| return field()->name(_constants()); | |
| } | |
| Symbol* signature() const { | |
| return field()->signature(_constants()); | |
| } | |
| Symbol* generic_signature() const { | |
| if (field()->field_flags().is_generic()) { | |
| return _constants->symbol_at(field()->generic_signature_index()); | |
| } else { | |
| return nullptr; | |
| } | |
| } | |
| int offset() const { | |
| return field()->offset(); | |
| } | |
| bool is_contended() const { | |
| return field()->is_contended(); | |
| } | |
| int contended_group() const { | |
| return field()->contended_group(); | |
| } | |
| // Convenient methods | |
| const FieldInfo& to_FieldInfo() const { | |
| return _fi_buf; | |
| } | |
| int num_total_fields() const { | |
| return FieldInfoStream::num_total_fields(_fieldinfo_stream); | |
| } | |
| // bridge to a heavier API: | |
| fieldDescriptor& field_descriptor() const { | |
| fieldDescriptor& field = const_cast<fieldDescriptor&>(_fd_buf); | |
| field.reinitialize(field_holder(), to_FieldInfo()); | |
| return field; | |
| } | |
| }; | |
| // Iterate over only the Java fields | |
| class JavaFieldStream : public FieldStreamBase { | |
| Array<u1>* _search_table; | |
| public: | |
| JavaFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), 0, k->java_fields_count()), | |
| _search_table(k->fieldinfo_search_table()) {} | |
| u2 name_index() const { | |
| assert(!field()->field_flags().is_injected(), "regular only"); | |
| return field()->name_index(); | |
| } | |
| u2 signature_index() const { | |
| assert(!field()->field_flags().is_injected(), "regular only"); | |
| return field()->signature_index(); | |
| } | |
| u2 generic_signature_index() const { | |
| assert(!field()->field_flags().is_injected(), "regular only"); | |
| if (field()->field_flags().is_generic()) { | |
| return field()->generic_signature_index(); | |
| } | |
| return 0; | |
| } | |
| u2 initval_index() const { | |
| assert(!field()->field_flags().is_injected(), "regular only"); | |
| return field()->initializer_index(); | |
| } | |
| // Performs either a linear search or binary search through the stream | |
| // looking for a matching name/signature combo | |
| bool lookup(const Symbol* name, const Symbol* signature); | |
| }; | |
| // Iterate over only the internal fields | |
| class InternalFieldStream : public FieldStreamBase { | |
| public: | |
| InternalFieldStream(InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), k->java_fields_count(), 0) {} | |
| }; | |
| class AllFieldStream : public FieldStreamBase { | |
| public: | |
| AllFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants()) {} | |
| }; | |
| // Iterate over fields including the ones declared in supertypes | |
| template<typename FieldStreamType> | |
| class HierarchicalFieldStream : public StackObj { | |
| private: | |
| const Array<InstanceKlass*>* _interfaces; | |
| InstanceKlass* _next_klass; // null indicates no more type to visit | |
| FieldStreamType _current_stream; | |
| int _interface_index; | |
| void prepare() { | |
| _next_klass = next_klass_with_fields(); | |
| // special case: the initial klass has no fields. If any supertype has any fields, use that directly. | |
| // if no such supertype exists, done() will return false already. | |
| next_stream_if_done(); | |
| } | |
| InstanceKlass* next_klass_with_fields() { | |
| assert(_next_klass != nullptr, "reached end of types already"); | |
| InstanceKlass* result = _next_klass; | |
| do { | |
| if (!result->is_interface() && result->super() != nullptr) { | |
| result = result->java_super(); | |
| } else if (_interface_index > 0) { | |
| result = _interfaces->at(--_interface_index); | |
| } else { | |
| return nullptr; // we did not find any more supertypes with fields | |
| } | |
| } while (FieldStreamType(result).done()); | |
| return result; | |
| } | |
| // sets _current_stream to the next if the current is done and any more is available | |
| void next_stream_if_done() { | |
| if (_next_klass != nullptr && _current_stream.done()) { | |
| _current_stream = FieldStreamType(_next_klass); | |
| assert(!_current_stream.done(), "created empty stream"); | |
| _next_klass = next_klass_with_fields(); | |
| } | |
| } | |
| public: | |
| HierarchicalFieldStream(InstanceKlass* klass) : | |
| _interfaces(klass->transitive_interfaces()), | |
| _next_klass(klass), | |
| _current_stream(FieldStreamType(klass)), | |
| _interface_index(_interfaces->length()) { | |
| prepare(); | |
| } | |
| void next() { | |
| _current_stream.next(); | |
| next_stream_if_done(); | |
| } | |
| bool done() const { return _next_klass == nullptr && _current_stream.done(); } | |
| // bridge functions from FieldStreamBase | |
| AccessFlags access_flags() const { | |
| return _current_stream.access_flags(); | |
| } | |
| FieldInfo::FieldFlags field_flags() const { | |
| return _current_stream.field_flags(); | |
| } | |
| Symbol* name() const { | |
| return _current_stream.name(); | |
| } | |
| Symbol* signature() const { | |
| return _current_stream.signature(); | |
| } | |
| Symbol* generic_signature() const { | |
| return _current_stream.generic_signature(); | |
| } | |
| int offset() const { | |
| return _current_stream.offset(); | |
| } | |
| bool is_contended() const { | |
| return _current_stream.is_contended(); | |
| } | |
| int contended_group() const { | |
| return _current_stream.contended_group(); | |
| } | |
| FieldInfo to_FieldInfo() { | |
| return _current_stream.to_FieldInfo(); | |
| } | |
| fieldDescriptor& field_descriptor() const { | |
| return _current_stream.field_descriptor(); | |
| } | |
| }; | |
| #endif // SHARE_OOPS_FIELDSTREAMS_HPP |