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