1 /*
  2  * Copyright (c) 2021, 2026, 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_CDS_LAMBDAPROXYCLASSINFO_HPP
 26 #define SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP
 27 
 28 #include "cds/aotCompressedPointers.hpp"
 29 #include "cds/aotMetaspace.hpp"
 30 #include "classfile/compactHashtable.hpp"
 31 #include "classfile/javaClasses.hpp"
 32 #include "memory/metaspaceClosure.hpp"
 33 #include "utilities/growableArray.hpp"
 34 #include "utilities/hashTable.hpp"
 35 
 36 // This file contains *legacy* optimization for lambdas before JEP 483. May be removed in the future.
 37 //
 38 // The functionalties in this file are used only when CDSConfig::is_dumping_lambdas_in_legacy_mode()
 39 // returns true during the creation of a CDS archive.
 40 //
 41 // With the legacy optimization, generated lambda proxy classes (with names such as
 42 // java.util.ResourceBundle$Control$$Lambda/0x80000001d) are stored inside the CDS archive, accessible
 43 // by LambdaProxyClassDictionary::find_proxy_class(). This saves part of the time for resolving a
 44 // lambda call site (proxy class generation). However, a significant portion of the cost of
 45 // the lambda call site resolution still remains in the production run.
 46 //
 47 // In contrast, with JEP 483, the entire lambda call site (starting from the constant pool entry), is
 48 // resolved in the AOT cache assembly phase. No extra resolution is needed in the production run.
 49 
 50 class InstanceKlass;
 51 class Method;
 52 class MetaspaceClosure;
 53 class Symbol;
 54 class outputStream;
 55 
 56 class LambdaProxyClassKey {
 57   InstanceKlass* _caller_ik;
 58   Symbol*        _invoked_name;
 59   Symbol*        _invoked_type;
 60   Symbol*        _method_type;
 61   Method*        _member_method;
 62   Symbol*        _instantiated_method_type;
 63 
 64 public:
 65   LambdaProxyClassKey(InstanceKlass* caller_ik,
 66                       Symbol*        invoked_name,
 67                       Symbol*        invoked_type,
 68                       Symbol*        method_type,
 69                       Method*        member_method,
 70                       Symbol*        instantiated_method_type) :
 71     _caller_ik(caller_ik),
 72     _invoked_name(invoked_name),
 73     _invoked_type(invoked_type),
 74     _method_type(method_type),
 75     _member_method(member_method),
 76     _instantiated_method_type(instantiated_method_type) {}
 77 
 78   void metaspace_pointers_do(MetaspaceClosure* it) {
 79     it->push(&_caller_ik);
 80     it->push(&_invoked_name);
 81     it->push(&_invoked_type);
 82     it->push(&_method_type);
 83     it->push(&_member_method);
 84     it->push(&_instantiated_method_type);
 85   }
 86 
 87   bool equals(LambdaProxyClassKey const& other) const {
 88     return _caller_ik == other._caller_ik &&
 89            _invoked_name == other._invoked_name &&
 90            _invoked_type == other._invoked_type &&
 91            _method_type == other._method_type &&
 92            _member_method == other._member_method &&
 93            _instantiated_method_type == other._instantiated_method_type;
 94   }
 95 
 96   unsigned int hash() const;
 97 
 98   static unsigned int dumptime_hash(Symbol* sym)  {
 99     if (sym == nullptr) {
100       // _invoked_name maybe null
101       return 0;
102     }
103     return java_lang_String::hash_code((const jbyte*)sym->bytes(), sym->utf8_length());
104   }
105 
106   unsigned int dumptime_hash() const {
107     return dumptime_hash(_caller_ik->name()) +
108            dumptime_hash(_invoked_name) +
109            dumptime_hash(_invoked_type) +
110            dumptime_hash(_method_type) +
111            dumptime_hash(_instantiated_method_type);
112   }
113 
114   static inline unsigned int DUMPTIME_HASH(LambdaProxyClassKey const& key) {
115     return (key.dumptime_hash());
116   }
117 
118   static inline bool DUMPTIME_EQUALS(
119       LambdaProxyClassKey const& k1, LambdaProxyClassKey const& k2) {
120     return (k1.equals(k2));
121   }
122 
123   InstanceKlass* caller_ik()         const { return _caller_ik; }
124   Symbol* invoked_name()             const { return _invoked_name; }
125   Symbol* invoked_type()             const { return _invoked_type; }
126   Symbol* method_type()              const { return _method_type; }
127   Method* member_method()            const { return _member_method; }
128   Symbol* instantiated_method_type() const { return _instantiated_method_type; }
129 
130 #ifndef PRODUCT
131   void print_on(outputStream* st) const;
132 #endif
133 };
134 
135 class RunTimeLambdaProxyClassKey {
136   using narrowPtr = AOTCompressedPointers::narrowPtr;
137   narrowPtr _caller_ik;
138   narrowPtr _invoked_name;
139   narrowPtr _invoked_type;
140   narrowPtr _method_type;
141   narrowPtr _member_method;
142   narrowPtr _instantiated_method_type;
143 
144   RunTimeLambdaProxyClassKey(narrowPtr caller_ik,
145                              narrowPtr invoked_name,
146                              narrowPtr invoked_type,
147                              narrowPtr method_type,
148                              narrowPtr member_method,
149                              narrowPtr instantiated_method_type) :
150     _caller_ik(caller_ik),
151     _invoked_name(invoked_name),
152     _invoked_type(invoked_type),
153     _method_type(method_type),
154     _member_method(member_method),
155     _instantiated_method_type(instantiated_method_type) {}
156 
157 public:
158   static RunTimeLambdaProxyClassKey init_for_dumptime(LambdaProxyClassKey& key) {
159     narrowPtr caller_ik                = AOTCompressedPointers::encode_not_null(key.caller_ik());
160     narrowPtr invoked_name             = AOTCompressedPointers::encode_not_null(key.invoked_name());
161     narrowPtr invoked_type             = AOTCompressedPointers::encode_not_null(key.invoked_type());
162     narrowPtr method_type              = AOTCompressedPointers::encode_not_null(key.method_type());
163     narrowPtr member_method            = AOTCompressedPointers::encode(key.member_method()); // could be null
164     narrowPtr instantiated_method_type = AOTCompressedPointers::encode_not_null(key.instantiated_method_type());
165 
166     return RunTimeLambdaProxyClassKey(caller_ik, invoked_name, invoked_type, method_type,
167                                       member_method, instantiated_method_type);
168   }
169 
170   static RunTimeLambdaProxyClassKey init_for_runtime(InstanceKlass* caller_ik,
171                                                      Symbol*        invoked_name,
172                                                      Symbol*        invoked_type,
173                                                      Symbol*        method_type,
174                                                      Method*        member_method,
175                                                      Symbol*        instantiated_method_type) {
176     // All parameters must be in shared space, or else you'd get an assert in
177     // ArchiveUtils::to_offset().
178     return RunTimeLambdaProxyClassKey(AOTCompressedPointers::encode_address_in_cache(caller_ik),
179                                       AOTCompressedPointers::encode_address_in_cache(invoked_name),
180                                       AOTCompressedPointers::encode_address_in_cache(invoked_type),
181                                       AOTCompressedPointers::encode_address_in_cache(method_type),
182                                       AOTCompressedPointers::encode_address_in_cache_or_null(member_method), // could be null
183                                       AOTCompressedPointers::encode_address_in_cache(instantiated_method_type));
184   }
185 
186   unsigned int hash() const;
187   bool equals(RunTimeLambdaProxyClassKey const& other) const {
188     return _caller_ik == other._caller_ik &&
189            _invoked_name == other._invoked_name &&
190            _invoked_type == other._invoked_type &&
191            _method_type == other._method_type &&
192            _member_method == other._member_method &&
193            _instantiated_method_type == other._instantiated_method_type;
194   }
195 
196 #ifndef PRODUCT
197   void print_on(outputStream* st) const;
198 #endif
199 };
200 
201 class DumpTimeLambdaProxyClassInfo {
202 public:
203   GrowableArray<InstanceKlass*>* _proxy_klasses;
204   DumpTimeLambdaProxyClassInfo() : _proxy_klasses(nullptr) {}
205   DumpTimeLambdaProxyClassInfo& operator=(const DumpTimeLambdaProxyClassInfo&) = delete;
206   ~DumpTimeLambdaProxyClassInfo();
207 
208   void add_proxy_klass(InstanceKlass* proxy_klass) {
209     if (_proxy_klasses == nullptr) {
210       _proxy_klasses = new (mtClassShared) GrowableArray<InstanceKlass*>(5, mtClassShared);
211     }
212     assert(_proxy_klasses != nullptr, "sanity");
213     _proxy_klasses->append(proxy_klass);
214   }
215 
216   void metaspace_pointers_do(MetaspaceClosure* it) {
217     for (int i=0; i<_proxy_klasses->length(); i++) {
218       it->push(_proxy_klasses->adr_at(i));
219     }
220   }
221 };
222 
223 class RunTimeLambdaProxyClassInfo {
224   RunTimeLambdaProxyClassKey _key;
225   InstanceKlass* _proxy_klass_head;
226 public:
227   RunTimeLambdaProxyClassInfo(RunTimeLambdaProxyClassKey key, InstanceKlass* proxy_klass_head) :
228     _key(key), _proxy_klass_head(proxy_klass_head) {}
229 
230   InstanceKlass* proxy_klass_head() const { return _proxy_klass_head; }
231 
232   // Used by LambdaProxyClassDictionary to implement OffsetCompactHashtable::EQUALS
233   static inline bool EQUALS(
234        const RunTimeLambdaProxyClassInfo* value, RunTimeLambdaProxyClassKey* key, int len_unused) {
235     return (value->_key.equals(*key));
236   }
237   void init(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info);
238 
239   unsigned int hash() const {
240     return _key.hash();
241   }
242   RunTimeLambdaProxyClassKey key() const {
243     return _key;
244   }
245 #ifndef PRODUCT
246   void print_on(outputStream* st) const;
247 #endif
248 };
249 
250 class DumpTimeLambdaProxyClassDictionary
251   : public HashTable<LambdaProxyClassKey,
252                              DumpTimeLambdaProxyClassInfo,
253                              137, // prime number
254                              AnyObj::C_HEAP,
255                              mtClassShared,
256                              LambdaProxyClassKey::DUMPTIME_HASH,
257                              LambdaProxyClassKey::DUMPTIME_EQUALS> {
258 public:
259   DumpTimeLambdaProxyClassDictionary() : _count(0) {}
260   int _count;
261 };
262 
263 // *Legacy* optimization for lambdas before JEP 483. May be removed in the future.
264 class LambdaProxyClassDictionary : public OffsetCompactHashtable<
265   RunTimeLambdaProxyClassKey*,
266   const RunTimeLambdaProxyClassInfo*,
267   RunTimeLambdaProxyClassInfo::EQUALS>
268 {
269 private:
270   class CleanupDumpTimeLambdaProxyClassTable;
271   static DumpTimeLambdaProxyClassDictionary* _dumptime_table;
272   static LambdaProxyClassDictionary _runtime_static_table; // for static CDS archive
273   static LambdaProxyClassDictionary _runtime_dynamic_table; // for dynamic CDS archive
274 
275   static void add_to_dumptime_table(LambdaProxyClassKey& key,
276                                     InstanceKlass* proxy_klass);
277   static InstanceKlass* find_lambda_proxy_class(const RunTimeLambdaProxyClassInfo* info);
278   static InstanceKlass* find_lambda_proxy_class(InstanceKlass* caller_ik,
279                                                 Symbol* invoked_name,
280                                                 Symbol* invoked_type,
281                                                 Symbol* method_type,
282                                                 Method* member_method,
283                                                 Symbol* instantiated_method_type);
284   static InstanceKlass* load_and_init_lambda_proxy_class(InstanceKlass* lambda_ik,
285                                                          InstanceKlass* caller_ik, TRAPS);
286   static void reset_registered_lambda_proxy_class(InstanceKlass* ik);
287   static InstanceKlass* get_shared_nest_host(InstanceKlass* lambda_ik);
288 
289 public:
290   static void dumptime_init();
291   static void dumptime_classes_do(MetaspaceClosure* it);
292   static void add_lambda_proxy_class(InstanceKlass* caller_ik,
293                                      InstanceKlass* lambda_ik,
294                                      Symbol* invoked_name,
295                                      Symbol* invoked_type,
296                                      Symbol* method_type,
297                                      Method* member_method,
298                                      Symbol* instantiated_method_type,
299                                      TRAPS);
300   static bool is_supported_invokedynamic(BootstrapInfo* bsi);
301   static bool is_registered_lambda_proxy_class(InstanceKlass* ik);
302   static InstanceKlass* load_shared_lambda_proxy_class(InstanceKlass* caller_ik,
303                                                        Symbol* invoked_name,
304                                                        Symbol* invoked_type,
305                                                        Symbol* method_type,
306                                                        Method* member_method,
307                                                        Symbol* instantiated_method_type,
308                                                        TRAPS);
309   static void write_dictionary(bool is_static_archive);
310   static void adjust_dumptime_table();
311   static void cleanup_dumptime_table();
312 
313   static void reset_dictionary(bool is_static_archive) {
314     if (is_static_archive) {
315       _runtime_static_table.reset();
316     } else {
317       _runtime_dynamic_table.reset();
318     }
319   }
320 
321   static void serialize(SerializeClosure* soc, bool is_static_archive) {
322     if (is_static_archive) {
323       _runtime_static_table.serialize_header(soc);
324     } else {
325       _runtime_dynamic_table.serialize_header(soc);
326     }
327   }
328 
329   static void print_on(const char* prefix, outputStream* st,
330                        int start_index, bool is_static_archive);
331   static void print_statistics(outputStream* st,  bool is_static_archive);
332 };
333 
334 #endif // SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP