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