--- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPage.java 2019-02-14 18:20:35.672217968 +0100 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPage.java 2019-02-14 18:20:35.168217972 +0100 @@ -24,17 +24,29 @@ package sun.jvm.hotspot.gc.z; +import java.util.ArrayList; +import java.util.List; + import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.debugger.OopHandle; +import sun.jvm.hotspot.gc.shared.LiveRegionsProvider; +import sun.jvm.hotspot.memory.MemRegion; +import sun.jvm.hotspot.oops.Oop; +import sun.jvm.hotspot.oops.UnknownOopException; import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.runtime.VMObject; import sun.jvm.hotspot.runtime.VMObjectFactory; +import sun.jvm.hotspot.types.AddressField; import sun.jvm.hotspot.types.CIntegerField; import sun.jvm.hotspot.types.Type; import sun.jvm.hotspot.types.TypeDataBase; -public class ZPage extends VMObject { +public class ZPage extends VMObject implements LiveRegionsProvider { private static CIntegerField typeField; + private static CIntegerField seqnumField; private static long virtualFieldOffset; + private static AddressField topField; + private static CIntegerField refcountField; private static long forwardingFieldOffset; static { @@ -45,7 +57,10 @@ Type type = db.lookupType("ZPage"); typeField = type.getCIntegerField("_type"); + seqnumField = type.getCIntegerField("_seqnum"); virtualFieldOffset = type.getField("_virtual").getOffset(); + topField = type.getAddressField("_top"); + refcountField = type.getCIntegerField("_refcount"); forwardingFieldOffset = type.getField("_forwarding").getOffset(); } @@ -57,12 +72,40 @@ return typeField.getJByte(addr); } + private int seqnum() { + return seqnumField.getJInt(addr); + } + private ZVirtualMemory virtual() { - return (ZVirtualMemory)VMObjectFactory.newObject(ZVirtualMemory.class, addr.addOffsetTo(virtualFieldOffset)); + return VMObjectFactory.newObject(ZVirtualMemory.class, addr.addOffsetTo(virtualFieldOffset)); + } + + private Address top() { + return topField.getValue(addr); + } + + private int refcount() { + // refcount is uint32_t so need to be cautious when using this field. + return refcountField.getJInt(addr); } private ZForwardingTable forwarding() { - return (ZForwardingTable)VMObjectFactory.newObject(ZForwardingTable.class, addr.addOffsetTo(forwardingFieldOffset)); + return VMObjectFactory.newObject(ZForwardingTable.class, addr.addOffsetTo(forwardingFieldOffset)); + } + + private boolean is_forwarding() { + return forwarding().table() != null; + } + + private boolean is_relocatable() { + return is_active() && seqnum() < ZGlobals.ZGlobalSeqNum(); + } + + private boolean isPageRelocating() { + assert(is_active()); + // is_forwarding(): Has a (relocation) forwarding table + // is_relocatable(): Has not been freed yet + return is_forwarding() && is_relocatable(); } long start() { @@ -98,7 +141,6 @@ return ZAddress.good(from); } - long object_alignment_shift() { if (type() == ZGlobals.ZPageTypeSmall) { return ZGlobals.ZObjectAlignmentSmallShift(); @@ -109,4 +151,94 @@ return ZGlobals.ZObjectAlignmentLargeShift; } } + + long objectAlignmentSize() { + return 1 << object_alignment_shift(); + } + + public boolean is_active() { + return refcount() != 0; + } + + private long getObjectSize(Address good) { + OopHandle handle = good.addOffsetToAsOopHandle(0); + Oop obj = null; + + try { + obj = VM.getVM().getObjectHeap().newOop(handle); + } catch (UnknownOopException exp) { + throw new RuntimeException(" UnknownOopException " + exp); + } + + return VM.getVM().alignUp(obj.getObjectSize(), objectAlignmentSize()); + } + + private void addNotRelocatedRegions(List regions) { + MemRegion mr = null; + + // Some objects have already been forwarded to new locations. + long topValue = top().asLongValue(); + for (long offsetValue = start(); offsetValue < topValue;) { + Address from = ZAddress.good(ZUtils.longToAddress(offsetValue)); + + Address to = relocate_object(from); + + long byteSize; + try { + byteSize = getObjectSize(to); + } catch (Exception e) { + // Parsing the ZHeap is inherently unsafe + // when classes have been unloaded. Dead objects + // might have stale Klass pointers, and there's + // no way to get the size of the dead object. + // + // If possible, run with -XX:-ClassUnloading + // to ensure that all Klasses are kept alive. + System.err.println("Unparsable regions found. Skipping: " + + from + + " " + + from.addOffsetTo(topValue - offsetValue)); + + // Can't proceed further. Just return the collected regions. + return; + } + + if (from.equals(to)) { + // Not relocated - add region + if (mr == null) { + mr = new MemRegion(from, 0 /* wordSize */); + regions.add(mr); + } + + long wordSize = byteSize / VM.getVM().getBytesPerWord(); + mr.setWordSize(mr.wordSize() + wordSize); + } else { + // Forwarded somewhere else, split region. + mr = null; + } + + offsetValue += byteSize; + } + } + + public List getLiveRegions() { + List res = new ArrayList<>(); + + if (isPageRelocating()) { + addNotRelocatedRegions(res); + } else { + Address start = ZAddress.good(ZUtils.longToAddress(start())); + + // Can't convert top() to a "good" address because it might + // be at the top of the "offset" range, and therefore also + // looks like one of the color bits. Instead use the "good" + // address and add the size. + long size = top().asLongValue() - start(); + Address end = start.addOffsetTo(size); + + res.add(new MemRegion(start, end)); + } + + return res; + } }