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