1/* 2 * Copyright (c) 2014, 2016, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25package jdk.internal.jimage; 26 27import java.lang.ref.WeakReference; 28import java.nio.ByteBuffer; 29import java.util.Arrays; 30import java.util.Comparator; 31 32/** 33 * @implNote This class needs to maintain JDK 8 source compatibility. 34 * 35 * It is used internally in the JDK to implement jimage/jrtfs access, 36 * but also compiled and delivered as part of the jrt-fs.jar to support access 37 * to the jimage file provided by the shipped JDK by tools running on JDK 8. 38 */ 39class ImageBufferCache { 40 private static final int MAX_CACHED_BUFFERS = 3; 41 private static final int LARGE_BUFFER = 0x10000; 42 private static final ThreadLocal<BufferReference[]> CACHE = 43 new ThreadLocal<BufferReference[]>() { 44 @Override 45 protected BufferReference[] initialValue() { 46 // 1 extra slot to simplify logic of releaseBuffer() 47 return new BufferReference[MAX_CACHED_BUFFERS + 1]; 48 } 49 }; 50 51 private static ByteBuffer allocateBuffer(long size) { 52 return ByteBuffer.allocateDirect((int)((size + 0xFFF) & ~0xFFF)); 53 } 54 55 static ByteBuffer getBuffer(long size) { 56 if (size < 0 || Integer.MAX_VALUE < size) { 57 throw new IndexOutOfBoundsException("size"); 58 } 59 60 ByteBuffer result = null; 61 62 if (size > LARGE_BUFFER) { 63 result = allocateBuffer(size); 64 } else { 65 BufferReference[] cache = CACHE.get(); 66 67 // buffers are ordered by decreasing capacity 68 // cache[MAX_CACHED_BUFFERS] is always null 69 for (int i = MAX_CACHED_BUFFERS - 1; i >= 0; i--) { 70 BufferReference reference = cache[i]; 71 72 if (reference != null) { 73 ByteBuffer buffer = reference.get(); 74 75 if (buffer != null && size <= buffer.capacity()) { 76 cache[i] = null; 77 result = buffer; 78 result.rewind(); 79 break; 80 } 81 } 82 } 83 84 if (result == null) { 85 result = allocateBuffer(size); 86 } 87 } 88 89 result.limit((int)size); 90 91 return result; 92 } 93 94 static void releaseBuffer(ByteBuffer buffer) { 95 if (buffer.capacity() > LARGE_BUFFER) { 96 return; 97 } 98 99 BufferReference[] cache = CACHE.get(); 100 101 // expunge cleared BufferRef(s) 102 for (int i = 0; i < MAX_CACHED_BUFFERS; i++) { 103 BufferReference reference = cache[i]; 104 if (reference != null && reference.get() == null) { 105 cache[i] = null; 106 } 107 } 108 109 // insert buffer back with new BufferRef wrapping it 110 cache[MAX_CACHED_BUFFERS] = new BufferReference(buffer); 111 Arrays.sort(cache, DECREASING_CAPACITY_NULLS_LAST); 112 // squeeze the smallest one out 113 cache[MAX_CACHED_BUFFERS] = null; 114 } 115 116 private static Comparator<BufferReference> DECREASING_CAPACITY_NULLS_LAST = 117 new Comparator<BufferReference>() { 118 @Override 119 public int compare(BufferReference br1, BufferReference br2) { 120 return Integer.compare(br2 == null ? 0 : br2.capacity, 121 br1 == null ? 0 : br1.capacity); 122 } 123 }; 124 125 private static class BufferReference extends WeakReference<ByteBuffer> { 126 // saved capacity so that DECREASING_CAPACITY_NULLS_LAST comparator 127 // is stable in the presence of GC clearing the WeakReference concurrently 128 final int capacity; 129 130 BufferReference(ByteBuffer buffer) { 131 super(buffer); 132 capacity = buffer.capacity(); 133 } 134 } 135} 136