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 // 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_TYPES_JFRTYPESETUTILS_HPP
--- EOF ---