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);
521 for (int i = 0; i < comp_dep_count(); i++) {
522 fn(comp_dep(i));
523 }
524 }
525 };
526
527 // Information about particular JIT tasks.
528 class CompileTrainingData : public TrainingData {
529 friend TrainingData;
530 friend KlassTrainingData;
531
532 // Used by CDS. These classes need to access the private default constructor.
533 template <class T> friend class CppVtableTesterA;
534 template <class T> friend class CppVtableTesterB;
535 template <class T> friend class CppVtableCloner;
536
537 MethodTrainingData* _method;
538 const short _level;
539 const int _compile_id;
540
541 // classes that should be initialized before this JIT task runs
542 DepList<KlassTrainingData*> _init_deps;
543 // Number of uninitialized classes left, when it's 0, all deps are satisfied
544 volatile int _init_deps_left;
545
546 public:
547 // ciRecords is a generic meachanism to memoize CI responses to arbitary queries. For each function we're interested in we record
548 // (return_value, argument_values) tuples in a list. Arguments are allowed to have Metaspace pointers in them.
549 class ciRecords {
550 template <typename... Ts> class Arguments {
551 public:
552 bool operator==(const Arguments<>&) const { return true; }
553 void metaspace_pointers_do(MetaspaceClosure *iter) { }
554 };
555 template <typename T, typename... Ts> class Arguments<T, Ts...> {
556 private:
557 T _first;
558 Arguments<Ts...> _remaining;
559
560 public:
637 void remove_unshareable_info() {
638 ciMethod__inline_instructions_size.remove_unshareable_info();
639 }
640 #endif
641 void prepare() {
642 ciMethod__inline_instructions_size.prepare();
643 }
644 void metaspace_pointers_do(MetaspaceClosure *iter) {
645 ciMethod__inline_instructions_size.metaspace_pointers_do(iter);
646 }
647 };
648
649 private:
650 ciRecords _ci_records;
651
652 CompileTrainingData();
653 CompileTrainingData(MethodTrainingData* mtd,
654 int level,
655 int compile_id)
656 : TrainingData(), // empty key
657 _method(mtd), _level(level), _compile_id(compile_id), _init_deps_left(0) { }
658 public:
659 ciRecords& ci_records() { return _ci_records; }
660 static CompileTrainingData* make(CompileTask* task) NOT_CDS_RETURN_(nullptr);
661
662 virtual CompileTrainingData* as_CompileTrainingData() const { return const_cast<CompileTrainingData*>(this); };
663
664 MethodTrainingData* method() const { return _method; }
665
666 int level() const { return _level; }
667
668 int compile_id() const { return _compile_id; }
669
670 int init_dep_count() const {
671 TrainingDataLocker::assert_locked();
672 return _init_deps.length();
673 }
674 KlassTrainingData* init_dep(int i) const {
675 TrainingDataLocker::assert_locked();
676 return _init_deps.at(i);
677 }
678 void add_init_dep(KlassTrainingData* ktd) {
679 TrainingDataLocker::assert_locked();
680 ktd->add_comp_dep(this);
681 _init_deps.append_if_missing(ktd);
682 }
683 void clear_init_deps() {
684 TrainingDataLocker::assert_locked();
685 for (int i = 0; i < _init_deps.length(); i++) {
686 _init_deps.at(i)->remove_comp_dep(this);
687 }
688 _init_deps.clear();
689 }
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;
802 }
803 _level_mask |= level_mask(level);
804 }
805
806 void notice_toplevel_compilation(int level) {
807 _highest_top_level = MAX2(_highest_top_level, level);
808 }
809
810 static MethodTrainingData* make(const methodHandle& method,
811 bool null_if_not_found = false,
812 bool use_cache = true) NOT_CDS_RETURN_(nullptr);
813 static MethodTrainingData* find_fast(const methodHandle& method) { return make(method, true, true); }
814 static MethodTrainingData* find(const methodHandle& method) { return make(method, true, false); }
815
816 virtual MethodTrainingData* as_MethodTrainingData() const {
817 return const_cast<MethodTrainingData*>(this);
|
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);
530 for (int i = 0; i < comp_dep_count(); i++) {
531 fn(comp_dep(i));
532 }
533 }
534 };
535
536 // Information about particular JIT tasks.
537 class CompileTrainingData : public TrainingData {
538 friend TrainingData;
539 friend KlassTrainingData;
540
541 // Used by CDS. These classes need to access the private default constructor.
542 template <class T> friend class CppVtableTesterA;
543 template <class T> friend class CppVtableTesterB;
544 template <class T> friend class CppVtableCloner;
545
546 MethodTrainingData* _method;
547 const short _level;
548 const int _compile_id;
549
550 // Size of nmethod code during training
551 int _inline_instructions_size;
552
553 // classes that should be initialized before this JIT task runs
554 DepList<KlassTrainingData*> _init_deps;
555 // Number of uninitialized classes left, when it's 0, all deps are satisfied
556 volatile int _init_deps_left;
557
558 public:
559 // ciRecords is a generic meachanism to memoize CI responses to arbitary queries. For each function we're interested in we record
560 // (return_value, argument_values) tuples in a list. Arguments are allowed to have Metaspace pointers in them.
561 class ciRecords {
562 template <typename... Ts> class Arguments {
563 public:
564 bool operator==(const Arguments<>&) const { return true; }
565 void metaspace_pointers_do(MetaspaceClosure *iter) { }
566 };
567 template <typename T, typename... Ts> class Arguments<T, Ts...> {
568 private:
569 T _first;
570 Arguments<Ts...> _remaining;
571
572 public:
649 void remove_unshareable_info() {
650 ciMethod__inline_instructions_size.remove_unshareable_info();
651 }
652 #endif
653 void prepare() {
654 ciMethod__inline_instructions_size.prepare();
655 }
656 void metaspace_pointers_do(MetaspaceClosure *iter) {
657 ciMethod__inline_instructions_size.metaspace_pointers_do(iter);
658 }
659 };
660
661 private:
662 ciRecords _ci_records;
663
664 CompileTrainingData();
665 CompileTrainingData(MethodTrainingData* mtd,
666 int level,
667 int compile_id)
668 : TrainingData(), // empty key
669 _method(mtd), _level(level), _compile_id(compile_id), _inline_instructions_size(0), _init_deps_left(0) { }
670 public:
671 ciRecords& ci_records() { return _ci_records; }
672 static CompileTrainingData* make(CompileTask* task) NOT_CDS_RETURN_(nullptr);
673
674 virtual CompileTrainingData* as_CompileTrainingData() const { return const_cast<CompileTrainingData*>(this); };
675
676 MethodTrainingData* method() const { return _method; }
677
678 int level() const { return _level; }
679
680 int compile_id() const { return _compile_id; }
681
682 int inline_instructions_size() const { return _inline_instructions_size; }
683 void set_inline_instructions_size(int size) { _inline_instructions_size = size; }
684
685 int init_dep_count() const {
686 TrainingDataLocker::assert_locked();
687 return _init_deps.length();
688 }
689 KlassTrainingData* init_dep(int i) const {
690 TrainingDataLocker::assert_locked();
691 return _init_deps.at(i);
692 }
693 void add_init_dep(KlassTrainingData* ktd) {
694 TrainingDataLocker::assert_locked();
695 ktd->add_comp_dep(this);
696 _init_deps.append_if_missing(ktd);
697 }
698 void clear_init_deps() {
699 TrainingDataLocker::assert_locked();
700 for (int i = 0; i < _init_deps.length(); i++) {
701 _init_deps.at(i)->remove_comp_dep(this);
702 }
703 _init_deps.clear();
704 }
766 int _invocation_count;
767 int _backedge_count;
768
769 MethodTrainingData();
770 MethodTrainingData(Method* method, KlassTrainingData* ktd) : TrainingData(method) {
771 _klass = ktd;
772 _holder = method;
773 for (int i = 0; i < CompLevel_count - 1; i++) {
774 _last_toplevel_compiles[i] = nullptr;
775 }
776 _highest_top_level = CompLevel_none;
777 _level_mask = 0;
778 _was_toplevel = false;
779 _invocation_count = 0;
780 _backedge_count = 0;
781 }
782
783 static int level_mask(int level) {
784 return ((level & 0xF) != level ? 0 : 1 << level);
785 }
786 static CompLevel highest_level(int mask) {
787 if (mask == 0) return (CompLevel) 0;
788 int diff = (count_leading_zeros(level_mask(0)) - count_leading_zeros(mask));
789 return (CompLevel) diff;
790 }
791
792 public:
793 KlassTrainingData* klass() const { return _klass; }
794 bool has_holder() const { return _holder != nullptr; }
795 Method* holder() const { return _holder; }
796 bool only_inlined() const { return !_was_toplevel; }
797 bool saw_level(CompLevel l) const { return (_level_mask & level_mask(l)) != 0; }
798 int highest_level() const { return highest_level(_level_mask); }
799 int highest_top_level() const { return _highest_top_level; }
800 MethodData* final_profile() const { return _final_profile; }
801 int invocation_count() const { return _invocation_count; }
802 int backedge_count() const { return _backedge_count; }
803
804 Symbol* name() const {
805 precond(has_holder());
806 return holder()->name();
807 }
808 Symbol* signature() const {
809 precond(has_holder());
810 return holder()->signature();
811 }
812
813 CompileTrainingData* last_toplevel_compile(int level) const {
814 if (level > CompLevel_none) {
815 return _last_toplevel_compiles[level - 1];
816 }
817 return nullptr;
818 }
819
820 CompileTrainingData* compile_data_for_aot_code(int level) const {
821 CompileTrainingData* ctd = last_toplevel_compile(level);
822 if (ctd == nullptr && level == CompLevel_limited_profile) {
823 // We compile CompLevel_limited_profile AOT code for CompLevel_full_profile
824 ctd = _last_toplevel_compiles[CompLevel_full_profile - 1];
825 }
826 return ctd;
827 }
828
829 void notice_compilation(int level, bool inlined = false) {
830 if (!inlined) {
831 _was_toplevel = true;
832 }
833 _level_mask |= level_mask(level);
834 }
835
836 void notice_toplevel_compilation(int level) {
837 _highest_top_level = MAX2(_highest_top_level, level);
838 }
839
840 static MethodTrainingData* make(const methodHandle& method,
841 bool null_if_not_found = false,
842 bool use_cache = true) NOT_CDS_RETURN_(nullptr);
843 static MethodTrainingData* find_fast(const methodHandle& method) { return make(method, true, true); }
844 static MethodTrainingData* find(const methodHandle& method) { return make(method, true, false); }
845
846 virtual MethodTrainingData* as_MethodTrainingData() const {
847 return const_cast<MethodTrainingData*>(this);
|