1 /* 2 * Copyright (c) 2017, 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_VM_JFR_RECORDER_CHECKPOINT_CONSTANT_JFRTAGSETUTILS_HPP 26 #define SHARE_VM_JFR_RECORDER_CHECKPOINT_CONSTANT_JFRTAGSETUTILS_HPP 27 28 #include "jfr/recorder/checkpoint/constant/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 void tag_leakp_artifact(T const& value, bool class_unload) { 80 assert(value != NULL, "invariant"); 81 if (class_unload) { 82 SET_LEAKP_USED_THIS_EPOCH(value); 83 assert(LEAKP_USED_THIS_EPOCH(value), "invariant"); 84 } else { 85 SET_LEAKP_USED_PREV_EPOCH(value); 86 assert(LEAKP_USED_PREV_EPOCH(value), "invariant"); 87 } 88 } 89 90 template <typename T> 91 class LeakpClearArtifact { 92 bool _class_unload; 93 public: 94 LeakpClearArtifact(bool class_unload) : _class_unload(class_unload) {} 95 bool operator()(T const& value) { 96 if (_class_unload) { 97 if (LEAKP_USED_THIS_EPOCH(value)) { 98 LEAKP_UNUSE_THIS_EPOCH(value); 99 } 100 } else { 101 if (LEAKP_USED_PREV_EPOCH(value)) { 102 LEAKP_UNUSE_PREV_EPOCH(value); 103 } 104 } 105 return true; 106 } 107 }; 108 109 template <typename T> 110 class ClearArtifact { 111 bool _class_unload; 112 public: 113 ClearArtifact(bool class_unload) : _class_unload(class_unload) {} 114 bool operator()(T const& value) { 115 if (_class_unload) { 116 if (LEAKP_USED_THIS_EPOCH(value)) { 117 LEAKP_UNUSE_THIS_EPOCH(value); 118 } 119 if (USED_THIS_EPOCH(value)) { 120 UNUSE_THIS_EPOCH(value); 121 } 122 if (METHOD_USED_THIS_EPOCH(value)) { 123 UNUSE_METHOD_THIS_EPOCH(value); 124 } 125 } else { 126 if (LEAKP_USED_PREV_EPOCH(value)) { 127 LEAKP_UNUSE_PREV_EPOCH(value); 128 } 129 if (USED_PREV_EPOCH(value)) { 130 UNUSE_PREV_EPOCH(value); 131 } 132 if (METHOD_USED_PREV_EPOCH(value)) { 133 UNUSE_METHOD_PREV_EPOCH(value); 134 } 135 } 136 return true; 137 } 138 }; 139 140 template <> 141 class ClearArtifact<const Method*> { 142 bool _class_unload; 143 public: 144 ClearArtifact(bool class_unload) : _class_unload(class_unload) {} 145 bool operator()(const Method* method) { 146 if (_class_unload) { 147 if (METHOD_FLAG_USED_THIS_EPOCH(method)) { 148 CLEAR_METHOD_FLAG_USED_THIS_EPOCH(method); 149 } 150 } else { 151 if (METHOD_FLAG_USED_PREV_EPOCH(method)) { 152 CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method); 153 } 154 } 155 return true; 156 } 157 }; 158 159 template <typename T> 160 class LeakPredicate { 161 bool _class_unload; 162 public: 163 LeakPredicate(bool class_unload) : _class_unload(class_unload) {} 164 bool operator()(T const& value) { 165 return _class_unload ? LEAKP_USED_THIS_EPOCH(value) : LEAKP_USED_PREV_EPOCH(value); 166 } 167 }; 168 169 template <typename T> 170 class UsedPredicate { 171 bool _class_unload; 172 public: 173 UsedPredicate(bool class_unload) : _class_unload(class_unload) {} 174 bool operator()(T const& value) { 175 return _class_unload ? USED_THIS_EPOCH(value) : USED_PREV_EPOCH(value); 176 } 177 }; 178 179 template <typename T, int compare(const T&, const T&)> 180 class UniquePredicate { 181 private: 182 GrowableArray<T> _seen; 183 public: 184 UniquePredicate(bool) : _seen() {} 185 bool operator()(T const& value) { 186 bool not_unique; 187 _seen.template find_sorted<T, compare>(value, not_unique); 188 if (not_unique) { 189 return false; 190 } 191 _seen.template insert_sorted<compare>(value); 192 return true; 193 } 194 }; 195 196 class MethodFlagPredicate { 197 bool _class_unload; 198 public: 199 MethodFlagPredicate(bool class_unload) : _class_unload(class_unload) {} 200 bool operator()(const Method* method) { 201 return _class_unload ? METHOD_FLAG_USED_THIS_EPOCH(method) : METHOD_FLAG_USED_PREV_EPOCH(method); 202 } 203 }; 204 205 template <bool leakp> 206 class MethodUsedPredicate { 207 bool _class_unload; 208 public: 209 MethodUsedPredicate(bool class_unload) : _class_unload(class_unload) {} 210 bool operator()(const Klass* klass) { 211 assert(ANY_USED(klass), "invariant"); 212 if (_class_unload) { 213 return leakp ? LEAKP_METHOD_USED_THIS_EPOCH(klass) : METHOD_USED_THIS_EPOCH(klass); 214 } 215 return leakp ? LEAKP_METHOD_USED_PREV_EPOCH(klass) : METHOD_USED_PREV_EPOCH(klass); 216 } 217 }; 218 219 class JfrSymbolId : public JfrCHeapObj { 220 template <typename, typename, template<typename, typename> class, typename, size_t> 221 friend class HashTableHost; 222 typedef HashTableHost<const Symbol*, traceid, Entry, JfrSymbolId> SymbolTable; 223 typedef HashTableHost<const char*, traceid, Entry, JfrSymbolId> CStringTable; 224 public: 225 typedef SymbolTable::HashEntry SymbolEntry; 226 typedef CStringTable::HashEntry CStringEntry; 227 private: 228 SymbolTable* _sym_table; 229 CStringTable* _cstring_table; 230 traceid _symbol_id_counter; 231 232 // hashtable(s) callbacks 233 void assign_id(SymbolEntry* entry); 234 bool equals(const Symbol* query, uintptr_t hash, const SymbolEntry* entry); 235 void assign_id(CStringEntry* entry); 236 bool equals(const char* query, uintptr_t hash, const CStringEntry* entry); 237 238 public: 239 static bool is_anonymous_klass(const Klass* k); 240 static const char* create_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t& hashcode); 241 static uintptr_t anonymous_klass_name_hash_code(const InstanceKlass* ik); 242 static uintptr_t regular_klass_name_hash_code(const Klass* k); 243 244 JfrSymbolId(); 245 ~JfrSymbolId(); 246 247 void initialize(); 248 void clear(); 249 250 traceid mark_anonymous_klass_name(const Klass* k); 251 traceid mark(const Symbol* sym, uintptr_t hash); 252 traceid mark(const Klass* k); 253 traceid mark(const Symbol* symbol); 254 traceid mark(const char* str, uintptr_t hash); 255 256 const SymbolEntry* map_symbol(const Symbol* symbol) const; 257 const SymbolEntry* map_symbol(uintptr_t hash) const; 258 const CStringEntry* map_cstring(uintptr_t hash) const; 259 260 template <typename T> 261 void symbol(T& functor, const Klass* k) { 262 if (is_anonymous_klass(k)) { 263 return; 264 } 265 functor(map_symbol(regular_klass_name_hash_code(k))); 266 } 267 268 template <typename T> 269 void symbol(T& functor, const Method* method) { 270 assert(method != NULL, "invariant"); 271 functor(map_symbol((uintptr_t)method->name()->identity_hash())); 272 functor(map_symbol((uintptr_t)method->signature()->identity_hash())); 273 } 274 275 template <typename T> 276 void cstring(T& functor, const Klass* k) { 277 if (!is_anonymous_klass(k)) { 278 return; 279 } 280 functor(map_cstring(anonymous_klass_name_hash_code((const InstanceKlass*)k))); 281 } 282 283 template <typename T> 284 void iterate_symbols(T& functor) { 285 _sym_table->iterate_entry(functor); 286 } 287 288 template <typename T> 289 void iterate_cstrings(T& functor) { 290 _cstring_table->iterate_entry(functor); 291 } 292 293 bool has_entries() const { return has_symbol_entries() || has_cstring_entries(); } 294 bool has_symbol_entries() const { return _sym_table->has_entries(); } 295 bool has_cstring_entries() const { return _cstring_table->has_entries(); } 296 }; 297 298 // external name (synthetic) for the primordial "boot" class loader instance 299 const char* const boot_class_loader_name = "boot"; 300 301 /** 302 * When processing a set of artifacts, there will be a need 303 * to track transitive dependencies originating with each artifact. 304 * These might or might not be explicitly "tagged" at that point. 305 * With the introduction of "epochs" to allow for concurrent tagging, 306 * we attempt to avoid "tagging" an artifact to indicate its use in a 307 * previous epoch. This is mainly to reduce the risk for data races. 308 * Instead, JfrArtifactSet is used to track transitive dependencies 309 * during the write process itself. 310 * 311 * It can also provide opportunities for caching, as the ideal should 312 * be to reduce the amount of iterations neccessary for locating artifacts 313 * in the respective VM subsystems. 314 */ 315 class JfrArtifactSet : public JfrCHeapObj { 316 private: 317 JfrSymbolId* _symbol_id; 318 GrowableArray<const Klass*>* _klass_list; 319 bool _class_unload; 320 321 public: 322 JfrArtifactSet(bool class_unload); 323 ~JfrArtifactSet(); 324 325 // caller needs ResourceMark 326 void initialize(bool class_unload); 327 void clear(); 328 329 traceid mark(const Symbol* sym, uintptr_t hash); 330 traceid mark(const Klass* klass); 331 traceid mark(const Symbol* symbol); 332 traceid mark(const char* const str, uintptr_t hash); 333 traceid mark_anonymous_klass_name(const Klass* klass); 334 335 const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const; 336 const JfrSymbolId::SymbolEntry* map_symbol(uintptr_t hash) const; 337 const JfrSymbolId::CStringEntry* map_cstring(uintptr_t hash) const; 338 339 bool has_klass_entries() const; 340 int entries() const; 341 void register_klass(const Klass* k); 342 343 template <typename Functor> 344 void iterate_klasses(Functor& functor) const { 345 for (int i = 0; i < _klass_list->length(); ++i) { 346 if (!functor(_klass_list->at(i))) { 347 break; 348 } 349 } 350 } 351 352 template <typename T> 353 void iterate_symbols(T& functor) { 354 _symbol_id->iterate_symbols(functor); 355 } 356 357 template <typename T> 358 void iterate_cstrings(T& functor) { 359 _symbol_id->iterate_cstrings(functor); 360 } 361 }; 362 363 class KlassArtifactRegistrator { 364 private: 365 JfrArtifactSet* _artifacts; 366 public: 367 KlassArtifactRegistrator(JfrArtifactSet* artifacts) : 368 _artifacts(artifacts) { 369 assert(_artifacts != NULL, "invariant"); 370 } 371 372 bool operator()(const Klass* klass) { 373 assert(klass != NULL, "invariant"); 374 _artifacts->register_klass(klass); 375 return true; 376 } 377 }; 378 379 #endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_CONSTANT_JFRTAGSETUTILS_HPP