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 }