< prev index next >

src/hotspot/share/oops/trainingData.cpp

Print this page

 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "cds/cdsConfig.hpp"
 26 #include "ci/ciEnv.hpp"
 27 #include "ci/ciMetadata.hpp"
 28 #include "classfile/compactHashtable.hpp"
 29 #include "classfile/javaClasses.hpp"
 30 #include "classfile/symbolTable.hpp"
 31 #include "classfile/systemDictionaryShared.hpp"
 32 #include "compiler/compileTask.hpp"
 33 #include "memory/metadataFactory.hpp"
 34 #include "memory/metaspaceClosure.hpp"
 35 #include "memory/resourceArea.hpp"
 36 #include "memory/universe.hpp"
 37 #include "oops/method.hpp"
 38 #include "oops/method.inline.hpp"
 39 #include "oops/methodCounters.hpp"

 40 #include "oops/trainingData.hpp"
 41 #include "runtime/arguments.hpp"
 42 #include "runtime/javaThread.inline.hpp"
 43 #include "runtime/jniHandles.inline.hpp"
 44 #include "utilities/growableArray.hpp"
 45 
 46 TrainingData::TrainingDataSet TrainingData::_training_data_set(1024, 0x3fffffff);
 47 TrainingData::TrainingDataDictionary TrainingData::_archived_training_data_dictionary;
 48 TrainingData::TrainingDataDictionary TrainingData::_archived_training_data_dictionary_for_dumping;
 49 TrainingData::DumptimeTrainingDataDictionary* TrainingData::_dumptime_training_data_dictionary = nullptr;
 50 int TrainingData::TrainingDataLocker::_lock_mode;
 51 volatile bool TrainingData::TrainingDataLocker::_snapshot = false;
 52 
 53 MethodTrainingData::MethodTrainingData() {
 54   // Used by cppVtables.cpp only
 55   assert(CDSConfig::is_dumping_static_archive() || UseSharedSpaces, "only for CDS");
 56 }
 57 
 58 KlassTrainingData::KlassTrainingData() {
 59   // Used by cppVtables.cpp only
 60   assert(CDSConfig::is_dumping_static_archive() || UseSharedSpaces, "only for CDS");
 61 }
 62 
 63 CompileTrainingData::CompileTrainingData() : _level(-1), _compile_id(-1) {
 64   // Used by cppVtables.cpp only
 65   assert(CDSConfig::is_dumping_static_archive() || UseSharedSpaces, "only for CDS");
 66 }
 67 
 68 void TrainingData::initialize() {
 69   // this is a nop if training modes are not enabled
 70   if (have_data() || need_data()) {
 71     // Data structures that we have do not currently support iterative training. So you cannot replay
 72     // and train at the same time. Going forward we may want to adjust iteration/search to enable that.
 73     guarantee(have_data() != need_data(), "Iterative training is not supported");
 74     TrainingDataLocker::initialize();
 75   }

 76 }
 77 
 78 static void verify_archived_entry(TrainingData* td, const TrainingData::Key* k) {
 79   guarantee(TrainingData::Key::can_compute_cds_hash(k), "");
 80   TrainingData* td1 = TrainingData::lookup_archived_training_data(k);
 81   guarantee(td == td1, "");
 82 }
 83 
 84 void TrainingData::verify() {
 85   if (TrainingData::have_data() && !TrainingData::assembling_data()) {
 86     archived_training_data_dictionary()->iterate([&](TrainingData* td) {
 87       if (td->is_KlassTrainingData()) {
 88         KlassTrainingData* ktd = td->as_KlassTrainingData();
 89         if (ktd->has_holder() && ktd->holder()->is_loaded()) {
 90           Key k(ktd->holder());
 91           verify_archived_entry(td, &k);
 92         }
 93         ktd->verify();
 94       } else if (td->is_MethodTrainingData()) {
 95         MethodTrainingData* mtd = td->as_MethodTrainingData();

292     for (int i = 0, len = _init_deps.length(); i < len; i++) {
293       st->print(" dep:");
294       _init_deps.at(i)->print_on(st, true);
295     }
296   }
297 }
298 
299 void CompileTrainingData::notice_inlined_method(CompileTask* task,
300                                                 const methodHandle& method) {
301   MethodTrainingData* mtd = MethodTrainingData::make(method);
302   if (mtd != nullptr) {
303     mtd->notice_compilation(task->comp_level(), true);
304   }
305 }
306 
307 void CompileTrainingData::notice_jit_observation(ciEnv* env, ciBaseObject* what) {
308   // A JIT is starting to look at class k.
309   // We could follow the queries that it is making, but it is
310   // simpler to assume, conservatively, that the JIT will
311   // eventually depend on the initialization state of k.
312   CompileTask* task = env->task();
313   assert(task != nullptr, "");
314   Method* method = task->method();
315   if (what->is_metadata()) {
316     ciMetadata* md = what->as_metadata();
317     if (md->is_loaded() && md->is_instance_klass()) {
318       ciInstanceKlass* cik = md->as_instance_klass();
319 
320       if (cik->is_initialized()) {
321         InstanceKlass* ik = md->as_instance_klass()->get_instanceKlass();
322         KlassTrainingData* ktd = KlassTrainingData::make(ik);
323         if (ktd == nullptr) {
324           // Allocation failure or snapshot in progress
325           return;
326         }
327         // This JIT task is (probably) requesting that ik be initialized,
328         // so add him to my _init_deps list.
329         TrainingDataLocker l;
330         if (l.can_add()) {
331           add_init_dep(ktd);
332         }
333       }
334     }
335   }
336 }
337 
338 void KlassTrainingData::prepare(Visitor& visitor) {
339   if (visitor.is_visited(this)) {
340     return;
341   }
342   visitor.visit(this);
343   _comp_deps.prepare();
344 }
345 
346 void MethodTrainingData::prepare(Visitor& visitor) {
347   if (visitor.is_visited(this)) {
348     return;
349   }
350   visitor.visit(this);
351   klass()->prepare(visitor);
352   if (has_holder()) {
353     _final_counters = holder()->method_counters();

467   if (assembling_data()) {
468     _dumptime_training_data_dictionary = new DumptimeTrainingDataDictionary();
469     _archived_training_data_dictionary.iterate([&](TrainingData* record) {
470       _dumptime_training_data_dictionary->append(record);
471     });
472   }
473   if (need_data()) {
474     _dumptime_training_data_dictionary = new DumptimeTrainingDataDictionary();
475     TrainingDataLocker l;
476     TrainingDataLocker::snapshot();
477     ResourceMark rm;
478     Visitor visitor(training_data_set()->size());
479     training_data_set()->iterate([&](TrainingData* td) {
480       td->prepare(visitor);
481       if (!td->is_CompileTrainingData()) {
482         _dumptime_training_data_dictionary->append(td);
483       }
484     });
485   }
486 


487   if (AOTVerifyTrainingData) {
488     TrainingData::verify();
489   }
490 }
491 
492 void TrainingData::iterate_roots(MetaspaceClosure* it) {
493   if (_dumptime_training_data_dictionary != nullptr) {
494     for (int i = 0; i < _dumptime_training_data_dictionary->length(); i++) {
495       _dumptime_training_data_dictionary->at(i).metaspace_pointers_do(it);
496     }
497   }

498 }
499 
500 void TrainingData::dump_training_data() {
501   if (_dumptime_training_data_dictionary != nullptr) {
502     CompactHashtableStats stats;
503     _archived_training_data_dictionary_for_dumping.reset();
504     CompactHashtableWriter writer(_dumptime_training_data_dictionary->length(), &stats);
505     for (int i = 0; i < _dumptime_training_data_dictionary->length(); i++) {
506       TrainingData* td = _dumptime_training_data_dictionary->at(i).training_data();
507 #ifdef ASSERT
508       for (int j = i+1; j < _dumptime_training_data_dictionary->length(); j++) {
509         TrainingData* td1 = _dumptime_training_data_dictionary->at(j).training_data();
510         assert(!TrainingData::Key::equals(td1, td->key(), -1), "conflict");
511       }
512 #endif // ASSERT
513       td = ArchiveBuilder::current()->get_buffered_addr(td);
514       uint hash = TrainingData::Key::cds_hash(td->key());
515       u4 delta = ArchiveBuilder::current()->buffer_to_offset_u4((address)td);
516       writer.add(hash, delta);
517     }

524     ResourceMark rm;
525     Visitor visitor(_dumptime_training_data_dictionary->length());
526     for (int i = 0; i < _dumptime_training_data_dictionary->length(); i++) {
527       TrainingData* td = _dumptime_training_data_dictionary->at(i).training_data();
528       td->cleanup(visitor);
529     }
530     // Throw away all elements with empty keys
531     int j = 0;
532     for (int i = 0; i < _dumptime_training_data_dictionary->length(); i++) {
533       TrainingData* td = _dumptime_training_data_dictionary->at(i).training_data();
534       if (td->key()->is_empty()) {
535         continue;
536       }
537       if (i != j) { // no need to copy if it's the same
538         _dumptime_training_data_dictionary->at_put(j, td);
539       }
540       j++;
541     }
542     _dumptime_training_data_dictionary->trunc_to(j);
543   }

544 }
545 
546 void KlassTrainingData::cleanup(Visitor& visitor) {
547   if (visitor.is_visited(this)) {
548     return;
549   }
550   visitor.visit(this);
551   if (has_holder()) {
552     bool is_excluded = !holder()->is_loaded();
553     if (CDSConfig::is_at_aot_safepoint()) {
554       // Check for AOT exclusion only at AOT safe point.
555       is_excluded |= SystemDictionaryShared::should_be_excluded(holder());
556     }
557     if (is_excluded) {
558       ResourceMark rm;
559       log_debug(aot, training)("Cleanup KTD %s", name()->as_klass_external_name());
560       _holder = nullptr;
561       key()->make_empty();
562     }
563   }

637       tty->cr();
638     }
639     guarantee(invariant, "init deps invariant violation: %d >= %d", init_deps_left1, init_deps_left2);
640   }
641 }
642 
643 void CompileTrainingData::cleanup(Visitor& visitor) {
644   if (visitor.is_visited(this)) {
645     return;
646   }
647   visitor.visit(this);
648   method()->cleanup(visitor);
649 }
650 
651 void TrainingData::serialize(SerializeClosure* soc) {
652   if (soc->writing()) {
653     _archived_training_data_dictionary_for_dumping.serialize_header(soc);
654   } else {
655     _archived_training_data_dictionary.serialize_header(soc);
656   }

657 }
658 
659 class TrainingDataPrinter : StackObj {
660   outputStream* _st;
661   int _index;
662 public:
663   TrainingDataPrinter(outputStream* st) : _st(st), _index(0) {}
664   void do_value(TrainingData* td) {
665     const char* type = (td->is_KlassTrainingData()   ? "K" :
666                         td->is_MethodTrainingData()  ? "M" :
667                         td->is_CompileTrainingData() ? "C" : "?");
668     _st->print("%4d: %p %s ", _index++, td, type);
669     td->print_on(_st);
670     _st->cr();
671     if (td->is_KlassTrainingData()) {
672       td->as_KlassTrainingData()->iterate_comp_deps([&](CompileTrainingData* ctd) {
673         ResourceMark rm;
674         _st->print_raw("  C ");
675         ctd->print_on(_st);
676         _st->cr();
677       });
678     } else if (td->is_MethodTrainingData()) {
679       td->as_MethodTrainingData()->iterate_compiles([&](CompileTrainingData* ctd) {
680         ResourceMark rm;
681         _st->print_raw("  C ");
682         ctd->print_on(_st);
683         _st->cr();
684       });
685     } else if (td->is_CompileTrainingData()) {
686       // ?
687     }
688   }
689 };
690 
691 void TrainingData::print_archived_training_data_on(outputStream* st) {
692   st->print_cr("Archived TrainingData Dictionary");
693   TrainingDataPrinter tdp(st);
694   TrainingDataLocker::initialize();
695   _archived_training_data_dictionary.iterate(&tdp);

696 }
697 
698 void TrainingData::Key::metaspace_pointers_do(MetaspaceClosure *iter) {
699   iter->push(const_cast<Metadata**>(&_meta));
700 }
701 
702 void TrainingData::metaspace_pointers_do(MetaspaceClosure* iter) {
703   _key.metaspace_pointers_do(iter);
704 }
705 
706 bool TrainingData::Key::can_compute_cds_hash(const Key* const& k) {
707   return k->meta() == nullptr || MetaspaceObj::in_aot_cache(k->meta());
708 }
709 
710 uint TrainingData::Key::cds_hash(const Key* const& k) {
711   return SystemDictionaryShared::hash_for_shared_dictionary((address)k->meta());
712 }
713 
714 TrainingData* TrainingData::lookup_archived_training_data(const Key* k) {
715   // For this to work, all components of the key must be in shared metaspace.

 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "cds/cdsConfig.hpp"
 26 #include "ci/ciEnv.hpp"
 27 #include "ci/ciMetadata.hpp"
 28 #include "classfile/compactHashtable.hpp"
 29 #include "classfile/javaClasses.hpp"
 30 #include "classfile/symbolTable.hpp"
 31 #include "classfile/systemDictionaryShared.hpp"
 32 #include "compiler/compileTask.hpp"
 33 #include "memory/metadataFactory.hpp"
 34 #include "memory/metaspaceClosure.hpp"
 35 #include "memory/resourceArea.hpp"
 36 #include "memory/universe.hpp"
 37 #include "oops/method.hpp"
 38 #include "oops/method.inline.hpp"
 39 #include "oops/methodCounters.hpp"
 40 #include "oops/recompilationSchedule.hpp"
 41 #include "oops/trainingData.hpp"
 42 #include "runtime/arguments.hpp"
 43 #include "runtime/javaThread.inline.hpp"
 44 #include "runtime/jniHandles.inline.hpp"
 45 #include "utilities/growableArray.hpp"
 46 
 47 TrainingData::TrainingDataSet TrainingData::_training_data_set(1024, 0x3fffffff);
 48 TrainingData::TrainingDataDictionary TrainingData::_archived_training_data_dictionary;
 49 TrainingData::TrainingDataDictionary TrainingData::_archived_training_data_dictionary_for_dumping;
 50 TrainingData::DumptimeTrainingDataDictionary* TrainingData::_dumptime_training_data_dictionary = nullptr;
 51 int TrainingData::TrainingDataLocker::_lock_mode;
 52 volatile bool TrainingData::TrainingDataLocker::_snapshot = false;
 53 
 54 MethodTrainingData::MethodTrainingData() {
 55   // Used by cppVtables.cpp only
 56   assert(CDSConfig::is_dumping_static_archive() || UseSharedSpaces, "only for CDS");
 57 }
 58 
 59 KlassTrainingData::KlassTrainingData() {
 60   // Used by cppVtables.cpp only
 61   assert(CDSConfig::is_dumping_static_archive() || UseSharedSpaces, "only for CDS");
 62 }
 63 
 64 CompileTrainingData::CompileTrainingData() : _level(-1), _compile_id(-1) {
 65   // Used by cppVtables.cpp only
 66   assert(CDSConfig::is_dumping_static_archive() || UseSharedSpaces, "only for CDS");
 67 }
 68 
 69 void TrainingData::initialize() {
 70   // this is a nop if training modes are not enabled
 71   if (have_data() || need_data()) {
 72     // Data structures that we have do not currently support iterative training. So you cannot replay
 73     // and train at the same time. Going forward we may want to adjust iteration/search to enable that.
 74     guarantee(have_data() != need_data(), "Iterative training is not supported");
 75     TrainingDataLocker::initialize();
 76   }
 77   RecompilationSchedule::initialize();
 78 }
 79 
 80 static void verify_archived_entry(TrainingData* td, const TrainingData::Key* k) {
 81   guarantee(TrainingData::Key::can_compute_cds_hash(k), "");
 82   TrainingData* td1 = TrainingData::lookup_archived_training_data(k);
 83   guarantee(td == td1, "");
 84 }
 85 
 86 void TrainingData::verify() {
 87   if (TrainingData::have_data() && !TrainingData::assembling_data()) {
 88     archived_training_data_dictionary()->iterate([&](TrainingData* td) {
 89       if (td->is_KlassTrainingData()) {
 90         KlassTrainingData* ktd = td->as_KlassTrainingData();
 91         if (ktd->has_holder() && ktd->holder()->is_loaded()) {
 92           Key k(ktd->holder());
 93           verify_archived_entry(td, &k);
 94         }
 95         ktd->verify();
 96       } else if (td->is_MethodTrainingData()) {
 97         MethodTrainingData* mtd = td->as_MethodTrainingData();

294     for (int i = 0, len = _init_deps.length(); i < len; i++) {
295       st->print(" dep:");
296       _init_deps.at(i)->print_on(st, true);
297     }
298   }
299 }
300 
301 void CompileTrainingData::notice_inlined_method(CompileTask* task,
302                                                 const methodHandle& method) {
303   MethodTrainingData* mtd = MethodTrainingData::make(method);
304   if (mtd != nullptr) {
305     mtd->notice_compilation(task->comp_level(), true);
306   }
307 }
308 
309 void CompileTrainingData::notice_jit_observation(ciEnv* env, ciBaseObject* what) {
310   // A JIT is starting to look at class k.
311   // We could follow the queries that it is making, but it is
312   // simpler to assume, conservatively, that the JIT will
313   // eventually depend on the initialization state of k.
314   ciMetadata* md = nullptr;
315   if (what->is_object()) {
316     md = what->as_object()->klass();
317   } else if (what->is_metadata()) {
318     md = what->as_metadata();
319   }
320   if (md != nullptr && md->is_loaded() && md->is_instance_klass()) {
321     ciInstanceKlass* cik = md->as_instance_klass();
322     if (!cik->is_initialized()) {
323       return;
324     }
325     KlassTrainingData* ktd = KlassTrainingData::make(cik->get_instanceKlass());
326     if (ktd == nullptr) {
327       // Allocation failure or snapshot in progress
328       return;
329     }
330     // This JIT task is (probably) requesting that ik be initialized,
331     // so add it to my _init_deps list.
332     TrainingDataLocker l;
333     if (l.can_add()) {
334       add_init_dep(ktd);

335     }
336   }
337 }
338 
339 void KlassTrainingData::prepare(Visitor& visitor) {
340   if (visitor.is_visited(this)) {
341     return;
342   }
343   visitor.visit(this);
344   _comp_deps.prepare();
345 }
346 
347 void MethodTrainingData::prepare(Visitor& visitor) {
348   if (visitor.is_visited(this)) {
349     return;
350   }
351   visitor.visit(this);
352   klass()->prepare(visitor);
353   if (has_holder()) {
354     _final_counters = holder()->method_counters();

468   if (assembling_data()) {
469     _dumptime_training_data_dictionary = new DumptimeTrainingDataDictionary();
470     _archived_training_data_dictionary.iterate([&](TrainingData* record) {
471       _dumptime_training_data_dictionary->append(record);
472     });
473   }
474   if (need_data()) {
475     _dumptime_training_data_dictionary = new DumptimeTrainingDataDictionary();
476     TrainingDataLocker l;
477     TrainingDataLocker::snapshot();
478     ResourceMark rm;
479     Visitor visitor(training_data_set()->size());
480     training_data_set()->iterate([&](TrainingData* td) {
481       td->prepare(visitor);
482       if (!td->is_CompileTrainingData()) {
483         _dumptime_training_data_dictionary->append(td);
484       }
485     });
486   }
487 
488   RecompilationSchedule::prepare(CHECK);
489 
490   if (AOTVerifyTrainingData) {
491     TrainingData::verify();
492   }
493 }
494 
495 void TrainingData::iterate_roots(MetaspaceClosure* it) {
496   if (_dumptime_training_data_dictionary != nullptr) {
497     for (int i = 0; i < _dumptime_training_data_dictionary->length(); i++) {
498       _dumptime_training_data_dictionary->at(i).metaspace_pointers_do(it);
499     }
500   }
501   RecompilationSchedule::iterate_roots(it);
502 }
503 
504 void TrainingData::dump_training_data() {
505   if (_dumptime_training_data_dictionary != nullptr) {
506     CompactHashtableStats stats;
507     _archived_training_data_dictionary_for_dumping.reset();
508     CompactHashtableWriter writer(_dumptime_training_data_dictionary->length(), &stats);
509     for (int i = 0; i < _dumptime_training_data_dictionary->length(); i++) {
510       TrainingData* td = _dumptime_training_data_dictionary->at(i).training_data();
511 #ifdef ASSERT
512       for (int j = i+1; j < _dumptime_training_data_dictionary->length(); j++) {
513         TrainingData* td1 = _dumptime_training_data_dictionary->at(j).training_data();
514         assert(!TrainingData::Key::equals(td1, td->key(), -1), "conflict");
515       }
516 #endif // ASSERT
517       td = ArchiveBuilder::current()->get_buffered_addr(td);
518       uint hash = TrainingData::Key::cds_hash(td->key());
519       u4 delta = ArchiveBuilder::current()->buffer_to_offset_u4((address)td);
520       writer.add(hash, delta);
521     }

528     ResourceMark rm;
529     Visitor visitor(_dumptime_training_data_dictionary->length());
530     for (int i = 0; i < _dumptime_training_data_dictionary->length(); i++) {
531       TrainingData* td = _dumptime_training_data_dictionary->at(i).training_data();
532       td->cleanup(visitor);
533     }
534     // Throw away all elements with empty keys
535     int j = 0;
536     for (int i = 0; i < _dumptime_training_data_dictionary->length(); i++) {
537       TrainingData* td = _dumptime_training_data_dictionary->at(i).training_data();
538       if (td->key()->is_empty()) {
539         continue;
540       }
541       if (i != j) { // no need to copy if it's the same
542         _dumptime_training_data_dictionary->at_put(j, td);
543       }
544       j++;
545     }
546     _dumptime_training_data_dictionary->trunc_to(j);
547   }
548   RecompilationSchedule::cleanup();
549 }
550 
551 void KlassTrainingData::cleanup(Visitor& visitor) {
552   if (visitor.is_visited(this)) {
553     return;
554   }
555   visitor.visit(this);
556   if (has_holder()) {
557     bool is_excluded = !holder()->is_loaded();
558     if (CDSConfig::is_at_aot_safepoint()) {
559       // Check for AOT exclusion only at AOT safe point.
560       is_excluded |= SystemDictionaryShared::should_be_excluded(holder());
561     }
562     if (is_excluded) {
563       ResourceMark rm;
564       log_debug(aot, training)("Cleanup KTD %s", name()->as_klass_external_name());
565       _holder = nullptr;
566       key()->make_empty();
567     }
568   }

642       tty->cr();
643     }
644     guarantee(invariant, "init deps invariant violation: %d >= %d", init_deps_left1, init_deps_left2);
645   }
646 }
647 
648 void CompileTrainingData::cleanup(Visitor& visitor) {
649   if (visitor.is_visited(this)) {
650     return;
651   }
652   visitor.visit(this);
653   method()->cleanup(visitor);
654 }
655 
656 void TrainingData::serialize(SerializeClosure* soc) {
657   if (soc->writing()) {
658     _archived_training_data_dictionary_for_dumping.serialize_header(soc);
659   } else {
660     _archived_training_data_dictionary.serialize_header(soc);
661   }
662   RecompilationSchedule::serialize(soc);
663 }
664 
665 class TrainingDataPrinter : StackObj {
666   outputStream* _st;
667   int _index;
668 public:
669   TrainingDataPrinter(outputStream* st) : _st(st), _index(0) {}
670   void do_value(TrainingData* td) {
671     const char* type = (td->is_KlassTrainingData()   ? "K" :
672                         td->is_MethodTrainingData()  ? "M" :
673                         td->is_CompileTrainingData() ? "C" : "?");
674     _st->print("%4d: %p %s ", _index++, td, type);
675     td->print_on(_st);
676     _st->cr();
677     if (td->is_KlassTrainingData()) {
678       td->as_KlassTrainingData()->iterate_comp_deps([&](CompileTrainingData* ctd) {
679         ResourceMark rm;
680         _st->print_raw("  C ");
681         ctd->print_on(_st);
682         _st->cr();
683       });
684     } else if (td->is_MethodTrainingData()) {
685       td->as_MethodTrainingData()->iterate_compiles([&](CompileTrainingData* ctd) {
686         ResourceMark rm;
687         _st->print_raw("  C ");
688         ctd->print_on(_st);
689         _st->cr();
690       });
691     } else if (td->is_CompileTrainingData()) {
692       // ?
693     }
694   }
695 };
696 
697 void TrainingData::print_archived_training_data_on(outputStream* st) {
698   st->print_cr("Archived TrainingData Dictionary");
699   TrainingDataPrinter tdp(st);
700   TrainingDataLocker::initialize();
701   _archived_training_data_dictionary.iterate(&tdp);
702   RecompilationSchedule::print_archived_training_data_on(st);
703 }
704 
705 void TrainingData::Key::metaspace_pointers_do(MetaspaceClosure *iter) {
706   iter->push(const_cast<Metadata**>(&_meta));
707 }
708 
709 void TrainingData::metaspace_pointers_do(MetaspaceClosure* iter) {
710   _key.metaspace_pointers_do(iter);
711 }
712 
713 bool TrainingData::Key::can_compute_cds_hash(const Key* const& k) {
714   return k->meta() == nullptr || MetaspaceObj::in_aot_cache(k->meta());
715 }
716 
717 uint TrainingData::Key::cds_hash(const Key* const& k) {
718   return SystemDictionaryShared::hash_for_shared_dictionary((address)k->meta());
719 }
720 
721 TrainingData* TrainingData::lookup_archived_training_data(const Key* k) {
722   // For this to work, all components of the key must be in shared metaspace.
< prev index next >