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[11]; 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 } 134 135 public FileMapHeader getHeader() { 136 return headerObj; 137 } 138 139 public boolean inCopiedVtableSpace(Address vptrAddress) { 140 FileMapHeader fmHeader = getHeader(); 141 return fmHeader.inCopiedVtableSpace(vptrAddress); 142 } 143 144 public Type getTypeForVptrAddress(Address vptrAddress) { 145 if (vTableTypeMap == null) { 146 getHeader().createVtableTypeMapping(); 147 } 148 return vTableTypeMap.get(vptrAddress); 149 } 150 151 152 //------------------------------------------------------------------------------------------ 153 154 public static class FileMapHeader extends VMObject { 155 156 public FileMapHeader(Address addr) { 157 super(addr); 158 } 159 160 public boolean inCopiedVtableSpace(Address vptrAddress) { 161 if (vptrAddress == null) { 162 return false; 163 } 164 if (vptrAddress.greaterThan(rwRegionBaseAddress) && 165 vptrAddress.lessThanOrEqual(rwRegionEndAddress)) { 166 return true; 167 } 168 return false; 169 } 170 171 public void createVtableTypeMapping() { 172 vTableTypeMap = new HashMap<Address, Type>(); 173 long addressSize = VM.getVM().getAddressSize(); 174 175 // vtablesIndex points to to an array like this: 176 // long info[] = { 177 // offset of the CppVtableInfo for ConstantPool, 178 // offset of the CppVtableInfo for InstanceKlass, 179 // offset of the CppVtableInfo for InstanceClassLoaderKlass, 180 // ... 181 // }; 182 // 183 // class CppVtableInfo { 184 // intptr_t _vtable_size; 185 // intptr_t _cloned_vtable[1]; 186 // ... 187 // }; 188 // 189 // The loop below computes the following 190 // CppVtableInfo* t_ConstantPool = mapped_base_address + info[0]; 191 // CppVtableInfo* t_InstanceKlass = mapped_base_address + info[1]; 192 // ... 193 // 194 // If we have the following objects 195 // ConstantPool* cp = ....; // an archived constant pool 196 // InstanceKlass* ik = ....;// an archived class 197 // 198 // then the following holds true: 199 // ((intptr_t**)cp)[0] == &t_ConstantPool->_cloned_vtable[0] // The vtable for archived ConstantPools 200 // ((intptr_t**)ik)[0] == &t_InstanceKlass->_cloned_vtable[0] // The vtable for archived InstanceKlasses 201 // 202 // To get an idea what these address look like, do this: 203 // 204 // $ java -Xlog:cds+vtables=debug -XX:+UnlockDiagnosticVMOptions -XX:ArchiveRelocationMode=0 --version 205 // [0.002s][debug][cds,vtables] Copying 14 vtable entries for ConstantPool to 0x800000018 206 // [0.002s][debug][cds,vtables] Copying 41 vtable entries for InstanceKlass to 0x800000090 207 // [0.002s][debug][cds,vtables] Copying 41 vtable entries for InstanceClassLoaderKlass to 0x8000001e0 208 // [0.002s][debug][cds,vtables] Copying 41 vtable entries for InstanceMirrorKlass to 0x800000330 209 // [0.002s][debug][cds,vtables] Copying 41 vtable entries for InstanceRefKlass to 0x800000480 210 // [0.002s][debug][cds,vtables] Copying 41 vtable entries for InstanceStackChunkKlass to 0x8000005d0 211 // [0.002s][debug][cds,vtables] Copying 14 vtable entries for Method to 0x800000720 212 // [0.002s][debug][cds,vtables] Copying 42 vtable entries for ObjArrayKlass to 0x800000798 213 // [0.002s][debug][cds,vtables] Copying 42 vtable entries for TypeArrayKlass to 0x8000008f0 214 // java 23-internal 2024-09-17 215 // ... 216 217 for (int i=0; i < metadataTypeArray.length; i++) { 218 long vtable_offset = vtablesIndex.getJLongAt(i * addressSize); // long offset = _index[i] 219 220 // CppVtableInfo* t = the address of the CppVtableInfo for the i-th table 221 Address vtableInfoAddress = mapped_base_address.addOffsetTo(vtable_offset); 222 223 // vtableAddress = &t->_cloned_vtable[0] 224 Address vtableAddress = vtableInfoAddress.addOffsetTo(addressSize); 225 226 vTableTypeMap.put(vtableAddress, metadataTypeArray[i]); 227 } 228 } 229 } 230 }