package sun.jvm.hotspot.oops;
import java.util.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.gc.shared.*;
import sun.jvm.hotspot.gc.epsilon.*;
import sun.jvm.hotspot.gc.g1.*;
import sun.jvm.hotspot.gc.shenandoah.*;
import sun.jvm.hotspot.gc.parallel.*;
import sun.jvm.hotspot.gc.z.*;
import sun.jvm.hotspot.memory.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;
public class ObjectHeap {
private static final boolean DEBUG;
static {
DEBUG = System.getProperty("sun.jvm.hotspot.oops.ObjectHeap.DEBUG") != null;
}
public ObjectHeap(TypeDataBase db) throws WrongTypeException {
oopSize = VM.getVM().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();
}
public boolean equal(Oop o1, Oop o2) {
if (o1 != null) return o1.equals(o2);
return (o2 == null);
}
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; }
public static interface ObjectFilter {
public boolean canInclude(Oop obj);
}
public void iterate(HeapVisitor visitor) {
iterateLiveRegions(collectLiveRegions(), visitor, null);
}
public void iterate(HeapVisitor visitor, ObjectFilter of) {
iterateLiveRegions(collectLiveRegions(), visitor, of);
}
public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k, boolean includeSubtypes) {
if (includeSubtypes) {
if (k.isFinal()) {
iterateExact(visitor, k);
} else {
iterateSubtypes(visitor, k);
}
} else {
if (!k.isAbstract() && !k.isInterface()) {
iterateExact(visitor, k);
}
}
}
public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k) {
iterateObjectsOfKlass(visitor, k, true);
}
public void iterateRaw(RawHeapVisitor visitor) {
List<Address> liveRegions = collectLiveRegions();
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);
while (bottom.lessThan(top)) {
visitor.visitAddress(bottom);
bottom = bottom.addOffsetTo(VM.getVM().getAddressSize());
}
}
visitor.epilogue();
}
public boolean isValidMethod(Address handle) {
try {
Method m = (Method)Metadata.instantiateWrapperFor(handle);
return true;
} catch (Exception e) {
return false;
}
}
public Oop newOop(OopHandle handle) {
if (handle == null) return null;
Klass klass = Oop.getKlassForOopHandle(handle);
if (klass != null) {
if (klass instanceof TypeArrayKlass) return new TypeArray(handle, this);
if (klass instanceof ObjArrayKlass) return new ObjArray(handle, this);
if (klass instanceof InstanceKlass) return new Instance(handle, this);
}
if (DEBUG) {
System.err.println("Unknown oop at " + handle);
System.err.println("Oop's klass is " + klass);
}
throw new UnknownOopException();
}
public void print() {
HeapPrinter printer = new HeapPrinter(System.out);
iterate(printer);
}
private void iterateExact(HeapVisitor visitor, final Klass k) {
iterateLiveRegions(collectLiveRegions(), visitor, new ObjectFilter() {
public boolean canInclude(Oop obj) {
Klass tk = obj.getKlass();
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();
return (tk != null && tk.isSubtypeOf(k));
}
});
}
private void iterateLiveRegions(List<Address> liveRegions, HeapVisitor visitor, ObjectFilter of) {
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);
try {
OopHandle handle = bottom.addOffsetToAsOopHandle(0);
while (handle.lessThan(top)) {
Oop obj = null;
obj = newOop(handle);
if (obj == null) {
throw new UnknownOopException();
}
if (of == null || of.canInclude(obj)) {
if (visitor.doObj(obj)) {
break;
}
}
handle = handle.addOffsetToAsOopHandle(obj.getObjectSize());
}
} catch (AddressException | UnknownOopException | WrongTypeException e) {
}
}
visitor.epilogue();
}
private static class LiveRegionsCollector implements LiveRegionsClosure {
LiveRegionsCollector(List<Address> l) {
liveRegions = l;
}
@Override
public void doLiveRegions(LiveRegionsProvider lrp) {
for (MemRegion reg : lrp.getLiveRegions()) {
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");
}
liveRegions.add(top);
liveRegions.add(bottom);
if (DEBUG) {
System.err.println("Live region: " + lrp + ": " + bottom + ", " + top);
}
}
}
private List<Address> liveRegions;
}
private List<Address> collectLiveRegions() {
List<Address> liveRegions = new ArrayList<>();
LiveRegionsCollector lrc = new LiveRegionsCollector(liveRegions);
CollectedHeap heap = VM.getVM().getUniverse().heap();
heap.liveRegionsIterate(lrc);
if (VM.getVM().getUseTLAB()) {
Threads threads = VM.getVM().getThreads();
for (int i = 0; i < threads.getNumberOfThreads(); i++) {
JavaThread thread = threads.getJavaThreadAt(i);
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 {
if (DEBUG) {
System.err.print("TLAB for " + thread.getThreadName() + ", #");
thread.printThreadIDOn(System.err);
System.err.print(": ");
tlab.printOn(System.err);
}
liveRegions.add(tlab.start());
liveRegions.add(tlab.start());
liveRegions.add(tlab.top());
liveRegions.add(tlab.hardEnd());
}
}
}
}
sortLiveRegions(liveRegions);
if (Assert.ASSERTS_ENABLED) {
Assert.that(liveRegions.size() % 2 == 0, "Must have even number of region boundaries");
}
if (DEBUG) {
System.err.println("liveRegions:");
for (int i = 0; i < liveRegions.size(); i += 2) {
Address bottom = (Address) liveRegions.get(i);
Address top = (Address) liveRegions.get(i+1);
System.err.println(" " + bottom + " - " + top);
}
}
return liveRegions;
}
private void sortLiveRegions(List<Address> liveRegions) {
Collections.sort(liveRegions, new Comparator<Address>() {
public int compare(Address a1, Address a2) {
if (AddressOps.lt(a1, a2)) {
return -1;
} else if (AddressOps.gt(a1, a2)) {
return 1;
}
return 0;
}
});
}
}