8218922: SA: Enable best-effort implementation of live regions iteration for ZGC
authorstefank
Tue, 19 Feb 2019 10:04:28 +0100
changeset 53815 46ce458df412
parent 53814 eff915f3d3f2
child 53816 f3e0c8ca50d9
8218922: SA: Enable best-effort implementation of live regions iteration for ZGC Reviewed-by: eosterlund, ysuenaga
src/hotspot/share/gc/z/vmStructs_z.cpp
src/hotspot/share/gc/z/vmStructs_z.hpp
src/hotspot/share/gc/z/zCollectedHeap.cpp
src/hotspot/share/gc/z/zCollectedHeap.hpp
src/hotspot/share/gc/z/zMark.cpp
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZAddress.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZAddressRangeMapForPageTable.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZCollectedHeap.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZExternalBitMap.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZGlobals.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZGlobalsForVMStructs.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZOop.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPage.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPageTable.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPageTableEntry.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZUtils.java
--- a/src/hotspot/share/gc/z/vmStructs_z.cpp	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/hotspot/share/gc/z/vmStructs_z.cpp	Tue Feb 19 10:04:28 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. 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
@@ -26,6 +26,7 @@
 
 ZGlobalsForVMStructs::ZGlobalsForVMStructs() :
     _ZGlobalPhase(&ZGlobalPhase),
+    _ZGlobalSeqNum(&ZGlobalSeqNum),
     _ZAddressGoodMask(&ZAddressGoodMask),
     _ZAddressBadMask(&ZAddressBadMask),
     _ZAddressWeakBadMask(&ZAddressWeakBadMask),
--- a/src/hotspot/share/gc/z/vmStructs_z.hpp	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/hotspot/share/gc/z/vmStructs_z.hpp	Tue Feb 19 10:04:28 2019 +0100
@@ -42,6 +42,8 @@
 
   uint32_t* _ZGlobalPhase;
 
+  uint32_t* _ZGlobalSeqNum;
+
   uintptr_t* _ZAddressGoodMask;
   uintptr_t* _ZAddressBadMask;
   uintptr_t* _ZAddressWeakBadMask;
@@ -55,6 +57,7 @@
 #define VM_STRUCTS_ZGC(nonstatic_field, volatile_nonstatic_field, static_field)                      \
   static_field(ZGlobalsForVMStructs,            _instance_p,          ZGlobalsForVMStructs*)         \
   nonstatic_field(ZGlobalsForVMStructs,         _ZGlobalPhase,        uint32_t*)                     \
+  nonstatic_field(ZGlobalsForVMStructs,         _ZGlobalSeqNum,       uint32_t*)                     \
   nonstatic_field(ZGlobalsForVMStructs,         _ZAddressGoodMask,    uintptr_t*)                    \
   nonstatic_field(ZGlobalsForVMStructs,         _ZAddressBadMask,     uintptr_t*)                    \
   nonstatic_field(ZGlobalsForVMStructs,         _ZAddressWeakBadMask, uintptr_t*)                    \
@@ -67,7 +70,10 @@
   nonstatic_field(ZHeap,                        _pagetable,           ZPageTable)                    \
                                                                                                      \
   nonstatic_field(ZPage,                        _type,                const uint8_t)                 \
+  nonstatic_field(ZPage,                        _seqnum,              uint32_t)                      \
   nonstatic_field(ZPage,                        _virtual,             const ZVirtualMemory)          \
+  volatile_nonstatic_field(ZPage,               _top,                 uintptr_t)                     \
+  volatile_nonstatic_field(ZPage,               _refcount,            uint32_t)                      \
   nonstatic_field(ZPage,                        _forwarding,          ZForwardingTable)              \
                                                                                                      \
   nonstatic_field(ZPageAllocator,               _physical,            ZPhysicalMemoryManager)        \
@@ -101,6 +107,7 @@
   declare_constant(ZAddressOffsetShift)                                                              \
   declare_constant(ZAddressOffsetBits)                                                               \
   declare_constant(ZAddressOffsetMask)                                                               \
+  declare_constant(ZAddressOffsetMax)                                                                \
   declare_constant(ZAddressSpaceStart)
 
 #define VM_TYPES_ZGC(declare_type, declare_toplevel_type, declare_integer_type)                      \
--- a/src/hotspot/share/gc/z/zCollectedHeap.cpp	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp	Tue Feb 19 10:04:28 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. 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
@@ -118,10 +118,6 @@
   return is_in(p);
 }
 
-void ZCollectedHeap::fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap) {
-  // Does nothing, not a parsable heap
-}
-
 HeapWord* ZCollectedHeap::allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size) {
   const size_t size_in_bytes = ZUtils::words_to_bytes(align_object_size(requested_size));
   const uintptr_t addr = _heap.alloc_tlab(size_in_bytes);
--- a/src/hotspot/share/gc/z/zCollectedHeap.hpp	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/hotspot/share/gc/z/zCollectedHeap.hpp	Tue Feb 19 10:04:28 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. 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
@@ -75,8 +75,6 @@
   virtual bool is_in(const void* p) const;
   virtual bool is_in_closed_subset(const void* p) const;
 
-  virtual void fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap);
-
   virtual HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded);
   virtual MetaWord* satisfy_failed_metadata_allocation(ClassLoaderData* loader_data,
                                                        size_t size,
--- a/src/hotspot/share/gc/z/zMark.cpp	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/hotspot/share/gc/z/zMark.cpp	Tue Feb 19 10:04:28 2019 +0100
@@ -119,6 +119,11 @@
 }
 
 class ZMarkRootsIteratorClosure : public ZRootsIteratorClosure {
+private:
+  static void fixup_address(HeapWord** p) {
+    *p = (HeapWord*)ZAddress::good_or_null((uintptr_t)*p);
+  }
+
 public:
   ZMarkRootsIteratorClosure() {
     ZStatTLAB::reset();
@@ -136,6 +141,7 @@
 
     // Retire TLAB
     if (UseTLAB && thread->is_Java_thread()) {
+      thread->tlab().addresses_do(fixup_address);
       thread->tlab().retire(ZStatTLAB::get());
       thread->tlab().resize();
     }
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZAddress.java	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZAddress.java	Tue Feb 19 10:04:28 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. 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
@@ -61,7 +61,7 @@
             value |= ZGlobals.ZAddressSpaceStart;
         }
 
-        return ZOop.to_address(value);
+        return ZUtils.longToAddress(value);
     }
 
     static Address good(Address value) {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZAddressRangeMapForPageTable.java	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZAddressRangeMapForPageTable.java	Tue Feb 19 10:04:28 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. 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
@@ -54,15 +54,38 @@
         return mapField.getValue(addr);
     }
 
+    public long size() {
+        return ZGlobals.ZAddressOffsetMax >> AddressRangeShift;
+    }
+
     private long index_for_addr(Address addr) {
         long index = ZAddress.offset(addr) >> AddressRangeShift;
 
         return index;
     }
 
+    Address at(long index) {
+        return map().getAddressAt(index * VM.getVM().getBytesPerLong());
+    }
+
     Address get(Address addr) {
         long index = index_for_addr(addr);
+        return at(index);
+    }
 
-        return map().getAddressAt(index * VM.getVM().getBytesPerLong());
+    public class Iterator {
+        private long next = 0;
+
+        boolean hasNext() {
+            return next < size();
+        }
+
+        Address next() {
+            if (next >= size()) {
+                throw new RuntimeException("OOIBE");
+            }
+
+            return at(next++);
+        }
     }
 }
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZCollectedHeap.java	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZCollectedHeap.java	Tue Feb 19 10:04:28 2019 +0100
@@ -25,6 +25,7 @@
 package sun.jvm.hotspot.gc.z;
 
 import java.io.PrintStream;
+import java.util.Iterator;
 
 import sun.jvm.hotspot.debugger.Address;
 import sun.jvm.hotspot.debugger.OopHandle;
@@ -121,9 +122,11 @@
 
     @Override
     public void liveRegionsIterate(LiveRegionsClosure closure) {
-        // Operation (currently) not supported with ZGC. Print
-        // a warning and leave the list of live regions empty.
-        System.err.println("Warning: Operation not supported with ZGC");
+        Iterator<ZPage> iter = heap().pageTable().activePagesIterator();
+        while (iter.hasNext()) {
+            ZPage page = iter.next();
+            closure.doLiveRegions(page);
+        }
     }
 
     @Override
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZExternalBitMap.java	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZExternalBitMap.java	Tue Feb 19 10:04:28 2019 +0100
@@ -47,7 +47,7 @@
             throw new RuntimeException("Not a Z offset: " + zOffset);
         }
 
-        ZPage page = pageTable.get(ZOop.to_address(zOffset));
+        ZPage page = pageTable.get(ZUtils.longToAddress(zOffset));
         if (page == null) {
             throw new RuntimeException("Address not in pageTable: " + zOffset);
         }
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZGlobals.java	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZGlobals.java	Tue Feb 19 10:04:28 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. 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
@@ -54,6 +54,7 @@
     // Pointer part of address
     public static long ZAddressOffsetBits;
     public static long ZAddressOffsetMask;
+    public static long ZAddressOffsetMax;
 
     // Address space start/end/size
     public static long ZAddressSpaceStart;
@@ -84,6 +85,7 @@
 
         ZAddressOffsetBits = db.lookupLongConstant("ZAddressOffsetBits").longValue();
         ZAddressOffsetMask = db.lookupLongConstant("ZAddressOffsetMask").longValue();
+        ZAddressOffsetMax  = db.lookupLongConstant("ZAddressOffsetMax").longValue();
 
         ZAddressSpaceStart = db.lookupLongConstant("ZAddressSpaceStart").longValue();
     }
@@ -96,6 +98,10 @@
         return instance().ZGlobalPhase();
     }
 
+    public static int ZGlobalSeqNum() {
+        return instance().ZGlobalSeqNum();
+    }
+
     public static long ZAddressGoodMask() {
         return instance().ZAddressGoodMask();
     }
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZGlobalsForVMStructs.java	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZGlobalsForVMStructs.java	Tue Feb 19 10:04:28 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. 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
@@ -33,6 +33,7 @@
 
 class ZGlobalsForVMStructs extends VMObject {
     private static AddressField ZGlobalPhaseField;
+    private static AddressField ZGlobalSeqNumField;
     private static AddressField ZAddressGoodMaskField;
     private static AddressField ZAddressBadMaskField;
     private static AddressField ZAddressWeakBadMaskField;
@@ -47,6 +48,7 @@
         Type type = db.lookupType("ZGlobalsForVMStructs");
 
         ZGlobalPhaseField = type.getAddressField("_ZGlobalPhase");
+        ZGlobalSeqNumField = type.getAddressField("_ZGlobalSeqNum");
         ZAddressGoodMaskField = type.getAddressField("_ZAddressGoodMask");
         ZAddressBadMaskField = type.getAddressField("_ZAddressBadMask");
         ZAddressWeakBadMaskField = type.getAddressField("_ZAddressWeakBadMask");
@@ -62,6 +64,10 @@
         return ZGlobalPhaseField.getValue(addr).getJIntAt(0);
     }
 
+    int ZGlobalSeqNum() {
+        return ZGlobalSeqNumField.getValue(addr).getJIntAt(0);
+    }
+
     long ZAddressGoodMask() {
         return ZAddressGoodMaskField.getValue(addr).getJLongAt(0);
     }
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZOop.java	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZOop.java	Tue Feb 19 10:04:28 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. 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
@@ -26,23 +26,9 @@
 
 import sun.jvm.hotspot.debugger.Address;
 import sun.jvm.hotspot.debugger.OopHandle;
-import sun.jvm.hotspot.runtime.VM;
 
 class ZOop {
-    private static final long MSB = ~0L ^ (~0L >>> 1);
-
-    private static Address msbAddress() {
-        return VM.getVM().getUniverse().heap().start().orWithMask(MSB).andWithMask(MSB);
-    }
-
-    static Address to_address(long value) {
-        // If the value of an Address becomes 0, null is returned instead of an Address.
-        // Start with a one-bit address and as a last step, remove that bit.
-        Address oneAddress = msbAddress();
-        return oneAddress.orWithMask(value).xorWithMask(ZAddress.as_long(oneAddress));
-    }
-
     static Address to_address(OopHandle oop) {
-        return to_address(ZAddress.as_long(oop));
+        return ZUtils.longToAddress(ZAddress.as_long(oop));
     }
 }
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPage.java	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPage.java	Tue Feb 19 10:04:28 2019 +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<MemRegion> 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<MemRegion> getLiveRegions() {
+        List<MemRegion> 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;
+    }
 }
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPageTable.java	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPageTable.java	Tue Feb 19 10:04:28 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. 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
@@ -24,6 +24,8 @@
 
 package sun.jvm.hotspot.gc.z;
 
+import java.util.Iterator;
+
 import sun.jvm.hotspot.debugger.Address;
 import sun.jvm.hotspot.runtime.VM;
 import sun.jvm.hotspot.runtime.VMObject;
@@ -63,4 +65,112 @@
     boolean is_relocating(Address o) {
         return getEntry(o).relocating();
     }
+
+    private class ZPagesIterator implements Iterator<ZPage> {
+        private ZAddressRangeMapForPageTable.Iterator mapIter;
+        private ZPage next;
+
+        ZPagesIterator() {
+            mapIter = map().new Iterator();
+            positionToNext();
+        }
+
+        private ZPage positionToNext() {
+            ZPage current = next;
+
+            // Find next
+            ZPage found = null;
+            while (mapIter.hasNext()) {
+                ZPageTableEntry entry = new ZPageTableEntry(mapIter.next());
+                if (!entry.isEmpty()) {
+                    ZPage page = entry.page();
+                    // Medium pages have repeated entries for all covered slots,
+                    // therefore we need to compare against the current page.
+                    if (page != null && !page.equals(current)) {
+                        found = page;
+                        break;
+                    }
+                }
+            }
+
+            next = found;
+
+            return current;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        @Override
+        public ZPage next() {
+            return positionToNext();
+        }
+
+        @Override
+        public void remove() {
+            /* not supported */
+        }
+    }
+
+    abstract class ZPageFilter {
+        public abstract boolean accept(ZPage page);
+    }
+
+    class ZPagesFilteredIterator implements Iterator<ZPage> {
+        private ZPage next;
+        private ZPagesIterator iter = new ZPagesIterator();
+        private ZPageFilter filter;
+
+        ZPagesFilteredIterator(ZPageFilter filter) {
+            this.filter = filter;
+            positionToNext();
+        }
+
+        public ZPage positionToNext() {
+            ZPage current = next;
+
+            // Find next
+            ZPage found = null;
+            while (iter.hasNext()) {
+                ZPage page = iter.next();
+                if (filter.accept(page)) {
+                    found = page;
+                    break;
+                }
+            }
+
+            next = found;
+
+            return current;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        @Override
+        public ZPage next() {
+            return positionToNext();
+        }
+
+        @Override
+        public void remove() {
+            /* not supported */
+        }
+    }
+
+    public Iterator<ZPage> iterator() {
+        return new ZPagesIterator();
+    }
+
+    public Iterator<ZPage> activePagesIterator() {
+        return new ZPagesFilteredIterator(new ZPageFilter() {
+            public boolean accept(ZPage page) {
+                return page.is_active();
+            }
+        });
+    }
 }
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPageTableEntry.java	Tue Feb 19 10:03:41 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZPageTableEntry.java	Tue Feb 19 10:04:28 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. 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
@@ -35,10 +35,18 @@
     }
 
     ZPage page() {
-        return (ZPage)VMObjectFactory.newObject(ZPage.class, entry.andWithMask(~1L));
+        return (ZPage)VMObjectFactory.newObject(ZPage.class, zPageBits());
+    }
+
+    private Address zPageBits() {
+        return entry.andWithMask(~1L);
     }
 
     boolean relocating() {
         return (entry.asLongValue() & 1) == 1;
     }
+
+    boolean isEmpty() {
+        return entry == null || zPageBits() == null;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/z/ZUtils.java	Tue Feb 19 10:04:28 2019 +0100
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.gc.z;
+
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.runtime.VM;
+
+class ZUtils {
+    private static final long MSB = ~0L ^ (~0L >>> 1);
+
+    private static Address msbAddress() {
+        return VM.getVM().getUniverse().heap().start().orWithMask(MSB).andWithMask(MSB);
+    }
+
+    static Address longToAddress(long value) {
+        // If the value of an Address becomes 0, null is returned instead of an Address.
+        // Start with a one-bit address and as a last step, remove that bit.
+        Address oneAddress = msbAddress();
+        return oneAddress.orWithMask(value).xorWithMask(ZAddress.as_long(oneAddress));
+    }
+}