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