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