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/archiveBuilder.hpp" 29 #include "cds/metaspaceShared.hpp" 30 #include "classfile/javaClasses.hpp" 31 #include "memory/metaspaceClosure.hpp" 32 #include "utilities/growableArray.hpp" 33 #include "utilities/resourceHash.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 // Try to preserve the order. get_shared_lambda_proxy_class returns shared classes in reverse order. 215 _proxy_klasses->insert_before(0, proxy_klass); 216 } 217 218 void metaspace_pointers_do(MetaspaceClosure* it) { 219 for (int i=0; i<_proxy_klasses->length(); i++) { 220 it->push(_proxy_klasses->adr_at(i)); 221 } 222 } 223 }; 224 225 class RunTimeLambdaProxyClassInfo { 226 RunTimeLambdaProxyClassKey _key; 227 InstanceKlass* _proxy_klass_head; 228 public: 229 RunTimeLambdaProxyClassInfo(RunTimeLambdaProxyClassKey key, InstanceKlass* proxy_klass_head) : 230 _key(key), _proxy_klass_head(proxy_klass_head) {} 231 232 InstanceKlass* proxy_klass_head() const { return _proxy_klass_head; } 233 234 // Used by LambdaProxyClassDictionary to implement OffsetCompactHashtable::EQUALS 235 static inline bool EQUALS( 236 const RunTimeLambdaProxyClassInfo* value, RunTimeLambdaProxyClassKey* key, int len_unused) { 237 return (value->_key.equals(*key)); 238 } 239 void init(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info); 240 241 unsigned int hash() const { 242 return _key.hash(); 243 } 244 RunTimeLambdaProxyClassKey key() const { 245 return _key; 246 } 247 #ifndef PRODUCT 248 void print_on(outputStream* st) const; 249 #endif 250 }; 251 252 class DumpTimeLambdaProxyClassDictionary 253 : public ResourceHashtable<LambdaProxyClassKey, 254 DumpTimeLambdaProxyClassInfo, 255 137, // prime number 256 AnyObj::C_HEAP, 257 mtClassShared, 258 LambdaProxyClassKey::DUMPTIME_HASH, 259 LambdaProxyClassKey::DUMPTIME_EQUALS> { 260 public: 261 DumpTimeLambdaProxyClassDictionary() : _count(0) {} 262 int _count; 263 }; 264 265 // *Legacy* optimization for lambdas before JEP 483. May be removed in the future. 266 class LambdaProxyClassDictionary : public OffsetCompactHashtable< 267 RunTimeLambdaProxyClassKey*, 268 const RunTimeLambdaProxyClassInfo*, 269 RunTimeLambdaProxyClassInfo::EQUALS> 270 { 271 private: 272 class CleanupDumpTimeLambdaProxyClassTable; 273 static DumpTimeLambdaProxyClassDictionary* _dumptime_table; 274 static LambdaProxyClassDictionary _runtime_static_table; // for static CDS archive 275 static LambdaProxyClassDictionary _runtime_dynamic_table; // for dynamic CDS archive 276 277 static void add_to_dumptime_table(LambdaProxyClassKey& key, 278 InstanceKlass* proxy_klass); 279 static InstanceKlass* find_lambda_proxy_class(const RunTimeLambdaProxyClassInfo* info); 280 static InstanceKlass* find_lambda_proxy_class(InstanceKlass* caller_ik, 281 Symbol* invoked_name, 282 Symbol* invoked_type, 283 Symbol* method_type, 284 Method* member_method, 285 Symbol* instantiated_method_type); 286 static InstanceKlass* load_and_init_lambda_proxy_class(InstanceKlass* lambda_ik, 287 InstanceKlass* caller_ik, TRAPS); 288 static void reset_registered_lambda_proxy_class(InstanceKlass* ik); 289 static InstanceKlass* get_shared_nest_host(InstanceKlass* lambda_ik); 290 291 public: 292 static void dumptime_init(); 293 static void dumptime_classes_do(MetaspaceClosure* it); 294 static void add_lambda_proxy_class(InstanceKlass* caller_ik, 295 InstanceKlass* lambda_ik, 296 Symbol* invoked_name, 297 Symbol* invoked_type, 298 Symbol* method_type, 299 Method* member_method, 300 Symbol* instantiated_method_type, 301 TRAPS); 302 static bool is_supported_invokedynamic(BootstrapInfo* bsi); 303 static bool is_registered_lambda_proxy_class(InstanceKlass* ik); 304 static InstanceKlass* load_shared_lambda_proxy_class(InstanceKlass* caller_ik, 305 Symbol* invoked_name, 306 Symbol* invoked_type, 307 Symbol* method_type, 308 Method* member_method, 309 Symbol* instantiated_method_type, 310 TRAPS); 311 static void write_dictionary(bool is_static_archive); 312 static void adjust_dumptime_table(); 313 static void cleanup_dumptime_table(); 314 315 static void reset_dictionary(bool is_static_archive) { 316 if (is_static_archive) { 317 _runtime_static_table.reset(); 318 } else { 319 _runtime_dynamic_table.reset(); 320 } 321 } 322 323 static void serialize(SerializeClosure* soc, bool is_static_archive) { 324 if (is_static_archive) { 325 _runtime_static_table.serialize_header(soc); 326 } else { 327 _runtime_dynamic_table.serialize_header(soc); 328 } 329 } 330 331 static void print_on(const char* prefix, outputStream* st, 332 int start_index, bool is_static_archive); 333 static void print_statistics(outputStream* st, bool is_static_archive); 334 }; 335 336 #endif // SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP