Mon, 15 Jun 2020 14:08:11 +0300
8245167: Top package in method profiling shows null in JMC
Reviewed-by: neugens
Contributed-by: asemenov@azul.com
1 /*
2 * Copyright (c) 2017, 2018, 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 */
25 #ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP
26 #define SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP
28 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
29 #include "jfr/utilities/jfrAllocation.hpp"
30 #include "jfr/utilities/jfrHashtable.hpp"
31 #include "oops/klass.hpp"
32 #include "oops/method.hpp"
33 #include "utilities/growableArray.hpp"
35 // XXX is it correct?
36 // external name (synthetic) for the primordial "bootstrap" class loader instance
37 #define BOOTSTRAP_LOADER_NAME "<bootloader>" // XXX bootstrap
38 #define BOOTSTRAP_LOADER_NAME_LEN 9
40 // Composite callback/functor building block
41 template <typename T, typename Func1, typename Func2>
42 class CompositeFunctor {
43 private:
44 Func1* _f;
45 Func2* _g;
46 public:
47 CompositeFunctor(Func1* f, Func2* g) : _f(f), _g(g) {
48 assert(f != NULL, "invariant");
49 assert(g != NULL, "invariant");
50 }
51 bool operator()(T const& value) {
52 return (*_f)(value) && (*_g)(value);
53 }
54 };
56 class JfrArtifactClosure {
57 public:
58 virtual void do_artifact(const void* artifact) = 0;
59 };
61 template <typename T, typename Callback>
62 class JfrArtifactCallbackHost : public JfrArtifactClosure {
63 private:
64 Callback* _callback;
65 public:
66 JfrArtifactCallbackHost(Callback* callback) : _callback(callback) {}
67 void do_artifact(const void* artifact) {
68 (*_callback)(reinterpret_cast<T const&>(artifact));
69 }
70 };
72 template <typename FieldSelector, typename Letter>
73 class KlassToFieldEnvelope {
74 Letter* _letter;
75 public:
76 KlassToFieldEnvelope(Letter* letter) : _letter(letter) {}
77 bool operator()(const Klass* klass) {
78 typename FieldSelector::TypePtr t = FieldSelector::select(klass);
79 return t != NULL ? (*_letter)(t) : true;
80 }
81 };
83 template <typename T>
84 void tag_leakp_artifact(T const& value, bool class_unload) {
85 assert(value != NULL, "invariant");
86 if (class_unload) {
87 SET_LEAKP_USED_THIS_EPOCH(value);
88 assert(LEAKP_USED_THIS_EPOCH(value), "invariant");
89 } else {
90 SET_LEAKP_USED_PREV_EPOCH(value);
91 assert(LEAKP_USED_PREV_EPOCH(value), "invariant");
92 }
93 }
95 template <typename T>
96 class LeakpClearArtifact {
97 bool _class_unload;
98 public:
99 LeakpClearArtifact(bool class_unload) : _class_unload(class_unload) {}
100 bool operator()(T const& value) {
101 if (_class_unload) {
102 if (LEAKP_USED_THIS_EPOCH(value)) {
103 LEAKP_UNUSE_THIS_EPOCH(value);
104 }
105 } else {
106 if (LEAKP_USED_PREV_EPOCH(value)) {
107 LEAKP_UNUSE_PREV_EPOCH(value);
108 }
109 }
110 return true;
111 }
112 };
114 template <typename T>
115 class ClearArtifact {
116 bool _class_unload;
117 public:
118 ClearArtifact(bool class_unload) : _class_unload(class_unload) {}
119 bool operator()(T const& value) {
120 if (_class_unload) {
121 if (LEAKP_USED_THIS_EPOCH(value)) {
122 LEAKP_UNUSE_THIS_EPOCH(value);
123 }
124 if (USED_THIS_EPOCH(value)) {
125 UNUSE_THIS_EPOCH(value);
126 }
127 if (METHOD_USED_THIS_EPOCH(value)) {
128 UNUSE_METHOD_THIS_EPOCH(value);
129 }
130 } else {
131 if (LEAKP_USED_PREV_EPOCH(value)) {
132 LEAKP_UNUSE_PREV_EPOCH(value);
133 }
134 if (USED_PREV_EPOCH(value)) {
135 UNUSE_PREV_EPOCH(value);
136 }
137 if (METHOD_USED_PREV_EPOCH(value)) {
138 UNUSE_METHOD_PREV_EPOCH(value);
139 }
140 }
141 return true;
142 }
143 };
145 template <>
146 class ClearArtifact<const Method*> {
147 bool _class_unload;
148 public:
149 ClearArtifact(bool class_unload) : _class_unload(class_unload) {}
150 bool operator()(const Method* method) {
151 if (_class_unload) {
152 if (METHOD_FLAG_USED_THIS_EPOCH(method)) {
153 CLEAR_METHOD_FLAG_USED_THIS_EPOCH(method);
154 }
155 } else {
156 if (METHOD_FLAG_USED_PREV_EPOCH(method)) {
157 CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method);
158 }
159 }
160 return true;
161 }
162 };
164 template <typename T>
165 class LeakPredicate {
166 bool _class_unload;
167 public:
168 LeakPredicate(bool class_unload) : _class_unload(class_unload) {}
169 bool operator()(T const& value) {
170 return _class_unload ? LEAKP_USED_THIS_EPOCH(value) : LEAKP_USED_PREV_EPOCH(value);
171 }
172 };
174 template <typename T>
175 class UsedPredicate {
176 bool _class_unload;
177 public:
178 UsedPredicate(bool class_unload) : _class_unload(class_unload) {}
179 bool operator()(T const& value) {
180 return _class_unload ? USED_THIS_EPOCH(value) : USED_PREV_EPOCH(value);
181 }
182 };
184 template <typename T, int compare(const T&, const T&)>
185 class UniquePredicate {
186 private:
187 GrowableArray<T> _seen;
188 public:
189 UniquePredicate(bool) : _seen() {}
190 bool operator()(T const& value) {
191 bool not_unique;
192 _seen.template find_sorted<T, compare>(value, not_unique);
193 if (not_unique) {
194 return false;
195 }
196 _seen.template insert_sorted<compare>(value);
197 return true;
198 }
199 };
201 class MethodFlagPredicate {
202 bool _class_unload;
203 public:
204 MethodFlagPredicate(bool class_unload) : _class_unload(class_unload) {}
205 bool operator()(const Method* method) {
206 return _class_unload ? METHOD_FLAG_USED_THIS_EPOCH(method) : METHOD_FLAG_USED_PREV_EPOCH(method);
207 }
208 };
210 template <bool leakp>
211 class MethodUsedPredicate {
212 bool _class_unload;
213 public:
214 MethodUsedPredicate(bool class_unload) : _class_unload(class_unload) {}
215 bool operator()(const Klass* klass) {
216 assert(ANY_USED(klass), "invariant");
217 if (_class_unload) {
218 return leakp ? LEAKP_METHOD_USED_THIS_EPOCH(klass) : METHOD_USED_THIS_EPOCH(klass);
219 }
220 return leakp ? LEAKP_METHOD_USED_PREV_EPOCH(klass) : METHOD_USED_PREV_EPOCH(klass);
221 }
222 };
224 class JfrSymbolId : public JfrCHeapObj {
225 template <typename, typename, template<typename, typename> class, typename, size_t>
226 friend class HashTableHost;
227 typedef HashTableHost<const Symbol*, traceid, Entry, JfrSymbolId> SymbolTable;
228 typedef HashTableHost<const char*, traceid, Entry, JfrSymbolId> CStringTable;
229 public:
230 typedef SymbolTable::HashEntry SymbolEntry;
231 typedef CStringTable::HashEntry CStringEntry;
232 private:
233 traceid _symbol_id_counter;
234 SymbolTable* _sym_table;
235 CStringTable* _cstring_table;
236 CStringTable* _pkg_table;
238 // hashtable(s) callbacks
239 void assign_id(SymbolEntry* entry);
240 bool equals(const Symbol* query, uintptr_t hash, const SymbolEntry* entry);
241 void assign_id(CStringEntry* entry);
242 bool equals(const char* query, uintptr_t hash, const CStringEntry* entry);
244 public:
245 static bool is_anonymous_klass(const Klass* k);
246 static const char* create_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t& hashcode);
247 static uintptr_t anonymous_klass_name_hash_code(const InstanceKlass* ik);
248 static uintptr_t regular_klass_name_hash_code(const Klass* k);
250 JfrSymbolId();
251 ~JfrSymbolId();
253 void initialize();
254 void clear();
256 traceid mark_anonymous_klass_name(const Klass* k);
257 traceid mark(const Symbol* sym, uintptr_t hash);
258 traceid mark(const Klass* k);
259 traceid mark(const Symbol* symbol);
260 traceid mark(const char* str, uintptr_t hash);
261 traceid markPackage(const char* name, uintptr_t hash);
263 template <typename T>
264 void iterate_packages(T& functor) {
265 _pkg_table->iterate_entry(functor);
266 }
268 const SymbolEntry* map_symbol(const Symbol* symbol) const;
269 const SymbolEntry* map_symbol(uintptr_t hash) const;
270 const CStringEntry* map_cstring(uintptr_t hash) const;
272 template <typename T>
273 void symbol(T& functor, const Klass* k) {
274 if (is_anonymous_klass(k)) {
275 return;
276 }
277 functor(map_symbol(regular_klass_name_hash_code(k)));
278 }
280 template <typename T>
281 void symbol(T& functor, const Method* method) {
282 assert(method != NULL, "invariant");
283 functor(map_symbol((uintptr_t)method->name()->identity_hash()));
284 functor(map_symbol((uintptr_t)method->signature()->identity_hash()));
285 }
287 template <typename T>
288 void cstring(T& functor, const Klass* k) {
289 if (!is_anonymous_klass(k)) {
290 return;
291 }
292 functor(map_cstring(anonymous_klass_name_hash_code((const InstanceKlass*)k)));
293 }
295 template <typename T>
296 void iterate_symbols(T& functor) {
297 _sym_table->iterate_entry(functor);
298 }
300 template <typename T>
301 void iterate_cstrings(T& functor) {
302 _cstring_table->iterate_entry(functor);
303 }
305 bool has_entries() const { return has_symbol_entries() || has_cstring_entries(); }
306 bool has_symbol_entries() const { return _sym_table->has_entries(); }
307 bool has_cstring_entries() const { return _cstring_table->has_entries(); }
308 };
310 /**
311 * When processing a set of artifacts, there will be a need
312 * to track transitive dependencies originating with each artifact.
313 * These might or might not be explicitly "tagged" at that point.
314 * With the introduction of "epochs" to allow for concurrent tagging,
315 * we attempt to avoid "tagging" an artifact to indicate its use in a
316 * previous epoch. This is mainly to reduce the risk for data races.
317 * Instead, JfrArtifactSet is used to track transitive dependencies
318 * during the write process itself.
319 *
320 * It can also provide opportunities for caching, as the ideal should
321 * be to reduce the amount of iterations neccessary for locating artifacts
322 * in the respective VM subsystems.
323 */
324 class JfrArtifactSet : public JfrCHeapObj {
325 private:
326 JfrSymbolId* _symbol_id;
327 GrowableArray<const Klass*>* _klass_list;
328 bool _class_unload;
330 public:
331 JfrArtifactSet(bool class_unload);
332 ~JfrArtifactSet();
334 // caller needs ResourceMark
335 void initialize(bool class_unload);
336 void clear();
338 traceid mark(const Symbol* sym, uintptr_t hash);
339 traceid mark(const Klass* klass);
340 traceid mark(const Symbol* symbol);
341 traceid mark(const char* const str, uintptr_t hash);
342 traceid mark_anonymous_klass_name(const Klass* klass);
344 traceid markPackage(const char* const name, uintptr_t hash);
346 const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const;
347 const JfrSymbolId::SymbolEntry* map_symbol(uintptr_t hash) const;
348 const JfrSymbolId::CStringEntry* map_cstring(uintptr_t hash) const;
350 bool has_klass_entries() const;
351 int entries() const;
352 void register_klass(const Klass* k);
354 template <typename Functor>
355 void iterate_klasses(Functor& functor) const {
356 for (int i = 0; i < _klass_list->length(); ++i) {
357 if (!functor(_klass_list->at(i))) {
358 break;
359 }
360 }
361 }
363 template <typename T>
364 void iterate_symbols(T& functor) {
365 _symbol_id->iterate_symbols(functor);
366 }
368 template <typename T>
369 void iterate_cstrings(T& functor) {
370 _symbol_id->iterate_cstrings(functor);
371 }
373 template <typename T>
374 void iterate_packages(T& functor) {
375 _symbol_id->iterate_packages(functor);
376 }
377 };
379 class KlassArtifactRegistrator {
380 private:
381 JfrArtifactSet* _artifacts;
382 public:
383 KlassArtifactRegistrator(JfrArtifactSet* artifacts) :
384 _artifacts(artifacts) {
385 assert(_artifacts != NULL, "invariant");
386 }
388 bool operator()(const Klass* klass) {
389 assert(klass != NULL, "invariant");
390 _artifacts->register_klass(klass);
391 return true;
392 }
393 };
395 #endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP