1 | /* |
2 | * Copyright (c) 1999, 2019, 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_RUNTIME_REFLECTIONUTILS_HPP |
26 | #define SHARE_RUNTIME_REFLECTIONUTILS_HPP |
27 | |
28 | #include "memory/allocation.hpp" |
29 | #include "oops/instanceKlass.hpp" |
30 | #include "oops/objArrayOop.hpp" |
31 | #include "oops/oopsHierarchy.hpp" |
32 | #include "runtime/handles.hpp" |
33 | #include "runtime/reflection.hpp" |
34 | #include "utilities/accessFlags.hpp" |
35 | #include "utilities/globalDefinitions.hpp" |
36 | #include "utilities/growableArray.hpp" |
37 | |
38 | // A KlassStream is an abstract stream for streaming over self, superclasses |
39 | // and (super)interfaces. Streaming is done in reverse order (subclasses first, |
40 | // interfaces last). |
41 | // |
42 | // for (KlassStream st(k, false, false, false); !st.eos(); st.next()) { |
43 | // Klass* k = st.klass(); |
44 | // ... |
45 | // } |
46 | |
47 | class KlassStream { |
48 | protected: |
49 | InstanceKlass* _klass; // current klass/interface iterated over |
50 | InstanceKlass* _base_klass; // initial klass/interface to iterate over |
51 | Array<InstanceKlass*>*_interfaces; // transitive interfaces for initial class |
52 | int _interface_index; // current interface being processed |
53 | bool _local_only; // process initial class/interface only |
54 | bool _classes_only; // process classes only (no interfaces) |
55 | bool _walk_defaults; // process default methods |
56 | bool _base_class_search_defaults; // time to process default methods |
57 | bool _defaults_checked; // already checked for default methods |
58 | int _index; |
59 | |
60 | virtual int length() = 0; |
61 | |
62 | public: |
63 | // constructor |
64 | KlassStream(InstanceKlass* klass, bool local_only, bool classes_only, bool walk_defaults); |
65 | |
66 | // testing |
67 | bool eos(); |
68 | |
69 | // iterating |
70 | virtual void next() = 0; |
71 | |
72 | // accessors |
73 | InstanceKlass* klass() const { return _klass; } |
74 | int index() const { return _index; } |
75 | bool base_class_search_defaults() const { return _base_class_search_defaults; } |
76 | void base_class_search_defaults(bool b) { _base_class_search_defaults = b; } |
77 | }; |
78 | |
79 | |
80 | // A MethodStream streams over all methods in a class, superclasses and (super)interfaces. |
81 | // Streaming is done in reverse order (subclasses first, methods in reverse order) |
82 | // Usage: |
83 | // |
84 | // for (MethodStream st(k, false, false); !st.eos(); st.next()) { |
85 | // Method* m = st.method(); |
86 | // ... |
87 | // } |
88 | |
89 | class MethodStream : public KlassStream { |
90 | private: |
91 | int length() { return methods()->length(); } |
92 | Array<Method*>* methods() { |
93 | if (base_class_search_defaults()) { |
94 | base_class_search_defaults(false); |
95 | return _klass->default_methods(); |
96 | } else { |
97 | return _klass->methods(); |
98 | } |
99 | } |
100 | public: |
101 | MethodStream(InstanceKlass* klass, bool local_only, bool classes_only) |
102 | : KlassStream(klass, local_only, classes_only, true) { |
103 | _index = length(); |
104 | next(); |
105 | } |
106 | |
107 | void next() { _index--; } |
108 | Method* method() { return methods()->at(index()); } |
109 | }; |
110 | |
111 | |
112 | // A FieldStream streams over all fields in a class, superclasses and (super)interfaces. |
113 | // Streaming is done in reverse order (subclasses first, fields in reverse order) |
114 | // Usage: |
115 | // |
116 | // for (FieldStream st(k, false, false); !st.eos(); st.next()) { |
117 | // Symbol* field_name = st.name(); |
118 | // ... |
119 | // } |
120 | |
121 | |
122 | class FieldStream : public KlassStream { |
123 | private: |
124 | int length() { return _klass->java_fields_count(); } |
125 | |
126 | fieldDescriptor _fd_buf; |
127 | |
128 | public: |
129 | FieldStream(InstanceKlass* klass, bool local_only, bool classes_only) |
130 | : KlassStream(klass, local_only, classes_only, false) { |
131 | _index = length(); |
132 | next(); |
133 | } |
134 | |
135 | void next() { _index -= 1; } |
136 | |
137 | // Accessors for current field |
138 | AccessFlags access_flags() const { |
139 | AccessFlags flags; |
140 | flags.set_flags(_klass->field_access_flags(_index)); |
141 | return flags; |
142 | } |
143 | Symbol* name() const { |
144 | return _klass->field_name(_index); |
145 | } |
146 | Symbol* signature() const { |
147 | return _klass->field_signature(_index); |
148 | } |
149 | // missing: initval() |
150 | int offset() const { |
151 | return _klass->field_offset( index() ); |
152 | } |
153 | // bridge to a heavier API: |
154 | fieldDescriptor& field_descriptor() const { |
155 | fieldDescriptor& field = const_cast<fieldDescriptor&>(_fd_buf); |
156 | field.reinitialize(_klass, _index); |
157 | return field; |
158 | } |
159 | }; |
160 | |
161 | class FilteredField : public CHeapObj<mtInternal> { |
162 | private: |
163 | Klass* _klass; |
164 | int _field_offset; |
165 | |
166 | public: |
167 | FilteredField(Klass* klass, int field_offset) { |
168 | _klass = klass; |
169 | _field_offset = field_offset; |
170 | } |
171 | Klass* klass() { return _klass; } |
172 | int field_offset() { return _field_offset; } |
173 | }; |
174 | |
175 | class FilteredFieldsMap : AllStatic { |
176 | private: |
177 | static GrowableArray<FilteredField *> *_filtered_fields; |
178 | public: |
179 | static void initialize(); |
180 | static bool is_filtered_field(Klass* klass, int field_offset) { |
181 | for (int i=0; i < _filtered_fields->length(); i++) { |
182 | if (klass == _filtered_fields->at(i)->klass() && |
183 | field_offset == _filtered_fields->at(i)->field_offset()) { |
184 | return true; |
185 | } |
186 | } |
187 | return false; |
188 | } |
189 | static int filtered_fields_count(Klass* klass, bool local_only) { |
190 | int nflds = 0; |
191 | for (int i=0; i < _filtered_fields->length(); i++) { |
192 | if (local_only && klass == _filtered_fields->at(i)->klass()) { |
193 | nflds++; |
194 | } else if (klass->is_subtype_of(_filtered_fields->at(i)->klass())) { |
195 | nflds++; |
196 | } |
197 | } |
198 | return nflds; |
199 | } |
200 | }; |
201 | |
202 | |
203 | // A FilteredFieldStream streams over all fields in a class, superclasses and |
204 | // (super)interfaces. Streaming is done in reverse order (subclasses first, |
205 | // fields in reverse order) |
206 | // |
207 | // Usage: |
208 | // |
209 | // for (FilteredFieldStream st(k, false, false); !st.eos(); st.next()) { |
210 | // Symbol* field_name = st.name(); |
211 | // ... |
212 | // } |
213 | |
214 | class FilteredFieldStream : public FieldStream { |
215 | private: |
216 | int _filtered_fields_count; |
217 | bool has_filtered_field() { return (_filtered_fields_count > 0); } |
218 | |
219 | public: |
220 | FilteredFieldStream(InstanceKlass* klass, bool local_only, bool classes_only) |
221 | : FieldStream(klass, local_only, classes_only) { |
222 | _filtered_fields_count = FilteredFieldsMap::filtered_fields_count(klass, local_only); |
223 | } |
224 | int field_count(); |
225 | void next() { |
226 | _index -= 1; |
227 | if (has_filtered_field()) { |
228 | while (_index >=0 && FilteredFieldsMap::is_filtered_field((Klass*)_klass, offset())) { |
229 | _index -= 1; |
230 | } |
231 | } |
232 | } |
233 | }; |
234 | |
235 | #endif // SHARE_RUNTIME_REFLECTIONUTILS_HPP |
236 | |