1 /* 2 * Copyright (c) 2020, 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/archiveUtils.hpp" 27 #include "cds/archiveBuilder.hpp" 28 #include "cds/cdsConfig.hpp" 29 #include "cds/cppVtables.hpp" 30 #include "cds/metaspaceShared.hpp" 31 #include "logging/log.hpp" 32 #include "oops/flatArrayKlass.hpp" 33 #include "oops/inlineKlass.hpp" 34 #include "oops/instanceClassLoaderKlass.hpp" 35 #include "oops/instanceKlass.inline.hpp" 36 #include "oops/instanceMirrorKlass.hpp" 37 #include "oops/instanceRefKlass.hpp" 38 #include "oops/instanceStackChunkKlass.hpp" 39 #include "oops/methodData.hpp" 40 #include "oops/objArrayKlass.hpp" 41 #include "oops/typeArrayKlass.hpp" 42 #include "runtime/arguments.hpp" 43 #include "utilities/globalDefinitions.hpp" 44 45 // Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables. 46 // (In GCC this is the field <Type>::_vptr, i.e., first word in the object.) 47 // 48 // Addresses of the vtables and the methods may be different across JVM runs, 49 // if libjvm.so is dynamically loaded at a different base address. 50 // 51 // To ensure that the Metadata objects in the CDS archive always have the correct vtable: 52 // 53 // + at dump time: we redirect the _vptr to point to our own vtables inside 54 // the CDS image 55 // + at run time: we clone the actual contents of the vtables from libjvm.so 56 // into our own tables. 57 58 // Currently, the archive contains ONLY the following types of objects that have C++ vtables. 59 // NOTE: this table must be in-sync with sun.jvm.hotspot.memory.FileMapInfo::populateMetadataTypeArray(). 60 #define CPP_VTABLE_TYPES_DO(f) \ 61 f(ConstantPool) \ 62 f(InstanceKlass) \ 63 f(InstanceClassLoaderKlass) \ 64 f(InstanceMirrorKlass) \ 65 f(InstanceRefKlass) \ 66 f(InstanceStackChunkKlass) \ 67 f(Method) \ 68 f(ObjArrayKlass) \ 69 f(TypeArrayKlass) \ 70 f(FlatArrayKlass) \ 71 f(InlineKlass) 72 73 class CppVtableInfo { 74 intptr_t _vtable_size; 75 intptr_t _cloned_vtable[1]; // Pseudo flexible array member. 76 static size_t cloned_vtable_offset() { return offset_of(CppVtableInfo, _cloned_vtable); } 77 public: 78 int vtable_size() { return int(uintx(_vtable_size)); } 79 void set_vtable_size(int n) { _vtable_size = intptr_t(n); } 80 // Using _cloned_vtable[i] for i > 0 causes undefined behavior. We use address calculation instead. 81 intptr_t* cloned_vtable() { return (intptr_t*)((char*)this + cloned_vtable_offset()); } 82 void zero() { memset(cloned_vtable(), 0, sizeof(intptr_t) * vtable_size()); } 83 // Returns the address of the next CppVtableInfo that can be placed immediately after this CppVtableInfo 84 static size_t byte_size(int vtable_size) { 85 return cloned_vtable_offset() + (sizeof(intptr_t) * vtable_size); 86 } 87 }; 88 89 static inline intptr_t* vtable_of(const Metadata* m) { 90 return *((intptr_t**)m); 91 } 92 93 template <class T> class CppVtableCloner { 94 static int get_vtable_length(const char* name); 95 96 public: 97 // Allocate a clone of the vtable of T from the shared metaspace; 98 // Initialize the contents of this clone. 99 static CppVtableInfo* allocate_and_initialize(const char* name); 100 101 // Copy the contents of the vtable of T into info->_cloned_vtable; 102 static void initialize(const char* name, CppVtableInfo* info); 103 104 static void init_orig_cpp_vtptr(int kind); 105 }; 106 107 template <class T> 108 CppVtableInfo* CppVtableCloner<T>::allocate_and_initialize(const char* name) { 109 int n = get_vtable_length(name); 110 CppVtableInfo* info = 111 (CppVtableInfo*)ArchiveBuilder::current()->rw_region()->allocate(CppVtableInfo::byte_size(n)); 112 info->set_vtable_size(n); 113 initialize(name, info); 114 return info; 115 } 116 117 template <class T> 118 void CppVtableCloner<T>::initialize(const char* name, CppVtableInfo* info) { 119 T tmp; // Allocate temporary dummy metadata object to get to the original vtable. 120 int n = info->vtable_size(); 121 intptr_t* srcvtable = vtable_of(&tmp); 122 intptr_t* dstvtable = info->cloned_vtable(); 123 124 // We already checked (and, if necessary, adjusted n) when the vtables were allocated, so we are 125 // safe to do memcpy. 126 log_debug(cds, vtables)("Copying %3d vtable entries for %s", n, name); 127 memcpy(dstvtable, srcvtable, sizeof(intptr_t) * n); 128 } 129 130 // To determine the size of the vtable for each type, we use the following 131 // trick by declaring 2 subclasses: 132 // 133 // class CppVtableTesterA: public InstanceKlass {virtual int last_virtual_method() {return 1;} }; 134 // class CppVtableTesterB: public InstanceKlass {virtual void* last_virtual_method() {return nullptr}; }; 135 // 136 // CppVtableTesterA and CppVtableTesterB's vtables have the following properties: 137 // - Their size (N+1) is exactly one more than the size of InstanceKlass's vtable (N) 138 // - The first N entries have are exactly the same as in InstanceKlass's vtable. 139 // - Their last entry is different. 140 // 141 // So to determine the value of N, we just walk CppVtableTesterA and CppVtableTesterB's tables 142 // and find the first entry that's different. 143 // 144 // This works on all C++ compilers supported by Oracle, but you may need to tweak it for more 145 // esoteric compilers. 146 147 template <class T> class CppVtableTesterB: public T { 148 public: 149 virtual int last_virtual_method() {return 1;} 150 }; 151 152 template <class T> class CppVtableTesterA : public T { 153 public: 154 virtual void* last_virtual_method() { 155 // Make this different than CppVtableTesterB::last_virtual_method so the C++ 156 // compiler/linker won't alias the two functions. 157 return nullptr; 158 } 159 }; 160 161 template <class T> 162 int CppVtableCloner<T>::get_vtable_length(const char* name) { 163 CppVtableTesterA<T> a; 164 CppVtableTesterB<T> b; 165 166 intptr_t* avtable = vtable_of(&a); 167 intptr_t* bvtable = vtable_of(&b); 168 169 // Start at slot 1, because slot 0 may be RTTI (on Solaris/Sparc) 170 int vtable_len = 1; 171 for (; ; vtable_len++) { 172 if (avtable[vtable_len] != bvtable[vtable_len]) { 173 break; 174 } 175 } 176 log_debug(cds, vtables)("Found %3d vtable entries for %s", vtable_len, name); 177 178 return vtable_len; 179 } 180 181 #define ALLOCATE_AND_INITIALIZE_VTABLE(c) \ 182 _index[c##_Kind] = CppVtableCloner<c>::allocate_and_initialize(#c); \ 183 ArchivePtrMarker::mark_pointer(&_index[c##_Kind]); 184 185 #define INITIALIZE_VTABLE(c) \ 186 CppVtableCloner<c>::initialize(#c, _index[c##_Kind]); 187 188 #define INIT_ORIG_CPP_VTPTRS(c) \ 189 CppVtableCloner<c>::init_orig_cpp_vtptr(c##_Kind); 190 191 #define DECLARE_CLONED_VTABLE_KIND(c) c ## _Kind, 192 193 enum ClonedVtableKind { 194 // E.g., ConstantPool_Kind == 0, InstanceKlass_Kind == 1, etc. 195 CPP_VTABLE_TYPES_DO(DECLARE_CLONED_VTABLE_KIND) 196 _num_cloned_vtable_kinds 197 }; 198 199 // This is a map of all the original vtptrs. E.g., for 200 // ConstantPool *cp = new (...) ConstantPool(...) ; // a dynamically allocated constant pool 201 // the following holds true: 202 // _orig_cpp_vtptrs[ConstantPool_Kind] == ((intptr_t**)cp)[0] 203 static intptr_t* _orig_cpp_vtptrs[_num_cloned_vtable_kinds]; 204 static bool _orig_cpp_vtptrs_inited = false; 205 206 template <class T> 207 void CppVtableCloner<T>::init_orig_cpp_vtptr(int kind) { 208 assert(kind < _num_cloned_vtable_kinds, "sanity"); 209 T tmp; // Allocate temporary dummy metadata object to get to the original vtable. 210 intptr_t* srcvtable = vtable_of(&tmp); 211 _orig_cpp_vtptrs[kind] = srcvtable; 212 } 213 214 // This is the index of all the cloned vtables. E.g., for 215 // ConstantPool* cp = ....; // an archived constant pool 216 // InstanceKlass* ik = ....;// an archived class 217 // the following holds true: 218 // _index[ConstantPool_Kind]->cloned_vtable() == ((intptr_t**)cp)[0] 219 // _index[InstanceKlass_Kind]->cloned_vtable() == ((intptr_t**)ik)[0] 220 static CppVtableInfo* _index[_num_cloned_vtable_kinds]; 221 222 // Vtables are all fixed offsets from ArchiveBuilder::current()->mapped_base() 223 // E.g. ConstantPool is at offset 0x58. We can archive these offsets in the 224 // RO region and use them to alculate their location at runtime without storing 225 // the pointers in the RW region 226 char* CppVtables::_vtables_serialized_base = nullptr; 227 228 void CppVtables::dumptime_init(ArchiveBuilder* builder) { 229 assert(CDSConfig::is_dumping_static_archive(), "cpp tables are only dumped into static archive"); 230 231 CPP_VTABLE_TYPES_DO(ALLOCATE_AND_INITIALIZE_VTABLE); 232 233 size_t cpp_tables_size = builder->rw_region()->top() - builder->rw_region()->base(); 234 builder->alloc_stats()->record_cpp_vtables((int)cpp_tables_size); 235 } 236 237 void CppVtables::serialize(SerializeClosure* soc) { 238 if (!soc->reading()) { 239 _vtables_serialized_base = (char*)ArchiveBuilder::current()->buffer_top(); 240 } 241 for (int i = 0; i < _num_cloned_vtable_kinds; i++) { 242 soc->do_ptr(&_index[i]); 243 } 244 if (soc->reading()) { 245 CPP_VTABLE_TYPES_DO(INITIALIZE_VTABLE); 246 } 247 } 248 249 intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address obj) { 250 if (!_orig_cpp_vtptrs_inited) { 251 CPP_VTABLE_TYPES_DO(INIT_ORIG_CPP_VTPTRS); 252 _orig_cpp_vtptrs_inited = true; 253 } 254 255 assert(CDSConfig::is_dumping_archive(), "sanity"); 256 int kind = -1; 257 switch (msotype) { 258 case MetaspaceObj::SymbolType: 259 case MetaspaceObj::TypeArrayU1Type: 260 case MetaspaceObj::TypeArrayU2Type: 261 case MetaspaceObj::TypeArrayU4Type: 262 case MetaspaceObj::TypeArrayU8Type: 263 case MetaspaceObj::TypeArrayOtherType: 264 case MetaspaceObj::ConstMethodType: 265 case MetaspaceObj::ConstantPoolCacheType: 266 case MetaspaceObj::AnnotationsType: 267 case MetaspaceObj::MethodCountersType: 268 case MetaspaceObj::SharedClassPathEntryType: 269 case MetaspaceObj::RecordComponentType: 270 // These have no vtables. 271 break; 272 case MetaspaceObj::MethodDataType: 273 // We don't archive MethodData <-- should have been removed in removed_unsharable_info 274 ShouldNotReachHere(); 275 break; 276 default: 277 for (kind = 0; kind < _num_cloned_vtable_kinds; kind ++) { 278 if (vtable_of((Metadata*)obj) == _orig_cpp_vtptrs[kind]) { 279 break; 280 } 281 } 282 if (kind >= _num_cloned_vtable_kinds) { 283 fatal("Cannot find C++ vtable for " INTPTR_FORMAT " -- you probably added" 284 " a new subtype of Klass or MetaData without updating CPP_VTABLE_TYPES_DO or the cases in this 'switch' statement", 285 p2i(obj)); 286 } 287 } 288 289 if (kind >= 0) { 290 assert(kind < _num_cloned_vtable_kinds, "must be"); 291 return _index[kind]->cloned_vtable(); 292 } else { 293 return nullptr; 294 } 295 } 296 297 void CppVtables::zero_archived_vtables() { 298 assert(CDSConfig::is_dumping_static_archive(), "cpp tables are only dumped into static archive"); 299 for (int kind = 0; kind < _num_cloned_vtable_kinds; kind ++) { 300 _index[kind]->zero(); 301 } 302 } 303 304 bool CppVtables::is_valid_shared_method(const Method* m) { 305 assert(MetaspaceShared::is_in_shared_metaspace(m), "must be"); 306 return vtable_of(m) == _index[Method_Kind]->cloned_vtable(); 307 } --- EOF ---