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 // 26 // The ObjectHeap is an abstraction over all generations in the VM 27 // It gives access to all present objects and classes. 28 // 29 30 package sun.jvm.hotspot.oops; 31 32 import java.util.*; 33 34 import sun.jvm.hotspot.debugger.*; 35 import sun.jvm.hotspot.gc_interface.*; 36 import sun.jvm.hotspot.gc_implementation.parallelScavenge.*; 37 import sun.jvm.hotspot.memory.*; 38 import sun.jvm.hotspot.runtime.*; 39 import sun.jvm.hotspot.types.*; 40 import sun.jvm.hotspot.utilities.*; 41 42 public class ObjectHeap { 43 44 private static final boolean DEBUG; 45 46 static { 47 DEBUG = System.getProperty("sun.jvm.hotspot.oops.ObjectHeap.DEBUG") != null; 48 } 49 50 private OopHandle methodKlassHandle; 51 private OopHandle constMethodKlassHandle; 52 private OopHandle methodDataKlassHandle; 53 private OopHandle constantPoolKlassHandle; 54 private OopHandle constantPoolCacheKlassHandle; 55 private OopHandle klassKlassHandle; 56 private OopHandle instanceKlassKlassHandle; 57 private OopHandle typeArrayKlassKlassHandle; 58 private OopHandle objArrayKlassKlassHandle; 59 private OopHandle boolArrayKlassHandle; 60 private OopHandle byteArrayKlassHandle; 61 private OopHandle charArrayKlassHandle; 62 private OopHandle intArrayKlassHandle; 63 private OopHandle shortArrayKlassHandle; 64 private OopHandle longArrayKlassHandle; 65 private OopHandle singleArrayKlassHandle; 66 private OopHandle doubleArrayKlassHandle; 67 private OopHandle arrayKlassKlassHandle; 68 private OopHandle compiledICHolderKlassHandle; 69 70 private MethodKlass methodKlassObj; 71 private ConstMethodKlass constMethodKlassObj; 72 private MethodDataKlass methodDataKlassObj; 73 private ConstantPoolKlass constantPoolKlassObj; 74 private ConstantPoolCacheKlass constantPoolCacheKlassObj; 75 private KlassKlass klassKlassObj; 76 private InstanceKlassKlass instanceKlassKlassObj; 77 private TypeArrayKlassKlass typeArrayKlassKlassObj; 78 private ObjArrayKlassKlass objArrayKlassKlassObj; 79 private TypeArrayKlass boolArrayKlassObj; 80 private TypeArrayKlass byteArrayKlassObj; 81 private TypeArrayKlass charArrayKlassObj; 82 private TypeArrayKlass intArrayKlassObj; 83 private TypeArrayKlass shortArrayKlassObj; 84 private TypeArrayKlass longArrayKlassObj; 85 private TypeArrayKlass singleArrayKlassObj; 86 private TypeArrayKlass doubleArrayKlassObj; 87 private ArrayKlassKlass arrayKlassKlassObj; 88 private CompiledICHolderKlass compiledICHolderKlassObj; 89 90 public void initialize(TypeDataBase db) throws WrongTypeException { 91 // Lookup the roots in the object hierarchy. 92 Type universeType = db.lookupType("Universe"); 93 94 methodKlassHandle = universeType.getOopField("_methodKlassObj").getValue(); 95 methodKlassObj = new MethodKlass(methodKlassHandle, this); 96 97 constMethodKlassHandle = universeType.getOopField("_constMethodKlassObj").getValue(); 98 constMethodKlassObj = new ConstMethodKlass(constMethodKlassHandle, this); 99 100 constantPoolKlassHandle = universeType.getOopField("_constantPoolKlassObj").getValue(); 101 constantPoolKlassObj = new ConstantPoolKlass(constantPoolKlassHandle, this); 102 103 constantPoolCacheKlassHandle = universeType.getOopField("_constantPoolCacheKlassObj").getValue(); 104 constantPoolCacheKlassObj = new ConstantPoolCacheKlass(constantPoolCacheKlassHandle, this); 105 106 klassKlassHandle = universeType.getOopField("_klassKlassObj").getValue(); 107 klassKlassObj = new KlassKlass(klassKlassHandle, this); 108 109 arrayKlassKlassHandle = universeType.getOopField("_arrayKlassKlassObj").getValue(); 110 arrayKlassKlassObj = new ArrayKlassKlass(arrayKlassKlassHandle, this); 111 112 instanceKlassKlassHandle = universeType.getOopField("_instanceKlassKlassObj").getValue(); 113 instanceKlassKlassObj = new InstanceKlassKlass(instanceKlassKlassHandle, this); 114 115 typeArrayKlassKlassHandle = universeType.getOopField("_typeArrayKlassKlassObj").getValue(); 116 typeArrayKlassKlassObj = new TypeArrayKlassKlass(typeArrayKlassKlassHandle, this); 117 118 objArrayKlassKlassHandle = universeType.getOopField("_objArrayKlassKlassObj").getValue(); 119 objArrayKlassKlassObj = new ObjArrayKlassKlass(objArrayKlassKlassHandle, this); 120 121 boolArrayKlassHandle = universeType.getOopField("_boolArrayKlassObj").getValue(); 122 boolArrayKlassObj = new TypeArrayKlass(boolArrayKlassHandle, this); 123 124 byteArrayKlassHandle = universeType.getOopField("_byteArrayKlassObj").getValue(); 125 byteArrayKlassObj = new TypeArrayKlass(byteArrayKlassHandle, this); 126 127 charArrayKlassHandle = universeType.getOopField("_charArrayKlassObj").getValue(); 128 charArrayKlassObj = new TypeArrayKlass(charArrayKlassHandle, this); 129 130 intArrayKlassHandle = universeType.getOopField("_intArrayKlassObj").getValue(); 131 intArrayKlassObj = new TypeArrayKlass(intArrayKlassHandle, this); 132 133 shortArrayKlassHandle = universeType.getOopField("_shortArrayKlassObj").getValue(); 134 shortArrayKlassObj = new TypeArrayKlass(shortArrayKlassHandle, this); 135 136 longArrayKlassHandle = universeType.getOopField("_longArrayKlassObj").getValue(); 137 longArrayKlassObj = new TypeArrayKlass(longArrayKlassHandle, this); 138 139 singleArrayKlassHandle = universeType.getOopField("_singleArrayKlassObj").getValue(); 140 singleArrayKlassObj = new TypeArrayKlass(singleArrayKlassHandle, this); 141 142 doubleArrayKlassHandle = universeType.getOopField("_doubleArrayKlassObj").getValue(); 143 doubleArrayKlassObj = new TypeArrayKlass(doubleArrayKlassHandle, this); 144 145 if (!VM.getVM().isCore()) { 146 methodDataKlassHandle = universeType.getOopField("_methodDataKlassObj").getValue(); 147 methodDataKlassObj = new MethodDataKlass(methodDataKlassHandle, this); 148 149 compiledICHolderKlassHandle = universeType.getOopField("_compiledICHolderKlassObj").getValue(); 150 compiledICHolderKlassObj= new CompiledICHolderKlass(compiledICHolderKlassHandle ,this); 151 } 152 } 153 154 public ObjectHeap(TypeDataBase db) throws WrongTypeException { 155 // Get commonly used sizes of basic types 156 oopSize = VM.getVM().getOopSize(); 157 byteSize = db.getJByteType().getSize(); 158 charSize = db.getJCharType().getSize(); 159 booleanSize = db.getJBooleanType().getSize(); 160 intSize = db.getJIntType().getSize(); 161 shortSize = db.getJShortType().getSize(); 162 longSize = db.getJLongType().getSize(); 163 floatSize = db.getJFloatType().getSize(); 164 doubleSize = db.getJDoubleType().getSize(); 165 166 initialize(db); 167 } 168 169 /** Comparison operation for oops, either or both of which may be null */ 170 public boolean equal(Oop o1, Oop o2) { 171 if (o1 != null) return o1.equals(o2); 172 return (o2 == null); 173 } 174 175 // Cached sizes of basic types 176 private long oopSize; 177 private long byteSize; 178 private long charSize; 179 private long booleanSize; 180 private long intSize; 181 private long shortSize; 182 private long longSize; 183 private long floatSize; 184 private long doubleSize; 185 186 public long getOopSize() { return oopSize; } 187 public long getByteSize() { return byteSize; } 188 public long getCharSize() { return charSize; } 189 public long getBooleanSize() { return booleanSize; } 190 public long getIntSize() { return intSize; } 191 public long getShortSize() { return shortSize; } 192 public long getLongSize() { return longSize; } 193 public long getFloatSize() { return floatSize; } 194 public long getDoubleSize() { return doubleSize; } 195 196 // Accessors for well-known system classes (from Universe) 197 public MethodKlass getMethodKlassObj() { return methodKlassObj; } 198 public ConstMethodKlass getConstMethodKlassObj() { return constMethodKlassObj; } 199 public MethodDataKlass getMethodDataKlassObj() { return methodDataKlassObj; } 200 public ConstantPoolKlass getConstantPoolKlassObj() { return constantPoolKlassObj; } 201 public ConstantPoolCacheKlass getConstantPoolCacheKlassObj() { return constantPoolCacheKlassObj; } 202 public KlassKlass getKlassKlassObj() { return klassKlassObj; } 203 public ArrayKlassKlass getArrayKlassKlassObj() { return arrayKlassKlassObj; } 204 public InstanceKlassKlass getInstanceKlassKlassObj() { return instanceKlassKlassObj; } 205 public ObjArrayKlassKlass getObjArrayKlassKlassObj() { return objArrayKlassKlassObj; } 206 public TypeArrayKlassKlass getTypeArrayKlassKlassObj() { return typeArrayKlassKlassObj; } 207 public TypeArrayKlass getBoolArrayKlassObj() { return boolArrayKlassObj; } 208 public TypeArrayKlass getByteArrayKlassObj() { return byteArrayKlassObj; } 209 public TypeArrayKlass getCharArrayKlassObj() { return charArrayKlassObj; } 210 public TypeArrayKlass getIntArrayKlassObj() { return intArrayKlassObj; } 211 public TypeArrayKlass getShortArrayKlassObj() { return shortArrayKlassObj; } 212 public TypeArrayKlass getLongArrayKlassObj() { return longArrayKlassObj; } 213 public TypeArrayKlass getSingleArrayKlassObj() { return singleArrayKlassObj; } 214 public TypeArrayKlass getDoubleArrayKlassObj() { return doubleArrayKlassObj; } 215 public CompiledICHolderKlass getCompiledICHolderKlassObj() { 216 if (Assert.ASSERTS_ENABLED) { 217 Assert.that(!VM.getVM().isCore(), "must not be called for core build"); 218 } 219 return compiledICHolderKlassObj; 220 } 221 222 /** Takes a BasicType and returns the corresponding primitive array 223 klass */ 224 public Klass typeArrayKlassObj(int t) { 225 if (t == BasicType.getTBoolean()) return getBoolArrayKlassObj(); 226 if (t == BasicType.getTChar()) return getCharArrayKlassObj(); 227 if (t == BasicType.getTFloat()) return getSingleArrayKlassObj(); 228 if (t == BasicType.getTDouble()) return getDoubleArrayKlassObj(); 229 if (t == BasicType.getTByte()) return getByteArrayKlassObj(); 230 if (t == BasicType.getTShort()) return getShortArrayKlassObj(); 231 if (t == BasicType.getTInt()) return getIntArrayKlassObj(); 232 if (t == BasicType.getTLong()) return getLongArrayKlassObj(); 233 throw new RuntimeException("Illegal basic type " + t); 234 } 235 236 /** an interface to filter objects while walking heap */ 237 public static interface ObjectFilter { 238 public boolean canInclude(Oop obj); 239 } 240 241 /** The base heap iteration mechanism */ 242 public void iterate(HeapVisitor visitor) { 243 iterateLiveRegions(collectLiveRegions(), visitor, null); 244 } 245 246 /** iterate objects satisfying a specified ObjectFilter */ 247 public void iterate(HeapVisitor visitor, ObjectFilter of) { 248 iterateLiveRegions(collectLiveRegions(), visitor, of); 249 } 250 251 /** iterate objects of given Klass. param 'includeSubtypes' tells whether to 252 * include objects of subtypes or not */ 253 public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k, boolean includeSubtypes) { 254 if (includeSubtypes) { 255 if (k.isFinal()) { 256 // do the simpler "exact" klass loop 257 iterateExact(visitor, k); 258 } else { 259 iterateSubtypes(visitor, k); 260 } 261 } else { 262 // there can no object of abstract classes and interfaces 263 if (!k.isAbstract() && !k.isInterface()) { 264 iterateExact(visitor, k); 265 } 266 } 267 } 268 269 /** iterate objects of given Klass (objects of subtypes included) */ 270 public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k) { 271 iterateObjectsOfKlass(visitor, k, true); 272 } 273 274 /** This routine can be used to iterate through the heap at an 275 extremely low level (stepping word-by-word) to provide the 276 ability to do very low-level debugging */ 277 public void iterateRaw(RawHeapVisitor visitor) { 278 List liveRegions = collectLiveRegions(); 279 280 // Summarize size 281 long totalSize = 0; 282 for (int i = 0; i < liveRegions.size(); i += 2) { 283 Address bottom = (Address) liveRegions.get(i); 284 Address top = (Address) liveRegions.get(i+1); 285 totalSize += top.minus(bottom); 286 } 287 visitor.prologue(totalSize); 288 289 for (int i = 0; i < liveRegions.size(); i += 2) { 290 Address bottom = (Address) liveRegions.get(i); 291 Address top = (Address) liveRegions.get(i+1); 292 293 // Traverses the space from bottom to top 294 while (bottom.lessThan(top)) { 295 visitor.visitAddress(bottom); 296 bottom = bottom.addOffsetTo(VM.getVM().getAddressSize()); 297 } 298 } 299 300 visitor.epilogue(); 301 } 302 303 // Iterates through only the perm generation for the purpose of 304 // finding static fields for liveness analysis 305 public void iteratePerm(HeapVisitor visitor) { 306 CollectedHeap heap = VM.getVM().getUniverse().heap(); 307 List liveRegions = new ArrayList(); 308 addPermGenLiveRegions(liveRegions, heap); 309 sortLiveRegions(liveRegions); 310 iterateLiveRegions(liveRegions, visitor, null); 311 } 312 313 public boolean isValidMethod(OopHandle handle) { 314 OopHandle klass = Oop.getKlassForOopHandle(handle); 315 if (klass != null && klass.equals(methodKlassHandle)) { 316 return true; 317 } 318 return false; 319 } 320 321 // Creates an instance from the Oop hierarchy based based on the handle 322 public Oop newOop(OopHandle handle) { 323 // The only known way to detect the right type of an oop is 324 // traversing the class chain until a well-known klass is recognized. 325 // A more direct solution would require the klasses to expose 326 // the C++ vtbl structure. 327 328 // Handle the null reference 329 if (handle == null) return null; 330 331 // First check if handle is one of the root objects 332 if (handle.equals(methodKlassHandle)) return getMethodKlassObj(); 333 if (handle.equals(constMethodKlassHandle)) return getConstMethodKlassObj(); 334 if (handle.equals(constantPoolKlassHandle)) return getConstantPoolKlassObj(); 335 if (handle.equals(constantPoolCacheKlassHandle)) return getConstantPoolCacheKlassObj(); 336 if (handle.equals(instanceKlassKlassHandle)) return getInstanceKlassKlassObj(); 337 if (handle.equals(objArrayKlassKlassHandle)) return getObjArrayKlassKlassObj(); 338 if (handle.equals(klassKlassHandle)) return getKlassKlassObj(); 339 if (handle.equals(arrayKlassKlassHandle)) return getArrayKlassKlassObj(); 340 if (handle.equals(typeArrayKlassKlassHandle)) return getTypeArrayKlassKlassObj(); 341 if (handle.equals(boolArrayKlassHandle)) return getBoolArrayKlassObj(); 342 if (handle.equals(byteArrayKlassHandle)) return getByteArrayKlassObj(); 343 if (handle.equals(charArrayKlassHandle)) return getCharArrayKlassObj(); 344 if (handle.equals(intArrayKlassHandle)) return getIntArrayKlassObj(); 345 if (handle.equals(shortArrayKlassHandle)) return getShortArrayKlassObj(); 346 if (handle.equals(longArrayKlassHandle)) return getLongArrayKlassObj(); 347 if (handle.equals(singleArrayKlassHandle)) return getSingleArrayKlassObj(); 348 if (handle.equals(doubleArrayKlassHandle)) return getDoubleArrayKlassObj(); 349 if (!VM.getVM().isCore()) { 350 if (handle.equals(compiledICHolderKlassHandle)) return getCompiledICHolderKlassObj(); 351 if (handle.equals(methodDataKlassHandle)) return getMethodDataKlassObj(); 352 } 353 354 // Then check if obj.klass() is one of the root objects 355 OopHandle klass = Oop.getKlassForOopHandle(handle); 356 if (klass != null) { 357 if (klass.equals(methodKlassHandle)) return new Method(handle, this); 358 if (klass.equals(constMethodKlassHandle)) return new ConstMethod(handle, this); 359 if (klass.equals(constantPoolKlassHandle)) return new ConstantPool(handle, this); 360 if (klass.equals(constantPoolCacheKlassHandle)) return new ConstantPoolCache(handle, this); 361 if (!VM.getVM().isCore()) { 362 if (klass.equals(compiledICHolderKlassHandle)) return new CompiledICHolder(handle, this); 363 if (klass.equals(methodDataKlassHandle)) return new MethodData(handle, this); 364 } 365 if (klass.equals(instanceKlassKlassHandle)) return new InstanceKlass(handle, this); 366 if (klass.equals(objArrayKlassKlassHandle)) return new ObjArrayKlass(handle, this); 367 if (klass.equals(typeArrayKlassKlassHandle)) return new TypeArrayKlass(handle, this); 368 369 // Lastly check if obj.klass().klass() is on of the root objects 370 OopHandle klassKlass = Oop.getKlassForOopHandle(klass); 371 if (klassKlass != null) { 372 if (klassKlass.equals(instanceKlassKlassHandle)) return new Instance(handle, this); 373 if (klassKlass.equals(objArrayKlassKlassHandle)) return new ObjArray(handle, this); 374 if (klassKlass.equals(typeArrayKlassKlassHandle)) return new TypeArray(handle, this); 375 } 376 } 377 378 if (DEBUG) { 379 System.err.println("Unknown oop at " + handle); 380 System.err.println("Oop's klass is " + klass); 381 } 382 383 throw new UnknownOopException(); 384 } 385 386 // Print all objects in the object heap 387 public void print() { 388 HeapPrinter printer = new HeapPrinter(System.out); 389 iterate(printer); 390 } 391 392 //--------------------------------------------------------------------------- 393 // Internals only below this point 394 // 395 396 private void iterateExact(HeapVisitor visitor, final Klass k) { 397 iterateLiveRegions(collectLiveRegions(), visitor, new ObjectFilter() { 398 public boolean canInclude(Oop obj) { 399 Klass tk = obj.getKlass(); 400 // null Klass is seen sometimes! 401 return (tk != null && tk.equals(k)); 402 } 403 }); 404 } 405 406 private void iterateSubtypes(HeapVisitor visitor, final Klass k) { 407 iterateLiveRegions(collectLiveRegions(), visitor, new ObjectFilter() { 408 public boolean canInclude(Oop obj) { 409 Klass tk = obj.getKlass(); 410 // null Klass is seen sometimes! 411 return (tk != null && tk.isSubtypeOf(k)); 412 } 413 }); 414 } 415 416 private void iterateLiveRegions(List liveRegions, HeapVisitor visitor, ObjectFilter of) { 417 // Summarize size 418 long totalSize = 0; 419 for (int i = 0; i < liveRegions.size(); i += 2) { 420 Address bottom = (Address) liveRegions.get(i); 421 Address top = (Address) liveRegions.get(i+1); 422 totalSize += top.minus(bottom); 423 } 424 visitor.prologue(totalSize); 425 426 CompactibleFreeListSpace cmsSpaceOld = null; 427 CompactibleFreeListSpace cmsSpacePerm = null; 428 CollectedHeap heap = VM.getVM().getUniverse().heap(); 429 430 if (heap instanceof GenCollectedHeap) { 431 GenCollectedHeap genHeap = (GenCollectedHeap) heap; 432 Generation genOld = genHeap.getGen(1); 433 Generation genPerm = genHeap.permGen(); 434 if (genOld instanceof ConcurrentMarkSweepGeneration) { 435 ConcurrentMarkSweepGeneration concGen = (ConcurrentMarkSweepGeneration)genOld; 436 cmsSpaceOld = concGen.cmsSpace(); 437 } 438 if (genPerm instanceof ConcurrentMarkSweepGeneration) { 439 ConcurrentMarkSweepGeneration concGen = (ConcurrentMarkSweepGeneration)genPerm; 440 cmsSpacePerm = concGen.cmsSpace(); 441 } 442 } 443 444 for (int i = 0; i < liveRegions.size(); i += 2) { 445 Address bottom = (Address) liveRegions.get(i); 446 Address top = (Address) liveRegions.get(i+1); 447 448 try { 449 // Traverses the space from bottom to top 450 OopHandle handle = bottom.addOffsetToAsOopHandle(0); 451 452 while (handle.lessThan(top)) { 453 Oop obj = null; 454 455 try { 456 obj = newOop(handle); 457 } catch (UnknownOopException exp) { 458 if (DEBUG) { 459 throw new RuntimeException(" UnknownOopException " + exp); 460 } 461 } 462 if (obj == null) { 463 //Find the object size using Printezis bits and skip over 464 System.err.println("Finding object size using Printezis bits and skipping over..."); 465 long size = 0; 466 467 if ( (cmsSpaceOld != null) && cmsSpaceOld.contains(handle) ){ 468 size = cmsSpaceOld.collector().blockSizeUsingPrintezisBits(handle); 469 } else if ((cmsSpacePerm != null) && cmsSpacePerm.contains(handle) ){ 470 size = cmsSpacePerm.collector().blockSizeUsingPrintezisBits(handle); 471 } 472 473 if (size <= 0) { 474 //Either Printezis bits not set or handle is not in cms space. 475 throw new UnknownOopException(); 476 } 477 478 handle = handle.addOffsetToAsOopHandle(CompactibleFreeListSpace.adjustObjectSizeInBytes(size)); 479 continue; 480 } 481 if (of == null || of.canInclude(obj)) { 482 if (visitor.doObj(obj)) { 483 // doObj() returns true to abort this loop. 484 break; 485 } 486 } 487 if ( (cmsSpaceOld != null) && cmsSpaceOld.contains(handle) || 488 (cmsSpacePerm != null) && cmsSpacePerm.contains(handle) ) { 489 handle = handle.addOffsetToAsOopHandle(CompactibleFreeListSpace.adjustObjectSizeInBytes(obj.getObjectSize()) ); 490 } else { 491 handle = handle.addOffsetToAsOopHandle(obj.getObjectSize()); 492 } 493 } 494 } 495 catch (AddressException e) { 496 // This is okay at the top of these regions 497 } 498 catch (UnknownOopException e) { 499 // This is okay at the top of these regions 500 } 501 } 502 503 visitor.epilogue(); 504 } 505 506 private void addPermGenLiveRegions(List output, CollectedHeap heap) { 507 LiveRegionsCollector lrc = new LiveRegionsCollector(output); 508 if (heap instanceof GenCollectedHeap) { 509 GenCollectedHeap genHeap = (GenCollectedHeap) heap; 510 Generation gen = genHeap.permGen(); 511 gen.spaceIterate(lrc, true); 512 } else if (heap instanceof ParallelScavengeHeap) { 513 ParallelScavengeHeap psh = (ParallelScavengeHeap) heap; 514 PSPermGen permGen = psh.permGen(); 515 addLiveRegions(permGen.objectSpace().getLiveRegions(), output); 516 } else { 517 if (Assert.ASSERTS_ENABLED) { 518 Assert.that(false, "Expecting GenCollectedHeap or ParallelScavengeHeap, but got " + 519 heap.getClass().getName()); 520 } 521 } 522 } 523 524 private void addLiveRegions(List input, List output) { 525 for (Iterator itr = input.iterator(); itr.hasNext();) { 526 MemRegion reg = (MemRegion) itr.next(); 527 Address top = reg.end(); 528 Address bottom = reg.start(); 529 if (Assert.ASSERTS_ENABLED) { 530 Assert.that(top != null, "top address in a live region should not be null"); 531 } 532 if (Assert.ASSERTS_ENABLED) { 533 Assert.that(bottom != null, "bottom address in a live region should not be null"); 534 } 535 output.add(top); 536 output.add(bottom); 537 } 538 } 539 540 private class LiveRegionsCollector implements SpaceClosure { 541 LiveRegionsCollector(List l) { 542 liveRegions = l; 543 } 544 545 public void doSpace(Space s) { 546 addLiveRegions(s.getLiveRegions(), liveRegions); 547 } 548 private List liveRegions; 549 } 550 551 // Returns a List<Address> where the addresses come in pairs. These 552 // designate the live regions of the heap. 553 private List collectLiveRegions() { 554 // We want to iterate through all live portions of the heap, but 555 // do not want to abort the heap traversal prematurely if we find 556 // a problem (like an allocated but uninitialized object at the 557 // top of a generation). To do this we enumerate all generations' 558 // bottom and top regions, and factor in TLABs if necessary. 559 560 // List<Address>. Addresses come in pairs. 561 List liveRegions = new ArrayList(); 562 LiveRegionsCollector lrc = new LiveRegionsCollector(liveRegions); 563 564 CollectedHeap heap = VM.getVM().getUniverse().heap(); 565 566 if (heap instanceof GenCollectedHeap) { 567 GenCollectedHeap genHeap = (GenCollectedHeap) heap; 568 // Run through all generations, obtaining bottom-top pairs. 569 for (int i = 0; i < genHeap.nGens(); i++) { 570 Generation gen = genHeap.getGen(i); 571 gen.spaceIterate(lrc, true); 572 } 573 } else if (heap instanceof ParallelScavengeHeap) { 574 ParallelScavengeHeap psh = (ParallelScavengeHeap) heap; 575 PSYoungGen youngGen = psh.youngGen(); 576 // Add eden space 577 addLiveRegions(youngGen.edenSpace().getLiveRegions(), liveRegions); 578 // Add from-space but not to-space 579 addLiveRegions(youngGen.fromSpace().getLiveRegions(), liveRegions); 580 PSOldGen oldGen = psh.oldGen(); 581 addLiveRegions(oldGen.objectSpace().getLiveRegions(), liveRegions); 582 } else { 583 if (Assert.ASSERTS_ENABLED) { 584 Assert.that(false, "Expecting GenCollectedHeap or ParallelScavengeHeap, but got " + 585 heap.getClass().getName()); 586 } 587 } 588 589 // handle perm generation 590 addPermGenLiveRegions(liveRegions, heap); 591 592 // If UseTLAB is enabled, snip out regions associated with TLABs' 593 // dead regions. Note that TLABs can be present in any generation. 594 595 // FIXME: consider adding fewer boundaries to live region list. 596 // Theoretically only need to stop at TLAB's top and resume at its 597 // end. 598 599 if (VM.getVM().getUseTLAB()) { 600 for (JavaThread thread = VM.getVM().getThreads().first(); thread != null; thread = thread.next()) { 601 if (thread.isJavaThread()) { 602 ThreadLocalAllocBuffer tlab = thread.tlab(); 603 if (tlab.start() != null) { 604 if ((tlab.top() == null) || (tlab.end() == null)) { 605 System.err.print("Warning: skipping invalid TLAB for thread "); 606 thread.printThreadIDOn(System.err); 607 System.err.println(); 608 } else { 609 // Go from: 610 // - below start() to start() 611 // - start() to top() 612 // - end() and above 613 liveRegions.add(tlab.start()); 614 liveRegions.add(tlab.start()); 615 liveRegions.add(tlab.top()); 616 liveRegions.add(tlab.end()); 617 } 618 } 619 } 620 } 621 } 622 623 // Now sort live regions 624 sortLiveRegions(liveRegions); 625 626 if (Assert.ASSERTS_ENABLED) { 627 Assert.that(liveRegions.size() % 2 == 0, "Must have even number of region boundaries"); 628 } 629 630 return liveRegions; 631 } 632 633 private void sortLiveRegions(List liveRegions) { 634 Collections.sort(liveRegions, new Comparator() { 635 public int compare(Object o1, Object o2) { 636 Address a1 = (Address) o1; 637 Address a2 = (Address) o2; 638 if (AddressOps.lt(a1, a2)) { 639 return -1; 640 } else if (AddressOps.gt(a1, a2)) { 641 return 1; 642 } 643 return 0; 644 } 645 }); 646 } 647 }