Mon, 19 Aug 2019 12:47:38 +0200
8229873: 8229401 broke jdk8u-jfr-incubator
Reviewed-by: neugens
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 SymbolTable* _sym_table;
234 CStringTable* _cstring_table;
235 traceid _symbol_id_counter;
237 // hashtable(s) callbacks
238 void assign_id(SymbolEntry* entry);
239 bool equals(const Symbol* query, uintptr_t hash, const SymbolEntry* entry);
240 void assign_id(CStringEntry* entry);
241 bool equals(const char* query, uintptr_t hash, const CStringEntry* entry);
243 public:
244 static bool is_anonymous_klass(const Klass* k);
245 static const char* create_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t& hashcode);
246 static uintptr_t anonymous_klass_name_hash_code(const InstanceKlass* ik);
247 static uintptr_t regular_klass_name_hash_code(const Klass* k);
249 JfrSymbolId();
250 ~JfrSymbolId();
252 void initialize();
253 void clear();
255 traceid mark_anonymous_klass_name(const Klass* k);
256 traceid mark(const Symbol* sym, uintptr_t hash);
257 traceid mark(const Klass* k);
258 traceid mark(const Symbol* symbol);
259 traceid mark(const char* str, uintptr_t hash);
261 const SymbolEntry* map_symbol(const Symbol* symbol) const;
262 const SymbolEntry* map_symbol(uintptr_t hash) const;
263 const CStringEntry* map_cstring(uintptr_t hash) const;
265 template <typename T>
266 void symbol(T& functor, const Klass* k) {
267 if (is_anonymous_klass(k)) {
268 return;
269 }
270 functor(map_symbol(regular_klass_name_hash_code(k)));
271 }
273 template <typename T>
274 void symbol(T& functor, const Method* method) {
275 assert(method != NULL, "invariant");
276 functor(map_symbol((uintptr_t)method->name()->identity_hash()));
277 functor(map_symbol((uintptr_t)method->signature()->identity_hash()));
278 }
280 template <typename T>
281 void cstring(T& functor, const Klass* k) {
282 if (!is_anonymous_klass(k)) {
283 return;
284 }
285 functor(map_cstring(anonymous_klass_name_hash_code((const InstanceKlass*)k)));
286 }
288 template <typename T>
289 void iterate_symbols(T& functor) {
290 _sym_table->iterate_entry(functor);
291 }
293 template <typename T>
294 void iterate_cstrings(T& functor) {
295 _cstring_table->iterate_entry(functor);
296 }
298 bool has_entries() const { return has_symbol_entries() || has_cstring_entries(); }
299 bool has_symbol_entries() const { return _sym_table->has_entries(); }
300 bool has_cstring_entries() const { return _cstring_table->has_entries(); }
301 };
303 /**
304 * When processing a set of artifacts, there will be a need
305 * to track transitive dependencies originating with each artifact.
306 * These might or might not be explicitly "tagged" at that point.
307 * With the introduction of "epochs" to allow for concurrent tagging,
308 * we attempt to avoid "tagging" an artifact to indicate its use in a
309 * previous epoch. This is mainly to reduce the risk for data races.
310 * Instead, JfrArtifactSet is used to track transitive dependencies
311 * during the write process itself.
312 *
313 * It can also provide opportunities for caching, as the ideal should
314 * be to reduce the amount of iterations neccessary for locating artifacts
315 * in the respective VM subsystems.
316 */
317 class JfrArtifactSet : public JfrCHeapObj {
318 private:
319 JfrSymbolId* _symbol_id;
320 GrowableArray<const Klass*>* _klass_list;
321 bool _class_unload;
323 public:
324 JfrArtifactSet(bool class_unload);
325 ~JfrArtifactSet();
327 // caller needs ResourceMark
328 void initialize(bool class_unload);
329 void clear();
331 traceid mark(const Symbol* sym, uintptr_t hash);
332 traceid mark(const Klass* klass);
333 traceid mark(const Symbol* symbol);
334 traceid mark(const char* const str, uintptr_t hash);
335 traceid mark_anonymous_klass_name(const Klass* klass);
337 const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const;
338 const JfrSymbolId::SymbolEntry* map_symbol(uintptr_t hash) const;
339 const JfrSymbolId::CStringEntry* map_cstring(uintptr_t hash) const;
341 bool has_klass_entries() const;
342 int entries() const;
343 void register_klass(const Klass* k);
345 template <typename Functor>
346 void iterate_klasses(Functor& functor) const {
347 for (int i = 0; i < _klass_list->length(); ++i) {
348 if (!functor(_klass_list->at(i))) {
349 break;
350 }
351 }
352 }
354 template <typename T>
355 void iterate_symbols(T& functor) {
356 _symbol_id->iterate_symbols(functor);
357 }
359 template <typename T>
360 void iterate_cstrings(T& functor) {
361 _symbol_id->iterate_cstrings(functor);
362 }
363 };
365 class KlassArtifactRegistrator {
366 private:
367 JfrArtifactSet* _artifacts;
368 public:
369 KlassArtifactRegistrator(JfrArtifactSet* artifacts) :
370 _artifacts(artifacts) {
371 assert(_artifacts != NULL, "invariant");
372 }
374 bool operator()(const Klass* klass) {
375 assert(klass != NULL, "invariant");
376 _artifacts->register_klass(klass);
377 return true;
378 }
379 };
381 #endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP