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