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
klass() const73   InstanceKlass* klass() const      { return _klass; }
index() const74   int index() const                 { return _index; }
base_class_search_defaults() const75   bool base_class_search_defaults() const { return _base_class_search_defaults; }
base_class_search_defaults(bool b)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:
length()91   int length()                    { return methods()->length(); }
methods()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:
MethodStream(InstanceKlass * klass,bool local_only,bool classes_only)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 
next()107   void next() { _index--; }
method()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:
length()124   int length() { return _klass->java_fields_count(); }
125 
126   fieldDescriptor _fd_buf;
127 
128  public:
FieldStream(InstanceKlass * klass,bool local_only,bool classes_only)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 
next()135   void next() { _index -= 1; }
136 
137   // Accessors for current field
access_flags() const138   AccessFlags access_flags() const {
139     AccessFlags flags;
140     flags.set_flags(_klass->field_access_flags(_index));
141     return flags;
142   }
name() const143   Symbol* name() const {
144     return _klass->field_name(_index);
145   }
signature() const146   Symbol* signature() const {
147     return _klass->field_signature(_index);
148   }
149   // missing: initval()
offset() const150   int offset() const {
151     return _klass->field_offset( index() );
152   }
153   // bridge to a heavier API:
field_descriptor() const154   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:
FilteredField(Klass * klass,int field_offset)167   FilteredField(Klass* klass, int field_offset) {
168     _klass = klass;
169     _field_offset = field_offset;
170   }
klass()171   Klass* klass() { return _klass; }
field_offset()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();
is_filtered_field(Klass * klass,int field_offset)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   }
filtered_fields_count(Klass * klass,bool local_only)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;
has_filtered_field()217   bool has_filtered_field() { return (_filtered_fields_count > 0); }
218 
219  public:
FilteredFieldStream(InstanceKlass * klass,bool local_only,bool classes_only)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();
next()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