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 */ 24 25 #ifndef SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP 26 #define SHARE_VM_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 // 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 39 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 }; 55 56 class JfrArtifactClosure { 57 public: 58 virtual void do_artifact(const void* artifact) = 0; 59 }; 60 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 }; 71 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 }; 82 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 } 94 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 }; 113 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 }; 144 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 }; 163 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 }; 173 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 }; 183 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 }; 200 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 }; 209 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 }; 223 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; 236 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); 242 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); 248 249 JfrSymbolId(); 250 ~JfrSymbolId(); 251 252 void initialize(); 253 void clear(); 254 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); 260 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; 264 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 } 272 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 } 279 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 } 287 288 template <typename T> 289 void iterate_symbols(T& functor) { 290 _sym_table->iterate_entry(functor); 291 } 292 293 template <typename T> 294 void iterate_cstrings(T& functor) { 295 _cstring_table->iterate_entry(functor); 296 } 297 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 }; 302 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; 322 323 public: 324 JfrArtifactSet(bool class_unload); 325 ~JfrArtifactSet(); 326 327 // caller needs ResourceMark 328 void initialize(bool class_unload); 329 void clear(); 330 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); 336 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; 340 341 bool has_klass_entries() const; 342 int entries() const; 343 void register_klass(const Klass* k); 344 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 } 353 354 template <typename T> 355 void iterate_symbols(T& functor) { 356 _symbol_id->iterate_symbols(functor); 357 } 358 359 template <typename T> 360 void iterate_cstrings(T& functor) { 361 _symbol_id->iterate_cstrings(functor); 362 } 363 }; 364 365 class KlassArtifactRegistrator { 366 private: 367 JfrArtifactSet* _artifacts; 368 public: 369 KlassArtifactRegistrator(JfrArtifactSet* artifacts) : 370 _artifacts(artifacts) { 371 assert(_artifacts != NULL, "invariant"); 372 } 373 374 bool operator()(const Klass* klass) { 375 assert(klass != NULL, "invariant"); 376 _artifacts->register_klass(klass); 377 return true; 378 } 379 }; 380 381 #endif // SHARE_VM_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP