1 /* 2 * Copyright (c) 2023, 2024, 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/archiveUtils.hpp" 29 #include "classfile/compactHashtable.hpp" 30 #include "compiler/compilerDefinitions.hpp" 31 #include "compiler/compiler_globals.hpp" 32 #include "memory/allocation.hpp" 33 #include "memory/metaspaceClosure.hpp" 34 #include "oops/instanceKlass.hpp" 35 #include "oops/symbolHandle.hpp" 36 #include "runtime/fieldDescriptor.inline.hpp" 37 #include "runtime/handles.hpp" 38 #include "runtime/mutexLocker.hpp" 39 #include "utilities/count_leading_zeros.hpp" 40 #include "utilities/resizeableResourceHash.hpp" 41 42 class ciEnv; 43 class ciBaseObject; 44 class CompileTask; 45 class xmlStream; 46 class CompileTrainingData; 47 class KlassTrainingData; 48 class MethodTrainingData; 49 class TrainingDataDumper; 50 class TrainingDataSetLocker; 51 class DumpTimeTrainingDataInfo; 52 class RunTimeClassInfo; 53 class RunTimeMethodDataInfo; 54 55 class TrainingData : public Metadata { 56 friend KlassTrainingData; 57 friend MethodTrainingData; 58 friend CompileTrainingData; 59 public: 60 class Key { 61 mutable Metadata* _meta; 62 // These guys can get to my constructors: 63 friend TrainingData; 64 friend KlassTrainingData; 65 friend MethodTrainingData; 66 friend CompileTrainingData; 67 68 // The empty key 69 Key() : _meta(nullptr) { } 70 bool is_empty() const { return _meta == nullptr; } 71 public: 72 Key(Metadata* meta) : _meta(meta) { } 73 74 static bool can_compute_cds_hash(const Key* const& k); 75 static uint cds_hash(const Key* const& k); 76 static unsigned hash(const Key* const& k) { 77 return primitive_hash(k->meta()); 78 } 79 static bool equals(const Key* const& k1, const Key* const& k2) { 80 return k1->meta() == k2->meta(); 81 } 82 static inline bool equals(TrainingData* value, const TrainingData::Key* key, int unused) { 83 return equals(value->key(), key); 84 } 85 int cmp(const Key* that) const { 86 auto m1 = this->meta(); 87 auto m2 = that->meta(); 88 if (m1 < m2) return -1; 89 if (m1 > m2) return +1; 90 return 0; 91 } 92 Metadata* meta() const { return _meta; } 93 void metaspace_pointers_do(MetaspaceClosure *iter); 94 void make_empty() const { _meta = nullptr; } 95 }; 96 97 class TrainingDataLocker { 98 static volatile bool _snapshot; 99 static int _lock_mode; 100 static void lock() { 101 assert(_lock_mode != 0, "Forgot to call TrainingDataLocker::initialize()"); 102 if (_lock_mode > 0) { 103 TrainingData_lock->lock(); 104 } 105 } 106 static void unlock() { 107 if (_lock_mode > 0) { 108 TrainingData_lock->unlock(); 109 } 110 } 111 static bool safely_locked() { 112 assert(_lock_mode != 0, "Forgot to call TrainingDataLocker::initialize()"); 113 if (_lock_mode > 0) { 114 return TrainingData_lock->owned_by_self(); 115 } else { 116 return true; 117 } 118 } 119 public: 120 static void snapshot() { 121 assert_locked(); 122 _snapshot = true; 123 } 124 static bool can_add() { 125 assert_locked(); 126 return !_snapshot; 127 } 128 static void initialize() { 129 _lock_mode = need_data() ? +1 : -1; // if -1, we go lock-free 130 } 131 static void assert_locked() { 132 assert(safely_locked(), "use under TrainingDataLocker"); 133 } 134 static void assert_can_add() { 135 assert(can_add(), "Cannot add TrainingData objects"); 136 } 137 TrainingDataLocker() { 138 lock(); 139 } 140 ~TrainingDataLocker() { 141 unlock(); 142 } 143 }; 144 class TrainingDataSet { 145 friend TrainingData; 146 ResizeableResourceHashtable<const Key*, TrainingData*, 147 AnyObj::C_HEAP, MemTag::mtCompiler, 148 &TrainingData::Key::hash, 149 &TrainingData::Key::equals> 150 _table; 151 152 public: 153 template<typename... Arg> 154 TrainingDataSet(Arg... arg) 155 : _table(arg...) { 156 } 157 TrainingData* find(const Key* key) const { 158 TrainingDataLocker::assert_locked(); 159 if (TrainingDataLocker::can_add()) { 160 auto res = _table.get(key); 161 return res == nullptr ? nullptr : *res; 162 } 163 return nullptr; 164 } 165 bool remove(const Key* key) { 166 return _table.remove(key); 167 } 168 TrainingData* install(TrainingData* tdata) { 169 TrainingDataLocker::assert_locked(); 170 TrainingDataLocker::assert_can_add(); 171 auto key = tdata->key(); 172 if (key->is_empty()) return tdata; // unkeyed TD not installed 173 bool created = false; 174 auto prior = _table.put_if_absent(key, tdata, &created); 175 if (prior == nullptr || *prior == tdata) { 176 return tdata; 177 } 178 assert(false, "no pre-existing elements allowed"); 179 return *prior; 180 } 181 template<typename FN> 182 void iterate_all(FN fn) const { // lambda enabled API 183 return _table.iterate_all(fn); 184 } 185 int size() const { return _table.number_of_entries(); } 186 187 void verify() const { 188 TrainingDataLocker::assert_locked(); 189 iterate_all([&](const TrainingData::Key* k, TrainingData* td) { 190 td->verify(); 191 }); 192 } 193 }; 194 195 class Visitor { 196 ResizeableResourceHashtable<TrainingData*, bool> _visited; 197 public: 198 Visitor(unsigned size) : _visited(size, 0x3fffffff) { } 199 bool is_visited(TrainingData* td) { 200 return _visited.contains(td); 201 } 202 void visit(TrainingData* td) { 203 bool created; 204 _visited.put_if_absent(td, &created); 205 } 206 }; 207 208 typedef OffsetCompactHashtable<const TrainingData::Key*, TrainingData*, TrainingData::Key::equals> TrainingDataDictionary; 209 private: 210 Key _key; 211 212 // just forward all constructor arguments to the embedded key 213 template<typename... Arg> 214 TrainingData(Arg... arg) 215 : _key(arg...) { } 216 217 static TrainingDataSet _training_data_set; 218 static TrainingDataDictionary _archived_training_data_dictionary; 219 static TrainingDataDictionary _archived_training_data_dictionary_for_dumping; 220 typedef GrowableArrayCHeap<DumpTimeTrainingDataInfo, mtClassShared> DumptimeTrainingDataDictionary; 221 static DumptimeTrainingDataDictionary* _dumptime_training_data_dictionary; 222 public: 223 // Returns the key under which this TD is installed, or else 224 // Key::EMPTY if it is not installed. 225 const Key* key() const { return &_key; } 226 227 static bool have_data() { return ReplayTraining; } // Going to read 228 static bool need_data() { return RecordTraining; } // Going to write 229 230 static TrainingDataSet* training_data_set() { return &_training_data_set; } 231 static TrainingDataDictionary* archived_training_data_dictionary() { return &_archived_training_data_dictionary; } 232 233 virtual MethodTrainingData* as_MethodTrainingData() const { return nullptr; } 234 virtual KlassTrainingData* as_KlassTrainingData() const { return nullptr; } 235 virtual CompileTrainingData* as_CompileTrainingData() const { return nullptr; } 236 bool is_MethodTrainingData() const { return as_MethodTrainingData() != nullptr; } 237 bool is_KlassTrainingData() const { return as_KlassTrainingData() != nullptr; } 238 bool is_CompileTrainingData() const { return as_CompileTrainingData() != nullptr; } 239 240 virtual void prepare(Visitor& visitor) = 0; 241 virtual void cleanup(Visitor& visitor) = 0; 242 243 static void initialize(); 244 245 static void verify(); 246 247 // Widget for recording dependencies, as an N-to-M graph relation, 248 // possibly cyclic. 249 template<typename E> 250 class DepList : public StackObj { 251 GrowableArrayCHeap<E, mtCompiler>* _deps_dyn; 252 Array<E>* _deps; 253 // (hmm, could we have state-selected union of these two?) 254 public: 255 DepList() { 256 _deps_dyn = nullptr; 257 _deps = nullptr; 258 } 259 260 int length() const { 261 return (_deps_dyn != nullptr ? _deps_dyn->length() 262 : _deps != nullptr ? _deps->length() 263 : 0); 264 } 265 E* adr_at(int i) const { 266 return (_deps_dyn != nullptr ? _deps_dyn->adr_at(i) 267 : _deps != nullptr ? _deps->adr_at(i) 268 : nullptr); 269 } 270 E at(int i) const { 271 assert(i >= 0 && i < length(), "oob"); 272 return *adr_at(i); 273 } 274 bool append_if_missing(E dep) { 275 if (_deps_dyn == nullptr) { 276 _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(10); 277 _deps_dyn->append(dep); 278 return true; 279 } else { 280 return _deps_dyn->append_if_missing(dep); 281 } 282 } 283 bool remove_if_existing(E dep) { 284 if (_deps_dyn != nullptr) { 285 return _deps_dyn->remove_if_existing(dep); 286 } 287 return false; 288 } 289 void clear() { 290 if (_deps_dyn != nullptr) { 291 _deps_dyn->clear(); 292 } 293 } 294 void append(E dep) { 295 if (_deps_dyn == nullptr) { 296 _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(10); 297 } 298 _deps_dyn->append(dep); 299 } 300 bool contains(E dep) { 301 for (int i = 0; i < length(); i++) { 302 if (dep == at(i)) { 303 return true; // found 304 } 305 } 306 return false; // not found 307 } 308 309 #if INCLUDE_CDS 310 void remove_unshareable_info() { 311 _deps_dyn = nullptr; 312 } 313 #endif 314 void prepare(ClassLoaderData* loader_data); 315 void metaspace_pointers_do(MetaspaceClosure *iter); 316 }; 317 318 virtual void metaspace_pointers_do(MetaspaceClosure *iter); 319 320 static void init_dumptime_table(TRAPS); 321 322 #if INCLUDE_CDS 323 virtual void remove_unshareable_info() {} 324 static void iterate_roots(MetaspaceClosure* it); 325 static void dump_training_data(); 326 static void cleanup_training_data(); 327 static void serialize_training_data(SerializeClosure* soc); 328 static void print_archived_training_data_on(outputStream* st); 329 static void write_training_data_dictionary(TrainingDataDictionary* dictionary); 330 static size_t estimate_size_for_archive(); 331 332 static TrainingData* lookup_archived_training_data(const Key* k); 333 #endif 334 335 static KlassTrainingData* lookup_for(InstanceKlass* ik); 336 static MethodTrainingData* lookup_for(Method* m); 337 }; 338 339 class KlassTrainingData : public TrainingData { 340 friend TrainingData; 341 friend CompileTrainingData; 342 343 // Used by CDS. These classes need to access the private default constructor. 344 template <class T> friend class CppVtableTesterA; 345 template <class T> friend class CppVtableTesterB; 346 template <class T> friend class CppVtableCloner; 347 348 // cross-link to live klass, or null if not loaded or encountered yet 349 InstanceKlass* _holder; 350 jobject _holder_mirror; // extra link to prevent unloading by GC 351 352 DepList<CompileTrainingData*> _comp_deps; // compiles that depend on me 353 354 KlassTrainingData(); 355 KlassTrainingData(InstanceKlass* klass); 356 357 int comp_dep_count() const { 358 TrainingDataLocker::assert_locked(); 359 return _comp_deps.length(); 360 } 361 CompileTrainingData* comp_dep(int i) const { 362 TrainingDataLocker::assert_locked(); 363 return _comp_deps.at(i); 364 } 365 void add_comp_dep(CompileTrainingData* ctd) { 366 TrainingDataLocker::assert_locked(); 367 _comp_deps.append_if_missing(ctd); 368 } 369 void remove_comp_dep(CompileTrainingData* ctd) { 370 TrainingDataLocker::assert_locked(); 371 _comp_deps.remove_if_existing(ctd); 372 } 373 374 public: 375 Symbol* name() const { 376 precond(has_holder()); 377 return holder()->name(); 378 } 379 Symbol* loader_name() const { 380 precond(has_holder()); 381 return holder()->class_loader_name_and_id(); 382 } 383 bool has_holder() const { return _holder != nullptr; } 384 InstanceKlass* holder() const { return _holder; } 385 386 static KlassTrainingData* make(InstanceKlass* holder, 387 bool null_if_not_found = false); 388 static KlassTrainingData* find(InstanceKlass* holder) { 389 return make(holder, true); 390 } 391 virtual KlassTrainingData* as_KlassTrainingData() const { return const_cast<KlassTrainingData*>(this); }; 392 393 ClassLoaderData* class_loader_data() { 394 assert(has_holder(), ""); 395 return holder()->class_loader_data(); 396 } 397 void notice_fully_initialized(); 398 399 void print_on(outputStream* st, bool name_only) const; 400 virtual void print_on(outputStream* st) const { print_on(st, false); } 401 virtual void print_value_on(outputStream* st) const { print_on(st, true); } 402 403 virtual void prepare(Visitor& visitor); 404 virtual void cleanup(Visitor& visitor) NOT_CDS_RETURN; 405 406 MetaspaceObj::Type type() const { 407 return KlassTrainingDataType; 408 } 409 410 #if INCLUDE_CDS 411 virtual void remove_unshareable_info(); 412 #endif 413 414 void metaspace_pointers_do(MetaspaceClosure *iter); 415 416 int size() const { 417 return (int)align_metadata_size(align_up(sizeof(KlassTrainingData), BytesPerWord)/BytesPerWord); 418 } 419 420 const char* internal_name() const { 421 return "{ klass training data }"; 422 }; 423 424 void verify(); 425 426 static KlassTrainingData* allocate(InstanceKlass* holder); 427 428 template<typename FN> 429 void iterate_all_comp_deps(FN fn) const { // lambda enabled API 430 TrainingDataLocker l; 431 for (int i = 0; i < comp_dep_count(); i++) { 432 fn(comp_dep(i)); 433 } 434 } 435 }; 436 437 // Information about particular JIT tasks. 438 class CompileTrainingData : public TrainingData { 439 friend KlassTrainingData; 440 441 // Used by CDS. These classes need to access the private default constructor. 442 template <class T> friend class CppVtableTesterA; 443 template <class T> friend class CppVtableTesterB; 444 template <class T> friend class CppVtableCloner; 445 446 MethodTrainingData* _method; 447 const short _level; 448 const int _compile_id; 449 int _nm_total_size; 450 float _qtime, _stime, _etime; // time queued, started, ended 451 452 // classes that should be initialized before this JIT task runs 453 DepList<KlassTrainingData*> _init_deps; 454 volatile int _init_deps_left; 455 456 public: 457 class ciRecords { 458 template <typename... Ts> class Arguments { 459 public: 460 bool operator==(const Arguments<>&) const { return true; } 461 void metaspace_pointers_do(MetaspaceClosure *iter) { } 462 }; 463 template <typename T, typename... Ts> class Arguments<T, Ts...> { 464 private: 465 T _first; 466 Arguments<Ts...> _remaining; 467 468 public: 469 constexpr Arguments(const T& first, const Ts&... remaining) noexcept 470 : _first(first), _remaining(remaining...) {} 471 constexpr Arguments() noexcept : _first(), _remaining() {} 472 bool operator==(const Arguments<T, Ts...>& that) const { 473 return _first == that._first && _remaining == that._remaining; 474 } 475 template<typename U = T, std::enable_if_t<std::is_pointer<U>::value && std::is_base_of<MetaspaceObj, typename std::remove_pointer<U>::type>::value, int> = 0> 476 void metaspace_pointers_do(MetaspaceClosure *iter) { 477 iter->push(&_first); 478 _remaining.metaspace_pointers_do(iter); 479 } 480 template<typename U = T, std::enable_if_t<!(std::is_pointer<U>::value && std::is_base_of<MetaspaceObj, typename std::remove_pointer<U>::type>::value), int> = 0> 481 void metaspace_pointers_do(MetaspaceClosure *iter) { 482 _remaining.metaspace_pointers_do(iter); 483 } 484 }; 485 486 template <typename ReturnType, typename... Args> class ciMemoizedFunction : public StackObj { 487 public: 488 class OptionalReturnType { 489 bool _valid; 490 ReturnType _result; 491 public: 492 OptionalReturnType(bool valid, const ReturnType& result) : _valid(valid), _result(result) {} 493 bool is_valid() const { return _valid; } 494 ReturnType result() const { return _result; } 495 }; 496 private: 497 typedef Arguments<Args...> ArgumentsType; 498 class Record : public MetaspaceObj { 499 ReturnType _result; 500 ArgumentsType _arguments; 501 public: 502 Record(const ReturnType& result, const ArgumentsType& arguments) : _result(result), _arguments(arguments) {} 503 Record() { } 504 ReturnType result() const { return _result; } 505 ArgumentsType arguments() const { return _arguments; } 506 bool operator==(const Record& that) { return _arguments == that._arguments; } 507 void metaspace_pointers_do(MetaspaceClosure *iter) { _arguments.metaspace_pointers_do(iter); } 508 }; 509 DepList<Record> _data; 510 public: 511 OptionalReturnType find(const Args&... args) { 512 ArgumentsType a(args...); 513 for (int i = 0; i < _data.length(); i++) { 514 if (_data.at(i).arguments() == a) { 515 return OptionalReturnType(true, _data.at(i).result()); 516 } 517 } 518 return OptionalReturnType(false, ReturnType()); 519 } 520 bool append_if_missing(const ReturnType& result, const Args&... args) { 521 return _data.append_if_missing(Record(result, ArgumentsType(args...))); 522 } 523 #if INCLUDE_CDS 524 void remove_unshareable_info() { _data.remove_unshareable_info(); } 525 #endif 526 void prepare(ClassLoaderData* loader_data) { 527 _data.prepare(loader_data); 528 } 529 void metaspace_pointers_do(MetaspaceClosure *iter) { 530 _data.metaspace_pointers_do(iter); 531 } 532 }; 533 534 535 public: 536 typedef ciMemoizedFunction<int, MethodTrainingData*> ciMethod__inline_instructions_size_type; 537 ciMethod__inline_instructions_size_type ciMethod__inline_instructions_size; 538 #if INCLUDE_CDS 539 void remove_unshareable_info() { 540 ciMethod__inline_instructions_size.remove_unshareable_info(); 541 } 542 #endif 543 void prepare(ClassLoaderData* loader_data) { 544 ciMethod__inline_instructions_size.prepare(loader_data); 545 } 546 void metaspace_pointers_do(MetaspaceClosure *iter) { 547 ciMethod__inline_instructions_size.metaspace_pointers_do(iter); 548 } 549 }; 550 551 private: 552 ciRecords _ci_records; 553 554 CompileTrainingData(); 555 // (should we also capture counters or MDO state or replay data?) 556 CompileTrainingData(MethodTrainingData* mtd, 557 int level, 558 int compile_id) 559 : TrainingData(), // empty key 560 _method(mtd), _level(level), _compile_id(compile_id) 561 { 562 _qtime = _stime = _etime = 0; 563 _nm_total_size = 0; 564 _init_deps_left = 0; 565 } 566 567 public: 568 ciRecords& ci_records() { return _ci_records; } 569 static CompileTrainingData* make(CompileTask* task); 570 571 virtual CompileTrainingData* as_CompileTrainingData() const { return const_cast<CompileTrainingData*>(this); }; 572 573 MethodTrainingData* method() const { return _method; } 574 575 int level() const { return _level; } 576 577 int compile_id() const { return _compile_id; } 578 579 int init_dep_count() const { 580 TrainingDataLocker::assert_locked(); 581 return _init_deps.length(); 582 } 583 KlassTrainingData* init_dep(int i) const { 584 TrainingDataLocker::assert_locked(); 585 return _init_deps.at(i); 586 } 587 void add_init_dep(KlassTrainingData* ktd) { 588 TrainingDataLocker::assert_locked(); 589 ktd->add_comp_dep(this); 590 _init_deps.append_if_missing(ktd); 591 } 592 void clear_init_deps() { 593 TrainingDataLocker::assert_locked(); 594 for (int i = 0; i < _init_deps.length(); i++) { 595 _init_deps.at(i)->remove_comp_dep(this); 596 } 597 _init_deps.clear(); 598 } 599 void dec_init_deps_left(KlassTrainingData* ktd); 600 int init_deps_left() const { 601 return Atomic::load(&_init_deps_left); 602 } 603 uint compute_init_deps_left(bool count_initialized = false); 604 605 void record_compilation_queued(CompileTask* task); 606 void record_compilation_start(CompileTask* task); 607 void record_compilation_end(CompileTask* task); 608 void notice_inlined_method(CompileTask* task, const methodHandle& method); 609 610 // The JIT looks at classes and objects too and can depend on their state. 611 // These simple calls just report the *possibility* of an observation. 612 void notice_jit_observation(ciEnv* env, ciBaseObject* what); 613 614 virtual void prepare(Visitor& visitor); 615 virtual void cleanup(Visitor& visitor) NOT_CDS_RETURN; 616 617 void print_on(outputStream* st, bool name_only) const; 618 virtual void print_on(outputStream* st) const { print_on(st, false); } 619 virtual void print_value_on(outputStream* st) const { print_on(st, true); } 620 621 #if INCLUDE_CDS 622 virtual void remove_unshareable_info(); 623 #endif 624 625 virtual void metaspace_pointers_do(MetaspaceClosure* iter); 626 virtual MetaspaceObj::Type type() const { return CompileTrainingDataType; } 627 628 virtual const char* internal_name() const { 629 return "{ compile training data }"; 630 }; 631 632 virtual int size() const { 633 return (int)align_metadata_size(align_up(sizeof(CompileTrainingData), BytesPerWord)/BytesPerWord); 634 } 635 636 void verify(); 637 638 static CompileTrainingData* allocate(MethodTrainingData* mtd, int level, int compile_id); 639 }; 640 641 // Record information about a method at the time compilation is requested. 642 class MethodTrainingData : public TrainingData { 643 friend TrainingData; 644 friend CompileTrainingData; 645 646 // Used by CDS. These classes need to access the private default constructor. 647 template <class T> friend class CppVtableTesterA; 648 template <class T> friend class CppVtableTesterB; 649 template <class T> friend class CppVtableCloner; 650 651 KlassTrainingData* _klass; 652 Method* _holder; // can be null 653 CompileTrainingData* _last_toplevel_compiles[CompLevel_count]; 654 int _highest_top_level; 655 int _level_mask; // bit-set of all possible levels 656 bool _was_inlined; 657 bool _was_toplevel; 658 // metadata snapshots of final state: 659 MethodCounters* _final_counters; 660 MethodData* _final_profile; 661 662 MethodTrainingData(); 663 MethodTrainingData(Method* method, KlassTrainingData* ktd) : TrainingData(method) { 664 _klass = ktd; 665 _holder = method; 666 for (int i = 0; i < CompLevel_count; i++) { 667 _last_toplevel_compiles[i] = nullptr; 668 } 669 _highest_top_level = CompLevel_none; 670 _level_mask = 0; 671 _was_inlined = _was_toplevel = false; 672 } 673 674 static int level_mask(int level) { 675 return ((level & 0xF) != level ? 0 : 1 << level); 676 } 677 static CompLevel highest_level(int mask) { 678 if (mask == 0) return (CompLevel) 0; 679 int diff = (count_leading_zeros(level_mask(0)) - count_leading_zeros(mask)); 680 return (CompLevel) diff; 681 } 682 683 public: 684 KlassTrainingData* klass() const { return _klass; } 685 bool has_holder() const { return _holder != nullptr; } 686 Method* holder() const { return _holder; } 687 bool only_inlined() const { return !_was_toplevel; } 688 bool never_inlined() const { return !_was_inlined; } 689 bool saw_level(CompLevel l) const { return (_level_mask & level_mask(l)) != 0; } 690 int highest_level() const { return highest_level(_level_mask); } 691 int highest_top_level() const { return _highest_top_level; } 692 MethodData* final_profile() const { return _final_profile; } 693 694 Symbol* name() const { 695 precond(has_holder()); 696 return holder()->name(); 697 } 698 Symbol* signature() const { 699 precond(has_holder()); 700 return holder()->signature(); 701 } 702 703 CompileTrainingData* last_toplevel_compile(int level) const { 704 if (level > CompLevel_none) { 705 return _last_toplevel_compiles[level - 1]; 706 } 707 return nullptr; 708 } 709 710 void notice_compilation(int level, bool inlined = false) { 711 if (inlined) { 712 _was_inlined = true; 713 } else { 714 _was_toplevel = true; 715 } 716 _level_mask |= level_mask(level); 717 } 718 719 static MethodTrainingData* make(const methodHandle& method, 720 bool null_if_not_found = false); 721 static MethodTrainingData* find(const methodHandle& method) { 722 return make(method, true); 723 } 724 725 virtual MethodTrainingData* as_MethodTrainingData() const { 726 return const_cast<MethodTrainingData*>(this); 727 }; 728 729 void print_on(outputStream* st, bool name_only) const; 730 virtual void print_on(outputStream* st) const { print_on(st, false); } 731 virtual void print_value_on(outputStream* st) const { print_on(st, true); } 732 733 virtual void prepare(Visitor& visitor); 734 virtual void cleanup(Visitor& visitor) NOT_CDS_RETURN; 735 736 template<typename FN> 737 void iterate_all_compiles(FN fn) const { // lambda enabled API 738 for (int i = 0; i < CompLevel_count; i++) { 739 CompileTrainingData* ctd = _last_toplevel_compiles[i]; 740 if (ctd != nullptr) { 741 fn(ctd); 742 } 743 } 744 } 745 746 virtual void metaspace_pointers_do(MetaspaceClosure* iter); 747 virtual MetaspaceObj::Type type() const { return MethodTrainingDataType; } 748 749 #if INCLUDE_CDS 750 virtual void remove_unshareable_info(); 751 #endif 752 753 virtual int size() const { 754 return (int)align_metadata_size(align_up(sizeof(MethodTrainingData), BytesPerWord)/BytesPerWord); 755 } 756 757 virtual const char* internal_name() const { 758 return "{ method training data }"; 759 }; 760 761 void verify(); 762 763 static MethodTrainingData* allocate(Method* m, KlassTrainingData* ktd); 764 }; 765 766 // CDS support 767 768 class DumpTimeTrainingDataInfo { 769 TrainingData* _training_data; 770 public: 771 DumpTimeTrainingDataInfo() : DumpTimeTrainingDataInfo(nullptr) {} 772 773 DumpTimeTrainingDataInfo(TrainingData* training_data) 774 : _training_data(training_data) {} 775 776 void metaspace_pointers_do(MetaspaceClosure* it) { 777 it->push(&_training_data); 778 } 779 780 TrainingData* training_data() { 781 return _training_data; 782 } 783 }; 784 785 786 class TrainingDataPrinter : StackObj { 787 outputStream* _st; 788 int _index; 789 public: 790 TrainingDataPrinter(outputStream* st) : _st(st), _index(0) {} 791 void do_value(TrainingData* record); 792 }; 793 794 #endif // SHARE_OOPS_TRAININGDATA_HPP