1 /* 2 * Copyright (c) 2018, 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 package sun.jvm.hotspot.memory; 26 27 import java.util.*; 28 import sun.jvm.hotspot.debugger.Address; 29 import sun.jvm.hotspot.runtime.VM; 30 import sun.jvm.hotspot.runtime.VMObject; 31 import sun.jvm.hotspot.runtime.VMObjectFactory; 32 import sun.jvm.hotspot.types.*; 33 import sun.jvm.hotspot.utilities.Observable; 34 import sun.jvm.hotspot.utilities.Observer; 35 36 public class FileMapInfo { 37 private static FileMapHeader headerObj; 38 39 // Fields for handling the copied C++ vtables 40 private static Address rwRegionBaseAddress; 41 private static Address rwRegionEndAddress; 42 private static Address vtablesIndex; 43 private static Address mapped_base_address; 44 45 // HashMap created by mapping the vTable addresses in the rw region with 46 // the corresponding metadata type. 47 private static Map<Address, Type> vTableTypeMap; 48 49 private static Type metadataTypeArray[]; 50 51 static { 52 VM.registerVMInitializedObserver(new Observer() { 53 public void update(Observable o, Object data) { 54 initialize(VM.getVM().getTypeDataBase()); 55 } 56 }); 57 } 58 59 static Address getStatic_AddressField(Type type, String fieldName) { 60 AddressField field = type.getAddressField(fieldName); 61 return field.getValue(); 62 } 63 64 static Address get_AddressField(Type type, Address instance, String fieldName) { 65 AddressField field = type.getAddressField(fieldName); 66 return field.getValue(instance); 67 } 68 69 static long get_CIntegerField(Type type, Address instance, String fieldName) { 70 CIntegerField field = type.getCIntegerField(fieldName); 71 return field.getValue(instance); 72 } 73 74 // C equivalent: return &header->_regions[index]; 75 static Address get_CDSFileMapRegion(Type FileMapHeader_type, Address header, int index) { 76 AddressField regionsField = FileMapHeader_type.getAddressField("_regions[0]"); 77 78 // size_t offset = offsetof(FileMapHeader, _regions[0]); 79 // CDSFileMapRegion* regions_0 = ((char*)header) + offset; // regions_0 = &header->_regions[index]; 80 // return ((char*)regions_0) + index * sizeof(CDSFileMapRegion); 81 long offset = regionsField.getOffset(); 82 Address regions_0 = header.addOffsetTo(offset); 83 return regions_0.addOffsetTo(index * regionsField.getSize()); 84 } 85 86 private static void initialize(TypeDataBase db) { 87 vTableTypeMap = null; // force vTableTypeMap to get re-initialized later 88 89 Type FileMapInfo_type = db.lookupType("FileMapInfo"); 90 Type FileMapHeader_type = db.lookupType("FileMapHeader"); 91 Type CDSFileMapRegion_type = db.lookupType("CDSFileMapRegion"); 92 93 // FileMapInfo * info = FileMapInfo::_current_info; 94 // FileMapHeader* header = info->_header 95 Address info = getStatic_AddressField(FileMapInfo_type, "_current_info"); 96 Address header = get_AddressField(FileMapInfo_type, info, "_header"); 97 headerObj = VMObjectFactory.newObject(FileMapHeader.class, header); 98 99 // char* mapped_base_address = header->_mapped_base_address 100 // size_t cloned_vtable_offset = header->_cloned_vtable_offset 101 // CppVtableInfo** vtablesIndex = mapped_base_address + cloned_vtable_offset; 102 mapped_base_address = get_AddressField(FileMapHeader_type, header, "_mapped_base_address"); 103 long cloned_vtable_offset = get_CIntegerField(FileMapHeader_type, header, "_cloned_vtables_offset"); 104 vtablesIndex = mapped_base_address.addOffsetTo(cloned_vtable_offset); 105 106 // CDSFileMapRegion* rw_region = &header->_region[rw]; 107 // char* rwRegionBaseAddress = rw_region->_mapped_base; 108 // size_t used = rw_region->_used; 109 // char* rwRegionEndAddress = rwRegionBaseAddress + used; 110 Address rw_region = get_CDSFileMapRegion(FileMapHeader_type, header, 0); 111 rwRegionBaseAddress = get_AddressField(CDSFileMapRegion_type, rw_region, "_mapped_base"); 112 long used = get_CIntegerField(CDSFileMapRegion_type, rw_region, "_used"); 113 rwRegionEndAddress = rwRegionBaseAddress.addOffsetTo(used); 114 115 populateMetadataTypeArray(db); 116 } 117 118 private static void populateMetadataTypeArray(TypeDataBase db) { 119 metadataTypeArray = new Type[14]; 120 // The order needs to match up with CPP_VTABLE_TYPES_DO in src/hotspot/share/cds/cppVtables.cpp 121 122 metadataTypeArray[0] = db.lookupType("ConstantPool"); 123 metadataTypeArray[1] = db.lookupType("InstanceKlass"); 124 metadataTypeArray[2] = db.lookupType("InstanceClassLoaderKlass"); 125 metadataTypeArray[3] = db.lookupType("InstanceMirrorKlass"); 126 metadataTypeArray[4] = db.lookupType("InstanceRefKlass"); 127 metadataTypeArray[5] = db.lookupType("InstanceStackChunkKlass"); 128 metadataTypeArray[6] = db.lookupType("Method"); 129 metadataTypeArray[7] = db.lookupType("MethodData"); 130 metadataTypeArray[8] = db.lookupType("MethodCounters"); 131 metadataTypeArray[9] = db.lookupType("ObjArrayKlass"); 132 metadataTypeArray[10] = db.lookupType("TypeArrayKlass"); 133 metadataTypeArray[11] = db.lookupType("FlatArrayKlass"); 134 metadataTypeArray[12] = db.lookupType("InlineKlass"); 135 metadataTypeArray[11] = db.lookupType("RefArrayKlass"); 136 } 137 138 public FileMapHeader getHeader() { 139 return headerObj; 140 } 141 142 public boolean inCopiedVtableSpace(Address vptrAddress) { 143 FileMapHeader fmHeader = getHeader(); 144 return fmHeader.inCopiedVtableSpace(vptrAddress); 145 } 146 147 public Type getTypeForVptrAddress(Address vptrAddress) { 148 if (vTableTypeMap == null) { 149 getHeader().createVtableTypeMapping(); 150 } 151 return vTableTypeMap.get(vptrAddress); 152 } 153 154 155 //------------------------------------------------------------------------------------------ 156 157 public static class FileMapHeader extends VMObject { 158 159 public FileMapHeader(Address addr) { 160 super(addr); 161 } 162 163 public boolean inCopiedVtableSpace(Address vptrAddress) { 164 if (vptrAddress == null) { 165 return false; 166 } 167 if (vptrAddress.greaterThan(rwRegionBaseAddress) && 168 vptrAddress.lessThanOrEqual(rwRegionEndAddress)) { 169 return true; 170 } 171 return false; 172 } 173 174 public void createVtableTypeMapping() { 175 vTableTypeMap = new HashMap<Address, Type>(); 176 long addressSize = VM.getVM().getAddressSize(); 177 178 // vtablesIndex points to to an array like this: 179 // long info[] = { 180 // offset of the CppVtableInfo for ConstantPool, 181 // offset of the CppVtableInfo for InstanceKlass, 182 // offset of the CppVtableInfo for InstanceClassLoaderKlass, 183 // ... 184 // }; 185 // 186 // class CppVtableInfo { 187 // intptr_t _vtable_size; 188 // intptr_t _cloned_vtable[1]; 189 // ... 190 // }; 191 // 192 // The loop below computes the following 193 // CppVtableInfo* t_ConstantPool = mapped_base_address + info[0]; 194 // CppVtableInfo* t_InstanceKlass = mapped_base_address + info[1]; 195 // ... 196 // 197 // If we have the following objects 198 // ConstantPool* cp = ....; // an archived constant pool 199 // InstanceKlass* ik = ....;// an archived class 200 // 201 // then the following holds true: 202 // ((intptr_t**)cp)[0] == &t_ConstantPool->_cloned_vtable[0] // The vtable for archived ConstantPools 203 // ((intptr_t**)ik)[0] == &t_InstanceKlass->_cloned_vtable[0] // The vtable for archived InstanceKlasses 204 // 205 // To get an idea what these address look like, do this: 206 // 207 // $ java -Xlog:cds+vtables=debug -XX:+UnlockDiagnosticVMOptions -XX:ArchiveRelocationMode=0 --version 208 // [0.002s][debug][cds,vtables] Copying 14 vtable entries for ConstantPool to 0x800000018 209 // [0.002s][debug][cds,vtables] Copying 41 vtable entries for InstanceKlass to 0x800000090 210 // [0.002s][debug][cds,vtables] Copying 41 vtable entries for InstanceClassLoaderKlass to 0x8000001e0 211 // [0.002s][debug][cds,vtables] Copying 41 vtable entries for InstanceMirrorKlass to 0x800000330 212 // [0.002s][debug][cds,vtables] Copying 41 vtable entries for InstanceRefKlass to 0x800000480 213 // [0.002s][debug][cds,vtables] Copying 41 vtable entries for InstanceStackChunkKlass to 0x8000005d0 214 // [0.002s][debug][cds,vtables] Copying 14 vtable entries for Method to 0x800000720 215 // [0.002s][debug][cds,vtables] Copying 42 vtable entries for ObjArrayKlass to 0x800000798 216 // [0.002s][debug][cds,vtables] Copying 42 vtable entries for TypeArrayKlass to 0x8000008f0 217 // java 23-internal 2024-09-17 218 // ... 219 220 for (int i=0; i < metadataTypeArray.length; i++) { 221 long vtable_offset = vtablesIndex.getJLongAt(i * addressSize); // long offset = _index[i] 222 223 // CppVtableInfo* t = the address of the CppVtableInfo for the i-th table 224 Address vtableInfoAddress = mapped_base_address.addOffsetTo(vtable_offset); 225 226 // vtableAddress = &t->_cloned_vtable[0] 227 Address vtableAddress = vtableInfoAddress.addOffsetTo(addressSize); 228 229 vTableTypeMap.put(vtableAddress, metadataTypeArray[i]); 230 } 231 } 232 } 233 }