1 /* 2 * Copyright (c) 2014, 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 */ 25 package jdk.internal.jimage; 26 27 import java.nio.ByteBuffer; 28 import java.util.ArrayList; 29 30 class ImageBufferCache { 31 private static final int MAX_FREE_BUFFERS = 3; 32 private static final int LARGE_BUFFER = 0x10000; 33 private static final ThreadLocal<ArrayList<ImageBufferCache>> 34 threadLocal = new ThreadLocal<>(); 35 36 private final ByteBuffer buffer; 37 private boolean isUsed; 38 39 static ByteBuffer getBuffer(long size) { 40 assert size < Integer.MAX_VALUE; 41 ByteBuffer buffer = null; 42 43 if (size > LARGE_BUFFER) { 44 buffer = ByteBuffer.allocateDirect((int)((size + 0xFFF) & ~0xFFF)); 45 } else { 46 ArrayList<ImageBufferCache> buffers = threadLocal.get(); 47 48 if (buffers == null) { 49 buffers = new ArrayList<>(MAX_FREE_BUFFERS); 50 threadLocal.set(buffers); 51 } 52 53 int i = 0, j = buffers.size(); 54 for (ImageBufferCache imageBuffer : buffers) { 55 if (size <= imageBuffer.capacity()) { 56 j = i; 57 58 if (!imageBuffer.isUsed) { 59 imageBuffer.isUsed = true; 60 buffer = imageBuffer.buffer; 61 62 break; 63 } 64 } else { 65 break; 66 } 67 68 i++; 69 } 70 71 if (buffer == null) { 72 ImageBufferCache imageBuffer = new ImageBufferCache((int)size); 73 buffers.add(j, imageBuffer); 74 buffer = imageBuffer.buffer; 75 } 76 } 77 78 buffer.rewind(); 79 buffer.limit((int)size); 80 81 return buffer; 82 } 83 84 static void releaseBuffer(ByteBuffer buffer) { 85 ArrayList<ImageBufferCache> buffers = threadLocal.get(); 86 87 if (buffers == null ) { 88 return; 89 } 90 91 if (buffer.capacity() > LARGE_BUFFER) { 92 return; 93 } 94 95 int i = 0, j = buffers.size(); 96 for (ImageBufferCache imageBuffer : buffers) { 97 if (!imageBuffer.isUsed) { 98 j = Math.min(j, i); 99 } 100 101 if (imageBuffer.buffer == buffer) { 102 imageBuffer.isUsed = false; 103 j = Math.min(j, i); 104 105 break; 106 } 107 } 108 109 if (buffers.size() > MAX_FREE_BUFFERS && j != buffers.size()) { 110 buffers.remove(j); 111 } 112 } 113 114 private ImageBufferCache(int needed) { 115 this.buffer = ByteBuffer.allocateDirect((needed + 0xFFF) & ~0xFFF); 116 this.isUsed = true; 117 this.buffer.limit(needed); 118 } 119 120 private long capacity() { 121 return buffer.capacity(); 122 } 123 }