1 /* 2 * Copyright (c) 2024, 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 #include "precompiled.hpp" 26 #include "cds/aotConstantPoolResolver.hpp" 27 #include "cds/archiveBuilder.hpp" 28 #include "cds/archiveUtils.inline.hpp" 29 #include "cds/cdsConfig.hpp" 30 #include "cds/finalImageRecipes.hpp" 31 #include "classfile/classLoader.hpp" 32 #include "classfile/systemDictionary.hpp" 33 #include "classfile/systemDictionaryShared.hpp" 34 #include "classfile/vmClasses.hpp" 35 #include "memory/oopFactory.hpp" 36 #include "memory/resourceArea.hpp" 37 #include "oops/constantPool.inline.hpp" 38 #include "runtime/handles.inline.hpp" 39 40 GrowableArray<InstanceKlass*>* FinalImageRecipes::_tmp_reflect_klasses = nullptr; 41 GrowableArray<int>* FinalImageRecipes::_tmp_reflect_flags = nullptr; 42 GrowableArray<FinalImageRecipes::TmpDynamicProxyClassInfo>* FinalImageRecipes::_tmp_dynamic_proxy_classes = nullptr; 43 static FinalImageRecipes* _final_image_recipes = nullptr; 44 45 void* FinalImageRecipes::operator new(size_t size) throw() { 46 return ArchiveBuilder::current()->ro_region_alloc(size); 47 } 48 49 void FinalImageRecipes::record_recipes_impl() { 50 assert(CDSConfig::is_dumping_preimage_static_archive(), "must be"); 51 ResourceMark rm; 52 GrowableArray<Klass*>* klasses = ArchiveBuilder::current()->klasses(); 53 54 // The recipes are recorded regardless of CDSConfig::is_dumping_{invokedynamic,dynamic_proxies,reflection_data}(). 55 // If some of these options are not enabled, the corresponding recipes will be 56 // ignored during the final image assembly. 57 58 // InvokeDynamic 59 GrowableArray<InstanceKlass*> tmp_indy_klasses; 60 GrowableArray<Array<int>*> tmp_indy_cp_indices; 61 int total_indys_to_resolve = 0; 62 for (int i = 0; i < klasses->length(); i++) { 63 Klass* k = klasses->at(i); 64 if (k->is_instance_klass()) { 65 InstanceKlass* ik = InstanceKlass::cast(k); 66 GrowableArray<int> indices; 67 68 if (ik->constants()->cache() != nullptr) { 69 Array<ResolvedIndyEntry>* tmp_indy_entries = ik->constants()->cache()->resolved_indy_entries(); 70 if (tmp_indy_entries != nullptr) { 71 for (int i = 0; i < tmp_indy_entries->length(); i++) { 72 ResolvedIndyEntry* rie = tmp_indy_entries->adr_at(i); 73 int cp_index = rie->constant_pool_index(); 74 if (rie->is_resolved()) { 75 indices.append(cp_index); 76 } 77 } 78 } 79 } 80 81 if (indices.length() > 0) { 82 tmp_indy_klasses.append(ArchiveBuilder::current()->get_buffered_addr(ik)); 83 tmp_indy_cp_indices.append(ArchiveUtils::archive_array(&indices)); 84 total_indys_to_resolve += indices.length(); 85 } 86 } 87 } 88 89 assert(tmp_indy_klasses.length() == tmp_indy_cp_indices.length(), "must be"); 90 if (tmp_indy_klasses.length() > 0) { 91 _indy_klasses = ArchiveUtils::archive_array(&tmp_indy_klasses); 92 _indy_cp_indices = ArchiveUtils::archive_array(&tmp_indy_cp_indices); 93 94 ArchivePtrMarker::mark_pointer(&_indy_klasses); 95 ArchivePtrMarker::mark_pointer(&_indy_cp_indices); 96 } 97 log_info(cds)("%d indies in %d classes will be resolved in final CDS image", total_indys_to_resolve, tmp_indy_klasses.length()); 98 99 // Reflection Data 100 int reflect_count = 0; 101 if (_tmp_reflect_klasses != nullptr) { 102 for (int i = _tmp_reflect_klasses->length() - 1; i >= 0; i--) { 103 InstanceKlass* ik = _tmp_reflect_klasses->at(i); 104 if (SystemDictionaryShared::is_excluded_class(ik)) { 105 _tmp_reflect_klasses->remove_at(i); 106 _tmp_reflect_flags->remove_at(i); 107 } else { 108 _tmp_reflect_klasses->at_put(i, ArchiveBuilder::current()->get_buffered_addr(ik)); 109 } 110 } 111 if (_tmp_reflect_klasses->length() > 0) { 112 _reflect_klasses = ArchiveUtils::archive_array(_tmp_reflect_klasses); 113 _reflect_flags = ArchiveUtils::archive_array(_tmp_reflect_flags); 114 115 ArchivePtrMarker::mark_pointer(&_reflect_klasses); 116 ArchivePtrMarker::mark_pointer(&_reflect_flags); 117 reflect_count = _tmp_reflect_klasses->length(); 118 } 119 } 120 log_info(cds)("ReflectionData of %d classes will be archived in final CDS image", reflect_count); 121 122 // Dynamic Proxies 123 if (_tmp_dynamic_proxy_classes != nullptr) { 124 int len = _tmp_dynamic_proxy_classes->length(); 125 _dynamic_proxy_classes = ArchiveBuilder::new_ro_array<DynamicProxyClassInfo>(len); 126 ArchivePtrMarker::mark_pointer(&_dynamic_proxy_classes); 127 for (int i = 0; i < len; i++) { 128 TmpDynamicProxyClassInfo* tmp_info = _tmp_dynamic_proxy_classes->adr_at(i); 129 DynamicProxyClassInfo* info = _dynamic_proxy_classes->adr_at(i); 130 info->_loader_type = tmp_info->_loader_type; 131 info->_access_flags = tmp_info->_access_flags; 132 info->_proxy_name = ArchiveBuilder::current()->ro_strdup(tmp_info->_proxy_name); 133 134 ResourceMark rm; 135 GrowableArray<Klass*> buffered_interfaces; 136 for (int j = 0; j < tmp_info->_interfaces->length(); j++) { 137 // FIXME: tmp_info->_interfaces->at(j) could be excluded from archive! 138 buffered_interfaces.append(ArchiveBuilder::current()->get_buffered_addr(tmp_info->_interfaces->at(j))); 139 } 140 info->_interfaces = ArchiveUtils::archive_array(&buffered_interfaces); 141 142 ArchivePtrMarker::mark_pointer(&info->_proxy_name); 143 ArchivePtrMarker::mark_pointer(&info->_interfaces); 144 ArchiveBuilder::alloc_stats()->record_dynamic_proxy_class(); 145 } 146 } 147 } 148 149 void FinalImageRecipes::apply_recipes_for_invokedynamic(TRAPS) { 150 assert(CDSConfig::is_dumping_final_static_archive(), "must be"); 151 152 if (CDSConfig::is_dumping_invokedynamic() && _indy_klasses != nullptr) { 153 assert(_indy_cp_indices != nullptr, "must be"); 154 for (int i = 0; i < _indy_klasses->length(); i++) { 155 InstanceKlass* ik = _indy_klasses->at(i); 156 ConstantPool* cp = ik->constants(); 157 Array<int>* cp_indices = _indy_cp_indices->at(i); 158 GrowableArray<bool> preresolve_list(cp->length(), cp->length(), false); 159 for (int j = 0; j < cp_indices->length(); j++) { 160 preresolve_list.at_put(cp_indices->at(j), true); 161 } 162 AOTConstantPoolResolver::preresolve_indy_cp_entries(THREAD, ik, &preresolve_list); 163 } 164 } 165 } 166 167 void FinalImageRecipes::apply_recipes_for_reflection_data(JavaThread* current) { 168 assert(CDSConfig::is_dumping_final_static_archive(), "must be"); 169 170 if (CDSConfig::is_dumping_reflection_data() && _reflect_klasses != nullptr) { 171 assert(_reflect_flags != nullptr, "must be"); 172 for (int i = 0; i < _reflect_klasses->length(); i++) { 173 InstanceKlass* ik = _reflect_klasses->at(i); 174 int rd_flags = _reflect_flags->at(i); 175 AOTConstantPoolResolver::generate_reflection_data(current, ik, rd_flags); 176 } 177 } 178 } 179 180 void FinalImageRecipes::add_reflection_data_flags(InstanceKlass* ik, TRAPS) { 181 assert(CDSConfig::is_dumping_preimage_static_archive(), "must be"); 182 if (SystemDictionaryShared::is_builtin_loader(ik->class_loader_data()) && !ik->is_hidden() && 183 java_lang_Class::has_reflection_data(ik->java_mirror())) { 184 int rd_flags = AOTConstantPoolResolver::class_reflection_data_flags(ik, CHECK); 185 if (_tmp_reflect_klasses == nullptr) { 186 _tmp_reflect_klasses = new (mtClassShared) GrowableArray<InstanceKlass*>(100, mtClassShared); 187 _tmp_reflect_flags = new (mtClassShared) GrowableArray<int>(100, mtClassShared); 188 } 189 _tmp_reflect_klasses->append(ik); 190 _tmp_reflect_flags->append(rd_flags); 191 } 192 } 193 194 void FinalImageRecipes::add_dynamic_proxy_class(oop loader, const char* proxy_name, objArrayOop interfaces, int access_flags) { 195 int loader_type; 196 if (loader == nullptr) { 197 loader_type = ClassLoader::BOOT_LOADER; 198 } else if (loader == SystemDictionary::java_platform_loader()) { 199 loader_type = ClassLoader::PLATFORM_LOADER; 200 } else if (loader == SystemDictionary::java_system_loader()) { 201 loader_type = ClassLoader::APP_LOADER; 202 } else { 203 return; 204 } 205 206 if (_tmp_dynamic_proxy_classes == nullptr) { 207 _tmp_dynamic_proxy_classes = new (mtClassShared) GrowableArray<TmpDynamicProxyClassInfo>(32, mtClassShared); 208 } 209 210 log_info(cds, dynamic, proxy)("Adding proxy name %s", proxy_name); 211 212 TmpDynamicProxyClassInfo info; 213 info._loader_type = loader_type; 214 info._access_flags = access_flags; 215 info._proxy_name = os::strdup(proxy_name); 216 info._interfaces = new (mtClassShared) GrowableArray<Klass*>(interfaces->length(), mtClassShared); 217 for (int i = 0; i < interfaces->length(); i++) { 218 Klass* intf = java_lang_Class::as_Klass(interfaces->obj_at(i)); 219 info._interfaces->append(intf); 220 221 if (log_is_enabled(Info, cds, dynamic, proxy)) { 222 ResourceMark rm; 223 log_info(cds, dynamic, proxy)("interface[%d] = %s", i, intf->external_name()); 224 } 225 } 226 _tmp_dynamic_proxy_classes->append(info); 227 } 228 229 void FinalImageRecipes::apply_recipes_for_dynamic_proxies(TRAPS) { 230 if (CDSConfig::is_dumping_dynamic_proxies() && _dynamic_proxy_classes != nullptr) { 231 for (int proxy_index = 0; proxy_index < _dynamic_proxy_classes->length(); proxy_index++) { 232 DynamicProxyClassInfo* info = _dynamic_proxy_classes->adr_at(proxy_index); 233 234 Handle loader(THREAD, ArchiveUtils::builtin_loader_from_type(info->_loader_type)); 235 236 oop proxy_name_oop = java_lang_String::create_oop_from_str(info->_proxy_name, CHECK); 237 Handle proxy_name(THREAD, proxy_name_oop); 238 239 int num_intfs = info->_interfaces->length(); 240 objArrayOop interfaces_oop = oopFactory::new_objArray(vmClasses::Class_klass(), num_intfs, CHECK); 241 objArrayHandle interfaces(THREAD, interfaces_oop); 242 for (int intf_index = 0; intf_index < num_intfs; intf_index++) { 243 Klass* k = info->_interfaces->at(intf_index); 244 assert(k->java_mirror() != nullptr, "must be loaded"); 245 interfaces()->obj_at_put(intf_index, k->java_mirror()); 246 } 247 248 AOTConstantPoolResolver::define_dynamic_proxy_class(loader, proxy_name, interfaces, info->_access_flags, CHECK); 249 } 250 } 251 } 252 253 void FinalImageRecipes::record_recipes() { 254 _final_image_recipes = new FinalImageRecipes(); 255 _final_image_recipes->record_recipes_impl(); 256 } 257 258 void FinalImageRecipes::apply_recipes(TRAPS) { 259 assert(CDSConfig::is_dumping_final_static_archive(), "must be"); 260 261 if (_final_image_recipes != nullptr) { 262 _final_image_recipes->apply_recipes_for_invokedynamic(CHECK); 263 _final_image_recipes->apply_recipes_for_reflection_data(THREAD); 264 _final_image_recipes->apply_recipes_for_dynamic_proxies(CHECK); 265 } 266 267 // Set it to null as we don't need to write this table into the final image. 268 _final_image_recipes = nullptr; 269 } 270 271 void FinalImageRecipes::serialize(SerializeClosure* soc, bool is_static_archive) { 272 if (is_static_archive) { 273 soc->do_ptr((void**)&_final_image_recipes); 274 } 275 }