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