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