Mercurial > hg > truffle
diff agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | ba764ed4b6f2 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,635 @@ +/* + * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +// +// The ObjectHeap is an abstraction over all generations in the VM +// It gives access to all present objects and classes. +// + +package sun.jvm.hotspot.oops; + +import java.util.*; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.gc_interface.*; +import sun.jvm.hotspot.gc_implementation.parallelScavenge.*; +import sun.jvm.hotspot.memory.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; + +public class ObjectHeap { + + private OopHandle symbolKlassHandle; + private OopHandle methodKlassHandle; + private OopHandle constMethodKlassHandle; + private OopHandle methodDataKlassHandle; + private OopHandle constantPoolKlassHandle; + private OopHandle constantPoolCacheKlassHandle; + private OopHandle klassKlassHandle; + private OopHandle instanceKlassKlassHandle; + private OopHandle typeArrayKlassKlassHandle; + private OopHandle objArrayKlassKlassHandle; + private OopHandle boolArrayKlassHandle; + private OopHandle byteArrayKlassHandle; + private OopHandle charArrayKlassHandle; + private OopHandle intArrayKlassHandle; + private OopHandle shortArrayKlassHandle; + private OopHandle longArrayKlassHandle; + private OopHandle singleArrayKlassHandle; + private OopHandle doubleArrayKlassHandle; + private OopHandle arrayKlassKlassHandle; + private OopHandle compiledICHolderKlassHandle; + + private SymbolKlass symbolKlassObj; + private MethodKlass methodKlassObj; + private ConstMethodKlass constMethodKlassObj; + private MethodDataKlass methodDataKlassObj; + private ConstantPoolKlass constantPoolKlassObj; + private ConstantPoolCacheKlass constantPoolCacheKlassObj; + private KlassKlass klassKlassObj; + private InstanceKlassKlass instanceKlassKlassObj; + private TypeArrayKlassKlass typeArrayKlassKlassObj; + private ObjArrayKlassKlass objArrayKlassKlassObj; + private TypeArrayKlass boolArrayKlassObj; + private TypeArrayKlass byteArrayKlassObj; + private TypeArrayKlass charArrayKlassObj; + private TypeArrayKlass intArrayKlassObj; + private TypeArrayKlass shortArrayKlassObj; + private TypeArrayKlass longArrayKlassObj; + private TypeArrayKlass singleArrayKlassObj; + private TypeArrayKlass doubleArrayKlassObj; + private ArrayKlassKlass arrayKlassKlassObj; + private CompiledICHolderKlass compiledICHolderKlassObj; + + public void initialize(TypeDataBase db) throws WrongTypeException { + // Lookup the roots in the object hierarchy. + Type universeType = db.lookupType("Universe"); + + symbolKlassHandle = universeType.getOopField("_symbolKlassObj").getValue(); + symbolKlassObj = new SymbolKlass(symbolKlassHandle, this); + + methodKlassHandle = universeType.getOopField("_methodKlassObj").getValue(); + methodKlassObj = new MethodKlass(methodKlassHandle, this); + + constMethodKlassHandle = universeType.getOopField("_constMethodKlassObj").getValue(); + constMethodKlassObj = new ConstMethodKlass(constMethodKlassHandle, this); + + constantPoolKlassHandle = universeType.getOopField("_constantPoolKlassObj").getValue(); + constantPoolKlassObj = new ConstantPoolKlass(constantPoolKlassHandle, this); + + constantPoolCacheKlassHandle = universeType.getOopField("_constantPoolCacheKlassObj").getValue(); + constantPoolCacheKlassObj = new ConstantPoolCacheKlass(constantPoolCacheKlassHandle, this); + + klassKlassHandle = universeType.getOopField("_klassKlassObj").getValue(); + klassKlassObj = new KlassKlass(klassKlassHandle, this); + + arrayKlassKlassHandle = universeType.getOopField("_arrayKlassKlassObj").getValue(); + arrayKlassKlassObj = new ArrayKlassKlass(arrayKlassKlassHandle, this); + + instanceKlassKlassHandle = universeType.getOopField("_instanceKlassKlassObj").getValue(); + instanceKlassKlassObj = new InstanceKlassKlass(instanceKlassKlassHandle, this); + + typeArrayKlassKlassHandle = universeType.getOopField("_typeArrayKlassKlassObj").getValue(); + typeArrayKlassKlassObj = new TypeArrayKlassKlass(typeArrayKlassKlassHandle, this); + + objArrayKlassKlassHandle = universeType.getOopField("_objArrayKlassKlassObj").getValue(); + objArrayKlassKlassObj = new ObjArrayKlassKlass(objArrayKlassKlassHandle, this); + + boolArrayKlassHandle = universeType.getOopField("_boolArrayKlassObj").getValue(); + boolArrayKlassObj = new TypeArrayKlass(boolArrayKlassHandle, this); + + byteArrayKlassHandle = universeType.getOopField("_byteArrayKlassObj").getValue(); + byteArrayKlassObj = new TypeArrayKlass(byteArrayKlassHandle, this); + + charArrayKlassHandle = universeType.getOopField("_charArrayKlassObj").getValue(); + charArrayKlassObj = new TypeArrayKlass(charArrayKlassHandle, this); + + intArrayKlassHandle = universeType.getOopField("_intArrayKlassObj").getValue(); + intArrayKlassObj = new TypeArrayKlass(intArrayKlassHandle, this); + + shortArrayKlassHandle = universeType.getOopField("_shortArrayKlassObj").getValue(); + shortArrayKlassObj = new TypeArrayKlass(shortArrayKlassHandle, this); + + longArrayKlassHandle = universeType.getOopField("_longArrayKlassObj").getValue(); + longArrayKlassObj = new TypeArrayKlass(longArrayKlassHandle, this); + + singleArrayKlassHandle = universeType.getOopField("_singleArrayKlassObj").getValue(); + singleArrayKlassObj = new TypeArrayKlass(singleArrayKlassHandle, this); + + doubleArrayKlassHandle = universeType.getOopField("_doubleArrayKlassObj").getValue(); + doubleArrayKlassObj = new TypeArrayKlass(doubleArrayKlassHandle, this); + + if (!VM.getVM().isCore()) { + methodDataKlassHandle = universeType.getOopField("_methodDataKlassObj").getValue(); + methodDataKlassObj = new MethodDataKlass(methodDataKlassHandle, this); + + compiledICHolderKlassHandle = universeType.getOopField("_compiledICHolderKlassObj").getValue(); + compiledICHolderKlassObj= new CompiledICHolderKlass(compiledICHolderKlassHandle ,this); + } + } + + public ObjectHeap(TypeDataBase db) throws WrongTypeException { + // Get commonly used sizes of basic types + oopSize = db.getOopSize(); + byteSize = db.getJByteType().getSize(); + charSize = db.getJCharType().getSize(); + booleanSize = db.getJBooleanType().getSize(); + intSize = db.getJIntType().getSize(); + shortSize = db.getJShortType().getSize(); + longSize = db.getJLongType().getSize(); + floatSize = db.getJFloatType().getSize(); + doubleSize = db.getJDoubleType().getSize(); + + initialize(db); + } + + /** Comparison operation for oops, either or both of which may be null */ + public boolean equal(Oop o1, Oop o2) { + if (o1 != null) return o1.equals(o2); + return (o2 == null); + } + + // Cached sizes of basic types + private long oopSize; + private long byteSize; + private long charSize; + private long booleanSize; + private long intSize; + private long shortSize; + private long longSize; + private long floatSize; + private long doubleSize; + + public long getOopSize() { return oopSize; } + public long getByteSize() { return byteSize; } + public long getCharSize() { return charSize; } + public long getBooleanSize() { return booleanSize; } + public long getIntSize() { return intSize; } + public long getShortSize() { return shortSize; } + public long getLongSize() { return longSize; } + public long getFloatSize() { return floatSize; } + public long getDoubleSize() { return doubleSize; } + + // Accessors for well-known system classes (from Universe) + public SymbolKlass getSymbolKlassObj() { return symbolKlassObj; } + public MethodKlass getMethodKlassObj() { return methodKlassObj; } + public ConstMethodKlass getConstMethodKlassObj() { return constMethodKlassObj; } + public MethodDataKlass getMethodDataKlassObj() { return methodDataKlassObj; } + public ConstantPoolKlass getConstantPoolKlassObj() { return constantPoolKlassObj; } + public ConstantPoolCacheKlass getConstantPoolCacheKlassObj() { return constantPoolCacheKlassObj; } + public KlassKlass getKlassKlassObj() { return klassKlassObj; } + public ArrayKlassKlass getArrayKlassKlassObj() { return arrayKlassKlassObj; } + public InstanceKlassKlass getInstanceKlassKlassObj() { return instanceKlassKlassObj; } + public ObjArrayKlassKlass getObjArrayKlassKlassObj() { return objArrayKlassKlassObj; } + public TypeArrayKlassKlass getTypeArrayKlassKlassObj() { return typeArrayKlassKlassObj; } + public TypeArrayKlass getBoolArrayKlassObj() { return boolArrayKlassObj; } + public TypeArrayKlass getByteArrayKlassObj() { return byteArrayKlassObj; } + public TypeArrayKlass getCharArrayKlassObj() { return charArrayKlassObj; } + public TypeArrayKlass getIntArrayKlassObj() { return intArrayKlassObj; } + public TypeArrayKlass getShortArrayKlassObj() { return shortArrayKlassObj; } + public TypeArrayKlass getLongArrayKlassObj() { return longArrayKlassObj; } + public TypeArrayKlass getSingleArrayKlassObj() { return singleArrayKlassObj; } + public TypeArrayKlass getDoubleArrayKlassObj() { return doubleArrayKlassObj; } + public CompiledICHolderKlass getCompiledICHolderKlassObj() { + if (Assert.ASSERTS_ENABLED) { + Assert.that(!VM.getVM().isCore(), "must not be called for core build"); + } + return compiledICHolderKlassObj; + } + + /** Takes a BasicType and returns the corresponding primitive array + klass */ + public Klass typeArrayKlassObj(int t) { + if (t == BasicType.getTBoolean()) return getBoolArrayKlassObj(); + if (t == BasicType.getTChar()) return getCharArrayKlassObj(); + if (t == BasicType.getTFloat()) return getSingleArrayKlassObj(); + if (t == BasicType.getTDouble()) return getDoubleArrayKlassObj(); + if (t == BasicType.getTByte()) return getByteArrayKlassObj(); + if (t == BasicType.getTShort()) return getShortArrayKlassObj(); + if (t == BasicType.getTInt()) return getIntArrayKlassObj(); + if (t == BasicType.getTLong()) return getLongArrayKlassObj(); + throw new RuntimeException("Illegal basic type " + t); + } + + /** an interface to filter objects while walking heap */ + public static interface ObjectFilter { + public boolean canInclude(Oop obj); + } + + /** The base heap iteration mechanism */ + public void iterate(HeapVisitor visitor) { + iterateLiveRegions(collectLiveRegions(), visitor, null); + } + + /** iterate objects satisfying a specified ObjectFilter */ + public void iterate(HeapVisitor visitor, ObjectFilter of) { + iterateLiveRegions(collectLiveRegions(), visitor, of); + } + + /** iterate objects of given Klass. param 'includeSubtypes' tells whether to + * include objects of subtypes or not */ + public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k, boolean includeSubtypes) { + if (includeSubtypes) { + if (k.isFinal()) { + // do the simpler "exact" klass loop + iterateExact(visitor, k); + } else { + iterateSubtypes(visitor, k); + } + } else { + // there can no object of abstract classes and interfaces + if (!k.isAbstract() && !k.isInterface()) { + iterateExact(visitor, k); + } + } + } + + /** iterate objects of given Klass (objects of subtypes included) */ + public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k) { + iterateObjectsOfKlass(visitor, k, true); + } + + /** This routine can be used to iterate through the heap at an + extremely low level (stepping word-by-word) to provide the + ability to do very low-level debugging */ + public void iterateRaw(RawHeapVisitor visitor) { + List liveRegions = collectLiveRegions(); + + // Summarize size + long totalSize = 0; + for (int i = 0; i < liveRegions.size(); i += 2) { + Address bottom = (Address) liveRegions.get(i); + Address top = (Address) liveRegions.get(i+1); + totalSize += top.minus(bottom); + } + visitor.prologue(totalSize); + + for (int i = 0; i < liveRegions.size(); i += 2) { + Address bottom = (Address) liveRegions.get(i); + Address top = (Address) liveRegions.get(i+1); + + // Traverses the space from bottom to top + while (bottom.lessThan(top)) { + visitor.visitAddress(bottom); + bottom = bottom.addOffsetTo(VM.getVM().getAddressSize()); + } + } + + visitor.epilogue(); + } + + // Iterates through only the perm generation for the purpose of + // finding static fields for liveness analysis + public void iteratePerm(HeapVisitor visitor) { + CollectedHeap heap = VM.getVM().getUniverse().heap(); + List liveRegions = new ArrayList(); + addPermGenLiveRegions(liveRegions, heap); + sortLiveRegions(liveRegions); + iterateLiveRegions(liveRegions, visitor, null); + } + + // Creates an instance from the Oop hierarchy based based on the handle + public Oop newOop(OopHandle handle) { + // The only known way to detect the right type of an oop is + // traversing the class chain until a well-known klass is recognized. + // A more direct solution would require the klasses to expose + // the C++ vtbl structure. + + // Handle the null reference + if (handle == null) return null; + + // First check if handle is one of the root objects + if (handle.equals(methodKlassHandle)) return getMethodKlassObj(); + if (handle.equals(constMethodKlassHandle)) return getConstMethodKlassObj(); + if (handle.equals(symbolKlassHandle)) return getSymbolKlassObj(); + if (handle.equals(constantPoolKlassHandle)) return getConstantPoolKlassObj(); + if (handle.equals(constantPoolCacheKlassHandle)) return getConstantPoolCacheKlassObj(); + if (handle.equals(instanceKlassKlassHandle)) return getInstanceKlassKlassObj(); + if (handle.equals(objArrayKlassKlassHandle)) return getObjArrayKlassKlassObj(); + if (handle.equals(klassKlassHandle)) return getKlassKlassObj(); + if (handle.equals(arrayKlassKlassHandle)) return getArrayKlassKlassObj(); + if (handle.equals(typeArrayKlassKlassHandle)) return getTypeArrayKlassKlassObj(); + if (handle.equals(boolArrayKlassHandle)) return getBoolArrayKlassObj(); + if (handle.equals(byteArrayKlassHandle)) return getByteArrayKlassObj(); + if (handle.equals(charArrayKlassHandle)) return getCharArrayKlassObj(); + if (handle.equals(intArrayKlassHandle)) return getIntArrayKlassObj(); + if (handle.equals(shortArrayKlassHandle)) return getShortArrayKlassObj(); + if (handle.equals(longArrayKlassHandle)) return getLongArrayKlassObj(); + if (handle.equals(singleArrayKlassHandle)) return getSingleArrayKlassObj(); + if (handle.equals(doubleArrayKlassHandle)) return getDoubleArrayKlassObj(); + if (!VM.getVM().isCore()) { + if (handle.equals(compiledICHolderKlassHandle)) return getCompiledICHolderKlassObj(); + if (handle.equals(methodDataKlassHandle)) return getMethodDataKlassObj(); + } + + // Then check if obj.klass() is one of the root objects + OopHandle klass = Oop.getKlassForOopHandle(handle); + if (klass != null) { + if (klass.equals(methodKlassHandle)) return new Method(handle, this); + if (klass.equals(constMethodKlassHandle)) return new ConstMethod(handle, this); + if (klass.equals(symbolKlassHandle)) return new Symbol(handle, this); + if (klass.equals(constantPoolKlassHandle)) return new ConstantPool(handle, this); + if (klass.equals(constantPoolCacheKlassHandle)) return new ConstantPoolCache(handle, this); + if (!VM.getVM().isCore()) { + if (klass.equals(compiledICHolderKlassHandle)) return new CompiledICHolder(handle, this); + if (klass.equals(methodDataKlassHandle)) return new MethodData(handle, this); + } + if (klass.equals(instanceKlassKlassHandle)) return new InstanceKlass(handle, this); + if (klass.equals(objArrayKlassKlassHandle)) return new ObjArrayKlass(handle, this); + if (klass.equals(typeArrayKlassKlassHandle)) return new TypeArrayKlass(handle, this); + + // Lastly check if obj.klass().klass() is on of the root objects + OopHandle klassKlass = Oop.getKlassForOopHandle(klass); + if (klassKlass != null) { + if (klassKlass.equals(instanceKlassKlassHandle)) return new Instance(handle, this); + if (klassKlass.equals(objArrayKlassKlassHandle)) return new ObjArray(handle, this); + if (klassKlass.equals(typeArrayKlassKlassHandle)) return new TypeArray(handle, this); + } + } + + System.err.println("Unknown oop at " + handle); + System.err.println("Oop's klass is " + klass); + + throw new UnknownOopException(); + } + + // Print all objects in the object heap + public void print() { + HeapPrinter printer = new HeapPrinter(System.out); + iterate(printer); + } + + //--------------------------------------------------------------------------- + // Internals only below this point + // + + private void iterateExact(HeapVisitor visitor, final Klass k) { + iterateLiveRegions(collectLiveRegions(), visitor, new ObjectFilter() { + public boolean canInclude(Oop obj) { + Klass tk = obj.getKlass(); + // null Klass is seen sometimes! + return (tk != null && tk.equals(k)); + } + }); + } + + private void iterateSubtypes(HeapVisitor visitor, final Klass k) { + iterateLiveRegions(collectLiveRegions(), visitor, new ObjectFilter() { + public boolean canInclude(Oop obj) { + Klass tk = obj.getKlass(); + // null Klass is seen sometimes! + return (tk != null && tk.isSubtypeOf(k)); + } + }); + } + + private void iterateLiveRegions(List liveRegions, HeapVisitor visitor, ObjectFilter of) { + // Summarize size + long totalSize = 0; + for (int i = 0; i < liveRegions.size(); i += 2) { + Address bottom = (Address) liveRegions.get(i); + Address top = (Address) liveRegions.get(i+1); + totalSize += top.minus(bottom); + } + visitor.prologue(totalSize); + + CompactibleFreeListSpace cmsSpaceOld = null; + CompactibleFreeListSpace cmsSpacePerm = null; + CollectedHeap heap = VM.getVM().getUniverse().heap(); + + if (heap instanceof GenCollectedHeap) { + GenCollectedHeap genHeap = (GenCollectedHeap) heap; + Generation genOld = genHeap.getGen(1); + Generation genPerm = genHeap.permGen(); + if (genOld instanceof ConcurrentMarkSweepGeneration) { + ConcurrentMarkSweepGeneration concGen = (ConcurrentMarkSweepGeneration)genOld; + cmsSpaceOld = concGen.cmsSpace(); + } + if (genPerm instanceof ConcurrentMarkSweepGeneration) { + ConcurrentMarkSweepGeneration concGen = (ConcurrentMarkSweepGeneration)genPerm; + cmsSpacePerm = concGen.cmsSpace(); + } + } + + for (int i = 0; i < liveRegions.size(); i += 2) { + Address bottom = (Address) liveRegions.get(i); + Address top = (Address) liveRegions.get(i+1); + + try { + // Traverses the space from bottom to top + OopHandle handle = bottom.addOffsetToAsOopHandle(0); + while (handle.lessThan(top)) { + Oop obj = null; + + try { + obj = newOop(handle); + } catch (UnknownOopException exp) { + } + if (obj == null) { + //Find the object size using Printezis bits and skip over + System.err.println("Finding object size using Printezis bits and skipping over..."); + long size = 0; + + if ( (cmsSpaceOld != null) && cmsSpaceOld.contains(handle) ){ + size = cmsSpaceOld.collector().blockSizeUsingPrintezisBits(handle); + } else if ((cmsSpacePerm != null) && cmsSpacePerm.contains(handle) ){ + size = cmsSpacePerm.collector().blockSizeUsingPrintezisBits(handle); + } + + if (size <= 0) { + //Either Printezis bits not set or handle is not in cms space. + throw new UnknownOopException(); + } + + handle = handle.addOffsetToAsOopHandle(CompactibleFreeListSpace.adjustObjectSizeInBytes(size)); + continue; + } + if (of == null || of.canInclude(obj)) { + if (visitor.doObj(obj)) { + // doObj() returns true to abort this loop. + break; + } + } + if ( (cmsSpaceOld != null) && cmsSpaceOld.contains(handle) || + (cmsSpacePerm != null) && cmsSpacePerm.contains(handle) ) { + handle = handle.addOffsetToAsOopHandle(CompactibleFreeListSpace.adjustObjectSizeInBytes(obj.getObjectSize()) ); + } else { + handle = handle.addOffsetToAsOopHandle(obj.getObjectSize()); + } + } + } + catch (AddressException e) { + // This is okay at the top of these regions + } + catch (UnknownOopException e) { + // This is okay at the top of these regions + } + } + + visitor.epilogue(); + } + + private void addPermGenLiveRegions(List output, CollectedHeap heap) { + LiveRegionsCollector lrc = new LiveRegionsCollector(output); + if (heap instanceof GenCollectedHeap) { + GenCollectedHeap genHeap = (GenCollectedHeap) heap; + Generation gen = genHeap.permGen(); + gen.spaceIterate(lrc, true); + } else if (heap instanceof ParallelScavengeHeap) { + ParallelScavengeHeap psh = (ParallelScavengeHeap) heap; + PSPermGen permGen = psh.permGen(); + addLiveRegions(permGen.objectSpace().getLiveRegions(), output); + } else { + if (Assert.ASSERTS_ENABLED) { + Assert.that(false, "Expecting GenCollectedHeap or ParallelScavengeHeap, but got " + + heap.getClass().getName()); + } + } + } + + private void addLiveRegions(List input, List output) { + for (Iterator itr = input.iterator(); itr.hasNext();) { + MemRegion reg = (MemRegion) itr.next(); + Address top = reg.end(); + Address bottom = reg.start(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(top != null, "top address in a live region should not be null"); + } + if (Assert.ASSERTS_ENABLED) { + Assert.that(bottom != null, "bottom address in a live region should not be null"); + } + output.add(top); + output.add(bottom); + } + } + + private class LiveRegionsCollector implements SpaceClosure { + LiveRegionsCollector(List l) { + liveRegions = l; + } + + public void doSpace(Space s) { + addLiveRegions(s.getLiveRegions(), liveRegions); + } + private List liveRegions; + } + + // Returns a List<Address> where the addresses come in pairs. These + // designate the live regions of the heap. + private List collectLiveRegions() { + // We want to iterate through all live portions of the heap, but + // do not want to abort the heap traversal prematurely if we find + // a problem (like an allocated but uninitialized object at the + // top of a generation). To do this we enumerate all generations' + // bottom and top regions, and factor in TLABs if necessary. + + // List<Address>. Addresses come in pairs. + List liveRegions = new ArrayList(); + LiveRegionsCollector lrc = new LiveRegionsCollector(liveRegions); + + CollectedHeap heap = VM.getVM().getUniverse().heap(); + + if (heap instanceof GenCollectedHeap) { + GenCollectedHeap genHeap = (GenCollectedHeap) heap; + // Run through all generations, obtaining bottom-top pairs. + for (int i = 0; i < genHeap.nGens(); i++) { + Generation gen = genHeap.getGen(i); + gen.spaceIterate(lrc, true); + } + } else if (heap instanceof ParallelScavengeHeap) { + ParallelScavengeHeap psh = (ParallelScavengeHeap) heap; + PSYoungGen youngGen = psh.youngGen(); + // Add eden space + addLiveRegions(youngGen.edenSpace().getLiveRegions(), liveRegions); + // Add from-space but not to-space + addLiveRegions(youngGen.fromSpace().getLiveRegions(), liveRegions); + PSOldGen oldGen = psh.oldGen(); + addLiveRegions(oldGen.objectSpace().getLiveRegions(), liveRegions); + } else { + if (Assert.ASSERTS_ENABLED) { + Assert.that(false, "Expecting GenCollectedHeap or ParallelScavengeHeap, but got " + + heap.getClass().getName()); + } + } + + // handle perm generation + addPermGenLiveRegions(liveRegions, heap); + + // If UseTLAB is enabled, snip out regions associated with TLABs' + // dead regions. Note that TLABs can be present in any generation. + + // FIXME: consider adding fewer boundaries to live region list. + // Theoretically only need to stop at TLAB's top and resume at its + // end. + + if (VM.getVM().getUseTLAB()) { + for (JavaThread thread = VM.getVM().getThreads().first(); thread != null; thread = thread.next()) { + if (thread.isJavaThread()) { + ThreadLocalAllocBuffer tlab = thread.tlab(); + if (tlab.start() != null) { + if ((tlab.top() == null) || (tlab.end() == null)) { + System.err.print("Warning: skipping invalid TLAB for thread "); + thread.printThreadIDOn(System.err); + System.err.println(); + } else { + // Go from: + // - below start() to start() + // - start() to top() + // - end() and above + liveRegions.add(tlab.start()); + liveRegions.add(tlab.start()); + liveRegions.add(tlab.top()); + liveRegions.add(tlab.end()); + } + } + } + } + } + + // Now sort live regions + sortLiveRegions(liveRegions); + + if (Assert.ASSERTS_ENABLED) { + Assert.that(liveRegions.size() % 2 == 0, "Must have even number of region boundaries"); + } + + return liveRegions; + } + + private void sortLiveRegions(List liveRegions) { + Collections.sort(liveRegions, new Comparator() { + public int compare(Object o1, Object o2) { + Address a1 = (Address) o1; + Address a2 = (Address) o2; + if (AddressOps.lt(a1, a2)) { + return -1; + } else if (AddressOps.gt(a1, a2)) { + return 1; + } + return 0; + } + }); + } +}