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