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.
|