1 /* 2 * Copyright (c) 2017, 2019, Red Hat, Inc. All rights reserved. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 * 22 */ 23 24 package sun.jvm.hotspot.gc.shenandoah; 25 26 import sun.jvm.hotspot.debugger.OopHandle; 27 import sun.jvm.hotspot.gc.shared.ContiguousSpace; 28 import sun.jvm.hotspot.gc.shared.LiveRegionsProvider; 29 import sun.jvm.hotspot.memory.MemRegion; 30 import sun.jvm.hotspot.oops.Mark; 31 import sun.jvm.hotspot.oops.Oop; 32 import sun.jvm.hotspot.oops.UnknownOopException; 33 import sun.jvm.hotspot.types.*; 34 import sun.jvm.hotspot.runtime.VM; 35 import sun.jvm.hotspot.runtime.VMObject; 36 import sun.jvm.hotspot.debugger.Address; 37 import sun.jvm.hotspot.utilities.AddressOps; 38 39 import java.util.ArrayList; 40 import java.util.List; 41 import java.util.Observable; 42 import java.util.Observer; 43 44 45 public class ShenandoahHeapRegion extends VMObject implements LiveRegionsProvider { 46 private static int EmptyUncommitted; 47 private static int EmptyCommitted; 48 private static int Regular; 49 private static int HumongousStart; 50 private static int HumongousCont; 51 private static int PinnedHumongousStart; 52 private static int CSet; 53 private static int Pinned; 54 private static int PinnedCSet; 55 private static int Trash; 56 57 private static CIntegerField RegionSizeBytesField; 58 private static Field RegionStateField; 59 private static CIntegerField RegionIndexField; 60 private static CIntegerField RegionSizeBytesShiftField; 61 62 private static AddressField BottomField; 63 private static AddressField TopField; 64 private static AddressField EndField; 65 66 private ShenandoahHeap heap; 67 68 static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { initialize(VM.getVM().getTypeDataBase()); } })69 VM.registerVMInitializedObserver(new Observer() { 70 public void update(Observable o, Object data) { 71 initialize(VM.getVM().getTypeDataBase()); 72 } 73 }); 74 } 75 initialize(TypeDataBase db)76 static private synchronized void initialize(TypeDataBase db) { 77 Type type = db.lookupType("ShenandoahHeapRegion"); 78 RegionSizeBytesField = type.getCIntegerField("RegionSizeBytes"); 79 RegionStateField = type.getField("_state"); 80 RegionIndexField = type.getCIntegerField("_index"); 81 BottomField = type.getAddressField("_bottom"); 82 TopField = type.getAddressField("_top"); 83 EndField = type.getAddressField("_end"); 84 85 RegionSizeBytesShiftField = type.getCIntegerField("RegionSizeBytesShift"); 86 87 EmptyUncommitted = db.lookupIntConstant("ShenandoahHeapRegion::_empty_uncommitted").intValue(); 88 EmptyCommitted = db.lookupIntConstant("ShenandoahHeapRegion::_empty_committed").intValue(); 89 Regular = db.lookupIntConstant("ShenandoahHeapRegion::_regular").intValue(); 90 HumongousStart = db.lookupIntConstant("ShenandoahHeapRegion::_humongous_start").intValue(); 91 HumongousCont = db.lookupIntConstant("ShenandoahHeapRegion::_humongous_cont").intValue(); 92 PinnedHumongousStart = db.lookupIntConstant("ShenandoahHeapRegion::_pinned_humongous_start").intValue(); 93 CSet = db.lookupIntConstant("ShenandoahHeapRegion::_cset").intValue(); 94 Pinned = db.lookupIntConstant("ShenandoahHeapRegion::_pinned").intValue(); 95 PinnedCSet = db.lookupIntConstant("ShenandoahHeapRegion::_pinned_cset").intValue(); 96 Trash = db.lookupIntConstant("ShenandoahHeapRegion::_trash").intValue(); 97 } 98 regionSizeBytes()99 public static long regionSizeBytes() { 100 return RegionSizeBytesField.getValue(); 101 } 102 regionSizeBytesShift()103 public static int regionSizeBytesShift() { 104 return RegionSizeBytesShiftField.getJInt(); 105 } 106 ShenandoahHeapRegion(Address addr)107 public ShenandoahHeapRegion(Address addr) { 108 super(addr); 109 } 110 setHeap(ShenandoahHeap heap)111 public void setHeap(ShenandoahHeap heap) { 112 this.heap = heap; 113 } 114 bottom()115 public Address bottom() { 116 return BottomField.getValue(addr); 117 } 118 top()119 public Address top() { 120 return TopField.getValue(addr); 121 } 122 end()123 public Address end() { 124 return EndField.getValue(addr); 125 } 126 127 @Override hashCode()128 public int hashCode() { 129 return (int)index(); 130 } 131 132 @Override equals(Object other)133 public boolean equals(Object other) { 134 if (other instanceof ShenandoahHeapRegion) { 135 ShenandoahHeapRegion otherRegion = (ShenandoahHeapRegion)other; 136 return otherRegion.index() == index(); 137 } 138 return false; 139 } 140 getLiveRegions()141 public List<MemRegion> getLiveRegions() { 142 List<MemRegion> res = new ArrayList<>(); 143 int state = regionState(); 144 if (state == EmptyUncommitted || state == EmptyCommitted || state == Trash) { 145 // No live data 146 } else if (state == HumongousCont) { 147 // Handled by HumongousStart 148 } else if (state == HumongousStart || state == PinnedHumongousStart) { 149 handleHumongousRegion(res); 150 } else if (state == Regular || state == Pinned) { 151 handleRegularRegion(res); 152 } else if (state == CSet || state == PinnedCSet) { 153 // CSet 154 handleCSetRegion(res); 155 } else { 156 throw new RuntimeException("Unknown region state: " + state); 157 } 158 return res; 159 } 160 161 /* 162 * Note: RegionState is an enum on JVM side. Seems that there is not 163 * a standard way to read enum value. We read it as an integer 164 * from the field's offset. 165 */ regionState()166 private int regionState() { 167 long offset = RegionStateField.getOffset(); 168 return addr.getJIntAt(offset); 169 } 170 handleHumongousRegion(List<MemRegion> res)171 private void handleHumongousRegion(List<MemRegion> res) { 172 long index = index(); 173 Address topAddr = top(); 174 ShenandoahHeapRegion region = heap.getRegion(++ index); 175 while (region.regionState() == HumongousCont) { 176 topAddr = region.top(); 177 region = heap.getRegion(++ index); 178 } 179 res.add(new MemRegion(bottom(), topAddr)); 180 } 181 handleRegularRegion(List<MemRegion> res)182 private void handleRegularRegion(List<MemRegion> res) { 183 res.add(new MemRegion(bottom(), top())); 184 } 185 186 // Filter out forwarded objects, they should be counted in other regions handleCSetRegion(List<MemRegion> res)187 private void handleCSetRegion(List<MemRegion> res) { 188 Address end = top(); 189 Address start = bottom(); 190 191 Address regionStart = null; 192 Address regionEnd = null; 193 while (AddressOps.lessThan(start, end)) { 194 long size = getObjectSize(start); 195 if (hasForwardee(start)) { 196 // has to-space object, skip this one 197 if (regionEnd != null) { 198 MemRegion mr = new MemRegion(regionStart, regionEnd); 199 res.add(mr); 200 regionStart = null; 201 regionEnd = null; 202 } 203 } else { 204 if (regionStart == null) { 205 regionStart = start; 206 } else { 207 regionEnd = start.addOffsetTo(size); 208 } 209 } 210 start = start.addOffsetTo(size); 211 } 212 213 if (regionStart != null) { 214 MemRegion mr = new MemRegion(regionStart, top()); 215 res.add(mr); 216 } 217 } 218 index()219 public long index() { 220 return RegionIndexField.getValue(addr); 221 } 222 hasForwardee(Address rawPtr)223 private boolean hasForwardee(Address rawPtr) { 224 // Forwarding pointer is stored in mark word when it is flagged "marked" 225 Mark mark = new Mark(rawPtr); 226 return mark.isMarked(); 227 } 228 getObjectSize(Address rawPtr)229 private long getObjectSize(Address rawPtr) { 230 OopHandle handle = rawPtr.addOffsetToAsOopHandle(0); 231 Oop obj = null; 232 233 try { 234 // Best effort, may fail 235 obj = VM.getVM().getObjectHeap().newOop(handle); 236 } catch (UnknownOopException exp) { 237 throw new RuntimeException(" UnknownOopException " + exp); 238 } 239 return obj.getObjectSize(); 240 } 241 } 242