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