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 _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 ResourceHashtable<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