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/archiveBuilder.hpp" 27 #include "cds/cdsConfig.hpp" 28 #include "cds/dumpTimeClassInfo.inline.hpp" 29 #include "cds/runTimeClassInfo.hpp" 30 #include "classfile/classLoader.hpp" 31 #include "classfile/classLoaderData.inline.hpp" 32 #include "classfile/systemDictionaryShared.hpp" 33 #include "memory/resourceArea.hpp" 34 35 DumpTimeClassInfo::~DumpTimeClassInfo() { 36 if (_verifier_constraints != nullptr) { 37 assert(_verifier_constraint_flags != nullptr, "must be"); 38 delete _verifier_constraints; 39 delete _verifier_constraint_flags; 40 } 41 if (_loader_constraints != nullptr) { 42 delete _loader_constraints; 43 } 44 } 45 46 bool DumpTimeClassInfo::is_excluded() { 47 if (_excluded) { 48 return true; 49 } 50 if (_failed_verification) { 51 if (CDSConfig::preserve_all_dumptime_verification_states(_klass)) { 52 assert(CDSConfig::is_dumping_aot_linked_classes(), "sanity"); 53 // If the verification states are preserved, _klass will be archived in unlinked state. This is 54 // necessary to support the following scenario, where the verification of X requires that 55 // A be a subclass of B: 56 // class X { 57 // B getB() { return new A(); } 58 // } 59 // If X and B can be verified, but A fails verification, we still archive A (in a preloaded 60 // SystemDictionary) so that at runtime we cannot subvert the verification of X by replacing 61 // A with a version that is not a subtype of B. 62 } else { 63 // Don't archive this class. At runtime, load it from classfile and rerun verification. 64 return true; 65 } 66 } 67 return false; 68 } 69 70 size_t DumpTimeClassInfo::runtime_info_bytesize() const { 71 return RunTimeClassInfo::byte_size(_klass, num_verifier_constraints(), 72 num_loader_constraints(), 73 num_enum_klass_static_fields()); 74 } 75 76 void DumpTimeClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* name, 77 Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) { 78 if (_verifier_constraints == nullptr) { 79 _verifier_constraints = new (mtClass) GrowableArray<DTVerifierConstraint>(4, mtClass); 80 } 81 if (_verifier_constraint_flags == nullptr) { 82 _verifier_constraint_flags = new (mtClass) GrowableArray<char>(4, mtClass); 83 } 84 GrowableArray<DTVerifierConstraint>* vc_array = _verifier_constraints; 85 for (int i = 0; i < vc_array->length(); i++) { 86 if (vc_array->at(i).equals(name, from_name)) { 87 return; 88 } 89 } 90 DTVerifierConstraint cons(name, from_name); 91 vc_array->append(cons); 92 93 GrowableArray<char>* vcflags_array = _verifier_constraint_flags; 94 char c = 0; 95 c |= from_field_is_protected ? SystemDictionaryShared::FROM_FIELD_IS_PROTECTED : 0; 96 c |= from_is_array ? SystemDictionaryShared::FROM_IS_ARRAY : 0; 97 c |= from_is_object ? SystemDictionaryShared::FROM_IS_OBJECT : 0; 98 vcflags_array->append(c); 99 100 if (log_is_enabled(Trace, cds, verification)) { 101 ResourceMark rm; 102 log_trace(cds, verification)("add_verification_constraint: %s: %s must be subclass of %s [0x%x] array len %d flags len %d", 103 k->external_name(), from_name->as_klass_external_name(), 104 name->as_klass_external_name(), c, vc_array->length(), vcflags_array->length()); 105 } 106 } 107 108 static char get_loader_type_by(oop loader) { 109 assert(SystemDictionary::is_builtin_class_loader(loader), "Must be built-in loader"); 110 if (SystemDictionary::is_boot_class_loader(loader)) { 111 return (char)ClassLoader::BOOT_LOADER; 112 } else if (SystemDictionary::is_platform_class_loader(loader)) { 113 return (char)ClassLoader::PLATFORM_LOADER; 114 } else { 115 assert(SystemDictionary::is_system_class_loader(loader), "Class loader mismatch"); 116 return (char)ClassLoader::APP_LOADER; 117 } 118 } 119 120 void DumpTimeClassInfo::record_linking_constraint(Symbol* name, Handle loader1, Handle loader2) { 121 assert(loader1 != loader2, "sanity"); 122 LogTarget(Info, class, loader, constraints) log; 123 if (_loader_constraints == nullptr) { 124 _loader_constraints = new (mtClass) GrowableArray<DTLoaderConstraint>(4, mtClass); 125 } 126 char lt1 = get_loader_type_by(loader1()); 127 char lt2 = get_loader_type_by(loader2()); 128 DTLoaderConstraint lc(name, lt1, lt2); 129 for (int i = 0; i < _loader_constraints->length(); i++) { 130 if (lc.equals(_loader_constraints->at(i))) { 131 if (log.is_enabled()) { 132 ResourceMark rm; 133 // Use loader[0]/loader[1] to be consistent with the logs in loaderConstraints.cpp 134 log.print("[CDS record loader constraint for class: %s constraint_name: %s loader[0]: %s loader[1]: %s already added]", 135 _klass->external_name(), name->as_C_string(), 136 ClassLoaderData::class_loader_data(loader1())->loader_name_and_id(), 137 ClassLoaderData::class_loader_data(loader2())->loader_name_and_id()); 138 } 139 return; 140 } 141 } 142 _loader_constraints->append(lc); 143 if (log.is_enabled()) { 144 ResourceMark rm; 145 // Use loader[0]/loader[1] to be consistent with the logs in loaderConstraints.cpp 146 log.print("[CDS record loader constraint for class: %s constraint_name: %s loader[0]: %s loader[1]: %s total %d]", 147 _klass->external_name(), name->as_C_string(), 148 ClassLoaderData::class_loader_data(loader1())->loader_name_and_id(), 149 ClassLoaderData::class_loader_data(loader2())->loader_name_and_id(), 150 _loader_constraints->length()); 151 } 152 } 153 154 void DumpTimeClassInfo::add_enum_klass_static_field(int archived_heap_root_index) { 155 if (_enum_klass_static_fields == nullptr) { 156 _enum_klass_static_fields = new (mtClass) GrowableArray<int>(20, mtClass); 157 } 158 _enum_klass_static_fields->append(archived_heap_root_index); 159 } 160 161 int DumpTimeClassInfo::enum_klass_static_field(int which_field) { 162 assert(_enum_klass_static_fields != nullptr, "must be"); 163 return _enum_klass_static_fields->at(which_field); 164 } 165 166 bool DumpTimeClassInfo::is_builtin() { 167 return SystemDictionaryShared::is_builtin(_klass); 168 } 169 170 DumpTimeClassInfo* DumpTimeSharedClassTable::allocate_info(InstanceKlass* k) { 171 if (!CDSConfig::is_dumping_final_static_archive()) { 172 assert(!k->is_shared(), "Do not call with shared classes"); 173 } 174 bool created; 175 DumpTimeClassInfo* p = put_if_absent(k, &created); 176 assert(created, "must not exist in table"); 177 p->_klass = k; 178 return p; 179 } 180 181 DumpTimeClassInfo* DumpTimeSharedClassTable::get_info(InstanceKlass* k) { 182 if (!CDSConfig::is_dumping_final_static_archive()) { 183 assert(!k->is_shared(), "Do not call with shared classes"); 184 } 185 DumpTimeClassInfo* p = get(k); 186 assert(p != nullptr, "we must not see any non-shared InstanceKlass* that's " 187 "not stored with SystemDictionaryShared::init_dumptime_info"); 188 assert(p->_klass == k, "Sanity"); 189 return p; 190 } 191 192 class CountClassByCategory : StackObj { 193 DumpTimeSharedClassTable* _table; 194 public: 195 CountClassByCategory(DumpTimeSharedClassTable* table) : _table(table) {} 196 void do_entry(InstanceKlass* k, DumpTimeClassInfo& info) { 197 if (!info.is_excluded()) { 198 if (info.is_builtin()) { 199 _table->inc_builtin_count(); 200 } else { 201 _table->inc_unregistered_count(); 202 } 203 } 204 } 205 }; 206 207 void DumpTimeSharedClassTable::update_counts() { 208 _builtin_count = 0; 209 _unregistered_count = 0; 210 CountClassByCategory counter(this); 211 iterate_all_live_classes(&counter); 212 }