| /* | |
| * 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. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| * | |
| */ | |
| #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; | |
| class AsmRemarks; | |
| class DbgStrings; | |
| enum class vmIntrinsicID : int; | |
| enum CompLevel : signed char; | |
| #define DO_AOTCODEENTRY_KIND(Fn) \ | |
| Fn(None) \ | |
| Fn(Adapter) \ | |
| Fn(SharedBlob) \ | |
| Fn(C1Blob) \ | |
| Fn(C2Blob) \ | |
| // Descriptor of AOT Code Cache's entry | |
| 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; | |
| 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 > None && kind < Kind_count; } | |
| static bool is_blob(Kind kind) { return kind == SharedBlob || kind == C1Blob || kind == C2Blob; } | |
| static bool is_adapter(Kind kind) { return kind == Adapter; } | |
| }; | |
| // Addresses of stubs, blobs and runtime finctions called from compiled code. | |
| class AOTCodeAddressTable : public CHeapObj<mtCode> { | |
| private: | |
| address* _extrs_addr; | |
| address* _stubs_addr; | |
| address* _shared_blobs_addr; | |
| address* _C1_blobs_addr; | |
| uint _extrs_length; | |
| uint _stubs_length; | |
| uint _shared_blobs_length; | |
| uint _C1_blobs_length; | |
| bool _extrs_complete; | |
| bool _early_stubs_complete; | |
| bool _shared_blobs_complete; | |
| bool _early_c1_complete; | |
| bool _complete; | |
| public: | |
| AOTCodeAddressTable() : | |
| _extrs_addr(nullptr), | |
| _stubs_addr(nullptr), | |
| _shared_blobs_addr(nullptr), | |
| _C1_blobs_addr(nullptr), | |
| _extrs_length(0), | |
| _stubs_length(0), | |
| _shared_blobs_length(0), | |
| _C1_blobs_length(0), | |
| _extrs_complete(false), | |
| _early_stubs_complete(false), | |
| _shared_blobs_complete(false), | |
| _early_c1_complete(false), | |
| _complete(false) | |
| { } | |
| ~AOTCodeAddressTable(); | |
| void init_extrs(); | |
| void init_early_stubs(); | |
| void init_shared_blobs(); | |
| void init_early_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, CodeBlob* code_blob); | |
| address address_for_id(int id); | |
| }; | |
| class AOTCodeCache : public CHeapObj<mtCode> { | |
| // Classes used to describe AOT code cache. | |
| protected: | |
| class Config { | |
| address _compressedOopBase; | |
| uint _compressedOopShift; | |
| uint _compressedKlassShift; | |
| uint _contendedPaddingWidth; | |
| 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 _shared_blobs_count; | |
| uint _C1_blobs_count; | |
| uint _C2_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 shared_blobs_count, | |
| uint C1_blobs_count, uint C2_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; | |
| _shared_blobs_count = shared_blobs_count; | |
| _C1_blobs_count = C1_blobs_count; | |
| _C2_blobs_count = C2_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 shared_blobs_count() const { return _shared_blobs_count; } | |
| uint C1_blobs_count() const { return _C1_blobs_count; } | |
| uint C2_blobs_count() const { return _C2_blobs_count; } | |
| bool verify(uint load_size) const; | |
| bool verify_config() const { // Called after Universe initialized | |
| return _config.verify(); | |
| } | |
| }; | |
| // Continue with AOTCodeCache class definition. | |
| private: | |
| Header* _load_header; | |
| char* _load_buffer; // Aligned buffer for loading cached code | |
| char* _store_buffer; // Aligned buffer for storing cached code | |
| char* _C_store_buffer; // Original unaligned buffer | |
| uint _write_position; // Position in _store_buffer | |
| uint _load_size; // Used when reading cache | |
| uint _store_size; // Used when writing cache | |
| bool _for_use; // AOT cache is open for using AOT code | |
| 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; | |
| } | |
| 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_shared_blobs_table() NOT_CDS_RETURN; | |
| static void init_early_c1_table() NOT_CDS_RETURN; | |
| address address_for_C_string(int idx) const { return _table->address_for_C_string(idx); } | |
| 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); | |
| #ifndef PRODUCT | |
| bool write_asm_remarks(CodeBlob& cb); | |
| bool write_dbg_strings(CodeBlob& cb); | |
| #endif // PRODUCT | |
| 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 uint store_entries_cnt() { | |
| if (is_on_for_dump()) { | |
| return cache()->_store_entries_cnt; | |
| } | |
| return -1; | |
| } | |
| // Static access | |
| private: | |
| static AOTCodeCache* _cache; | |
| static bool open_cache(bool is_dumping, bool is_using); | |
| bool verify_config() { | |
| if (for_use()) { | |
| return _load_header->verify_config(); | |
| } | |
| return true; | |
| } | |
| public: | |
| 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() 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_adapter() NOT_CDS_RETURN_(false); | |
| static bool is_using_adapter() NOT_CDS_RETURN_(false); | |
| static bool is_dumping_stub() NOT_CDS_RETURN_(false); | |
| static bool is_using_stub() 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); | |
| #ifndef PRODUCT | |
| void read_asm_remarks(AsmRemarks& asm_remarks); | |
| void read_dbg_strings(DbgStrings& dbg_strings); | |
| #endif // PRODUCT | |
| }; | |
| #endif // SHARE_CODE_AOTCODECACHE_HPP |