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.  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 
  26 package sun.java2d.marlin;
  27 
  28 import java.util.Arrays;
  29 import static sun.java2d.marlin.MarlinUtils.logInfo;
  30 
  31 public final class ArrayCache implements MarlinConst {
  32 
  33     static final int BUCKETS = 4;
  34     static final int MIN_ARRAY_SIZE = 4096;
  35     static final int MAX_ARRAY_SIZE;
  36     static final int MASK_CLR_1 = ~1;
  37     // threshold to grow arrays only by (3/2) instead of 2
  38     static final int THRESHOLD_ARRAY_SIZE;
  39     static final int[] ARRAY_SIZES = new int[BUCKETS];
  40     // dirty byte array sizes
  41     static final int MIN_DIRTY_BYTE_ARRAY_SIZE = 32 * 2048; // 32px x 2048px
  42     static final int MAX_DIRTY_BYTE_ARRAY_SIZE;
  43     static final int[] DIRTY_BYTE_ARRAY_SIZES = new int[BUCKETS];
  44     // large array thresholds:
  45     static final long THRESHOLD_LARGE_ARRAY_SIZE;
  46     static final long THRESHOLD_HUGE_ARRAY_SIZE;
  47     // stats
  48     private static int resizeInt = 0;
  49     private static int resizeDirtyInt = 0;
  50     private static int resizeDirtyFloat = 0;
  51     private static int resizeDirtyByte = 0;
  52     private static int oversize = 0;
  53 
  54     static {
  55         // initialize buckets for int/float arrays
  56         int arraySize = MIN_ARRAY_SIZE;
  57 
  58         for (int i = 0; i < BUCKETS; i++, arraySize <<= 2) {
  59             ARRAY_SIZES[i] = arraySize;
  60 
  61             if (doTrace) {
  62                 logInfo("arraySize[" + i + "]: " + arraySize);
  63             }
  64         }
  65         MAX_ARRAY_SIZE = arraySize >> 2;
  66 
  67         /* initialize buckets for dirty byte arrays
  68          (large AA chunk = 32 x 2048 pixels) */
  69         arraySize = MIN_DIRTY_BYTE_ARRAY_SIZE;
  70 
  71         for (int i = 0; i < BUCKETS; i++, arraySize <<= 1) {
  72             DIRTY_BYTE_ARRAY_SIZES[i] = arraySize;
  73 
  74             if (doTrace) {
  75                 logInfo("dirty arraySize[" + i + "]: " + arraySize);
  76             }
  77         }
  78         MAX_DIRTY_BYTE_ARRAY_SIZE = arraySize >> 1;
  79 
  80         // threshold to grow arrays only by (3/2) instead of 2
  81         THRESHOLD_ARRAY_SIZE = Math.max(2 * 1024 * 1024, MAX_ARRAY_SIZE); // 2M
  82 
  83         THRESHOLD_LARGE_ARRAY_SIZE = 8L * THRESHOLD_ARRAY_SIZE; // 16M
  84         THRESHOLD_HUGE_ARRAY_SIZE  = 8L * THRESHOLD_LARGE_ARRAY_SIZE; // 128M
  85 
  86         if (doStats || doMonitors) {
  87             logInfo("ArrayCache.BUCKETS        = " + BUCKETS);
  88             logInfo("ArrayCache.MIN_ARRAY_SIZE = " + MIN_ARRAY_SIZE);
  89             logInfo("ArrayCache.MAX_ARRAY_SIZE = " + MAX_ARRAY_SIZE);
  90             logInfo("ArrayCache.ARRAY_SIZES = "
  91                     + Arrays.toString(ARRAY_SIZES));
  92             logInfo("ArrayCache.MIN_DIRTY_BYTE_ARRAY_SIZE = "
  93                     + MIN_DIRTY_BYTE_ARRAY_SIZE);
  94             logInfo("ArrayCache.MAX_DIRTY_BYTE_ARRAY_SIZE = "
  95                     + MAX_DIRTY_BYTE_ARRAY_SIZE);
  96             logInfo("ArrayCache.ARRAY_SIZES = "
  97                     + Arrays.toString(DIRTY_BYTE_ARRAY_SIZES));
  98             logInfo("ArrayCache.THRESHOLD_ARRAY_SIZE = "
  99                     + THRESHOLD_ARRAY_SIZE);
 100             logInfo("ArrayCache.THRESHOLD_LARGE_ARRAY_SIZE = "
 101                     + THRESHOLD_LARGE_ARRAY_SIZE);
 102             logInfo("ArrayCache.THRESHOLD_HUGE_ARRAY_SIZE = "
 103                     + THRESHOLD_HUGE_ARRAY_SIZE);
 104         }
 105     }
 106 
 107     private ArrayCache() {
 108         // Utility class
 109     }
 110 
 111     static synchronized void incResizeInt() {
 112         resizeInt++;
 113     }
 114 
 115     static synchronized void incResizeDirtyInt() {
 116         resizeDirtyInt++;
 117     }
 118 
 119     static synchronized void incResizeDirtyFloat() {
 120         resizeDirtyFloat++;
 121     }
 122 
 123     static synchronized void incResizeDirtyByte() {
 124         resizeDirtyByte++;
 125     }
 126 
 127     static synchronized void incOversize() {
 128         oversize++;
 129     }
 130 
 131     static void dumpStats() {
 132         if (resizeInt != 0 || resizeDirtyInt != 0 || resizeDirtyFloat != 0
 133                 || resizeDirtyByte != 0 || oversize != 0) {
 134             logInfo("ArrayCache: int resize: " + resizeInt
 135                     + " - dirty int resize: " + resizeDirtyInt
 136                     + " - dirty float resize: " + resizeDirtyFloat
 137                     + " - dirty byte resize: " + resizeDirtyByte
 138                     + " - oversize: " + oversize);
 139         }
 140     }
 141 
 142     // small methods used a lot (to be inlined / optimized by hotspot)
 143 
 144     static int getBucket(final int length) {
 145         for (int i = 0; i < ARRAY_SIZES.length; i++) {
 146             if (length <= ARRAY_SIZES[i]) {
 147                 return i;
 148             }
 149         }
 150         return -1;
 151     }
 152 
 153     static int getBucketDirtyBytes(final int length) {
 154         for (int i = 0; i < DIRTY_BYTE_ARRAY_SIZES.length; i++) {
 155             if (length <= DIRTY_BYTE_ARRAY_SIZES[i]) {
 156                 return i;
 157             }
 158         }
 159         return -1;
 160     }
 161 
 162     /**
 163      * Return the new array size (~ x2)
 164      * @param curSize current used size
 165      * @param needSize needed size
 166      * @return new array size
 167      */
 168     public static int getNewSize(final int curSize, final int needSize) {
 169         final int initial = (curSize & MASK_CLR_1);
 170         int size;
 171         if (initial > THRESHOLD_ARRAY_SIZE) {
 172             size = initial + (initial >> 1); // x(3/2)
 173         } else {
 174             size = (initial) << 1; // x2
 175         }
 176         // ensure the new size is >= needed size:
 177         if (size < needSize) {
 178             // align to 4096:
 179             size = ((needSize >> 12) + 1) << 12;
 180         }
 181         return size;
 182     }
 183 
 184     /**
 185      * Return the new array size (~ x2)
 186      * @param curSize current used size
 187      * @param needSize needed size
 188      * @return new array size
 189      */
 190     public static long getNewLargeSize(final long curSize, final long needSize) {
 191         long size;
 192         if (curSize > THRESHOLD_HUGE_ARRAY_SIZE) {
 193             size = curSize + (curSize >> 2L); // x(5/4)
 194         } else  if (curSize > THRESHOLD_LARGE_ARRAY_SIZE) {
 195             size = curSize + (curSize >> 1L); // x(3/2)
 196         } else {
 197             size = curSize << 1L; // x2
 198         }
 199         // ensure the new size is >= needed size:
 200         if (size < needSize) {
 201             // align to 4096:
 202             size = ((needSize >> 12) + 1) << 12;
 203         }
 204         if (size >= Integer.MAX_VALUE) {
 205             if (curSize >= Integer.MAX_VALUE) {
 206                 // hard overflow failure - we can't even accommodate
 207                 // new items without overflowing
 208                 throw new ArrayIndexOutOfBoundsException(
 209                               "array exceeds maximum capacity !");
 210             }
 211             // resize to maximum capacity:
 212             size = Integer.MAX_VALUE;
 213         }
 214         return size;
 215     }
 216 }