< prev index next >

src/hotspot/share/oops/trainingData.cpp

Print this page

 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 #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/methodCounters.hpp"

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

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

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

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


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

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

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

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

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

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

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

 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 #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/methodCounters.hpp"
 39 #include "oops/recompilationSchedule.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   RecompilationSchedule::initialize();
 77 }
 78 
 79 static void verify_archived_entry(TrainingData* td, const TrainingData::Key* k) {
 80   guarantee(TrainingData::Key::can_compute_cds_hash(k), "");
 81   TrainingData* td1 = TrainingData::lookup_archived_training_data(k);
 82   guarantee(td == td1, "");
 83 }
 84 
 85 void TrainingData::verify() {
 86   if (TrainingData::have_data() && !TrainingData::assembling_data()) {
 87     archived_training_data_dictionary()->iterate([&](TrainingData* td) {
 88       if (td->is_KlassTrainingData()) {
 89         KlassTrainingData* ktd = td->as_KlassTrainingData();
 90         if (ktd->has_holder() && ktd->holder()->is_loaded()) {
 91           Key k(ktd->holder());
 92           verify_archived_entry(td, &k);
 93         }
 94         ktd->verify();
 95       } else if (td->is_MethodTrainingData()) {
 96         MethodTrainingData* mtd = td->as_MethodTrainingData();

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

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();

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

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

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