1 /* 2 * Copyright (c) 2021, 2023, 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/cds_globals.hpp" 27 #include "cds/classListWriter.hpp" 28 #include "classfile/classFileStream.hpp" 29 #include "classfile/classLoader.hpp" 30 #include "classfile/classLoaderData.hpp" 31 #include "classfile/moduleEntry.hpp" 32 #include "classfile/systemDictionaryShared.hpp" 33 #include "memory/resourceArea.hpp" 34 #include "oops/instanceKlass.hpp" 35 #include "runtime/mutexLocker.hpp" 36 37 fileStream* ClassListWriter::_classlist_file = nullptr; 38 39 void ClassListWriter::init() { 40 // For -XX:DumpLoadedClassList=<file> option 41 if (DumpLoadedClassList != nullptr) { 42 const char* list_name = make_log_name(DumpLoadedClassList, nullptr); 43 _classlist_file = new(mtInternal) 44 fileStream(list_name); 45 _classlist_file->print_cr("# NOTE: Do not modify this file."); 46 _classlist_file->print_cr("#"); 47 _classlist_file->print_cr("# This file is generated via the -XX:DumpLoadedClassList=<class_list_file> option"); 48 _classlist_file->print_cr("# and is used at CDS archive dump time (see -Xshare:dump)."); 49 _classlist_file->print_cr("#"); 50 FREE_C_HEAP_ARRAY(char, list_name); 51 } 52 } 53 54 void ClassListWriter::write(const InstanceKlass* k, const ClassFileStream* cfs) { 55 assert(is_enabled(), "must be"); 56 57 if (!ClassLoader::has_jrt_entry()) { 58 log_warning(cds)("DumpLoadedClassList and CDS are not supported in exploded build"); 59 DumpLoadedClassList = nullptr; 60 return; 61 } 62 63 ClassListWriter w; 64 write_to_stream(k, w.stream(), cfs); 65 } 66 67 class ClassListWriter::IDTable : public ResourceHashtable< 68 const InstanceKlass*, int, 69 15889, // prime number 70 AnyObj::C_HEAP> {}; 71 72 ClassListWriter::IDTable* ClassListWriter::_id_table = nullptr; 73 int ClassListWriter::_total_ids = 0; 74 75 int ClassListWriter::get_id(const InstanceKlass* k) { 76 assert_locked(); 77 if (_id_table == nullptr) { 78 _id_table = new (mtClass)IDTable(); 79 } 80 bool created; 81 int* v = _id_table->put_if_absent(k, &created); 82 if (created) { 83 *v = _total_ids++; 84 } 85 return *v; 86 } 87 88 bool ClassListWriter::has_id(const InstanceKlass* k) { 89 assert_locked(); 90 if (_id_table != nullptr) { 91 return _id_table->get(k) != nullptr; 92 } else { 93 return false; 94 } 95 } 96 97 void ClassListWriter::handle_class_unloading(const InstanceKlass* klass) { 98 assert_locked(); 99 if (_id_table != nullptr) { 100 _id_table->remove(klass); 101 } 102 } 103 104 void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stream, const ClassFileStream* cfs) { 105 assert_locked(); 106 107 ClassLoaderData* loader_data = k->class_loader_data(); 108 bool is_builtin_loader = SystemDictionaryShared::is_builtin_loader(loader_data); 109 if (!is_builtin_loader) { 110 // class may be loaded from shared archive 111 if (!k->is_shared()) { 112 if (cfs == nullptr || cfs->source() == nullptr) { 113 // CDS static dump only handles unregistered class with known source. 114 return; 115 } 116 if (strncmp(cfs->source(), "file:", 5) != 0) { 117 return; 118 } 119 } else { 120 // Shared unregistered classes are skipped since their real source are not recorded in shared space. 121 return; 122 } 123 if (!SystemDictionaryShared::add_unregistered_class(Thread::current(), (InstanceKlass*)k)) { 124 return; 125 } 126 } 127 128 // filter out java/lang/invoke/BoundMethodHandle$Species... 129 if (cfs != nullptr && cfs->source() != nullptr && strcmp(cfs->source(), "_ClassSpecializer_generateConcreteSpeciesCode") == 0) { 130 return; 131 } 132 133 { 134 InstanceKlass* super = k->java_super(); 135 if (super != nullptr && !has_id(super)) { 136 return; 137 } 138 139 Array<InstanceKlass*>* interfaces = k->local_interfaces(); 140 int len = interfaces->length(); 141 for (int i = 0; i < len; i++) { 142 InstanceKlass* intf = interfaces->at(i); 143 if (!has_id(intf)) { 144 return; 145 } 146 } 147 } 148 149 if (k->is_hidden()) { 150 return; 151 } 152 153 if (k->module()->is_patched()) { 154 return; 155 } 156 157 ResourceMark rm; 158 stream->print("%s id: %d", k->name()->as_C_string(), get_id(k)); 159 if (!is_builtin_loader) { 160 InstanceKlass* super = k->java_super(); 161 assert(super != nullptr, "must be"); 162 stream->print(" super: %d", get_id(super)); 163 164 Array<InstanceKlass*>* interfaces = k->local_interfaces(); 165 int len = interfaces->length(); 166 if (len > 0) { 167 stream->print(" interfaces:"); 168 for (int i = 0; i < len; i++) { 169 InstanceKlass* intf = interfaces->at(i); 170 stream->print(" %d", get_id(intf)); 171 } 172 } 173 174 #ifdef _WINDOWS 175 // "file:/C:/dir/foo.jar" -> "C:/dir/foo.jar" 176 stream->print(" source: %s", cfs->source() + 6); 177 #else 178 // "file:/dir/foo.jar" -> "/dir/foo.jar" 179 stream->print(" source: %s", cfs->source() + 5); 180 #endif 181 } 182 183 stream->cr(); 184 stream->flush(); 185 } 186 187 void ClassListWriter::delete_classlist() { 188 if (_classlist_file != nullptr) { 189 delete _classlist_file; 190 } 191 }