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