1 /* 2 * Copyright (c) 2017, 2020, 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_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP 26 #define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP 27 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" 34 35 // Composite callback/functor building block 36 template <typename T, typename Func1, typename Func2> 37 class CompositeFunctor { 38 private: 39 Func1* _f; 40 Func2* _g; 41 public: 42 CompositeFunctor(Func1* f, Func2* g) : _f(f), _g(g) { 43 assert(f != NULL, "invariant"); 44 assert(g != NULL, "invariant"); 45 } 46 bool operator()(T const& value) { 47 return (*_f)(value) && (*_g)(value); 48 } 49 }; 50 51 class JfrArtifactClosure { 52 public: 53 virtual void do_artifact(const void* artifact) = 0; 54 }; 55 56 template <typename T, typename Callback> 57 class JfrArtifactCallbackHost : public JfrArtifactClosure { 58 private: 59 Callback* _callback; 60 public: 61 JfrArtifactCallbackHost(Callback* callback) : _callback(callback) {} 62 void do_artifact(const void* artifact) { 63 (*_callback)(reinterpret_cast<T const&>(artifact)); 64 } 65 }; 66 67 template <typename FieldSelector, typename Letter> 68 class KlassToFieldEnvelope { 69 Letter* _letter; 70 public: 71 KlassToFieldEnvelope(Letter* letter) : _letter(letter) {} 72 bool operator()(const Klass* klass) { 73 typename FieldSelector::TypePtr t = FieldSelector::select(klass); 74 return t != NULL ? (*_letter)(t) : true; 75 } 76 }; 77 78 template <typename T> 79 class ClearArtifact { 80 public: 81 bool operator()(T const& value) { 82 CLEAR_SERIALIZED(value); 83 assert(IS_NOT_SERIALIZED(value), "invariant"); 84 SET_PREV_EPOCH_CLEARED_BIT(value); 85 CLEAR_METHOD_AND_CLASS_PREV_EPOCH(value); 86 return true; 87 } 88 }; 89 90 template <> 91 class ClearArtifact<const Method*> { 92 public: 93 bool operator()(const Method* method) { 94 assert(METHOD_FLAG_USED_PREV_EPOCH(method), "invariant"); 95 CLEAR_METHOD_SERIALIZED(method); 96 assert(METHOD_NOT_SERIALIZED(method), "invariant"); 97 SET_PREV_EPOCH_METHOD_CLEARED_BIT(method); 98 CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method); 99 return true; 100 } 101 }; 102 103 template <typename T> 104 class SerializePredicate { 105 bool _class_unload; 106 public: 107 SerializePredicate(bool class_unload) : _class_unload(class_unload) {} 108 bool operator()(T const& value) { 109 assert(value != NULL, "invariant"); 110 return _class_unload ? true : IS_NOT_SERIALIZED(value); 111 } 112 }; 113 114 template <> 115 class SerializePredicate<const Method*> { 116 bool _class_unload; 117 public: 118 SerializePredicate(bool class_unload) : _class_unload(class_unload) {} 119 bool operator()(const Method* method) { 120 assert(method != NULL, "invariant"); 121 return _class_unload ? true : METHOD_NOT_SERIALIZED(method); 122 } 123 }; 124 125 template <typename T, bool leakp> 126 class SymbolPredicate { 127 bool _class_unload; 128 public: 129 SymbolPredicate(bool class_unload) : _class_unload(class_unload) {} 130 bool operator()(T const& value) { 131 assert(value != NULL, "invariant"); 132 if (_class_unload) { 133 return leakp ? value->is_leakp() : value->is_unloading(); 134 } 135 return leakp ? value->is_leakp() : !value->is_serialized(); 136 } 137 }; 138 139 template <bool leakp> 140 class MethodUsedPredicate { 141 bool _current_epoch; 142 public: 143 MethodUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {} 144 bool operator()(const Klass* klass) { 145 if (_current_epoch) { 146 return leakp ? IS_LEAKP(klass) : METHOD_USED_THIS_EPOCH(klass); 147 } 148 return leakp ? IS_LEAKP(klass) : METHOD_USED_PREV_EPOCH(klass); 149 } 150 }; 151 152 template <bool leakp> 153 class MethodFlagPredicate { 154 bool _current_epoch; 155 public: 156 MethodFlagPredicate(bool current_epoch) : _current_epoch(current_epoch) {} 157 bool operator()(const Method* method) { 158 if (_current_epoch) { 159 return leakp ? IS_METHOD_LEAKP_USED(method) : METHOD_FLAG_USED_THIS_EPOCH(method); 160 } 161 return leakp ? IS_METHOD_LEAKP_USED(method) : METHOD_FLAG_USED_PREV_EPOCH(method); 162 } 163 }; 164 165 template <typename T> 166 class LeakPredicate { 167 public: 168 LeakPredicate(bool class_unload) {} 169 bool operator()(T const& value) { 170 return IS_LEAKP(value); 171 } 172 }; 173 174 template <> 175 class LeakPredicate<const Method*> { 176 public: 177 LeakPredicate(bool class_unload) {} 178 bool operator()(const Method* method) { 179 assert(method != NULL, "invariant"); 180 return IS_METHOD_LEAKP_USED(method); 181 } 182 }; 183 184 template <typename T, typename IdType> 185 class ListEntry : public JfrHashtableEntry<T, IdType> { 186 public: 187 ListEntry(uintptr_t hash, const T& data) : JfrHashtableEntry<T, IdType>(hash, data), 188 _list_next(NULL), _serialized(false), _unloading(false), _leakp(false) {} 189 const ListEntry<T, IdType>* list_next() const { return _list_next; } 190 void reset() const { 191 _list_next = NULL; _serialized = false; _unloading = false; _leakp = false; 192 } 193 void set_list_next(const ListEntry<T, IdType>* next) const { _list_next = next; } 194 bool is_serialized() const { return _serialized; } 195 void set_serialized() const { _serialized = true; } 196 bool is_unloading() const { return _unloading; } 197 void set_unloading() const { _unloading = true; } 198 bool is_leakp() const { return _leakp; } 199 void set_leakp() const { _leakp = true; } 200 private: 201 mutable const ListEntry<T, IdType>* _list_next; 202 mutable bool _serialized; 203 mutable bool _unloading; 204 mutable bool _leakp; 205 }; 206 207 class JfrSymbolId : public JfrCHeapObj { 208 template <typename, typename, template<typename, typename> class, typename, size_t> 209 friend class HashTableHost; 210 typedef HashTableHost<const Symbol*, traceid, ListEntry, JfrSymbolId> SymbolTable; 211 typedef HashTableHost<const char*, traceid, ListEntry, JfrSymbolId> CStringTable; 212 friend class JfrArtifactSet; 213 public: 214 typedef SymbolTable::HashEntry SymbolEntry; 215 typedef CStringTable::HashEntry CStringEntry; 216 private: 217 SymbolTable* _sym_table; 218 CStringTable* _cstring_table; 219 const SymbolEntry* _sym_list; 220 const CStringEntry* _cstring_list; 221 const Symbol* _sym_query; 222 const char* _cstring_query; 223 traceid _symbol_id_counter; 224 bool _class_unload; 225 226 // hashtable(s) callbacks 227 void on_link(const SymbolEntry* entry); 228 bool on_equals(uintptr_t hash, const SymbolEntry* entry); 229 void on_unlink(const SymbolEntry* entry); 230 void on_link(const CStringEntry* entry); 231 bool on_equals(uintptr_t hash, const CStringEntry* entry); 232 void on_unlink(const CStringEntry* entry); 233 234 template <typename Functor, typename T> 235 void iterate(Functor& functor, const T* list) { 236 const T* symbol = list; 237 while (symbol != NULL) { 238 const T* next = symbol->list_next(); 239 functor(symbol); 240 symbol = next; 241 } 242 } 243 244 traceid mark_hidden_or_anon_klass_name(const InstanceKlass* k, bool leakp); 245 bool is_hidden_or_anon_klass(const Klass* k); 246 uintptr_t hidden_or_anon_klass_name_hash(const InstanceKlass* ik); 247 248 public: 249 JfrSymbolId(); 250 ~JfrSymbolId(); 251 252 void clear(); 253 void set_class_unload(bool class_unload); 254 255 traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); 256 traceid mark(const Klass* k, bool leakp); 257 traceid mark(const Symbol* symbol, bool leakp); 258 traceid mark(uintptr_t hash, const char* str, bool leakp); 259 traceid bootstrap_name(bool leakp); 260 261 template <typename Functor> 262 void iterate_symbols(Functor& functor) { 263 iterate(functor, _sym_list); 264 } 265 266 template <typename Functor> 267 void iterate_cstrings(Functor& functor) { 268 iterate(functor, _cstring_list); 269 } 270 271 bool has_entries() const { return has_symbol_entries() || has_cstring_entries(); } 272 bool has_symbol_entries() const { return _sym_list != NULL; } 273 bool has_cstring_entries() const { return _cstring_list != NULL; } 274 }; 275 276 /** 277 * When processing a set of artifacts, there will be a need 278 * to track transitive dependencies originating with each artifact. 279 * These might or might not be explicitly "tagged" at that point. 280 * With the introduction of "epochs" to allow for concurrent tagging, 281 * we attempt to avoid "tagging" an artifact to indicate its use in a 282 * previous epoch. This is mainly to reduce the risk for data races. 283 * Instead, JfrArtifactSet is used to track transitive dependencies 284 * during the write process itself. 285 * 286 * It can also provide opportunities for caching, as the ideal should 287 * be to reduce the amount of iterations neccessary for locating artifacts 288 * in the respective VM subsystems. 289 */ 290 class JfrArtifactSet : public JfrCHeapObj { 291 private: 292 JfrSymbolId* _symbol_id; 293 GrowableArray<const Klass*>* _klass_list; 294 size_t _total_count; 295 296 public: 297 JfrArtifactSet(bool class_unload); 298 ~JfrArtifactSet(); 299 300 // caller needs ResourceMark 301 void initialize(bool class_unload, bool clear = false); 302 303 traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); 304 traceid mark(const Klass* klass, bool leakp); 305 traceid mark(const Symbol* symbol, bool leakp); 306 traceid mark(uintptr_t hash, const char* const str, bool leakp); 307 traceid mark_hidden_or_anon_klass_name(const Klass* klass, bool leakp); 308 traceid bootstrap_name(bool leakp); 309 310 const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const; 311 const JfrSymbolId::SymbolEntry* map_symbol(uintptr_t hash) const; 312 const JfrSymbolId::CStringEntry* map_cstring(uintptr_t hash) const; 313 314 bool has_klass_entries() const; 315 int entries() const; 316 size_t total_count() const; 317 void register_klass(const Klass* k); 318 319 template <typename Functor> 320 void iterate_klasses(Functor& functor) const { 321 for (int i = 0; i < _klass_list->length(); ++i) { 322 if (!functor(_klass_list->at(i))) { 323 break; 324 } 325 } 326 } 327 328 template <typename T> 329 void iterate_symbols(T& functor) { 330 _symbol_id->iterate_symbols(functor); 331 } 332 333 template <typename T> 334 void iterate_cstrings(T& functor) { 335 _symbol_id->iterate_cstrings(functor); 336 } 337 338 template <typename Writer> 339 void tally(Writer& writer) { 340 _total_count += writer.count(); 341 } 342 343 }; 344 345 class KlassArtifactRegistrator { 346 private: 347 JfrArtifactSet* _artifacts; 348 public: 349 KlassArtifactRegistrator(JfrArtifactSet* artifacts) : 350 _artifacts(artifacts) { 351 assert(_artifacts != NULL, "invariant"); 352 } 353 354 bool operator()(const Klass* klass) { 355 assert(klass != NULL, "invariant"); 356 _artifacts->register_klass(klass); 357 return true; 358 } 359 }; 360 361 #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP