< prev index next >

src/hotspot/share/oops/trainingData.hpp

Print this page
*** 1,7 ***
  /*
!  * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.
--- 1,7 ---
  /*
!  * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.

*** 34,10 ***
--- 34,11 ---
  #include "oops/instanceKlass.hpp"
  #include "oops/method.hpp"
  #include "oops/objArrayKlass.hpp"
  #include "runtime/handles.hpp"
  #include "runtime/mutexLocker.hpp"
+ #include "utilities/count_leading_zeros.hpp"
  #include "utilities/resizableHashTable.hpp"
  
  class ciEnv;
  class ciBaseObject;
  class CompileTask;

*** 215,15 ***
        }
        assert(false, "no pre-existing elements allowed");
        return *prior;
      }
      template<typename Function>
!     void iterate(const Function& fn) const { // lambda enabled API
-       iterate(const_cast<Function&>(fn));
-     }
-     template<typename Function>
-     void iterate(Function& fn) const { // lambda enabled API
        return _table.iterate_all([&](const TrainingData::Key* k, TrainingData* td) { fn(td); });
      }
      int size() const { return _table.number_of_entries(); }
  
      void verify() const {
--- 216,11 ---
        }
        assert(false, "no pre-existing elements allowed");
        return *prior;
      }
      template<typename Function>
!     void iterate(Function fn) const { // lambda enabled API
        return _table.iterate_all([&](const TrainingData::Key* k, TrainingData* td) { fn(td); });
      }
      int size() const { return _table.number_of_entries(); }
  
      void verify() const {

*** 302,17 ***
      }
      return true;
    }
  
    template<typename Function>
!   static void iterate(const Function& fn) { iterate(const_cast<Function&>(fn)); }
- 
-   template<typename Function>
-   static void iterate(Function& fn) { // lambda enabled API
      TrainingDataLocker l;
!     if (have_data()) {
!       archived_training_data_dictionary()->iterate(fn);
      }
      if (need_data()) {
        training_data_set()->iterate(fn);
      }
    }
--- 299,14 ---
      }
      return true;
    }
  
    template<typename Function>
!   static void iterate(Function fn) { // lambda enabled API
      TrainingDataLocker l;
!     if (have_data() && !need_data()) {
!       archived_training_data_dictionary()->iterate_all([&](TrainingData* td) { fn(td); });
      }
      if (need_data()) {
        training_data_set()->iterate(fn);
      }
    }

*** 327,18 ***
    virtual void prepare(Visitor& visitor) = 0;
    virtual void cleanup(Visitor& visitor) = 0;
  
    static void initialize() NOT_CDS_RETURN;
  
!   static void verify();
  
    // Widget for recording dependencies, as an N-to-M graph relation,
    // possibly cyclic.
    template<typename E>
    class DepList : public StackObj {
      GrowableArrayCHeap<E, mtCompiler>* _deps_dyn;
      Array<E>*                          _deps;
    public:
      DepList() {
        _deps_dyn = nullptr;
        _deps = nullptr;
      }
--- 321,31 ---
    virtual void prepare(Visitor& visitor) = 0;
    virtual void cleanup(Visitor& visitor) = 0;
  
    static void initialize() NOT_CDS_RETURN;
  
!   static void verify() NOT_CDS_RETURN;
  
    // Widget for recording dependencies, as an N-to-M graph relation,
    // possibly cyclic.
    template<typename E>
    class DepList : public StackObj {
+     static const int INITIAL_CAPACITY = 10;
+ 
      GrowableArrayCHeap<E, mtCompiler>* _deps_dyn;
      Array<E>*                          _deps;
+ 
+     void copy_on_write_if_necessary() {
+       TrainingDataLocker::assert_locked_or_snapshotted();
+       if (_deps != nullptr && _deps_dyn == nullptr) {
+         _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(length() + INITIAL_CAPACITY);
+         for (int i = 0; _deps->length(); i++) {
+           _deps_dyn->append(_deps->at(i));
+         }
+         _deps = nullptr;
+       }
+     }
    public:
      DepList() {
        _deps_dyn = nullptr;
        _deps = nullptr;
      }

*** 347,48 ***
        TrainingDataLocker::assert_locked_or_snapshotted();
        return (_deps_dyn != nullptr ? _deps_dyn->length()
                : _deps   != nullptr ? _deps->length()
                : 0);
      }
-     E* adr_at(int i) const {
-       TrainingDataLocker::assert_locked_or_snapshotted();
-       return (_deps_dyn != nullptr ? _deps_dyn->adr_at(i)
-               : _deps   != nullptr ? _deps->adr_at(i)
-               : nullptr);
-     }
      E at(int i) const {
        TrainingDataLocker::assert_locked_or_snapshotted();
        assert(i >= 0 && i < length(), "oob");
!       return *adr_at(i);
      }
      bool append_if_missing(E dep) {
        TrainingDataLocker::assert_can_add();
        if (_deps_dyn == nullptr) {
!         _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(10);
          _deps_dyn->append(dep);
          return true;
        } else {
          return _deps_dyn->append_if_missing(dep);
        }
      }
      bool remove_if_existing(E dep) {
        TrainingDataLocker::assert_can_add();
        if (_deps_dyn != nullptr) {
          return _deps_dyn->remove_if_existing(dep);
        }
        return false;
      }
      void clear() {
        TrainingDataLocker::assert_can_add();
        if (_deps_dyn != nullptr)  {
          _deps_dyn->clear();
        }
      }
      void append(E dep) {
        TrainingDataLocker::assert_can_add();
        if (_deps_dyn == nullptr) {
!         _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(10);
        }
        _deps_dyn->append(dep);
      }
      bool contains(E dep) {
        TrainingDataLocker::assert_locked();
--- 354,50 ---
        TrainingDataLocker::assert_locked_or_snapshotted();
        return (_deps_dyn != nullptr ? _deps_dyn->length()
                : _deps   != nullptr ? _deps->length()
                : 0);
      }
      E at(int i) const {
        TrainingDataLocker::assert_locked_or_snapshotted();
        assert(i >= 0 && i < length(), "oob");
!       if (_deps_dyn != nullptr) {
+         return _deps_dyn->at(i);
+       } else if (_deps != nullptr) {
+         return _deps->at(i);
+       } else ShouldNotReachHere();
      }
      bool append_if_missing(E dep) {
        TrainingDataLocker::assert_can_add();
+       copy_on_write_if_necessary();
        if (_deps_dyn == nullptr) {
!         _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(INITIAL_CAPACITY);
          _deps_dyn->append(dep);
          return true;
        } else {
          return _deps_dyn->append_if_missing(dep);
        }
      }
      bool remove_if_existing(E dep) {
        TrainingDataLocker::assert_can_add();
+       copy_on_write_if_necessary();
        if (_deps_dyn != nullptr) {
          return _deps_dyn->remove_if_existing(dep);
        }
        return false;
      }
      void clear() {
        TrainingDataLocker::assert_can_add();
        if (_deps_dyn != nullptr)  {
          _deps_dyn->clear();
        }
+       _deps = nullptr;
      }
      void append(E dep) {
        TrainingDataLocker::assert_can_add();
+       copy_on_write_if_necessary();
        if (_deps_dyn == nullptr) {
!         _deps_dyn = new GrowableArrayCHeap<E, mtCompiler>(INITIAL_CAPACITY);
        }
        _deps_dyn->append(dep);
      }
      bool contains(E dep) {
        TrainingDataLocker::assert_locked();

*** 536,10 ***
--- 545,13 ---
  
    MethodTrainingData* _method;
    const short _level;
    const int _compile_id;
  
+   // Size of nmethod code during training
+   int _inline_instructions_size;
+ 
    // classes that should be initialized before this JIT task runs
    DepList<KlassTrainingData*> _init_deps;
    // Number of uninitialized classes left, when it's 0, all deps are satisfied
    volatile int _init_deps_left;
  

*** 652,11 ***
    CompileTrainingData();
    CompileTrainingData(MethodTrainingData* mtd,
                        int level,
                        int compile_id)
        : TrainingData(),  // empty key
!         _method(mtd), _level(level), _compile_id(compile_id), _init_deps_left(0) { }
  public:
    ciRecords& ci_records() { return _ci_records; }
    static CompileTrainingData* make(CompileTask* task) NOT_CDS_RETURN_(nullptr);
  
    virtual CompileTrainingData* as_CompileTrainingData() const { return const_cast<CompileTrainingData*>(this); };
--- 664,11 ---
    CompileTrainingData();
    CompileTrainingData(MethodTrainingData* mtd,
                        int level,
                        int compile_id)
        : TrainingData(),  // empty key
!         _method(mtd), _level(level), _compile_id(compile_id), _inline_instructions_size(0), _init_deps_left(0) { }
  public:
    ciRecords& ci_records() { return _ci_records; }
    static CompileTrainingData* make(CompileTask* task) NOT_CDS_RETURN_(nullptr);
  
    virtual CompileTrainingData* as_CompileTrainingData() const { return const_cast<CompileTrainingData*>(this); };

*** 665,10 ***
--- 677,13 ---
  
    int level() const { return _level; }
  
    int compile_id() const { return _compile_id; }
  
+   int inline_instructions_size() const { return _inline_instructions_size; }
+   void set_inline_instructions_size(int size) { _inline_instructions_size = size; }
+ 
    int init_dep_count() const {
      TrainingDataLocker::assert_locked();
      return _init_deps.length();
    }
    KlassTrainingData* init_dep(int i) const {

*** 766,17 ***
--- 781,23 ---
    }
  
    static int level_mask(int level) {
      return ((level & 0xF) != level ? 0 : 1 << level);
    }
+   static CompLevel highest_level(int mask) {
+     if (mask == 0)  return (CompLevel) 0;
+     int diff = (count_leading_zeros(level_mask(0)) - count_leading_zeros(mask));
+     return (CompLevel) diff;
+   }
  
   public:
    KlassTrainingData* klass()  const { return _klass; }
    bool has_holder()           const { return _holder != nullptr; }
    Method* holder()            const { return _holder; }
    bool only_inlined()         const { return !_was_toplevel; }
    bool saw_level(CompLevel l) const { return (_level_mask & level_mask(l)) != 0; }
+   int highest_level()         const { return highest_level(_level_mask); }
    int highest_top_level()     const { return _highest_top_level; }
    MethodData* final_profile() const { return _final_profile; }
    int invocation_count() const { return _invocation_count; }
    int backedge_count() const { return _backedge_count; }
  

*** 793,10 ***
--- 814,19 ---
      if (level > CompLevel_none) {
        return _last_toplevel_compiles[level - 1];
      }
      return nullptr;
    }
+ 
+   CompileTrainingData* compile_data_for_aot_code(int level) const {
+     CompileTrainingData* ctd = last_toplevel_compile(level);
+     if (ctd == nullptr && level == CompLevel_limited_profile) {
+       // We compile CompLevel_limited_profile AOT code for CompLevel_full_profile
+       ctd = _last_toplevel_compiles[CompLevel_full_profile - 1];
+     }
+     return ctd;
+   }
  
    void notice_compilation(int level, bool inlined = false) {
      if (!inlined) {
        _was_toplevel = true;
      }
< prev index next >