< prev index next >

src/hotspot/share/oops/trainingData.hpp

Print this page

  1 /*
  2  * Copyright (c) 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 "cds/cdsConfig.hpp"
 29 #include "classfile/compactHashtable.hpp"
 30 #include "compiler/compiler_globals.hpp"
 31 #include "compiler/compilerDefinitions.hpp"
 32 #include "memory/allocation.hpp"
 33 #include "memory/metaspaceClosure.hpp"
 34 #include "oops/instanceKlass.hpp"
 35 #include "oops/method.hpp"
 36 #include "oops/objArrayKlass.hpp"
 37 #include "runtime/handles.hpp"
 38 #include "runtime/mutexLocker.hpp"

 39 #include "utilities/resizableHashTable.hpp"
 40 
 41 class ciEnv;
 42 class ciBaseObject;
 43 class CompileTask;
 44 class CompileTrainingData;
 45 class KlassTrainingData;
 46 class MethodTrainingData;
 47 
 48 // Base class for all the training data varieties
 49 class TrainingData : public Metadata {
 50   friend KlassTrainingData;
 51   friend MethodTrainingData;
 52   friend CompileTrainingData;
 53 public:
 54   // Key is used to insert any TrainingData (TD) object into a hash tables. The key is currently a
 55   // pointer to a metaspace object the TD is associated with. For example,
 56   // for KlassTrainingData it's an InstanceKlass, for MethodTrainingData it's a Method.
 57   // The utility of the these hash tables is to be able to find a TD object for a given metaspace
 58   // metaspace object.

200     }
201     bool remove(const Key* key) {
202       return _table.remove(key);
203     }
204     TrainingData* install(TrainingData* td) {
205       TrainingDataLocker::assert_locked();
206       TrainingDataLocker::assert_can_add();
207       auto key = td->key();
208       if (key->is_empty()) {
209         return td;  // unkeyed TD not installed
210       }
211       bool created = false;
212       auto prior = _table.put_if_absent(key, td, &created);
213       if (prior == nullptr || *prior == td) {
214         return td;
215       }
216       assert(false, "no pre-existing elements allowed");
217       return *prior;
218     }
219     template<typename Function>
220     void iterate(const Function& fn) const { // lambda enabled API
221       iterate(const_cast<Function&>(fn));
222     }
223     template<typename Function>
224     void iterate(Function& fn) const { // lambda enabled API
225       return _table.iterate_all([&](const TrainingData::Key* k, TrainingData* td) { fn(td); });
226     }
227     int size() const { return _table.number_of_entries(); }
228 
229     void verify() const {
230       TrainingDataLocker::assert_locked();
231       iterate([&](TrainingData* td) { td->verify(); });
232     }
233   };
234 
235   // A widget to ensure that we visit TD object only once (TD objects can have pointer to
236   // other TD object that are sometimes circular).
237   class Visitor {
238     ResizeableHashTable<TrainingData*, bool> _visited;
239   public:
240     Visitor(unsigned size) : _visited(size, 0x3fffffff) { }
241     bool is_visited(TrainingData* td) {
242       return _visited.contains(td);
243     }
244     void visit(TrainingData* td) {

287   const Key* key() const { return &_key; }
288 
289   static bool have_data() { return AOTReplayTraining;  } // Going to read
290   static bool need_data() { return AOTRecordTraining;  } // Going to write
291   static bool assembling_data() { return have_data() && CDSConfig::is_dumping_final_static_archive() && CDSConfig::is_dumping_aot_linked_classes(); }
292 
293   static bool is_klass_loaded(Klass* k) {
294     if (have_data()) {
295       // If we're running in AOT mode some classes may not be loaded yet
296       if (k->is_objArray_klass()) {
297         k = ObjArrayKlass::cast(k)->bottom_klass();
298       }
299       if (k->is_instance_klass()) {
300         return InstanceKlass::cast(k)->is_loaded();
301       }
302     }
303     return true;
304   }
305 
306   template<typename Function>
307   static void iterate(const Function& fn) { iterate(const_cast<Function&>(fn)); }
308 
309   template<typename Function>
310   static void iterate(Function& fn) { // lambda enabled API
311     TrainingDataLocker l;
312     if (have_data()) {
313       archived_training_data_dictionary()->iterate(fn);
314     }
315     if (need_data()) {
316       training_data_set()->iterate(fn);
317     }
318   }
319 
320   virtual MethodTrainingData*   as_MethodTrainingData()  const { return nullptr; }
321   virtual KlassTrainingData*    as_KlassTrainingData()   const { return nullptr; }
322   virtual CompileTrainingData*  as_CompileTrainingData() const { return nullptr; }
323   bool is_MethodTrainingData()  const { return as_MethodTrainingData()  != nullptr; }
324   bool is_KlassTrainingData()   const { return as_KlassTrainingData()   != nullptr; }
325   bool is_CompileTrainingData() const { return as_CompileTrainingData() != nullptr; }
326 
327   virtual void prepare(Visitor& visitor) = 0;
328   virtual void cleanup(Visitor& visitor) = 0;
329 
330   static void initialize() NOT_CDS_RETURN;
331 
332   static void verify();
333 
334   // Widget for recording dependencies, as an N-to-M graph relation,
335   // possibly cyclic.
336   template<typename E>
337   class DepList : public StackObj {


338     GrowableArrayCHeap<E, mtCompiler>* _deps_dyn;
339     Array<E>*                          _deps;











340   public:
341     DepList() {
342       _deps_dyn = nullptr;
343       _deps = nullptr;
344     }
345 
346     int length() const {
347       TrainingDataLocker::assert_locked_or_snapshotted();
348       return (_deps_dyn != nullptr ? _deps_dyn->length()
349               : _deps   != nullptr ? _deps->length()
350               : 0);
351     }
352     E* adr_at(int i) const {
353       TrainingDataLocker::assert_locked_or_snapshotted();
354       return (_deps_dyn != nullptr ? _deps_dyn->adr_at(i)
355               : _deps   != nullptr ? _deps->adr_at(i)
356               : nullptr);
357     }
358     E at(int i) const {
359       TrainingDataLocker::assert_locked_or_snapshotted();
360       assert(i >= 0 && i < length(), "oob");
361       return *adr_at(i);




362     }
363     bool append_if_missing(E dep) {
364       TrainingDataLocker::assert_can_add();

365       if (_deps_dyn == nullptr) {
366         _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(10);
367         _deps_dyn->append(dep);
368         return true;
369       } else {
370         return _deps_dyn->append_if_missing(dep);
371       }
372     }
373     bool remove_if_existing(E dep) {
374       TrainingDataLocker::assert_can_add();

375       if (_deps_dyn != nullptr) {
376         return _deps_dyn->remove_if_existing(dep);
377       }
378       return false;
379     }
380     void clear() {
381       TrainingDataLocker::assert_can_add();
382       if (_deps_dyn != nullptr)  {
383         _deps_dyn->clear();
384       }

385     }
386     void append(E dep) {
387       TrainingDataLocker::assert_can_add();

388       if (_deps_dyn == nullptr) {
389         _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(10);
390       }
391       _deps_dyn->append(dep);
392     }
393     bool contains(E dep) {
394       TrainingDataLocker::assert_locked();
395       for (int i = 0; i < length(); i++) {
396         if (dep == at(i)) {
397           return true; // found
398         }
399       }
400       return false; // not found
401     }
402 
403 #if INCLUDE_CDS
404     void remove_unshareable_info() {
405       _deps_dyn = nullptr;
406     }
407 #endif
408     void prepare();
409     void metaspace_pointers_do(MetaspaceClosure *iter);

731 // Record information about a method at the time compilation is requested.
732 class MethodTrainingData : public TrainingData {
733   friend TrainingData;
734   friend CompileTrainingData;
735 
736   // Used by CDS. These classes need to access the private default constructor.
737   template <class T> friend class CppVtableTesterA;
738   template <class T> friend class CppVtableTesterB;
739   template <class T> friend class CppVtableCloner;
740 
741   KlassTrainingData* _klass;
742   Method* _holder;
743   CompileTrainingData* _last_toplevel_compiles[CompLevel_count - 1];
744   int _highest_top_level;
745   int _level_mask;  // bit-set of all possible levels
746   bool _was_toplevel;
747   // metadata snapshots of final state:
748   MethodCounters* _final_counters;
749   MethodData*     _final_profile;
750 

751   int _invocation_count;
752   int _backedge_count;
753 
754   MethodTrainingData();
755   MethodTrainingData(Method* method, KlassTrainingData* ktd) : TrainingData(method) {
756     _klass = ktd;
757     _holder = method;
758     for (int i = 0; i < CompLevel_count - 1; i++) {
759       _last_toplevel_compiles[i] = nullptr;
760     }
761     _highest_top_level = CompLevel_none;
762     _level_mask = 0;
763     _was_toplevel = false;
764     _invocation_count = 0;
765     _backedge_count = 0;

766   }
767 
768   static int level_mask(int level) {
769     return ((level & 0xF) != level ? 0 : 1 << level);
770   }





771 
772  public:
773   KlassTrainingData* klass()  const { return _klass; }
774   bool has_holder()           const { return _holder != nullptr; }
775   Method* holder()            const { return _holder; }
776   bool only_inlined()         const { return !_was_toplevel; }
777   bool saw_level(CompLevel l) const { return (_level_mask & level_mask(l)) != 0; }

778   int highest_top_level()     const { return _highest_top_level; }
779   MethodData* final_profile() const { return _final_profile; }
780   int invocation_count() const { return _invocation_count; }
781   int backedge_count() const { return _backedge_count; }

782 
783   Symbol* name() const {
784     precond(has_holder());
785     return holder()->name();
786   }
787   Symbol* signature() const {
788     precond(has_holder());
789     return holder()->signature();
790   }
791 
792   CompileTrainingData* last_toplevel_compile(int level) const {
793     if (level > CompLevel_none) {
794       return _last_toplevel_compiles[level - 1];
795     }
796     return nullptr;
797   }
798 
799   void notice_compilation(int level, bool inlined = false) {
800     if (!inlined) {
801       _was_toplevel = true;

  1 /*
  2  * Copyright (c) 2025, 2026, 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/cdsConfig.hpp"
 29 #include "classfile/compactHashtable.hpp"
 30 #include "compiler/compiler_globals.hpp"
 31 #include "compiler/compilerDefinitions.hpp"
 32 #include "memory/allocation.hpp"
 33 #include "memory/metaspaceClosure.hpp"
 34 #include "oops/instanceKlass.hpp"
 35 #include "oops/method.hpp"
 36 #include "oops/objArrayKlass.hpp"
 37 #include "runtime/handles.hpp"
 38 #include "runtime/mutexLocker.hpp"
 39 #include "utilities/count_leading_zeros.hpp"
 40 #include "utilities/resizableHashTable.hpp"
 41 
 42 class ciEnv;
 43 class ciBaseObject;
 44 class CompileTask;
 45 class CompileTrainingData;
 46 class KlassTrainingData;
 47 class MethodTrainingData;
 48 
 49 // Base class for all the training data varieties
 50 class TrainingData : public Metadata {
 51   friend KlassTrainingData;
 52   friend MethodTrainingData;
 53   friend CompileTrainingData;
 54 public:
 55   // Key is used to insert any TrainingData (TD) object into a hash tables. The key is currently a
 56   // pointer to a metaspace object the TD is associated with. For example,
 57   // for KlassTrainingData it's an InstanceKlass, for MethodTrainingData it's a Method.
 58   // The utility of the these hash tables is to be able to find a TD object for a given metaspace
 59   // metaspace object.

201     }
202     bool remove(const Key* key) {
203       return _table.remove(key);
204     }
205     TrainingData* install(TrainingData* td) {
206       TrainingDataLocker::assert_locked();
207       TrainingDataLocker::assert_can_add();
208       auto key = td->key();
209       if (key->is_empty()) {
210         return td;  // unkeyed TD not installed
211       }
212       bool created = false;
213       auto prior = _table.put_if_absent(key, td, &created);
214       if (prior == nullptr || *prior == td) {
215         return td;
216       }
217       assert(false, "no pre-existing elements allowed");
218       return *prior;
219     }
220     template<typename Function>
221     void iterate(Function fn) const { // lambda enabled API




222       return _table.iterate_all([&](const TrainingData::Key* k, TrainingData* td) { fn(td); });
223     }
224     int size() const { return _table.number_of_entries(); }
225 
226     void verify() const {
227       TrainingDataLocker::assert_locked();
228       iterate([&](TrainingData* td) { td->verify(); });
229     }
230   };
231 
232   // A widget to ensure that we visit TD object only once (TD objects can have pointer to
233   // other TD object that are sometimes circular).
234   class Visitor {
235     ResizeableHashTable<TrainingData*, bool> _visited;
236   public:
237     Visitor(unsigned size) : _visited(size, 0x3fffffff) { }
238     bool is_visited(TrainingData* td) {
239       return _visited.contains(td);
240     }
241     void visit(TrainingData* td) {

284   const Key* key() const { return &_key; }
285 
286   static bool have_data() { return AOTReplayTraining;  } // Going to read
287   static bool need_data() { return AOTRecordTraining;  } // Going to write
288   static bool assembling_data() { return have_data() && CDSConfig::is_dumping_final_static_archive() && CDSConfig::is_dumping_aot_linked_classes(); }
289 
290   static bool is_klass_loaded(Klass* k) {
291     if (have_data()) {
292       // If we're running in AOT mode some classes may not be loaded yet
293       if (k->is_objArray_klass()) {
294         k = ObjArrayKlass::cast(k)->bottom_klass();
295       }
296       if (k->is_instance_klass()) {
297         return InstanceKlass::cast(k)->is_loaded();
298       }
299     }
300     return true;
301   }
302 
303   template<typename Function>
304   static void iterate(Function fn) { // lambda enabled API



305     TrainingDataLocker l;
306     if (have_data() && !need_data()) {
307       archived_training_data_dictionary()->iterate_all([&](TrainingData* td) { fn(td); });
308     }
309     if (need_data()) {
310       training_data_set()->iterate(fn);
311     }
312   }
313 
314   virtual MethodTrainingData*   as_MethodTrainingData()  const { return nullptr; }
315   virtual KlassTrainingData*    as_KlassTrainingData()   const { return nullptr; }
316   virtual CompileTrainingData*  as_CompileTrainingData() const { return nullptr; }
317   bool is_MethodTrainingData()  const { return as_MethodTrainingData()  != nullptr; }
318   bool is_KlassTrainingData()   const { return as_KlassTrainingData()   != nullptr; }
319   bool is_CompileTrainingData() const { return as_CompileTrainingData() != nullptr; }
320 
321   virtual void prepare(Visitor& visitor) = 0;
322   virtual void cleanup(Visitor& visitor) = 0;
323 
324   static void initialize() NOT_CDS_RETURN;
325 
326   static void verify() NOT_CDS_RETURN;
327 
328   // Widget for recording dependencies, as an N-to-M graph relation,
329   // possibly cyclic.
330   template<typename E>
331   class DepList : public StackObj {
332     static const int INITIAL_CAPACITY = 10;
333 
334     GrowableArrayCHeap<E, mtCompiler>* _deps_dyn;
335     Array<E>*                          _deps;
336 
337     void copy_on_write_if_necessary() {
338       TrainingDataLocker::assert_locked_or_snapshotted();
339       if (_deps != nullptr && _deps_dyn == nullptr) {
340         _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(length() + INITIAL_CAPACITY);
341         for (int i = 0; _deps->length(); i++) {
342           _deps_dyn->append(_deps->at(i));
343         }
344         _deps = nullptr;
345       }
346     }
347   public:
348     DepList() {
349       _deps_dyn = nullptr;
350       _deps = nullptr;
351     }
352 
353     int length() const {
354       TrainingDataLocker::assert_locked_or_snapshotted();
355       return (_deps_dyn != nullptr ? _deps_dyn->length()
356               : _deps   != nullptr ? _deps->length()
357               : 0);
358     }






359     E at(int i) const {
360       TrainingDataLocker::assert_locked_or_snapshotted();
361       assert(i >= 0 && i < length(), "oob");
362       if (_deps_dyn != nullptr) {
363         return _deps_dyn->at(i);
364       } else if (_deps != nullptr) {
365         return _deps->at(i);
366       } else ShouldNotReachHere();
367     }
368     bool append_if_missing(E dep) {
369       TrainingDataLocker::assert_can_add();
370       copy_on_write_if_necessary();
371       if (_deps_dyn == nullptr) {
372         _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(INITIAL_CAPACITY);
373         _deps_dyn->append(dep);
374         return true;
375       } else {
376         return _deps_dyn->append_if_missing(dep);
377       }
378     }
379     bool remove_if_existing(E dep) {
380       TrainingDataLocker::assert_can_add();
381       copy_on_write_if_necessary();
382       if (_deps_dyn != nullptr) {
383         return _deps_dyn->remove_if_existing(dep);
384       }
385       return false;
386     }
387     void clear() {
388       TrainingDataLocker::assert_can_add();
389       if (_deps_dyn != nullptr)  {
390         _deps_dyn->clear();
391       }
392       _deps = nullptr;
393     }
394     void append(E dep) {
395       TrainingDataLocker::assert_can_add();
396       copy_on_write_if_necessary();
397       if (_deps_dyn == nullptr) {
398         _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(INITIAL_CAPACITY);
399       }
400       _deps_dyn->append(dep);
401     }
402     bool contains(E dep) {
403       TrainingDataLocker::assert_locked();
404       for (int i = 0; i < length(); i++) {
405         if (dep == at(i)) {
406           return true; // found
407         }
408       }
409       return false; // not found
410     }
411 
412 #if INCLUDE_CDS
413     void remove_unshareable_info() {
414       _deps_dyn = nullptr;
415     }
416 #endif
417     void prepare();
418     void metaspace_pointers_do(MetaspaceClosure *iter);

740 // Record information about a method at the time compilation is requested.
741 class MethodTrainingData : public TrainingData {
742   friend TrainingData;
743   friend CompileTrainingData;
744 
745   // Used by CDS. These classes need to access the private default constructor.
746   template <class T> friend class CppVtableTesterA;
747   template <class T> friend class CppVtableTesterB;
748   template <class T> friend class CppVtableCloner;
749 
750   KlassTrainingData* _klass;
751   Method* _holder;
752   CompileTrainingData* _last_toplevel_compiles[CompLevel_count - 1];
753   int _highest_top_level;
754   int _level_mask;  // bit-set of all possible levels
755   bool _was_toplevel;
756   // metadata snapshots of final state:
757   MethodCounters* _final_counters;
758   MethodData*     _final_profile;
759 
760   int64_t _aot_code_invocation_limit; // C2 code invocations count during training
761   int _invocation_count;
762   int _backedge_count;
763 
764   MethodTrainingData();
765   MethodTrainingData(Method* method, KlassTrainingData* ktd) : TrainingData(method) {
766     _klass = ktd;
767     _holder = method;
768     for (int i = 0; i < CompLevel_count - 1; i++) {
769       _last_toplevel_compiles[i] = nullptr;
770     }
771     _highest_top_level = CompLevel_none;
772     _level_mask = 0;
773     _was_toplevel = false;
774     _invocation_count = 0;
775     _backedge_count = 0;
776     _aot_code_invocation_limit = 0;
777   }
778 
779   static int level_mask(int level) {
780     return ((level & 0xF) != level ? 0 : 1 << level);
781   }
782   static CompLevel highest_level(int mask) {
783     if (mask == 0)  return (CompLevel) 0;
784     int diff = (count_leading_zeros(level_mask(0)) - count_leading_zeros(mask));
785     return (CompLevel) diff;
786   }
787 
788  public:
789   KlassTrainingData* klass()  const { return _klass; }
790   bool has_holder()           const { return _holder != nullptr; }
791   Method* holder()            const { return _holder; }
792   bool only_inlined()         const { return !_was_toplevel; }
793   bool saw_level(CompLevel l) const { return (_level_mask & level_mask(l)) != 0; }
794   int highest_level()         const { return highest_level(_level_mask); }
795   int highest_top_level()     const { return _highest_top_level; }
796   MethodData* final_profile() const { return _final_profile; }
797   int invocation_count() const { return _invocation_count; }
798   int backedge_count() const { return _backedge_count; }
799   int64_t  aot_code_invocation_limit() const { return _aot_code_invocation_limit;}
800 
801   Symbol* name() const {
802     precond(has_holder());
803     return holder()->name();
804   }
805   Symbol* signature() const {
806     precond(has_holder());
807     return holder()->signature();
808   }
809 
810   CompileTrainingData* last_toplevel_compile(int level) const {
811     if (level > CompLevel_none) {
812       return _last_toplevel_compiles[level - 1];
813     }
814     return nullptr;
815   }
816 
817   void notice_compilation(int level, bool inlined = false) {
818     if (!inlined) {
819       _was_toplevel = true;
< prev index next >