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