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 }