1 /*
  2  * Copyright (c) 2023, 2024, 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_OOPS_TRAININGDATA_HPP
 26 #define SHARE_OOPS_TRAININGDATA_HPP
 27 
 28 #include "cds/archiveUtils.hpp"
 29 #include "classfile/compactHashtable.hpp"
 30 #include "compiler/compilerDefinitions.hpp"
 31 #include "compiler/compiler_globals.hpp"
 32 #include "memory/allocation.hpp"
 33 #include "memory/metaspaceClosure.hpp"
 34 #include "oops/instanceKlass.hpp"
 35 #include "oops/symbolHandle.hpp"
 36 #include "runtime/fieldDescriptor.inline.hpp"
 37 #include "runtime/handles.hpp"
 38 #include "runtime/mutexLocker.hpp"
 39 #include "utilities/count_leading_zeros.hpp"
 40 #include "utilities/resizeableResourceHash.hpp"
 41 
 42 class ciEnv;
 43 class ciBaseObject;
 44 class CompileTask;
 45 class xmlStream;
 46 class CompileTrainingData;
 47 class KlassTrainingData;
 48 class MethodTrainingData;
 49 class TrainingDataDumper;
 50 class TrainingDataSetLocker;
 51 class DumpTimeTrainingDataInfo;
 52 class RunTimeClassInfo;
 53 class RunTimeMethodDataInfo;
 54 
 55 class TrainingData : public Metadata {
 56   friend KlassTrainingData;
 57   friend MethodTrainingData;
 58   friend CompileTrainingData;
 59  public:
 60   class Key {
 61     mutable Metadata* _meta;
 62     // These guys can get to my constructors:
 63     friend TrainingData;
 64     friend KlassTrainingData;
 65     friend MethodTrainingData;
 66     friend CompileTrainingData;
 67 
 68     // The empty key
 69     Key() : _meta(nullptr) { }
 70     bool is_empty() const { return _meta == nullptr; }
 71   public:
 72     Key(Metadata* meta) : _meta(meta) { }
 73 
 74     static bool can_compute_cds_hash(const Key* const& k);
 75     static uint cds_hash(const Key* const& k);
 76     static unsigned hash(const Key* const& k) {
 77       return primitive_hash(k->meta());
 78     }
 79     static bool equals(const Key* const& k1, const Key* const& k2) {
 80       return k1->meta() == k2->meta();
 81     }
 82     static inline bool equals(TrainingData* value, const TrainingData::Key* key, int unused) {
 83       return equals(value->key(), key);
 84     }
 85     int cmp(const Key* that) const {
 86       auto m1 = this->meta();
 87       auto m2 = that->meta();
 88       if (m1 < m2) return -1;
 89       if (m1 > m2) return +1;
 90       return 0;
 91     }
 92     Metadata* meta() const { return _meta; }
 93     void metaspace_pointers_do(MetaspaceClosure *iter);
 94     void make_empty() const { _meta = nullptr; }
 95   };
 96 
 97   class TrainingDataLocker {
 98     static volatile bool _snapshot;
 99     static int _lock_mode;
100     static void lock() {
101       assert(_lock_mode != 0, "Forgot to call TrainingDataLocker::initialize()");
102       if (_lock_mode > 0) {
103         TrainingData_lock->lock();
104       }
105     }
106     static void unlock() {
107       if (_lock_mode > 0) {
108         TrainingData_lock->unlock();
109       }
110     }
111     static bool safely_locked() {
112       assert(_lock_mode != 0, "Forgot to call TrainingDataLocker::initialize()");
113       if (_lock_mode > 0) {
114         return TrainingData_lock->owned_by_self();
115       } else {
116         return true;
117       }
118     }
119   public:
120     static void snapshot() {
121       assert_locked();
122       _snapshot = true;
123     }
124     static bool can_add() {
125       assert_locked();
126       return !_snapshot;
127     }
128     static void initialize() {
129       _lock_mode = need_data() ? +1 : -1;   // if -1, we go lock-free
130     }
131     static void assert_locked() {
132       assert(safely_locked(), "use under TrainingDataLocker");
133     }
134     static void assert_can_add() {
135       assert(can_add(), "Cannot add TrainingData objects");
136     }
137     TrainingDataLocker() {
138       lock();
139     }
140     ~TrainingDataLocker() {
141       unlock();
142     }
143   };
144   class TrainingDataSet {
145     friend TrainingData;
146     ResizeableResourceHashtable<const Key*, TrainingData*,
147                                 AnyObj::C_HEAP, MemTag::mtCompiler,
148                                 &TrainingData::Key::hash,
149                                 &TrainingData::Key::equals>
150       _table;
151 
152   public:
153     template<typename... Arg>
154     TrainingDataSet(Arg... arg)
155       : _table(arg...) {
156     }
157     TrainingData* find(const Key* key) const {
158       TrainingDataLocker::assert_locked();
159       if (TrainingDataLocker::can_add()) {
160         auto res = _table.get(key);
161         return res == nullptr ? nullptr : *res;
162       }
163       return nullptr;
164     }
165     bool remove(const Key* key) {
166       return _table.remove(key);
167     }
168     TrainingData* install(TrainingData* tdata) {
169       TrainingDataLocker::assert_locked();
170       TrainingDataLocker::assert_can_add();
171       auto key = tdata->key();
172       if (key->is_empty())   return tdata;  // unkeyed TD not installed
173       bool created = false;
174       auto prior = _table.put_if_absent(key, tdata, &created);
175       if (prior == nullptr || *prior == tdata) {
176         return tdata;
177       }
178       assert(false, "no pre-existing elements allowed");
179       return *prior;
180     }
181     template<typename FN>
182     void iterate_all(FN fn) const { // lambda enabled API
183       return _table.iterate_all(fn);
184     }
185     int size() const { return _table.number_of_entries(); }
186 
187     void verify() const {
188       TrainingDataLocker::assert_locked();
189       iterate_all([&](const TrainingData::Key* k, TrainingData* td) {
190         td->verify();
191       });
192     }
193   };
194 
195   class Visitor {
196     ResizeableResourceHashtable<TrainingData*, bool> _visited;
197   public:
198     Visitor(unsigned size) : _visited(size, 0x3fffffff) { }
199     bool is_visited(TrainingData* td) {
200       return _visited.contains(td);
201     }
202     void visit(TrainingData* td) {
203       bool created;
204       _visited.put_if_absent(td, &created);
205     }
206   };
207 
208   typedef OffsetCompactHashtable<const TrainingData::Key*, TrainingData*, TrainingData::Key::equals> TrainingDataDictionary;
209 private:
210   Key _key;
211 
212   // just forward all constructor arguments to the embedded key
213   template<typename... Arg>
214   TrainingData(Arg... arg)
215     : _key(arg...) { }
216 
217   static TrainingDataSet _training_data_set;
218   static TrainingDataDictionary _archived_training_data_dictionary;
219   static TrainingDataDictionary _archived_training_data_dictionary_for_dumping;
220   typedef GrowableArrayCHeap<DumpTimeTrainingDataInfo, mtClassShared> DumptimeTrainingDataDictionary;
221   static DumptimeTrainingDataDictionary* _dumptime_training_data_dictionary;
222 public:
223   // Returns the key under which this TD is installed, or else
224   // Key::EMPTY if it is not installed.
225   const Key* key() const { return &_key; }
226 
227   static bool have_data() { return ReplayTraining;  } // Going to read
228   static bool need_data() { return RecordTraining;  } // Going to write
229 
230   static TrainingDataSet* training_data_set() { return &_training_data_set; }
231   static TrainingDataDictionary* archived_training_data_dictionary() { return &_archived_training_data_dictionary; }
232 
233   virtual MethodTrainingData*   as_MethodTrainingData()  const { return nullptr; }
234   virtual KlassTrainingData*    as_KlassTrainingData()   const { return nullptr; }
235   virtual CompileTrainingData*  as_CompileTrainingData() const { return nullptr; }
236   bool is_MethodTrainingData()  const { return as_MethodTrainingData()  != nullptr; }
237   bool is_KlassTrainingData()   const { return as_KlassTrainingData()   != nullptr; }
238   bool is_CompileTrainingData() const { return as_CompileTrainingData() != nullptr; }
239 
240   virtual void prepare(Visitor& visitor) = 0;
241   virtual void cleanup(Visitor& visitor) = 0;
242 
243   static void initialize();
244 
245   static void verify();
246 
247   // Widget for recording dependencies, as an N-to-M graph relation,
248   // possibly cyclic.
249   template<typename E>
250   class DepList : public StackObj {
251     GrowableArrayCHeap<E, mtCompiler>* _deps_dyn;
252     Array<E>*                          _deps;
253     // (hmm, could we have state-selected union of these two?)
254   public:
255     DepList() {
256       _deps_dyn = nullptr;
257       _deps = nullptr;
258     }
259 
260     int length() const {
261       return (_deps_dyn != nullptr ? _deps_dyn->length()
262               : _deps   != nullptr ? _deps->length()
263               : 0);
264     }
265     E* adr_at(int i) const {
266       return (_deps_dyn != nullptr ? _deps_dyn->adr_at(i)
267               : _deps   != nullptr ? _deps->adr_at(i)
268               : nullptr);
269     }
270     E at(int i) const {
271       assert(i >= 0 && i < length(), "oob");
272       return *adr_at(i);
273     }
274     bool append_if_missing(E dep) {
275       if (_deps_dyn == nullptr) {
276         _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(10);
277         _deps_dyn->append(dep);
278         return true;
279       } else {
280         return _deps_dyn->append_if_missing(dep);
281       }
282     }
283     bool remove_if_existing(E dep) {
284       if (_deps_dyn != nullptr) {
285         return _deps_dyn->remove_if_existing(dep);
286       }
287       return false;
288     }
289     void clear() {
290       if (_deps_dyn != nullptr)  {
291         _deps_dyn->clear();
292       }
293     }
294     void append(E dep) {
295       if (_deps_dyn == nullptr) {
296         _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(10);
297       }
298       _deps_dyn->append(dep);
299     }
300     bool contains(E dep) {
301       for (int i = 0; i < length(); i++) {
302         if (dep == at(i)) {
303           return true; // found
304         }
305       }
306       return false; // not found
307     }
308 
309 #if INCLUDE_CDS
310     void remove_unshareable_info() {
311       _deps_dyn = nullptr;
312     }
313 #endif
314     void prepare(ClassLoaderData* loader_data);
315     void metaspace_pointers_do(MetaspaceClosure *iter);
316   };
317 
318   virtual void metaspace_pointers_do(MetaspaceClosure *iter);
319 
320   static void init_dumptime_table(TRAPS);
321 
322 #if INCLUDE_CDS
323   virtual void remove_unshareable_info() {}
324   static void iterate_roots(MetaspaceClosure* it);
325   static void dump_training_data();
326   static void cleanup_training_data();
327   static void serialize_training_data(SerializeClosure* soc);
328   static void print_archived_training_data_on(outputStream* st);
329   static void write_training_data_dictionary(TrainingDataDictionary* dictionary);
330   static size_t estimate_size_for_archive();
331 
332   static TrainingData* lookup_archived_training_data(const Key* k);
333 #endif
334 
335   static KlassTrainingData*  lookup_for(InstanceKlass* ik);
336   static MethodTrainingData* lookup_for(Method* m);
337 };
338 
339 class KlassTrainingData : public TrainingData {
340   friend TrainingData;
341   friend CompileTrainingData;
342 
343   // Used by CDS. These classes need to access the private default constructor.
344   template <class T> friend class CppVtableTesterA;
345   template <class T> friend class CppVtableTesterB;
346   template <class T> friend class CppVtableCloner;
347 
348   // cross-link to live klass, or null if not loaded or encountered yet
349   InstanceKlass* _holder;
350   jobject _holder_mirror;   // extra link to prevent unloading by GC
351 
352   DepList<CompileTrainingData*> _comp_deps; // compiles that depend on me
353 
354   KlassTrainingData();
355   KlassTrainingData(InstanceKlass* klass);
356 
357   int comp_dep_count() const {
358     TrainingDataLocker::assert_locked();
359     return _comp_deps.length();
360   }
361   CompileTrainingData* comp_dep(int i) const {
362     TrainingDataLocker::assert_locked();
363     return _comp_deps.at(i);
364   }
365   void add_comp_dep(CompileTrainingData* ctd) {
366     TrainingDataLocker::assert_locked();
367      _comp_deps.append_if_missing(ctd);
368   }
369   void remove_comp_dep(CompileTrainingData* ctd) {
370     TrainingDataLocker::assert_locked();
371      _comp_deps.remove_if_existing(ctd);
372   }
373 
374  public:
375   Symbol* name() const {
376     precond(has_holder());
377     return holder()->name();
378   }
379   Symbol* loader_name() const {
380     precond(has_holder());
381     return holder()->class_loader_name_and_id();
382   }
383   bool has_holder()       const { return _holder != nullptr; }
384   InstanceKlass* holder() const { return _holder; }
385 
386   static KlassTrainingData* make(InstanceKlass* holder,
387                                  bool null_if_not_found = false);
388   static KlassTrainingData* find(InstanceKlass* holder) {
389     return make(holder, true);
390   }
391   virtual KlassTrainingData* as_KlassTrainingData() const { return const_cast<KlassTrainingData*>(this); };
392 
393   ClassLoaderData* class_loader_data() {
394     assert(has_holder(), "");
395     return holder()->class_loader_data();
396   }
397   void notice_fully_initialized();
398 
399   void print_on(outputStream* st, bool name_only) const;
400   virtual void print_on(outputStream* st) const { print_on(st, false); }
401   virtual void print_value_on(outputStream* st) const { print_on(st, true); }
402 
403   virtual void prepare(Visitor& visitor);
404   virtual void cleanup(Visitor& visitor) NOT_CDS_RETURN;
405 
406   MetaspaceObj::Type type() const {
407     return KlassTrainingDataType;
408   }
409 
410 #if INCLUDE_CDS
411   virtual void remove_unshareable_info();
412 #endif
413 
414   void metaspace_pointers_do(MetaspaceClosure *iter);
415 
416   int size() const {
417     return (int)align_metadata_size(align_up(sizeof(KlassTrainingData), BytesPerWord)/BytesPerWord);
418   }
419 
420   const char* internal_name() const {
421     return "{ klass training data }";
422   };
423 
424   void verify();
425 
426   static KlassTrainingData* allocate(InstanceKlass* holder);
427 
428   template<typename FN>
429   void iterate_all_comp_deps(FN fn) const { // lambda enabled API
430     TrainingDataLocker l;
431     for (int i = 0; i < comp_dep_count(); i++) {
432       fn(comp_dep(i));
433     }
434   }
435 };
436 
437 // Information about particular JIT tasks.
438 class CompileTrainingData : public TrainingData {
439   friend KlassTrainingData;
440 
441   // Used by CDS. These classes need to access the private default constructor.
442   template <class T> friend class CppVtableTesterA;
443   template <class T> friend class CppVtableTesterB;
444   template <class T> friend class CppVtableCloner;
445 
446   MethodTrainingData* _method;
447   const short _level;
448   const int _compile_id;
449   int _nm_total_size;
450   float _qtime, _stime, _etime;   // time queued, started, ended
451 
452   // classes that should be initialized before this JIT task runs
453   DepList<KlassTrainingData*> _init_deps;
454   volatile int _init_deps_left;
455 
456 public:
457   class ciRecords {
458     template <typename... Ts> class Arguments {
459     public:
460       bool operator==(const Arguments<>&) const { return true; }
461       void metaspace_pointers_do(MetaspaceClosure *iter) { }
462     };
463     template <typename T, typename... Ts> class Arguments<T, Ts...> {
464     private:
465       T _first;
466       Arguments<Ts...> _remaining;
467 
468     public:
469       constexpr Arguments(const T& first, const Ts&... remaining) noexcept
470         : _first(first), _remaining(remaining...) {}
471       constexpr Arguments() noexcept : _first(), _remaining() {}
472       bool operator==(const Arguments<T, Ts...>& that) const {
473         return _first == that._first && _remaining == that._remaining;
474       }
475       template<typename U = T, std::enable_if_t<std::is_pointer<U>::value && std::is_base_of<MetaspaceObj, typename std::remove_pointer<U>::type>::value, int> = 0>
476       void metaspace_pointers_do(MetaspaceClosure *iter) {
477         iter->push(&_first);
478         _remaining.metaspace_pointers_do(iter);
479       }
480       template<typename U = T, std::enable_if_t<!(std::is_pointer<U>::value && std::is_base_of<MetaspaceObj, typename std::remove_pointer<U>::type>::value), int> = 0>
481       void metaspace_pointers_do(MetaspaceClosure *iter) {
482         _remaining.metaspace_pointers_do(iter);
483       }
484     };
485 
486     template <typename ReturnType, typename... Args> class ciMemoizedFunction : public StackObj {
487     public:
488       class OptionalReturnType {
489         bool _valid;
490         ReturnType _result;
491       public:
492         OptionalReturnType(bool valid, const ReturnType& result) : _valid(valid), _result(result) {}
493         bool is_valid() const { return _valid; }
494         ReturnType result() const { return _result; }
495       };
496     private:
497       typedef Arguments<Args...> ArgumentsType;
498       class Record : public MetaspaceObj {
499         ReturnType    _result;
500         ArgumentsType _arguments;
501       public:
502         Record(const ReturnType& result, const ArgumentsType& arguments) : _result(result), _arguments(arguments) {}
503         Record() { }
504         ReturnType result() const { return _result; }
505         ArgumentsType arguments() const { return _arguments; }
506         bool operator==(const Record& that) { return _arguments == that._arguments; }
507         void metaspace_pointers_do(MetaspaceClosure *iter) { _arguments.metaspace_pointers_do(iter); }
508       };
509       DepList<Record> _data;
510     public:
511       OptionalReturnType find(const Args&... args) {
512         ArgumentsType a(args...);
513         for (int i = 0; i < _data.length(); i++) {
514           if (_data.at(i).arguments() == a) {
515             return OptionalReturnType(true, _data.at(i).result());
516           }
517         }
518         return OptionalReturnType(false, ReturnType());
519       }
520       bool append_if_missing(const ReturnType& result, const Args&... args) {
521         return _data.append_if_missing(Record(result, ArgumentsType(args...)));
522       }
523 #if INCLUDE_CDS
524       void remove_unshareable_info() { _data.remove_unshareable_info(); }
525 #endif
526       void prepare(ClassLoaderData* loader_data) {
527         _data.prepare(loader_data);
528       }
529       void metaspace_pointers_do(MetaspaceClosure *iter) {
530         _data.metaspace_pointers_do(iter);
531       }
532     };
533 
534 
535 public:
536     typedef ciMemoizedFunction<int, MethodTrainingData*> ciMethod__inline_instructions_size_type;
537     ciMethod__inline_instructions_size_type ciMethod__inline_instructions_size;
538 #if INCLUDE_CDS
539     void remove_unshareable_info() {
540       ciMethod__inline_instructions_size.remove_unshareable_info();
541     }
542 #endif
543     void prepare(ClassLoaderData* loader_data) {
544       ciMethod__inline_instructions_size.prepare(loader_data);
545     }
546     void metaspace_pointers_do(MetaspaceClosure *iter) {
547       ciMethod__inline_instructions_size.metaspace_pointers_do(iter);
548     }
549   };
550 
551 private:
552   ciRecords _ci_records;
553 
554   CompileTrainingData();
555   // (should we also capture counters or MDO state or replay data?)
556   CompileTrainingData(MethodTrainingData* mtd,
557                       int level,
558                       int compile_id)
559       : TrainingData(),  // empty key
560         _method(mtd), _level(level), _compile_id(compile_id)
561   {
562     _qtime = _stime = _etime = 0;
563     _nm_total_size = 0;
564     _init_deps_left = 0;
565   }
566 
567 public:
568   ciRecords& ci_records() { return _ci_records; }
569   static CompileTrainingData* make(CompileTask* task);
570 
571   virtual CompileTrainingData* as_CompileTrainingData() const { return const_cast<CompileTrainingData*>(this); };
572 
573   MethodTrainingData* method() const { return _method; }
574 
575   int level() const { return _level; }
576 
577   int compile_id() const { return _compile_id; }
578 
579   int init_dep_count() const {
580     TrainingDataLocker::assert_locked();
581     return _init_deps.length();
582   }
583   KlassTrainingData* init_dep(int i) const {
584     TrainingDataLocker::assert_locked();
585     return _init_deps.at(i);
586   }
587   void add_init_dep(KlassTrainingData* ktd) {
588     TrainingDataLocker::assert_locked();
589     ktd->add_comp_dep(this);
590     _init_deps.append_if_missing(ktd);
591   }
592   void clear_init_deps() {
593     TrainingDataLocker::assert_locked();
594     for (int i = 0; i < _init_deps.length(); i++) {
595       _init_deps.at(i)->remove_comp_dep(this);
596     }
597     _init_deps.clear();
598   }
599   void dec_init_deps_left(KlassTrainingData* ktd);
600   int init_deps_left() const {
601     return Atomic::load(&_init_deps_left);
602   }
603   uint compute_init_deps_left(bool count_initialized = false);
604 
605   void record_compilation_queued(CompileTask* task);
606   void record_compilation_start(CompileTask* task);
607   void record_compilation_end(CompileTask* task);
608   void notice_inlined_method(CompileTask* task, const methodHandle& method);
609 
610   // The JIT looks at classes and objects too and can depend on their state.
611   // These simple calls just report the *possibility* of an observation.
612   void notice_jit_observation(ciEnv* env, ciBaseObject* what);
613 
614   virtual void prepare(Visitor& visitor);
615   virtual void cleanup(Visitor& visitor) NOT_CDS_RETURN;
616 
617   void print_on(outputStream* st, bool name_only) const;
618   virtual void print_on(outputStream* st) const { print_on(st, false); }
619   virtual void print_value_on(outputStream* st) const { print_on(st, true); }
620 
621 #if INCLUDE_CDS
622   virtual void remove_unshareable_info();
623 #endif
624 
625   virtual void metaspace_pointers_do(MetaspaceClosure* iter);
626   virtual MetaspaceObj::Type type() const { return CompileTrainingDataType; }
627 
628   virtual const char* internal_name() const {
629     return "{ compile training data }";
630   };
631 
632   virtual int size() const {
633     return (int)align_metadata_size(align_up(sizeof(CompileTrainingData), BytesPerWord)/BytesPerWord);
634   }
635 
636   void verify();
637 
638   static CompileTrainingData* allocate(MethodTrainingData* mtd, int level, int compile_id);
639 };
640 
641 // Record information about a method at the time compilation is requested.
642 class MethodTrainingData : public TrainingData {
643   friend TrainingData;
644   friend CompileTrainingData;
645 
646   // Used by CDS. These classes need to access the private default constructor.
647   template <class T> friend class CppVtableTesterA;
648   template <class T> friend class CppVtableTesterB;
649   template <class T> friend class CppVtableCloner;
650 
651   KlassTrainingData* _klass;
652   Method* _holder;  // can be null
653   CompileTrainingData* _last_toplevel_compiles[CompLevel_count];
654   int _highest_top_level;
655   int _level_mask;  // bit-set of all possible levels
656   bool _was_inlined;
657   bool _was_toplevel;
658   // metadata snapshots of final state:
659   MethodCounters* _final_counters;
660   MethodData*     _final_profile;
661 
662   MethodTrainingData();
663   MethodTrainingData(Method* method, KlassTrainingData* ktd) : TrainingData(method) {
664     _klass = ktd;
665     _holder = method;
666     for (int i = 0; i < CompLevel_count; i++) {
667       _last_toplevel_compiles[i] = nullptr;
668     }
669     _highest_top_level = CompLevel_none;
670     _level_mask = 0;
671     _was_inlined = _was_toplevel = false;
672   }
673 
674   static int level_mask(int level) {
675     return ((level & 0xF) != level ? 0 : 1 << level);
676   }
677   static CompLevel highest_level(int mask) {
678     if (mask == 0)  return (CompLevel) 0;
679     int diff = (count_leading_zeros(level_mask(0)) - count_leading_zeros(mask));
680     return (CompLevel) diff;
681   }
682 
683  public:
684   KlassTrainingData* klass()  const { return _klass; }
685   bool has_holder()           const { return _holder != nullptr; }
686   Method* holder()            const { return _holder; }
687   bool only_inlined()         const { return !_was_toplevel; }
688   bool never_inlined()        const { return !_was_inlined; }
689   bool saw_level(CompLevel l) const { return (_level_mask & level_mask(l)) != 0; }
690   int highest_level()         const { return highest_level(_level_mask); }
691   int highest_top_level()     const { return _highest_top_level; }
692   MethodData* final_profile() const { return _final_profile; }
693 
694   Symbol* name() const {
695     precond(has_holder());
696     return holder()->name();
697   }
698   Symbol* signature() const {
699     precond(has_holder());
700     return holder()->signature();
701   }
702 
703   CompileTrainingData* last_toplevel_compile(int level) const {
704     if (level > CompLevel_none) {
705       return _last_toplevel_compiles[level - 1];
706     }
707     return nullptr;
708   }
709 
710   void notice_compilation(int level, bool inlined = false) {
711     if (inlined) {
712       _was_inlined = true;
713     } else {
714       _was_toplevel = true;
715     }
716     _level_mask |= level_mask(level);
717   }
718 
719   static MethodTrainingData* make(const methodHandle& method,
720                                   bool null_if_not_found = false);
721   static MethodTrainingData* find(const methodHandle& method) {
722     return make(method, true);
723   }
724 
725   virtual MethodTrainingData* as_MethodTrainingData() const {
726     return const_cast<MethodTrainingData*>(this);
727   };
728 
729   void print_on(outputStream* st, bool name_only) const;
730   virtual void print_on(outputStream* st) const { print_on(st, false); }
731   virtual void print_value_on(outputStream* st) const { print_on(st, true); }
732 
733   virtual void prepare(Visitor& visitor);
734   virtual void cleanup(Visitor& visitor) NOT_CDS_RETURN;
735 
736   template<typename FN>
737   void iterate_all_compiles(FN fn) const { // lambda enabled API
738     for (int i = 0; i < CompLevel_count; i++) {
739       CompileTrainingData* ctd = _last_toplevel_compiles[i];
740       if (ctd != nullptr) {
741         fn(ctd);
742       }
743     }
744   }
745 
746   virtual void metaspace_pointers_do(MetaspaceClosure* iter);
747   virtual MetaspaceObj::Type type() const { return MethodTrainingDataType; }
748 
749 #if INCLUDE_CDS
750   virtual void remove_unshareable_info();
751 #endif
752 
753   virtual int size() const {
754     return (int)align_metadata_size(align_up(sizeof(MethodTrainingData), BytesPerWord)/BytesPerWord);
755   }
756 
757   virtual const char* internal_name() const {
758     return "{ method training data }";
759   };
760 
761   void verify();
762 
763   static MethodTrainingData* allocate(Method* m, KlassTrainingData* ktd);
764 };
765 
766 // CDS support
767 
768 class DumpTimeTrainingDataInfo {
769   TrainingData* _training_data;
770 public:
771   DumpTimeTrainingDataInfo() : DumpTimeTrainingDataInfo(nullptr) {}
772 
773   DumpTimeTrainingDataInfo(TrainingData* training_data)
774       : _training_data(training_data) {}
775 
776   void metaspace_pointers_do(MetaspaceClosure* it) {
777     it->push(&_training_data);
778   }
779 
780   TrainingData* training_data() {
781     return _training_data;
782   }
783 };
784 
785 
786 class TrainingDataPrinter : StackObj {
787   outputStream* _st;
788   int _index;
789 public:
790   TrainingDataPrinter(outputStream* st) : _st(st), _index(0) {}
791   void do_value(TrainingData* record);
792 };
793 
794 #endif // SHARE_OOPS_TRAININGDATA_HPP