1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. 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 package jdk.vm.ci.hotspot; 24 25 import java.lang.ref.Reference; 26 import java.lang.ref.ReferenceQueue; 27 import java.lang.ref.WeakReference; 28 import java.util.Arrays; 29 import java.util.Iterator; 30 31 import jdk.vm.ci.meta.JavaKind; 32 import jdk.vm.ci.meta.ResolvedJavaType; 33 34 /** 35 * This class manages the set of metadata roots that must be scanned during garbage collection. 36 * Because of class redefinition Method* and ConstantPool* can be freed if they don't appear to be 37 * in use so they must be tracked when there are live references to them from Java. 38 * 39 * The general theory of operation is that all {@link MetaspaceWrapperObject}s are created by 40 * calling into the VM which calls back out to actually create the wrapper instance. During the call 41 * the VM keeps the metadata reference alive through the use of metadata handles. Once the call 42 * completes the wrapper object is registered here and will be scanned during metadata scanning. The 43 * weakness of the reference to the wrapper object allows them to be reclaimed when they are no 44 * longer used. 45 * 46 */ 47 public class HotSpotJVMCIMetaAccessContext { 48 49 /** 50 * The set of currently live contexts used for tracking of live metadata. Examined from the VM 51 * during garbage collection. 52 */ 53 private static WeakReference<?>[] allContexts = new WeakReference<?>[0]; 54 55 /** 56 * This is a chunked list of metadata roots. It can be read from VM native code so it's been 57 * marked volatile to ensure the order of updates are respected. 58 */ 59 private volatile Object[] metadataRoots; 60 61 private ChunkedList<WeakReference<MetaspaceWrapperObject>> list = new ChunkedList<>(); 62 63 /** 64 * The number of weak references freed since the last time the list was shrunk. 65 */ 66 private int freed; 67 68 /** 69 * The {@link ReferenceQueue} tracking the weak references created by this context. 70 */ 71 private final ReferenceQueue<MetaspaceWrapperObject> queue = new ReferenceQueue<>(); 72 73 static synchronized void add(HotSpotJVMCIMetaAccessContext context) { 74 for (int i = 0; i < allContexts.length; i++) { 75 if (allContexts[i] == null || allContexts[i].get() == null) { 76 allContexts[i] = new WeakReference<>(context); 77 return; 78 } 79 } 80 int index = allContexts.length; 81 allContexts = Arrays.copyOf(allContexts, index + 2); 82 allContexts[index] = new WeakReference<>(context); 83 } 84 85 HotSpotJVMCIMetaAccessContext() { 86 add(this); 87 } 88 89 /** 90 * Periodically trim the list of tracked metadata. A new list is created to replace the old to 91 * avoid concurrent scanning issues. 92 */ 93 private void clean() { 94 Reference<?> ref = queue.poll(); 95 if (ref == null) { 96 return; 97 } 98 while (ref != null) { 99 freed++; 100 ref = queue.poll(); 101 } 102 if (freed > list.size() / 2) { 103 ChunkedList<WeakReference<MetaspaceWrapperObject>> newList = new ChunkedList<>(); 104 for (WeakReference<MetaspaceWrapperObject> element : list) { 105 /* 106 * The referent could become null anywhere in here but it doesn't matter. It will 107 * get cleaned up next time. 108 */ 109 if (element != null && element.get() != null) { 110 newList.add(element); 111 } 112 } 113 list = newList; 114 metadataRoots = list.getHead(); 115 freed = 0; 116 } 117 } 118 119 /** 120 * Add a {@link MetaspaceWrapperObject} to tracked by the GC. It's assumed that the caller is 121 * responsible for keeping the reference alive for the duration of the call. Once registration 122 * is complete then the VM will ensure it's kept alive. 123 * 124 * @param metaspaceObject 125 */ 126 127 public synchronized void add(MetaspaceWrapperObject metaspaceObject) { 128 clean(); 129 list.add(new WeakReference<>(metaspaceObject, queue)); 130 if (list.getHead() != metadataRoots) { 131 /* 132 * The list enlarged so update the head. 133 */ 134 metadataRoots = list.getHead(); 135 } 136 assert isRegistered(metaspaceObject); 137 } 138 139 protected ResolvedJavaType createClass(Class<?> javaClass) { 140 if (javaClass.isPrimitive()) { 141 JavaKind kind = JavaKind.fromJavaClass(javaClass); 142 return new HotSpotResolvedPrimitiveType(kind); 143 } else { 144 return new HotSpotResolvedObjectTypeImpl(javaClass, this); 145 } 146 } 147 148 private final ClassValue<WeakReference<ResolvedJavaType>> resolvedJavaType = new ClassValue<WeakReference<ResolvedJavaType>>() { 149 @Override 150 protected WeakReference<ResolvedJavaType> computeValue(Class<?> type) { 151 return new WeakReference<>(createClass(type)); 152 } 153 }; 154 155 /** 156 * Gets the JVMCI mirror for a {@link Class} object. 157 * 158 * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} 159 */ 160 public ResolvedJavaType fromClass(Class<?> javaClass) { 161 ResolvedJavaType javaType = null; 162 while (javaType == null) { 163 WeakReference<ResolvedJavaType> type = resolvedJavaType.get(javaClass); 164 javaType = type.get(); 165 if (javaType == null) { 166 /* 167 * If the referent has become null, clear out the current value 168 * and let computeValue above create a new value. Reload the 169 * value in a loop because in theory the WeakReference referent 170 * can be reclaimed at any point. 171 */ 172 resolvedJavaType.remove(javaClass); 173 } 174 } 175 return javaType; 176 } 177 178 /** 179 * A very simple append only chunked list implementation. 180 */ 181 static class ChunkedList<T> implements Iterable<T> { 182 private static final int CHUNK_SIZE = 32; 183 184 private static final int NEXT_CHUNK_INDEX = CHUNK_SIZE - 1; 185 186 private Object[] head; 187 private int index; 188 private int size; 189 190 ChunkedList() { 191 head = new Object[CHUNK_SIZE]; 192 index = 0; 193 } 194 195 void add(T element) { 196 if (index == NEXT_CHUNK_INDEX) { 197 Object[] newHead = new Object[CHUNK_SIZE]; 198 newHead[index] = head; 199 head = newHead; 200 index = 0; 201 } 202 head[index++] = element; 203 size++; 204 } 205 206 Object[] getHead() { 207 return head; 208 } 209 210 public Iterator<T> iterator() { 211 return new ChunkIterator<>(); 212 } 213 214 int size() { 215 return size; 216 } 217 218 class ChunkIterator<V> implements Iterator<V> { 219 220 ChunkIterator() { 221 currentChunk = head; 222 currentIndex = -1; 223 next = findNext(); 224 } 225 226 Object[] currentChunk; 227 int currentIndex; 228 V next; 229 230 @SuppressWarnings("unchecked") 231 V findNext() { 232 V result; 233 do { 234 currentIndex++; 235 if (currentIndex == NEXT_CHUNK_INDEX) { 236 currentChunk = (Object[]) currentChunk[currentIndex]; 237 currentIndex = 0; 238 if (currentChunk == null) { 239 return null; 240 } 241 } 242 result = (V) currentChunk[currentIndex]; 243 } while (result == null); 244 return result; 245 } 246 247 public boolean hasNext() { 248 return next != null; 249 } 250 251 public V next() { 252 V result = next; 253 next = findNext(); 254 return result; 255 } 256 257 } 258 259 } 260 261 synchronized boolean isRegistered(MetaspaceWrapperObject wrapper) { 262 for (WeakReference<MetaspaceWrapperObject> m : list) { 263 if (m != null && m.get() == wrapper) { 264 return true; 265 } 266 } 267 return false; 268 } 269 }