1 /* 2 * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_CODE_AOTCODECACHE_HPP 26 #define SHARE_CODE_AOTCODECACHE_HPP 27 28 /* 29 * AOT Code Cache collects code from Code Cache and corresponding metadata 30 * during application training run. 31 * In following "production" runs this code and data can be loaded into 32 * Code Cache skipping its generation. 33 */ 34 35 class CodeBuffer; 36 class RelocIterator; 37 class AOTCodeCache; 38 class AdapterBlob; 39 class ExceptionBlob; 40 class ImmutableOopMapSet; 41 42 enum class vmIntrinsicID : int; 43 enum CompLevel : signed char; 44 45 // Descriptor of AOT Code Cache's entry 46 class AOTCodeEntry { 47 public: 48 enum Kind { 49 None = 0, 50 Adapter = 1, 51 Blob = 2 52 }; 53 54 private: 55 AOTCodeEntry* _next; 56 Kind _kind; 57 uint _id; // Adapter's id, vmIntrinsic::ID for stub or name's hash for nmethod 58 uint _offset; // Offset to entry 59 uint _size; // Entry size 60 uint _name_offset; // Code blob name 61 uint _name_size; 62 uint _blob_offset; // Start of code in cache 63 bool _has_oop_maps; 64 address _dumptime_content_start_addr; // CodeBlob::content_begin() at dump time; used for applying relocations 65 66 public: 67 AOTCodeEntry(Kind kind, uint id, 68 uint offset, uint size, 69 uint name_offset, uint name_size, 70 uint blob_offset, bool has_oop_maps, 71 address dumptime_content_start_addr) { 72 _next = nullptr; 73 _kind = kind; 74 _id = id; 75 _offset = offset; 76 _size = size; 77 _name_offset = name_offset; 78 _name_size = name_size; 79 _blob_offset = blob_offset; 80 _has_oop_maps = has_oop_maps; 81 _dumptime_content_start_addr = dumptime_content_start_addr; 82 } 83 void* operator new(size_t x, AOTCodeCache* cache); 84 // Delete is a NOP 85 void operator delete( void *ptr ) {} 86 87 AOTCodeEntry* next() const { return _next; } 88 void set_next(AOTCodeEntry* next) { _next = next; } 89 90 Kind kind() const { return _kind; } 91 uint id() const { return _id; } 92 93 uint offset() const { return _offset; } 94 void set_offset(uint off) { _offset = off; } 95 96 uint size() const { return _size; } 97 uint name_offset() const { return _name_offset; } 98 uint name_size() const { return _name_size; } 99 uint blob_offset() const { return _blob_offset; } 100 bool has_oop_maps() const { return _has_oop_maps; } 101 address dumptime_content_start_addr() const { return _dumptime_content_start_addr; } 102 103 static bool is_valid_entry_kind(Kind kind) { return kind == Adapter || kind == Blob; } 104 }; 105 106 // Addresses of stubs, blobs and runtime finctions called from compiled code. 107 class AOTCodeAddressTable : public CHeapObj<mtCode> { 108 private: 109 address* _extrs_addr; 110 address* _blobs_addr; 111 uint _extrs_length; 112 uint _blobs_length; 113 114 bool _extrs_complete; 115 bool _shared_blobs_complete; 116 bool _complete; 117 118 public: 119 AOTCodeAddressTable() : 120 _extrs_addr(nullptr), 121 _blobs_addr(nullptr), 122 _extrs_length(0), 123 _blobs_length(0), 124 _extrs_complete(false), 125 _shared_blobs_complete(false), 126 _complete(false) 127 { } 128 ~AOTCodeAddressTable(); 129 void init_extrs(); 130 void init_shared_blobs(); 131 const char* add_C_string(const char* str); 132 int id_for_C_string(address str); 133 address address_for_C_string(int idx); 134 int id_for_address(address addr, RelocIterator iter, CodeBlob* code_blob); 135 address address_for_id(int id); 136 }; 137 138 class AOTCodeCache : public CHeapObj<mtCode> { 139 140 // Classes used to describe AOT code cache. 141 protected: 142 class Config { 143 uint _compressedOopShift; 144 uint _compressedKlassShift; 145 uint _contendedPaddingWidth; 146 uint _objectAlignment; 147 uint _gc; 148 enum Flags { 149 none = 0, 150 debugVM = 1, 151 compressedOops = 2, 152 compressedClassPointers = 4, 153 useTLAB = 8, 154 systemClassAssertions = 16, 155 userClassAssertions = 32, 156 enableContendedPadding = 64, 157 restrictContendedPadding = 128 158 }; 159 uint _flags; 160 161 public: 162 void record(); 163 bool verify() const; 164 }; 165 166 class Header : public CHeapObj<mtCode> { 167 private: 168 enum { 169 AOT_CODE_VERSION = 1 170 }; 171 uint _version; // AOT code version (should match when reading code cache) 172 uint _cache_size; // cache size in bytes 173 uint _strings_count; // number of recorded C strings 174 uint _strings_offset; // offset to recorded C strings 175 uint _entries_count; // number of recorded entries 176 uint _entries_offset; // offset of AOTCodeEntry array describing entries 177 uint _adapters_count; 178 uint _blobs_count; 179 Config _config; 180 181 public: 182 void init(uint cache_size, 183 uint strings_count, uint strings_offset, 184 uint entries_count, uint entries_offset, 185 uint adapters_count, uint blobs_count) { 186 _version = AOT_CODE_VERSION; 187 _cache_size = cache_size; 188 _strings_count = strings_count; 189 _strings_offset = strings_offset; 190 _entries_count = entries_count; 191 _entries_offset = entries_offset; 192 _adapters_count = adapters_count; 193 _blobs_count = blobs_count; 194 195 _config.record(); 196 } 197 198 199 uint cache_size() const { return _cache_size; } 200 uint strings_count() const { return _strings_count; } 201 uint strings_offset() const { return _strings_offset; } 202 uint entries_count() const { return _entries_count; } 203 uint entries_offset() const { return _entries_offset; } 204 uint adapters_count() const { return _adapters_count; } 205 uint blobs_count() const { return _blobs_count; } 206 207 bool verify_config(uint load_size) const; 208 bool verify_vm_config() const { // Called after Universe initialized 209 return _config.verify(); 210 } 211 }; 212 213 // Continue with AOTCodeCache class definition. 214 private: 215 Header* _load_header; 216 char* _load_buffer; // Aligned buffer for loading cached code 217 char* _store_buffer; // Aligned buffer for storing cached code 218 char* _C_store_buffer; // Original unaligned buffer 219 220 uint _write_position; // Position in _store_buffer 221 uint _load_size; // Used when reading cache 222 uint _store_size; // Used when writing cache 223 bool _for_use; // AOT cache is open for using AOT code 224 bool _for_dump; // AOT cache is open for dumping AOT code 225 bool _closing; // Closing cache file 226 bool _failed; // Failed read/write to/from cache (cache is broken?) 227 bool _lookup_failed; // Failed to lookup for info (skip only this code load) 228 229 AOTCodeAddressTable* _table; 230 231 AOTCodeEntry* _load_entries; // Used when reading cache 232 uint* _search_entries; // sorted by ID table [id, index] 233 AOTCodeEntry* _store_entries; // Used when writing cache 234 const char* _C_strings_buf; // Loaded buffer for _C_strings[] table 235 uint _store_entries_cnt; 236 237 static AOTCodeCache* open_for_use(); 238 static AOTCodeCache* open_for_dump(); 239 240 bool set_write_position(uint pos); 241 bool align_write(); 242 address reserve_bytes(uint nbytes); 243 uint write_bytes(const void* buffer, uint nbytes); 244 const char* addr(uint offset) const { return _load_buffer + offset; } 245 static AOTCodeAddressTable* addr_table() { 246 return is_on() && (cache()->_table != nullptr) ? cache()->_table : nullptr; 247 } 248 249 void set_lookup_failed() { _lookup_failed = true; } 250 void clear_lookup_failed() { _lookup_failed = false; } 251 bool lookup_failed() const { return _lookup_failed; } 252 253 public: 254 AOTCodeCache(bool is_dumping, bool is_using); 255 ~AOTCodeCache(); 256 257 const char* cache_buffer() const { return _load_buffer; } 258 bool failed() const { return _failed; } 259 void set_failed() { _failed = true; } 260 261 static uint max_aot_code_size(); 262 263 uint load_size() const { return _load_size; } 264 uint write_position() const { return _write_position; } 265 266 void load_strings(); 267 int store_strings(); 268 269 static void init_extrs_table() NOT_CDS_RETURN; 270 static void init_shared_blobs_table() NOT_CDS_RETURN; 271 272 address address_for_id(int id) const { return _table->address_for_id(id); } 273 274 bool for_use() const { return _for_use && !_failed; } 275 bool for_dump() const { return _for_dump && !_failed; } 276 277 bool closing() const { return _closing; } 278 279 AOTCodeEntry* add_entry() { 280 _store_entries_cnt++; 281 _store_entries -= 1; 282 return _store_entries; 283 } 284 285 AOTCodeEntry* find_entry(AOTCodeEntry::Kind kind, uint id); 286 287 bool finish_write(); 288 289 bool write_relocations(CodeBlob& code_blob); 290 bool write_oop_map_set(CodeBlob& cb); 291 292 static bool store_code_blob(CodeBlob& blob, 293 AOTCodeEntry::Kind entry_kind, 294 uint id, const char* name, 295 int entry_offset_count, 296 int* entry_offsets) NOT_CDS_RETURN_(false); 297 298 static CodeBlob* load_code_blob(AOTCodeEntry::Kind kind, 299 uint id, const char* name, 300 int entry_offset_count, 301 int* entry_offsets) NOT_CDS_RETURN_(nullptr); 302 303 static uint store_entries_cnt() { 304 if (is_on_for_dump()) { 305 return cache()->_store_entries_cnt; 306 } 307 return -1; 308 } 309 310 // Static access 311 312 private: 313 static AOTCodeCache* _cache; 314 315 static bool open_cache(bool is_dumping, bool is_using); 316 static bool verify_vm_config() { 317 if (is_on_for_use()) { 318 return _cache->_load_header->verify_vm_config(); 319 } 320 return true; 321 } 322 public: 323 static AOTCodeCache* cache() { return _cache; } 324 static void initialize() NOT_CDS_RETURN; 325 static void init2() NOT_CDS_RETURN; 326 static void close() NOT_CDS_RETURN; 327 static bool is_on() CDS_ONLY({ return _cache != nullptr && !_cache->closing(); }) NOT_CDS_RETURN_(false); 328 static bool is_on_for_use() { return is_on() && _cache->for_use(); } 329 static bool is_on_for_dump() { return is_on() && _cache->for_dump(); } 330 331 static bool is_dumping_adapters() NOT_CDS_RETURN_(false); 332 static bool is_using_adapters() NOT_CDS_RETURN_(false); 333 334 static const char* add_C_string(const char* str) NOT_CDS_RETURN_(str); 335 336 static void print_on(outputStream* st) NOT_CDS_RETURN; 337 }; 338 339 // Concurent AOT code reader 340 class AOTCodeReader { 341 private: 342 const AOTCodeCache* _cache; 343 const AOTCodeEntry* _entry; 344 const char* _load_buffer; // Loaded cached code buffer 345 uint _read_position; // Position in _load_buffer 346 uint read_position() const { return _read_position; } 347 void set_read_position(uint pos); 348 const char* addr(uint offset) const { return _load_buffer + offset; } 349 350 bool _lookup_failed; // Failed to lookup for info (skip only this code load) 351 void set_lookup_failed() { _lookup_failed = true; } 352 void clear_lookup_failed() { _lookup_failed = false; } 353 bool lookup_failed() const { return _lookup_failed; } 354 355 AOTCodeEntry* aot_code_entry() { return (AOTCodeEntry*)_entry; } 356 public: 357 AOTCodeReader(AOTCodeCache* cache, AOTCodeEntry* entry); 358 359 CodeBlob* compile_code_blob(const char* name, int entry_offset_count, int* entry_offsets); 360 361 ImmutableOopMapSet* read_oop_map_set(); 362 363 void fix_relocations(CodeBlob* code_blob); 364 }; 365 #endif // SHARE_CODE_AOTCODECACH_HPP