1 /* 2 * Copyright 2000-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20 * CA 95054 USA or visit www.sun.com if you need additional information or 21 * have any questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.compiler; 26 27 import java.util.*; 28 29 import sun.jvm.hotspot.code.*; 30 import sun.jvm.hotspot.debugger.*; 31 import sun.jvm.hotspot.runtime.*; 32 import sun.jvm.hotspot.types.*; 33 import sun.jvm.hotspot.utilities.*; 34 35 public class OopMapSet extends VMObject { 36 private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.compiler.OopMapSet.DEBUG") != null; 37 38 private static CIntegerField omCountField; 39 private static CIntegerField omSizeField; 40 private static AddressField omDataField; 41 private static int REG_COUNT; 42 private static int SAVED_ON_ENTRY_REG_COUNT; 43 private static int C_SAVED_ON_ENTRY_REG_COUNT; 44 private static class MyVisitor implements OopMapVisitor { 45 private AddressVisitor addressVisitor; 46 47 public MyVisitor(AddressVisitor oopVisitor) { 48 setAddressVisitor(oopVisitor); 49 } 50 51 public void setAddressVisitor(AddressVisitor addressVisitor) { 52 this.addressVisitor = addressVisitor; 53 } 54 55 public void visitOopLocation(Address oopAddr) { 56 addressVisitor.visitAddress(oopAddr); 57 } 58 59 public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr) { 60 if (VM.getVM().isClientCompiler()) { 61 Assert.that(false, "should not reach here"); 62 } else if (VM.getVM().isServerCompiler() && 63 VM.getVM().useDerivedPointerTable()) { 64 Assert.that(false, "FIXME: add derived pointer table"); 65 } 66 } 67 68 public void visitValueLocation(Address valueAddr) { 69 } 70 71 public void visitDeadLocation(Address deadAddr) { 72 } 73 } 74 75 static { 76 VM.registerVMInitializedObserver(new Observer() { 77 public void update(Observable o, Object data) { 78 initialize(VM.getVM().getTypeDataBase()); 79 } 80 }); 81 } 82 83 private static void initialize(TypeDataBase db) { 84 Type type = db.lookupType("OopMapSet"); 85 86 omCountField = type.getCIntegerField("_om_count"); 87 omSizeField = type.getCIntegerField("_om_size"); 88 omDataField = type.getAddressField("_om_data"); 89 90 if (!VM.getVM().isCore()) { 91 REG_COUNT = db.lookupIntConstant("REG_COUNT").intValue(); 92 if (VM.getVM().isServerCompiler()) { 93 SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("SAVED_ON_ENTRY_REG_COUNT").intValue(); 94 C_SAVED_ON_ENTRY_REG_COUNT = (int) db.lookupIntConstant("C_SAVED_ON_ENTRY_REG_COUNT").intValue(); 95 } 96 } 97 } 98 99 public OopMapSet(Address addr) { 100 super(addr); 101 } 102 103 /** Returns the number of OopMaps in this OopMapSet */ 104 public long getSize() { 105 return omCountField.getValue(addr); 106 } 107 108 /** returns the OopMap at a given index */ 109 public OopMap getMapAt(int index) { 110 if (Assert.ASSERTS_ENABLED) { 111 Assert.that((index >= 0) && (index <= getSize()),"bad index"); 112 } 113 Address omDataAddr = omDataField.getValue(addr); 114 Address oopMapAddr = omDataAddr.getAddressAt(index * VM.getVM().getAddressSize()); 115 if (oopMapAddr == null) { 116 return null; 117 } 118 return new OopMap(oopMapAddr); 119 } 120 121 public OopMap findMapAtOffset(long pcOffset, boolean debugging) { 122 int i; 123 int len = (int) getSize(); 124 if (Assert.ASSERTS_ENABLED) { 125 Assert.that(len > 0, "must have pointer maps"); 126 } 127 128 // Scan through oopmaps. Stop when current offset is either equal or greater 129 // than the one we are looking for. 130 for (i = 0; i < len; i++) { 131 if (getMapAt(i).getOffset() >= pcOffset) { 132 break; 133 } 134 } 135 136 if (!debugging) { 137 if (Assert.ASSERTS_ENABLED) { 138 Assert.that(i < len, "oopmap not found for pcOffset = " + pcOffset + "; len = " + len); 139 Assert.that(getMapAt(i).getOffset() == pcOffset, "oopmap not found"); 140 } 141 } else { 142 if (i == len) { 143 if (DEBUG) { 144 System.out.println("can't find oopmap at " + pcOffset); 145 System.out.print("Oopmap offsets are [ "); 146 for (i = 0; i < len; i++) { 147 System.out.print(getMapAt(i).getOffset()); 148 } 149 System.out.println("]"); 150 } 151 i = len - 1; 152 return getMapAt(i); 153 } 154 } 155 156 OopMap m = getMapAt(i); 157 return m; 158 } 159 160 /** Visitation -- iterates through the frame for a compiled method. 161 This is a very generic mechanism that requires the Address to be 162 dereferenced by the callee. Other, more specialized, visitation 163 mechanisms are given below. */ 164 public static void oopsDo(Frame fr, CodeBlob cb, RegisterMap regMap, AddressVisitor oopVisitor, boolean debugging) { 165 allDo(fr, cb, regMap, new MyVisitor(oopVisitor), debugging); 166 } 167 168 /** Note that there are 4 required AddressVisitors: one for oops, 169 one for derived oops, one for values, and one for dead values */ 170 public static void allDo(Frame fr, CodeBlob cb, RegisterMap regMap, OopMapVisitor visitor, boolean debugging) { 171 if (Assert.ASSERTS_ENABLED) { 172 CodeBlob tmpCB = VM.getVM().getCodeCache().findBlob(fr.getPC()); 173 Assert.that(tmpCB != null && cb.equals(tmpCB), "wrong codeblob passed in"); 174 } 175 176 OopMapSet maps = cb.getOopMaps(); 177 OopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging); 178 if (Assert.ASSERTS_ENABLED) { 179 Assert.that(map != null, "no ptr map found"); 180 } 181 182 // handle derived pointers first (otherwise base pointer may be 183 // changed before derived pointer offset has been collected) 184 OopMapValue omv; 185 { 186 for (OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE); !oms.isDone(); oms.next()) { 187 if (VM.getVM().isClientCompiler()) { 188 Assert.that(false, "should not reach here"); 189 } 190 omv = oms.getCurrent(); 191 Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap); 192 if (loc != null) { 193 Address baseLoc = fr.oopMapRegToLocation(omv.getContentReg(), regMap); 194 Address derivedLoc = loc; 195 visitor.visitDerivedOopLocation(baseLoc, derivedLoc); 196 } 197 } 198 } 199 200 // We want dead, value and oop oop_types 201 OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[] { 202 OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.VALUE_VALUE, OopMapValue.OopTypes.DEAD_VALUE 203 }; 204 205 { 206 for (OopMapStream oms = new OopMapStream(map, values); !oms.isDone(); oms.next()) { 207 omv = oms.getCurrent(); 208 Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap); 209 if (loc != null) { 210 if (omv.getType() == OopMapValue.OopTypes.OOP_VALUE) { 211 // This assert commented out because this will be useful 212 // to detect in the debugging system 213 // assert(Universe::is_heap_or_null(*loc), "found non oop pointer"); 214 visitor.visitOopLocation(loc); 215 } else if (omv.getType() == OopMapValue.OopTypes.VALUE_VALUE) { 216 visitor.visitValueLocation(loc); 217 } else if (omv.getType() == OopMapValue.OopTypes.DEAD_VALUE) { 218 visitor.visitDeadLocation(loc); 219 } 220 } 221 } 222 } 223 } 224 225 /** Update callee-saved register info for the following frame. 226 Should only be called in non-core builds. */ 227 public static void updateRegisterMap(Frame fr, CodeBlob cb, RegisterMap regMap, boolean debugging) { 228 if (Assert.ASSERTS_ENABLED) { 229 Assert.that(!VM.getVM().isCore(), "non-core builds only"); 230 } 231 232 if (!VM.getVM().isDebugging()) { 233 if (Assert.ASSERTS_ENABLED) { 234 OopMapSet maps = cb.getOopMaps(); 235 Assert.that((maps != null) && (maps.getSize() > 0), "found null or empty OopMapSet for CodeBlob"); 236 } 237 } else { 238 // Hack for some topmost frames that have been found with empty 239 // OopMapSets. (Actually have not seen the null case, but don't 240 // want to take any chances.) See HSDB.showThreadStackMemory(). 241 OopMapSet maps = cb.getOopMaps(); 242 if ((maps == null) || (maps.getSize() == 0)) { 243 return; 244 } 245 } 246 247 // Check if caller must update oop argument 248 regMap.setIncludeArgumentOops(cb.callerMustGCArguments(regMap.getThread())); 249 250 int nofCallee = 0; 251 Address[] locs = new Address[2 * REG_COUNT + 1]; 252 VMReg [] regs = new VMReg [2 * REG_COUNT + 1]; 253 // ("+1" because REG_COUNT might be zero) 254 255 // Scan through oopmap and find location of all callee-saved registers 256 // (we do not do update in place, since info could be overwritten) 257 OopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging); 258 if (Assert.ASSERTS_ENABLED) { 259 Assert.that(map != null, "no ptr map found"); 260 } 261 262 OopMapValue omv = null; 263 for(OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); !oms.isDone(); oms.next()) { 264 omv = oms.getCurrent(); 265 if (Assert.ASSERTS_ENABLED) { 266 Assert.that(nofCallee < 2 * REG_COUNT, "overflow"); 267 } 268 regs[nofCallee] = omv.getContentReg(); 269 locs[nofCallee] = fr.oopMapRegToLocation(omv.getReg(), regMap); 270 nofCallee++; 271 } 272 273 // Check that runtime stubs save all callee-saved registers 274 // After adapter frames were deleted C2 doesn't use callee save registers at present 275 if (Assert.ASSERTS_ENABLED) { 276 if (VM.getVM().isServerCompiler()) { 277 Assert.that(!cb.isRuntimeStub() || 278 (nofCallee >= SAVED_ON_ENTRY_REG_COUNT || nofCallee >= C_SAVED_ON_ENTRY_REG_COUNT), 279 "must save all"); 280 } 281 } 282 283 // Copy found callee-saved register to reg_map 284 for (int i = 0; i < nofCallee; i++) { 285 regMap.setLocation(regs[i], locs[i]); 286 } 287 } 288 }