1 /* 2 * Copyright (c) 2000, 2008, 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.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 ImmutableOopMapSet extends VMObject { 36 private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.compiler.ImmutableOopMapSet.DEBUG") != null; 37 38 private static CIntegerField countField; 39 private static CIntegerField sizeField; 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 long classSize; 45 46 private static class MyVisitor implements OopMapVisitor { 47 private AddressVisitor addressVisitor; 48 49 public MyVisitor(AddressVisitor oopVisitor) { 50 setAddressVisitor(oopVisitor); 51 } 52 53 public void setAddressVisitor(AddressVisitor addressVisitor) { 54 this.addressVisitor = addressVisitor; 55 } 56 57 public void visitOopLocation(Address oopAddr) { 58 addressVisitor.visitAddress(oopAddr); 59 } 60 61 public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr) { 62 if (VM.getVM().isClientCompiler()) { 63 Assert.that(false, "should not reach here"); 64 } else if (VM.getVM().isServerCompiler() && 65 VM.getVM().useDerivedPointerTable()) { 66 Assert.that(false, "FIXME: add derived pointer table"); 67 } 68 } 69 70 public void visitNarrowOopLocation(Address narrowOopAddr) { 71 addressVisitor.visitCompOopAddress(narrowOopAddr); 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("ImmutableOopMapSet"); 85 86 countField = type.getCIntegerField("_count"); 87 sizeField = type.getCIntegerField("_size"); 88 classSize = type.getSize(); 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 ImmutableOopMapSet(Address addr) { 100 super(addr); 101 } 102 103 /** 104 * Returns the number of OopMaps in this ImmutableOopMapSet 105 */ 106 public int getCount() { return (int) countField.getValue(addr); } 107 108 private Address dataStart() { 109 return (pairStart().addOffsetTo(ImmutableOopMapPair.classSize() * getCount())); 110 } 111 112 private Address pairStart() { 113 return addr.addOffsetTo(ImmutableOopMapSet.classSize); 114 } 115 116 public ImmutableOopMapPair pairAt(int index) { 117 Assert.that((index >= 0) && (index < getCount()), "bad index"); 118 return new ImmutableOopMapPair(pairStart().addOffsetTo(index * ImmutableOopMapPair.classSize())); 119 } 120 121 /** 122 * returns the OopMap at a given index 123 */ 124 public ImmutableOopMap getMapAt(int index) { 125 if (Assert.ASSERTS_ENABLED) { 126 Assert.that((index >= 0) && (index <= getCount()), "bad index"); 127 } 128 129 ImmutableOopMapPair immutableOopMapPair = pairAt(index); 130 return getMap(immutableOopMapPair); 131 } 132 133 public ImmutableOopMap findMapAtOffset(long pcOffset, boolean debugging) { 134 int i; 135 int len = getCount(); 136 if (Assert.ASSERTS_ENABLED) { 137 Assert.that(len > 0, "must have pointer maps"); 138 } 139 140 // Scan through oopmaps. Stop when current offset is either equal or greater 141 // than the one we are looking for. 142 for (i = 0; i < len; i++) { 143 if (pairAt(i).getPC() >= pcOffset) { 144 break; 145 } 146 } 147 148 if (!debugging) { 149 if (Assert.ASSERTS_ENABLED) { 150 Assert.that(i < len, "oopmap not found for pcOffset = " + pcOffset + "; len = " + len); 151 Assert.that(pairAt(i).getPC() == pcOffset, "oopmap not found"); 152 } 153 } else { 154 if (i == len) { 155 if (DEBUG) { 156 System.out.println("can't find oopmap at " + pcOffset); 157 System.out.print("Oopmap offsets are [ "); 158 for (i = 0; i < len; i++) { 159 System.out.print(pairAt(i).getPC()); 160 } 161 System.out.println("]"); 162 } 163 i = len - 1; 164 return getMapAt(i); 165 } 166 } 167 168 ImmutableOopMap m = getMapAt(i); 169 return m; 170 } 171 172 /** 173 * Visitation -- iterates through the frame for a compiled method. 174 * This is a very generic mechanism that requires the Address to be 175 * dereferenced by the callee. Other, more specialized, visitation 176 * mechanisms are given below. 177 */ 178 public static void oopsDo(Frame fr, CodeBlob cb, RegisterMap regMap, AddressVisitor oopVisitor, boolean debugging) { 179 allDo(fr, cb, regMap, new MyVisitor(oopVisitor), debugging); 180 } 181 182 /** 183 * Note that there are 4 required AddressVisitors: one for oops, 184 * one for derived oops, one for values, and one for dead values 185 */ 186 public static void allDo(Frame fr, CodeBlob cb, RegisterMap regMap, OopMapVisitor visitor, boolean debugging) { 187 if (Assert.ASSERTS_ENABLED) { 188 CodeBlob tmpCB = VM.getVM().getCodeCache().findBlob(fr.getPC()); 189 Assert.that(tmpCB != null && cb.equals(tmpCB), "wrong codeblob passed in"); 190 } 191 192 ImmutableOopMapSet maps = cb.getOopMaps(); 193 ImmutableOopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging); 194 if (Assert.ASSERTS_ENABLED) { 195 Assert.that(map != null, "no ptr map found"); 196 } 197 198 // handle derived pointers first (otherwise base pointer may be 199 // changed before derived pointer offset has been collected) 200 OopMapValue omv; 201 { 202 for (OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE); !oms.isDone(); oms.next()) { 203 if (VM.getVM().isClientCompiler()) { 204 Assert.that(false, "should not reach here"); 205 } 206 omv = oms.getCurrent(); 207 Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap); 208 if (loc != null) { 209 Address baseLoc = fr.oopMapRegToLocation(omv.getContentReg(), regMap); 210 Address derivedLoc = loc; 211 visitor.visitDerivedOopLocation(baseLoc, derivedLoc); 212 } 213 } 214 } 215 216 // We want narow oop and oop oop_types 217 OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[] { 218 OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE 219 }; 220 221 { 222 for (OopMapStream oms = new OopMapStream(map, values); !oms.isDone(); oms.next()) { 223 omv = oms.getCurrent(); 224 Address loc = fr.oopMapRegToLocation(omv.getReg(), regMap); 225 if (loc != null) { 226 if (omv.getType() == OopMapValue.OopTypes.OOP_VALUE) { 227 // This assert commented out because this will be useful 228 // to detect in the debugging system 229 // assert(Universe::is_heap_or_null(*loc), "found non oop pointer"); 230 visitor.visitOopLocation(loc); 231 } else if (omv.getType() == OopMapValue.OopTypes.NARROWOOP_VALUE) { 232 visitor.visitNarrowOopLocation(loc); 233 } 234 } 235 } 236 } 237 } 238 239 /** 240 * Update callee-saved register info for the following frame. 241 * Should only be called in non-core builds. 242 */ 243 public static void updateRegisterMap(Frame fr, CodeBlob cb, RegisterMap regMap, boolean debugging) { 244 if (Assert.ASSERTS_ENABLED) { 245 Assert.that(!VM.getVM().isCore(), "non-core builds only"); 246 } 247 248 if (!VM.getVM().isDebugging()) { 249 if (Assert.ASSERTS_ENABLED) { 250 ImmutableOopMapSet maps = cb.getOopMaps(); 251 Assert.that((maps != null) && (maps.getCount() > 0), "found null or empty ImmutableOopMapSet for CodeBlob"); 252 } 253 } else { 254 // Hack for some topmost frames that have been found with empty 255 // OopMapSets. (Actually have not seen the null case, but don't 256 // want to take any chances.) See HSDB.showThreadStackMemory(). 257 ImmutableOopMapSet maps = cb.getOopMaps(); 258 if ((maps == null) || (maps.getCount() == 0)) { 259 return; 260 } 261 } 262 263 // Check if caller must update oop argument 264 regMap.setIncludeArgumentOops(cb.callerMustGCArguments()); 265 266 int nofCallee = 0; 267 Address[] locs = new Address[2 * REG_COUNT + 1]; 268 VMReg[] regs = new VMReg[2 * REG_COUNT + 1]; 269 // ("+1" because REG_COUNT might be zero) 270 271 // Scan through oopmap and find location of all callee-saved registers 272 // (we do not do update in place, since info could be overwritten) 273 ImmutableOopMap map = cb.getOopMapForReturnAddress(fr.getPC(), debugging); 274 if (Assert.ASSERTS_ENABLED) { 275 Assert.that(map != null, "no ptr map found"); 276 } 277 278 OopMapValue omv = null; 279 for (OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); !oms.isDone(); oms.next()) { 280 omv = oms.getCurrent(); 281 if (Assert.ASSERTS_ENABLED) { 282 Assert.that(nofCallee < 2 * REG_COUNT, "overflow"); 283 } 284 regs[nofCallee] = omv.getContentReg(); 285 locs[nofCallee] = fr.oopMapRegToLocation(omv.getReg(), regMap); 286 nofCallee++; 287 } 288 289 // Check that runtime stubs save all callee-saved registers 290 // After adapter frames were deleted C2 doesn't use callee save registers at present 291 if (Assert.ASSERTS_ENABLED) { 292 if (VM.getVM().isServerCompiler()) { 293 Assert.that(!cb.isRuntimeStub() || 294 (nofCallee >= SAVED_ON_ENTRY_REG_COUNT || nofCallee >= C_SAVED_ON_ENTRY_REG_COUNT), 295 "must save all"); 296 } 297 } 298 299 // Copy found callee-saved register to reg_map 300 for (int i = 0; i < nofCallee; i++) { 301 regMap.setLocation(regs[i], locs[i]); 302 } 303 } 304 305 public ImmutableOopMapPair getPairAt(int index) { 306 return pairAt(index); 307 } 308 309 private int getSize() { 310 return (int) sizeField.getValue(addr); 311 } 312 313 public ImmutableOopMap getMap(ImmutableOopMapPair pair) { 314 Assert.that(pair.getOffset() < getSize(), "boundary check: this: " + this + " offset: " + pair); 315 return new ImmutableOopMap(dataStart().addOffsetTo(pair.getOffset())); 316 } 317 318 public String toString() { 319 StringBuilder builder = new StringBuilder(); 320 builder.append("Set{ ") 321 .append("addr = ").append(addr) 322 .append(", count = ").append(getCount()) 323 .append(", size = ").append(getSize()) 324 .append(", pairs = ["); 325 326 for (int i = 0; i < getCount(); ++i) { 327 builder.append(getPairAt(i)); 328 } 329 330 builder.append("]"); 331 return builder.toString(); 332 } 333 }