src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext.java
branchniosocketimpl-branch
changeset 57347 16c087c9103e
parent 57344 8b621b0d921c
parent 54696 0907dce4b90e
child 57353 ddfb12ab18e1
equal deleted inserted replaced
57344:8b621b0d921c 57347:16c087c9103e
     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 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<>() {
       
   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 and let computeValue
       
   168                  * above create a new value. Reload the value in a loop because in theory the
       
   169                  * WeakReference referent can be reclaimed at any point.
       
   170                  */
       
   171                 resolvedJavaType.remove(javaClass);
       
   172             }
       
   173         }
       
   174         return javaType;
       
   175     }
       
   176 
       
   177     /**
       
   178      * A very simple append only chunked list implementation.
       
   179      */
       
   180     static class ChunkedList<T> implements Iterable<T> {
       
   181         private static final int CHUNK_SIZE = 32;
       
   182 
       
   183         private static final int NEXT_CHUNK_INDEX = CHUNK_SIZE - 1;
       
   184 
       
   185         private Object[] head;
       
   186         private int index;
       
   187         private int size;
       
   188 
       
   189         ChunkedList() {
       
   190             head = new Object[CHUNK_SIZE];
       
   191             index = 0;
       
   192         }
       
   193 
       
   194         void add(T element) {
       
   195             if (index == NEXT_CHUNK_INDEX) {
       
   196                 Object[] newHead = new Object[CHUNK_SIZE];
       
   197                 newHead[index] = head;
       
   198                 head = newHead;
       
   199                 index = 0;
       
   200             }
       
   201             head[index++] = element;
       
   202             size++;
       
   203         }
       
   204 
       
   205         Object[] getHead() {
       
   206             return head;
       
   207         }
       
   208 
       
   209         @Override
       
   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             @Override
       
   248             public boolean hasNext() {
       
   249                 return next != null;
       
   250             }
       
   251 
       
   252             @Override
       
   253             public V next() {
       
   254                 V result = next;
       
   255                 next = findNext();
       
   256                 return result;
       
   257             }
       
   258 
       
   259         }
       
   260 
       
   261     }
       
   262 
       
   263     synchronized boolean isRegistered(MetaspaceWrapperObject wrapper) {
       
   264         for (WeakReference<MetaspaceWrapperObject> m : list) {
       
   265             if (m != null && m.get() == wrapper) {
       
   266                 return true;
       
   267             }
       
   268         }
       
   269         return false;
       
   270     }
       
   271 }