< prev index next >

src/hotspot/share/code/aotCodeCache.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) 2023, 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.

*** 23,118 ***
   */
  
  #ifndef SHARE_CODE_AOTCODECACHE_HPP
  #define SHARE_CODE_AOTCODECACHE_HPP
  
  /*
   * AOT Code Cache collects code from Code Cache and corresponding metadata
   * during application training run.
!  * In following "production" runs this code and data can be loaded into
   * Code Cache skipping its generation.
   */
  
! class CodeBuffer;
- class RelocIterator;
  class AOTCodeCache;
! class AdapterBlob;
! class ExceptionBlob;
  class ImmutableOopMapSet;
  
  enum class vmIntrinsicID : int;
- enum CompLevel : signed char;
  
! // Descriptor of AOT Code Cache's entry
  class AOTCodeEntry {
  public:
!   enum Kind {
!     None    = 0,
!     Adapter = 1,
!     Blob    = 2
    };
  
  private:
    AOTCodeEntry* _next;
    Kind   _kind;
    uint   _id;          // Adapter's id, vmIntrinsic::ID for stub or name's hash for nmethod
    uint   _offset;      // Offset to entry
    uint   _size;        // Entry size
!   uint   _name_offset; // Code blob name
    uint   _name_size;
!   uint   _blob_offset; // Start of code in cache
    bool   _has_oop_maps;
!   address _dumptime_content_start_addr; // CodeBlob::content_begin() at dump time; used for applying relocations
! 
  public:
    AOTCodeEntry(Kind kind,         uint id,
                 uint offset,       uint size,
                 uint name_offset,  uint name_size,
                 uint blob_offset,  bool has_oop_maps,
                 address dumptime_content_start_addr) {
      _next         = nullptr;
      _kind         = kind;
      _id           = id;
      _offset       = offset;
      _size         = size;
      _name_offset  = name_offset;
      _name_size    = name_size;
!     _blob_offset  = blob_offset;
!     _has_oop_maps = has_oop_maps;
      _dumptime_content_start_addr = dumptime_content_start_addr;
    }
    void* operator new(size_t x, AOTCodeCache* cache);
    // Delete is a NOP
    void operator delete( void *ptr ) {}
  
!   AOTCodeEntry* next()        const { return _next; }
    void set_next(AOTCodeEntry* next) { _next = next; }
  
    Kind kind()         const { return _kind; }
    uint id()           const { return _id; }
  
    uint offset()       const { return _offset; }
    void set_offset(uint off) { _offset = off; }
  
    uint size()         const { return _size; }
    uint name_offset()  const { return _name_offset; }
    uint name_size()    const { return _name_size; }
!   uint blob_offset()  const { return _blob_offset; }
!   bool has_oop_maps() const { return _has_oop_maps; }
    address dumptime_content_start_addr() const { return _dumptime_content_start_addr; }
  
    static bool is_valid_entry_kind(Kind kind) { return kind == Adapter || kind == Blob; }
  };
  
  // Addresses of stubs, blobs and runtime finctions called from compiled code.
  class AOTCodeAddressTable : public CHeapObj<mtCode> {
  private:
    address* _extrs_addr;
    address* _blobs_addr;
    uint     _extrs_length;
    uint     _blobs_length;
  
    bool _extrs_complete;
    bool _shared_blobs_complete;
    bool _complete;
  
  public:
!   AOTCodeAddressTable() :
!     _extrs_addr(nullptr),
!     _blobs_addr(nullptr),
!     _extrs_length(0),
!     _blobs_length(0),
!     _extrs_complete(false),
!     _shared_blobs_complete(false),
!     _complete(false)
!   { }
    ~AOTCodeAddressTable();
    void init_extrs();
    void init_shared_blobs();
    const char* add_C_string(const char* str);
    int  id_for_C_string(address str);
    address address_for_C_string(int idx);
!   int  id_for_address(address addr, RelocIterator iter, CodeBlob* code_blob);
    address address_for_id(int id);
  };
  
  class AOTCodeCache : public CHeapObj<mtCode> {
  
  // Classes used to describe AOT code cache.
--- 23,303 ---
   */
  
  #ifndef SHARE_CODE_AOTCODECACHE_HPP
  #define SHARE_CODE_AOTCODECACHE_HPP
  
+ #include "compiler/compilerDefinitions.hpp"
+ #include "memory/allocation.hpp"
+ #include "nmt/memTag.hpp"
+ #include "oops/oopsHierarchy.hpp"
+ #include "utilities/exceptions.hpp"
+ 
  /*
   * AOT Code Cache collects code from Code Cache and corresponding metadata
   * during application training run.
!  * In following "production" runs this code and data can me loaded into
   * Code Cache skipping its generation.
+  * Additionaly special compiled code "preload" is generated with class initialization
+  * barriers which can be called on first Java method invocation.
   */
  
! class AbstractCompiler;
  class AOTCodeCache;
! class ciConstant;
! class ciEnv;
+ class ciMethod;
+ class CodeBuffer;
+ class CodeBlob;
+ class CodeOffsets;
+ class CompileTask;
+ class DebugInformationRecorder;
+ class Dependencies;
+ class ExceptionTable;
+ class ExceptionHandlerTable;
+ template<typename E>
+ class GrowableArray;
  class ImmutableOopMapSet;
+ class ImplicitExceptionTable;
+ class JavaThread;
+ class Klass;
+ class methodHandle;
+ class Metadata;
+ class Method;
+ class nmethod;
+ class OopMapSet;
+ class OopRecorder;
+ class outputStream;
+ class RelocIterator;
+ class StubCodeGenerator;
  
  enum class vmIntrinsicID : int;
  
! #define DO_AOTCODEENTRY_KIND(Fn) \
+   Fn(None) \
+   Fn(Adapter) \
+   Fn(Stub) \
+   Fn(Blob) \
+   Fn(Code) \
+ 
+ // Code Cache's entry contain information from CodeBuffer
  class AOTCodeEntry {
  public:
!   enum Kind : s1 {
! #define DECL_KIND_ENUM(kind) kind,
!     DO_AOTCODEENTRY_KIND(DECL_KIND_ENUM)
! #undef DECL_KIND_ENUM
+     Kind_count
    };
  
  private:
    AOTCodeEntry* _next;
+   Method*       _method;
    Kind   _kind;
    uint   _id;          // Adapter's id, vmIntrinsic::ID for stub or name's hash for nmethod
+ 
    uint   _offset;      // Offset to entry
    uint   _size;        // Entry size
!   uint   _name_offset; // Method's or intrinsic name
    uint   _name_size;
!   uint   _code_offset; // Start of code in cache
+   uint   _code_size;   // Total size of all code sections
+   uint   _reloc_offset;// Relocations
+   uint   _reloc_size;  // Max size of relocations per code section
+   uint   _num_inlined_bytecodes;
+ 
+   uint   _comp_level;  // compilation level
+   uint   _comp_id;     // compilation id
+   uint   _decompile;   // Decompile count for this nmethod
    bool   _has_oop_maps;
!   bool   _has_clinit_barriers; // Generated code has class init checks
!   bool   _for_preload; // Code can be used for preload
+   bool   _loaded;      // Code was loaded
+   bool   _not_entrant; // Deoptimized
+   bool   _load_fail;   // Failed to load due to some klass state
+   bool   _ignore_decompile; // ignore decompile counter if compilation is done
+                             // during "assembly" phase without running application
+   address _dumptime_content_start_addr;
  public:
+   AOTCodeEntry(uint offset, uint size, uint name_offset, uint name_size,
+            uint code_offset, uint code_size,
+            uint reloc_offset, uint reloc_size,
+            Kind kind, uint id,
+            address dumptime_content_start_addr = nullptr,
+            uint comp_level = 0,
+            uint comp_id = 0, uint decomp = 0,
+            bool has_clinit_barriers = false,
+            bool for_preload = false,
+            bool ignore_decompile = false) {
+     _next         = nullptr;
+     _method       = nullptr;
+     _kind         = kind;
+     _id           = id;
+ 
+     _offset       = offset;
+     _size         = size;
+     _name_offset  = name_offset;
+     _name_size    = name_size;
+     _code_offset  = code_offset;
+     _code_size    = code_size;
+     _reloc_offset = reloc_offset;
+     _reloc_size   = reloc_size;
+ 
+     _dumptime_content_start_addr = dumptime_content_start_addr;
+     _num_inlined_bytecodes = 0;
+ 
+     _comp_level   = comp_level;
+     _comp_id      = comp_id;
+     _decompile    = decomp;
+     _has_oop_maps = false; // unused here
+     _has_clinit_barriers = has_clinit_barriers;
+     _for_preload  = for_preload;
+     _loaded       = false;
+     _not_entrant  = false;
+     _load_fail    = false;
+     _ignore_decompile = ignore_decompile;
+   }
+ 
    AOTCodeEntry(Kind kind,         uint id,
                 uint offset,       uint size,
                 uint name_offset,  uint name_size,
                 uint blob_offset,  bool has_oop_maps,
                 address dumptime_content_start_addr) {
      _next         = nullptr;
+     _method       = nullptr;
      _kind         = kind;
      _id           = id;
      _offset       = offset;
      _size         = size;
      _name_offset  = name_offset;
      _name_size    = name_size;
!     _code_offset  = blob_offset;
!     _code_size    = 0;
+     _reloc_offset = 0;
+     _reloc_size   = 0;
+ 
      _dumptime_content_start_addr = dumptime_content_start_addr;
+     _num_inlined_bytecodes = 0;
+ 
+     _comp_level   = 0;
+     _comp_id      = 0;
+     _decompile    = 0;
+     _has_oop_maps = has_oop_maps;
+     _has_clinit_barriers = false;
+     _for_preload  = false;
+     _loaded       = false;
+     _not_entrant  = false;
+     _load_fail    = false;
+     _ignore_decompile = true;
    }
+ 
    void* operator new(size_t x, AOTCodeCache* cache);
    // Delete is a NOP
    void operator delete( void *ptr ) {}
  
!   bool is_adapter() { return _kind == Adapter; }
+   bool is_stub() { return _kind == Stub; }
+   bool is_blob() { return _kind == Blob; }
+   bool is_code() { return _kind == Code; }
+ 
+   AOTCodeEntry* next()    const { return _next; }
    void set_next(AOTCodeEntry* next) { _next = next; }
  
+   Method*   method()  const { return _method; }
+   void set_method(Method* method) { _method = method; }
+   void update_method_for_writing();
+ 
    Kind kind()         const { return _kind; }
    uint id()           const { return _id; }
  
    uint offset()       const { return _offset; }
    void set_offset(uint off) { _offset = off; }
  
    uint size()         const { return _size; }
    uint name_offset()  const { return _name_offset; }
    uint name_size()    const { return _name_size; }
!   uint code_offset()  const { return _code_offset; }
!   uint code_size()    const { return _code_size; }
+   uint reloc_offset() const { return _reloc_offset; }
+   uint reloc_size()   const { return _reloc_size; }
+ 
    address dumptime_content_start_addr() const { return _dumptime_content_start_addr; }
  
+   uint num_inlined_bytecodes() const { return _num_inlined_bytecodes; }
+   void set_inlined_bytecodes(int bytes) { _num_inlined_bytecodes = bytes; }
+ 
+   uint comp_level()   const { return _comp_level; }
+   uint comp_id()      const { return _comp_id; }
+ 
+   uint decompile()    const { return _decompile; }
+   bool has_clinit_barriers() const { return _has_clinit_barriers; }
+   bool for_preload()  const { return _for_preload; }
+   bool is_loaded()    const { return _loaded; }
+   void set_loaded()         { _loaded = true; }
+   bool ignore_decompile() const { return _ignore_decompile; }
+ 
+   bool not_entrant()  const { return _not_entrant; }
+   void set_not_entrant()    { _not_entrant = true; }
+   void set_entrant()        { _not_entrant = false; }
+ 
+   bool load_fail()  const { return _load_fail; }
+   void set_load_fail()    { _load_fail = true; }
+ 
+   void print(outputStream* st) const;
+   uint blob_offset()  const { return _code_offset; }
+   bool has_oop_maps() const { return _has_oop_maps; }
+ 
    static bool is_valid_entry_kind(Kind kind) { return kind == Adapter || kind == Blob; }
  };
  
  // Addresses of stubs, blobs and runtime finctions called from compiled code.
  class AOTCodeAddressTable : public CHeapObj<mtCode> {
  private:
    address* _extrs_addr;
+   address* _stubs_addr;
    address* _blobs_addr;
+   address* _C1_blobs_addr;
+   address* _C2_blobs_addr;
    uint     _extrs_length;
+   uint     _stubs_length;
    uint     _blobs_length;
+   uint     _C1_blobs_length;
+   uint     _C2_blobs_length;
  
    bool _extrs_complete;
+   bool _early_stubs_complete;
    bool _shared_blobs_complete;
    bool _complete;
+   bool _opto_complete;
+   bool _c1_complete;
  
  public:
!   AOTCodeAddressTable() {
!     _extrs_addr = nullptr;
!     _stubs_addr = nullptr;
!     _blobs_addr = nullptr;
!     _extrs_complete = false;
!     _early_stubs_complete = false;
!     _shared_blobs_complete = false;
!     _complete = false;
!     _opto_complete = false;
+     _c1_complete = false;
+   }
    ~AOTCodeAddressTable();
    void init_extrs();
+   void init_early_stubs();
    void init_shared_blobs();
+   void init_stubs();
+   void init_opto();
+   void init_c1();
    const char* add_C_string(const char* str);
    int  id_for_C_string(address str);
    address address_for_C_string(int idx);
!   int  id_for_address(address addr, RelocIterator iter, CodeBuffer* buffer, CodeBlob* blob = nullptr);
    address address_for_id(int id);
+   bool opto_complete() const { return _opto_complete; }
+   bool c1_complete() const { return _c1_complete; }
+ };
+ 
+ struct AOTCodeSection {
+ public:
+   address _origin_address;
+   uint _size;
+   uint _offset;
+ };
+ 
+ enum class DataKind: int {
+   No_Data   = -1,
+   Null      = 0,
+   Klass     = 1,
+   Method    = 2,
+   String    = 3,
+   Primitive = 4, // primitive Class object
+   SysLoader = 5, // java_system_loader
+   PlaLoader = 6, // java_platform_loader
+   MethodCnts= 7,
+   Klass_Shared  = 8,
+   Method_Shared = 9,
+   String_Shared = 10,
+   MH_Oop_Shared = 11
  };
  
  class AOTCodeCache : public CHeapObj<mtCode> {
  
  // Classes used to describe AOT code cache.

*** 145,66 ***
      uint _contendedPaddingWidth;
      uint _objectAlignment;
      uint _gc;
      enum Flags {
        none                     = 0,
!       debugVM                  = 1,
!       compressedOops           = 2,
!       compressedClassPointers  = 4,
!       useTLAB                  = 8,
!       systemClassAssertions    = 16,
!       userClassAssertions      = 32,
!       enableContendedPadding   = 64,
!       restrictContendedPadding = 128
      };
      uint _flags;
  
    public:
!     void record();
      bool verify() const;
    };
  
    class Header : public CHeapObj<mtCode> {
    private:
      enum {
        AOT_CODE_VERSION = 1
      };
!     uint   _version;         // AOT code version (should match when reading code cache)
!     uint   _cache_size;      // cache size in bytes
!     uint   _strings_count;   // number of recorded C strings
!     uint   _strings_offset;  // offset to recorded C strings
!     uint   _entries_count;   // number of recorded entries
!     uint   _entries_offset;  // offset of AOTCodeEntry array describing entries
!     uint   _adapters_count;
!     uint   _blobs_count;
      Config _config;
  
! public:
      void init(uint cache_size,
!               uint strings_count,  uint strings_offset,
!               uint entries_count,  uint entries_offset,
!               uint adapters_count, uint blobs_count) {
        _version        = AOT_CODE_VERSION;
        _cache_size     = cache_size;
        _strings_count  = strings_count;
        _strings_offset = strings_offset;
        _entries_count  = entries_count;
        _entries_offset = entries_offset;
        _adapters_count = adapters_count;
        _blobs_count    = blobs_count;
  
!       _config.record();
      }
  
- 
      uint cache_size()     const { return _cache_size; }
      uint strings_count()  const { return _strings_count; }
      uint strings_offset() const { return _strings_offset; }
      uint entries_count()  const { return _entries_count; }
      uint entries_offset() const { return _entries_offset; }
      uint adapters_count() const { return _adapters_count; }
      uint blobs_count()    const { return _blobs_count; }
  
      bool verify_config(uint load_size)  const;
      bool verify_vm_config() const { // Called after Universe initialized
        return _config.verify();
      }
--- 330,82 ---
      uint _contendedPaddingWidth;
      uint _objectAlignment;
      uint _gc;
      enum Flags {
        none                     = 0,
!       metadataPointers         = 1,
!       debugVM                  = 2,
!       compressedOops           = 4,
!       compressedClassPointers  = 8,
!       useTLAB                  = 16,
!       systemClassAssertions    = 32,
!       userClassAssertions      = 64,
!       enableContendedPadding   = 128,
+       restrictContendedPadding = 256,
      };
      uint _flags;
  
    public:
!     void record(bool use_meta_ptrs);
      bool verify() const;
+ 
+     bool has_meta_ptrs()  const { return (_flags & metadataPointers) != 0; }
    };
  
    class Header : public CHeapObj<mtCode> {
    private:
+     // Here should be version and other verification fields
      enum {
        AOT_CODE_VERSION = 1
      };
!     uint _version;           // AOT code version (should match when reading code cache)
!     uint _cache_size;        // cache size in bytes
!     uint _strings_count;     // number of recorded C strings
!     uint _strings_offset;    // offset to recorded C strings
!     uint _entries_count;     // number of recorded entries in cache
!     uint _entries_offset;    // offset of AOTCodeEntry array describing entries
!     uint _preload_entries_count; // entries for pre-loading code
!     uint _preload_entries_offset;
+     uint _adapters_count;
+     uint _blobs_count;
+     uint _stubs_count;
      Config _config;
  
!   public:
      void init(uint cache_size,
!               uint strings_count, uint strings_offset,
!               uint entries_count, uint entries_offset,
!               uint preload_entries_count, uint preload_entries_offset,
+               uint adapters_count, uint blobs_count, uint stubs_count,
+               bool use_meta_ptrs) {
        _version        = AOT_CODE_VERSION;
        _cache_size     = cache_size;
        _strings_count  = strings_count;
        _strings_offset = strings_offset;
        _entries_count  = entries_count;
        _entries_offset = entries_offset;
+       _preload_entries_count  = preload_entries_count;
+       _preload_entries_offset = preload_entries_offset;
        _adapters_count = adapters_count;
        _blobs_count    = blobs_count;
+       _stubs_count    = stubs_count;
  
!       _config.record(use_meta_ptrs);
      }
  
      uint cache_size()     const { return _cache_size; }
      uint strings_count()  const { return _strings_count; }
      uint strings_offset() const { return _strings_offset; }
      uint entries_count()  const { return _entries_count; }
      uint entries_offset() const { return _entries_offset; }
+     uint preload_entries_count()  const { return _preload_entries_count; }
+     uint preload_entries_offset() const { return _preload_entries_offset; }
      uint adapters_count() const { return _adapters_count; }
      uint blobs_count()    const { return _blobs_count; }
+     uint stubs_count()    const { return _stubs_count; }
+     uint nmethods_count() const { return _entries_count - _stubs_count - _blobs_count - _adapters_count; }
+     bool has_meta_ptrs()  const { return _config.has_meta_ptrs(); }
  
      bool verify_config(uint load_size)  const;
      bool verify_vm_config() const { // Called after Universe initialized
        return _config.verify();
      }

*** 224,23 ***
    bool   _for_dump;        // AOT cache is open for dumping AOT code
    bool   _closing;         // Closing cache file
    bool   _failed;          // Failed read/write to/from cache (cache is broken?)
    bool   _lookup_failed;   // Failed to lookup for info (skip only this code load)
  
    AOTCodeAddressTable* _table;
  
!   AOTCodeEntry* _load_entries;   // Used when reading cache
!   uint*         _search_entries; // sorted by ID table [id, index]
!   AOTCodeEntry* _store_entries;  // Used when writing cache
!   const char*   _C_strings_buf;  // Loaded buffer for _C_strings[] table
    uint          _store_entries_cnt;
  
    static AOTCodeCache* open_for_use();
    static AOTCodeCache* open_for_dump();
  
    bool set_write_position(uint pos);
    bool align_write();
    address reserve_bytes(uint nbytes);
    uint write_bytes(const void* buffer, uint nbytes);
    const char* addr(uint offset) const { return _load_buffer + offset; }
    static AOTCodeAddressTable* addr_table() {
      return is_on() && (cache()->_table != nullptr) ? cache()->_table : nullptr;
--- 425,35 ---
    bool   _for_dump;        // AOT cache is open for dumping AOT code
    bool   _closing;         // Closing cache file
    bool   _failed;          // Failed read/write to/from cache (cache is broken?)
    bool   _lookup_failed;   // Failed to lookup for info (skip only this code load)
  
+   bool   _for_preload;         // Code for preload
+   bool   _gen_preload_code;    // Generate pre-loading code
+   bool   _has_clinit_barriers; // Code with clinit barriers
+ 
+   bool   _use_meta_ptrs;   // Store metadata pointers
+ 
    AOTCodeAddressTable* _table;
  
!   AOTCodeEntry* _load_entries;     // Used when reading cache
!   uint*         _search_entries;   // sorted by ID table [id, index]
!   AOTCodeEntry* _store_entries;    // Used when writing cache
!   const char*   _C_strings_buf;    // Loaded buffer for _C_strings[] table
    uint          _store_entries_cnt;
  
+   uint _compile_id;
+   uint _comp_level;
+   uint compile_id() const { return _compile_id; }
+   uint comp_level() const { return _comp_level; }
+ 
    static AOTCodeCache* open_for_use();
    static AOTCodeCache* open_for_dump();
  
    bool set_write_position(uint pos);
    bool align_write();
+ 
    address reserve_bytes(uint nbytes);
    uint write_bytes(const void* buffer, uint nbytes);
    const char* addr(uint offset) const { return _load_buffer + offset; }
    static AOTCodeAddressTable* addr_table() {
      return is_on() && (cache()->_table != nullptr) ? cache()->_table : nullptr;

*** 248,59 ***
  
    void set_lookup_failed()     { _lookup_failed = true; }
    void clear_lookup_failed()   { _lookup_failed = false; }
    bool lookup_failed()   const { return _lookup_failed; }
  
  public:
    AOTCodeCache(bool is_dumping, bool is_using);
    ~AOTCodeCache();
  
    const char* cache_buffer() const { return _load_buffer; }
    bool failed() const { return _failed; }
    void set_failed()   { _failed = true; }
  
    static uint max_aot_code_size();
  
    uint load_size() const { return _load_size; }
    uint write_position() const { return _write_position; }
  
    void load_strings();
    int store_strings();
  
    static void init_extrs_table() NOT_CDS_RETURN;
    static void init_shared_blobs_table() NOT_CDS_RETURN;
  
    address address_for_id(int id) const { return _table->address_for_id(id); }
  
    bool for_use()  const { return _for_use  && !_failed; }
    bool for_dump() const { return _for_dump && !_failed; }
  
    bool closing()          const { return _closing; }
  
    AOTCodeEntry* add_entry() {
      _store_entries_cnt++;
      _store_entries -= 1;
      return _store_entries;
    }
  
!   AOTCodeEntry* find_entry(AOTCodeEntry::Kind kind, uint id);
  
    bool finish_write();
  
    bool write_relocations(CodeBlob& code_blob);
    bool write_oop_map_set(CodeBlob& cb);
  
    static bool store_code_blob(CodeBlob& blob,
                                AOTCodeEntry::Kind entry_kind,
                                uint id, const char* name,
!                               int entry_offset_count,
!                               int* entry_offsets) NOT_CDS_RETURN_(false);
  
    static CodeBlob* load_code_blob(AOTCodeEntry::Kind kind,
                                    uint id, const char* name,
!                                   int entry_offset_count,
!                                   int* entry_offsets) NOT_CDS_RETURN_(nullptr);
  
    static uint store_entries_cnt() {
      if (is_on_for_dump()) {
        return cache()->_store_entries_cnt;
      }
--- 461,117 ---
  
    void set_lookup_failed()     { _lookup_failed = true; }
    void clear_lookup_failed()   { _lookup_failed = false; }
    bool lookup_failed()   const { return _lookup_failed; }
  
+   AOTCodeEntry* write_nmethod(nmethod* nm, bool for_preload);
+ 
+   // States:
+   //   S >= 0: allow new readers, S readers are currently active
+   //   S <  0: no new readers are allowed; (-S-1) readers are currently active
+   //     (special case: S = -1 means no readers are active, and would never be active again)
+   static volatile int _nmethod_readers;
+ 
+   static void wait_for_no_nmethod_readers();
+ 
+   class ReadingMark {
+   private:
+     bool _failed;
+   public:
+     ReadingMark();
+     ~ReadingMark();
+     bool failed() {
+       return _failed;
+     }
+   };
+ 
  public:
    AOTCodeCache(bool is_dumping, bool is_using);
    ~AOTCodeCache();
  
    const char* cache_buffer() const { return _load_buffer; }
    bool failed() const { return _failed; }
    void set_failed()   { _failed = true; }
  
+   static bool is_address_in_aot_cache(address p) NOT_CDS_RETURN_(false);
    static uint max_aot_code_size();
  
    uint load_size() const { return _load_size; }
    uint write_position() const { return _write_position; }
  
    void load_strings();
    int store_strings();
  
    static void init_extrs_table() NOT_CDS_RETURN;
+   static void init_early_stubs_table() NOT_CDS_RETURN;
    static void init_shared_blobs_table() NOT_CDS_RETURN;
+   static void init_stubs_table() NOT_CDS_RETURN;
+   static void init_opto_table() NOT_CDS_RETURN;
+   static void init_c1_table() NOT_CDS_RETURN;
  
    address address_for_id(int id) const { return _table->address_for_id(id); }
  
    bool for_use()  const { return _for_use  && !_failed; }
    bool for_dump() const { return _for_dump && !_failed; }
  
    bool closing()          const { return _closing; }
+   bool use_meta_ptrs()    const { return _use_meta_ptrs; }
+   bool gen_preload_code() const { return _gen_preload_code; }
  
    AOTCodeEntry* add_entry() {
      _store_entries_cnt++;
      _store_entries -= 1;
      return _store_entries;
    }
+   void preload_startup_code(TRAPS);
  
!   AOTCodeEntry* find_entry(AOTCodeEntry::Kind kind, uint id, uint comp_level = 0, uint decomp = 0);
+   void invalidate_entry(AOTCodeEntry* entry);
  
    bool finish_write();
  
+   void log_stats_on_exit();
+ 
+   static bool load_stub(StubCodeGenerator* cgen, vmIntrinsicID id, const char* name, address start) NOT_CDS_RETURN_(false);
+   static bool store_stub(StubCodeGenerator* cgen, vmIntrinsicID id, const char* name, address start) NOT_CDS_RETURN_(false);
+ 
+   bool write_klass(Klass* klass);
+   bool write_method(Method* method);
+ 
    bool write_relocations(CodeBlob& code_blob);
+   bool write_debug_info(DebugInformationRecorder* recorder);
+ 
    bool write_oop_map_set(CodeBlob& cb);
+   bool write_nmethod_reloc_immediates(GrowableArray<Handle>& oop_list, GrowableArray<Metadata*>& metadata_list);
+   bool write_nmethod_loadtime_relocations(JavaThread* thread, nmethod* nm, GrowableArray<Handle>& oop_list, GrowableArray<Metadata*>& metadata_list);
+ 
+   jobject read_oop(JavaThread* thread, const methodHandle& comp_method);
+   Metadata* read_metadata(const methodHandle& comp_method);
+   bool read_oops(OopRecorder* oop_recorder, ciMethod* target);
+   bool read_metadata(OopRecorder* oop_recorder, ciMethod* target);
+ 
+   bool write_oop(jobject& jo);
+   bool write_oop(oop obj);
+   bool write_oops(OopRecorder* oop_recorder);
+   bool write_metadata(Metadata* m);
+   bool write_metadata(OopRecorder* oop_recorder);
+   bool write_oops(nmethod* nm);
+   bool write_metadata(nmethod* nm);
  
    static bool store_code_blob(CodeBlob& blob,
                                AOTCodeEntry::Kind entry_kind,
                                uint id, const char* name,
!                               int entry_offset_count = 0,
!                               int* entry_offsets = nullptr) NOT_CDS_RETURN_(false);
  
    static CodeBlob* load_code_blob(AOTCodeEntry::Kind kind,
                                    uint id, const char* name,
!                                   int entry_offset_count = 0,
!                                   int* entry_offsets = nullptr) NOT_CDS_RETURN_(nullptr);
+ 
+   static bool load_nmethod(ciEnv* env, ciMethod* target, int entry_bci, AbstractCompiler* compiler, CompLevel comp_level) NOT_CDS_RETURN_(false);
+   static AOTCodeEntry* store_nmethod(nmethod* nm, AbstractCompiler* compiler, bool for_preload) NOT_CDS_RETURN_(nullptr);
  
    static uint store_entries_cnt() {
      if (is_on_for_dump()) {
        return cache()->_store_entries_cnt;
      }

*** 323,43 ***
    static AOTCodeCache* cache() { return _cache; }
    static void initialize() NOT_CDS_RETURN;
    static void init2() NOT_CDS_RETURN;
    static void close() NOT_CDS_RETURN;
    static bool is_on() CDS_ONLY({ return _cache != nullptr && !_cache->closing(); }) NOT_CDS_RETURN_(false);
!   static bool is_on_for_use()  { return is_on() && _cache->for_use(); }
!   static bool is_on_for_dump() { return is_on() && _cache->for_dump(); }
! 
!   static bool is_dumping_adapters() NOT_CDS_RETURN_(false);
!   static bool is_using_adapters() NOT_CDS_RETURN_(false);
  
    static const char* add_C_string(const char* str) NOT_CDS_RETURN_(str);
  
    static void print_on(outputStream* st) NOT_CDS_RETURN;
  };
  
  // Concurent AOT code reader
  class AOTCodeReader {
  private:
!   const AOTCodeCache*  _cache;
!   const AOTCodeEntry*  _entry;
!   const char*          _load_buffer; // Loaded cached code buffer
!   uint  _read_position;              // Position in _load_buffer
    uint  read_position() const { return _read_position; }
    void  set_read_position(uint pos);
    const char* addr(uint offset) const { return _load_buffer + offset; }
  
    bool _lookup_failed;       // Failed to lookup for info (skip only this code load)
    void set_lookup_failed()     { _lookup_failed = true; }
    void clear_lookup_failed()   { _lookup_failed = false; }
    bool lookup_failed()   const { return _lookup_failed; }
  
-   AOTCodeEntry* aot_code_entry() { return (AOTCodeEntry*)_entry; }
  public:
!   AOTCodeReader(AOTCodeCache* cache, AOTCodeEntry* entry);
  
    CodeBlob* compile_code_blob(const char* name, int entry_offset_count, int* entry_offsets);
  
    ImmutableOopMapSet* read_oop_map_set();
  
    void fix_relocations(CodeBlob* code_blob);
  };
! #endif // SHARE_CODE_AOTCODECACH_HPP
--- 594,262 ---
    static AOTCodeCache* cache() { return _cache; }
    static void initialize() NOT_CDS_RETURN;
    static void init2() NOT_CDS_RETURN;
    static void close() NOT_CDS_RETURN;
    static bool is_on() CDS_ONLY({ return _cache != nullptr && !_cache->closing(); }) NOT_CDS_RETURN_(false);
!   static bool is_C3_on() NOT_CDS_RETURN_(false);
!   static bool is_code_load_thread_on() NOT_CDS_RETURN_(false);
!   static bool is_on_for_use()  CDS_ONLY({ return is_on() && _cache->for_use(); }) NOT_CDS_RETURN_(false);
!   static bool is_on_for_dump() CDS_ONLY({ return is_on() && _cache->for_dump(); }) NOT_CDS_RETURN_(false);
!   static bool is_dumping_code() NOT_CDS_RETURN_(false);
+   static bool is_dumping_stub() NOT_CDS_RETURN_(false);
+   static bool is_dumping_adapter() NOT_CDS_RETURN_(false);
+   static bool is_using_code() NOT_CDS_RETURN_(false);
+   static bool is_using_stub() NOT_CDS_RETURN_(false);
+   static bool is_using_adapter() NOT_CDS_RETURN_(false);
+   static void enable_caching() NOT_CDS_RETURN;
+   static void disable_caching() NOT_CDS_RETURN;
+   static bool is_caching_enabled() NOT_CDS_RETURN_(false);
+ 
+   static bool gen_preload_code(ciMethod* m, int entry_bci) NOT_CDS_RETURN_(false);
+   static bool allow_const_field(ciConstant& value) NOT_CDS_RETURN_(false);
+   static void invalidate(AOTCodeEntry* entry) NOT_CDS_RETURN;
+   static bool is_loaded(AOTCodeEntry* entry);
+   static AOTCodeEntry* find_code_entry(const methodHandle& method, uint comp_level);
+   static void preload_code(JavaThread* thread) NOT_CDS_RETURN;
+ 
+   template<typename Function>
+   static void iterate(Function function) { // lambda enabled API
+     AOTCodeCache* cache = open_for_use();
+     if (cache != nullptr) {
+       ReadingMark rdmk;
+       if (rdmk.failed()) {
+         // Cache is closed, cannot touch anything.
+         return;
+       }
+ 
+       uint count = cache->_load_header->entries_count();
+       uint* search_entries = (uint*)cache->addr(cache->_load_header->entries_offset()); // [id, index]
+       AOTCodeEntry* load_entries = (AOTCodeEntry*)(search_entries + 2 * count);
+ 
+       for (uint i = 0; i < count; i++) {
+         int index = search_entries[2*i + 1];
+         AOTCodeEntry* entry = &(load_entries[index]);
+         function(entry);
+       }
+     }
+   }
  
    static const char* add_C_string(const char* str) NOT_CDS_RETURN_(str);
  
    static void print_on(outputStream* st) NOT_CDS_RETURN;
+   static void print_statistics_on(outputStream* st) NOT_CDS_RETURN;
+   static void print_timers_on(outputStream* st) NOT_CDS_RETURN;
+   static void print_unused_entries_on(outputStream* st) NOT_CDS_RETURN;
  };
  
  // Concurent AOT code reader
  class AOTCodeReader {
  private:
!   const AOTCodeCache* _cache;
!   const AOTCodeEntry* _entry;
!   const char*         _load_buffer; // Loaded cached code buffer
!   uint  _read_position;             // Position in _load_buffer
    uint  read_position() const { return _read_position; }
    void  set_read_position(uint pos);
    const char* addr(uint offset) const { return _load_buffer + offset; }
  
+   uint _compile_id;
+   uint _comp_level;
+   uint compile_id() const { return _compile_id; }
+   uint comp_level() const { return _comp_level; }
+ 
+   bool _preload;             // Preloading code before method execution
    bool _lookup_failed;       // Failed to lookup for info (skip only this code load)
    void set_lookup_failed()     { _lookup_failed = true; }
    void clear_lookup_failed()   { _lookup_failed = false; }
    bool lookup_failed()   const { return _lookup_failed; }
  
  public:
!   AOTCodeReader(AOTCodeCache* cache, AOTCodeEntry* entry, CompileTask* task);
+ 
+   AOTCodeEntry* aot_code_entry() { return (AOTCodeEntry*)_entry; }
+ 
+   // convenience method to convert offset in AOTCodeEntry data to its address
+   bool compile_nmethod(ciEnv* env, ciMethod* target, AbstractCompiler* compiler);
+   bool compile_blob(CodeBuffer* buffer, int* pc_offset);
  
    CodeBlob* compile_code_blob(const char* name, int entry_offset_count, int* entry_offsets);
  
+   Klass* read_klass(const methodHandle& comp_method, bool shared);
+   Method* read_method(const methodHandle& comp_method, bool shared);
+ 
+   DebugInformationRecorder* read_debug_info(OopRecorder* oop_recorder);
+ 
+   oop read_oop(JavaThread* thread, const methodHandle& comp_method);
+   Metadata* read_metadata(const methodHandle& comp_method);
+   bool read_oops(OopRecorder* oop_recorder, ciMethod* target);
+   bool read_metadata(OopRecorder* oop_recorder, ciMethod* target);
+ 
+   bool read_oop_metadata_list(JavaThread* thread, ciMethod* target, GrowableArray<Handle> &oop_list, GrowableArray<Metadata*> &metadata_list, OopRecorder* oop_recorder);
+   void apply_relocations(nmethod* nm, GrowableArray<Handle> &oop_list, GrowableArray<Metadata*> &metadata_list) NOT_CDS_RETURN;
+ 
    ImmutableOopMapSet* read_oop_map_set();
  
    void fix_relocations(CodeBlob* code_blob);
+ 
+   void print_on(outputStream* st);
+ };
+ 
+ // +1 for preload code
+ const int AOTCompLevel_count = CompLevel_count + 1; // 6 levels indexed from 0 to 5
+ 
+ struct AOTCodeStats {
+ private:
+   struct {
+     uint _kind_cnt[AOTCodeEntry::Kind_count];
+     uint _nmethod_cnt[AOTCompLevel_count];
+     uint _clinit_barriers_cnt;
+   } ccstats; // ccstats = cached code stats
+ 
+   void check_kind(uint kind) { assert(kind >= AOTCodeEntry::None && kind < AOTCodeEntry::Kind_count, "Invalid AOTCodeEntry kind %d", kind); }
+   void check_complevel(uint lvl) { assert(lvl >= CompLevel_none && lvl < AOTCompLevel_count, "Invalid compilation level %d", lvl); }
+ 
+ public:
+   void inc_entry_cnt(uint kind) { check_kind(kind); ccstats._kind_cnt[kind] += 1; }
+   void inc_nmethod_cnt(uint lvl) { check_complevel(lvl); ccstats._nmethod_cnt[lvl] += 1; }
+   void inc_preload_cnt() { ccstats._nmethod_cnt[AOTCompLevel_count-1] += 1; }
+   void inc_clinit_barriers_cnt() { ccstats._clinit_barriers_cnt += 1; }
+ 
+   void collect_entry_stats(AOTCodeEntry* entry) {
+     inc_entry_cnt(entry->kind());
+     if (entry->is_code()) {
+       entry->for_preload() ? inc_nmethod_cnt(AOTCompLevel_count-1)
+                            : inc_nmethod_cnt(entry->comp_level());
+       if (entry->has_clinit_barriers()) {
+         inc_clinit_barriers_cnt();
+       }
+     }
+   }
+ 
+   uint entry_count(uint kind) { check_kind(kind); return ccstats._kind_cnt[kind]; }
+   uint nmethod_count(uint lvl) { check_complevel(lvl); return ccstats._nmethod_cnt[lvl]; }
+   uint preload_count() { return ccstats._nmethod_cnt[AOTCompLevel_count-1]; }
+   uint clinit_barriers_count() { return ccstats._clinit_barriers_cnt; }
+ 
+   uint total_count() {
+     uint total = 0;
+     for (int kind = AOTCodeEntry::None; kind < AOTCodeEntry::Kind_count; kind++) {
+       total += ccstats._kind_cnt[kind];
+     }
+     return total;
+   }
+ 
+   static AOTCodeStats add_aot_code_stats(AOTCodeStats stats1, AOTCodeStats stats2);
+ 
+   // Runtime stats of the AOT code
+ private:
+   struct {
+     struct {
+       uint _loaded_cnt;
+       uint _invalidated_cnt;
+       uint _load_failed_cnt;
+     } _entry_kinds[AOTCodeEntry::Kind_count],
+       _nmethods[AOTCompLevel_count];
+   } rs; // rs = runtime stats
+ 
+ public:
+   void inc_entry_loaded_cnt(uint kind) { check_kind(kind); rs._entry_kinds[kind]._loaded_cnt += 1; }
+   void inc_entry_invalidated_cnt(uint kind) { check_kind(kind); rs._entry_kinds[kind]._invalidated_cnt += 1; }
+   void inc_entry_load_failed_cnt(uint kind) { check_kind(kind); rs._entry_kinds[kind]._load_failed_cnt += 1; }
+ 
+   void inc_nmethod_loaded_cnt(uint lvl) { check_complevel(lvl); rs._nmethods[lvl]._loaded_cnt += 1; }
+   void inc_nmethod_invalidated_cnt(uint lvl) { check_complevel(lvl); rs._nmethods[lvl]._invalidated_cnt += 1; }
+   void inc_nmethod_load_failed_cnt(uint lvl) { check_complevel(lvl); rs._nmethods[lvl]._load_failed_cnt += 1; }
+ 
+   uint entry_loaded_count(uint kind) { check_kind(kind); return rs._entry_kinds[kind]._loaded_cnt; }
+   uint entry_invalidated_count(uint kind) { check_kind(kind); return rs._entry_kinds[kind]._invalidated_cnt; }
+   uint entry_load_failed_count(uint kind) { check_kind(kind); return rs._entry_kinds[kind]._load_failed_cnt; }
+ 
+   uint nmethod_loaded_count(uint lvl) { check_complevel(lvl); return rs._nmethods[lvl]._loaded_cnt; }
+   uint nmethod_invalidated_count(uint lvl) { check_complevel(lvl); return rs._nmethods[lvl]._invalidated_cnt; }
+   uint nmethod_load_failed_count(uint lvl) { check_complevel(lvl); return rs._nmethods[lvl]._load_failed_cnt; }
+ 
+   void inc_loaded_cnt(AOTCodeEntry* entry) {
+     inc_entry_loaded_cnt(entry->kind());
+     if (entry->is_code()) {
+       entry->for_preload() ? inc_nmethod_loaded_cnt(AOTCompLevel_count-1)
+                            : inc_nmethod_loaded_cnt(entry->comp_level());
+     }
+   }
+ 
+   void inc_invalidated_cnt(AOTCodeEntry* entry) {
+     inc_entry_invalidated_cnt(entry->kind());
+     if (entry->is_code()) {
+       entry->for_preload() ? inc_nmethod_invalidated_cnt(AOTCompLevel_count-1)
+                            : inc_nmethod_invalidated_cnt(entry->comp_level());
+     }
+   }
+ 
+   void inc_load_failed_cnt(AOTCodeEntry* entry) {
+     inc_entry_load_failed_cnt(entry->kind());
+     if (entry->is_code()) {
+       entry->for_preload() ? inc_nmethod_load_failed_cnt(AOTCompLevel_count-1)
+                            : inc_nmethod_load_failed_cnt(entry->comp_level());
+     }
+   }
+ 
+   void collect_entry_runtime_stats(AOTCodeEntry* entry) {
+     if (entry->is_loaded()) {
+       inc_loaded_cnt(entry);
+     }
+     if (entry->not_entrant()) {
+       inc_invalidated_cnt(entry);
+     }
+     if (entry->load_fail()) {
+       inc_load_failed_cnt(entry);
+     }
+   }
+ 
+   void collect_all_stats(AOTCodeEntry* entry) {
+     collect_entry_stats(entry);
+     collect_entry_runtime_stats(entry);
+   }
+ 
+   AOTCodeStats() {
+     memset(this, 0, sizeof(AOTCodeStats));
+   }
  };
! 
+ // code cache internal runtime constants area used by AOT code
+ class AOTRuntimeConstants {
+  friend class AOTCodeCache;
+  private:
+   uint _grain_shift;
+   uint _card_shift;
+   static address _field_addresses_list[];
+   static AOTRuntimeConstants _aot_runtime_constants;
+   // private constructor for unique singleton
+   AOTRuntimeConstants() { }
+   // private for use by friend class AOTCodeCache
+   static void initialize_from_runtime();
+  public:
+ #if INCLUDE_CDS
+   static bool contains(address adr) {
+     address base = (address)&_aot_runtime_constants;
+     address hi = base + sizeof(AOTRuntimeConstants);
+     return (base <= adr && adr < hi);
+   }
+   static address grain_shift_address() { return (address)&_aot_runtime_constants._grain_shift; }
+   static address card_shift_address() { return (address)&_aot_runtime_constants._card_shift; }
+   static address* field_addresses_list() {
+     return _field_addresses_list;
+   }
+ #else
+   static bool contains(address adr)      { return false; }
+   static address grain_shift_address()   { return nullptr; }
+   static address card_shift_address()    { return nullptr; }
+   static address* field_addresses_list() { return nullptr; }
+ #endif
+ };
+ 
+ #endif // SHARE_CODE_AOTCODECACHE_HPP
< prev index next >