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