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