Path: blob/master/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java
41159 views
/*1* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.java2d.marlin;2627import static sun.java2d.marlin.ArrayCacheConst.ARRAY_SIZES;28import static sun.java2d.marlin.ArrayCacheConst.BUCKETS;29import static sun.java2d.marlin.ArrayCacheConst.MAX_ARRAY_SIZE;30import static sun.java2d.marlin.MarlinUtils.logInfo;31import static sun.java2d.marlin.MarlinUtils.logException;3233import java.lang.ref.WeakReference;34import java.util.Arrays;3536import sun.java2d.marlin.ArrayCacheConst.BucketStats;37import sun.java2d.marlin.ArrayCacheConst.CacheStats;3839/*40* Note that the [BYTE/INT/FLOAT/DOUBLE]ArrayCache files are nearly identical except41* for a few type and name differences. Typically, the [BYTE]ArrayCache.java file42* is edited manually and then [INT/FLOAT/DOUBLE]ArrayCache.java43* files are generated with the following command lines:44*/45// % sed -e 's/(b\yte)[ ]*//g' -e 's/b\yte/int/g' -e 's/B\yte/Int/g' < B\yteArrayCache.java > IntArrayCache.java46// % sed -e 's/(b\yte)[ ]*0/0.0f/g' -e 's/(b\yte)[ ]*/(float) /g' -e 's/b\yte/float/g' -e 's/B\yte/Float/g' < B\yteArrayCache.java > FloatArrayCache.java47// % sed -e 's/(b\yte)[ ]*0/0.0d/g' -e 's/(b\yte)[ ]*/(double) /g' -e 's/b\yte/double/g' -e 's/B\yte/Double/g' < B\yteArrayCache.java > DoubleArrayCache.java4849final class ByteArrayCache implements MarlinConst {5051final boolean clean;52private final int bucketCapacity;53private WeakReference<Bucket[]> refBuckets = null;54final CacheStats stats;5556ByteArrayCache(final boolean clean, final int bucketCapacity) {57this.clean = clean;58this.bucketCapacity = bucketCapacity;59this.stats = (DO_STATS) ?60new CacheStats(getLogPrefix(clean) + "ByteArrayCache") : null;61}6263Bucket getCacheBucket(final int length) {64final int bucket = ArrayCacheConst.getBucket(length);65return getBuckets()[bucket];66}6768private Bucket[] getBuckets() {69// resolve reference:70Bucket[] buckets = (refBuckets != null) ? refBuckets.get() : null;7172// create a new buckets ?73if (buckets == null) {74buckets = new Bucket[BUCKETS];7576for (int i = 0; i < BUCKETS; i++) {77buckets[i] = new Bucket(clean, ARRAY_SIZES[i], bucketCapacity,78(DO_STATS) ? stats.bucketStats[i] : null);79}8081// update weak reference:82refBuckets = new WeakReference<Bucket[]>(buckets);83}84return buckets;85}8687Reference createRef(final int initialSize) {88return new Reference(this, initialSize);89}9091static final class Reference {9293// initial array reference (direct access)94final byte[] initial;95private final boolean clean;96private final ByteArrayCache cache;9798Reference(final ByteArrayCache cache, final int initialSize) {99this.cache = cache;100this.clean = cache.clean;101this.initial = createArray(initialSize);102if (DO_STATS) {103cache.stats.totalInitial += initialSize;104}105}106107byte[] getArray(final int length) {108if (length <= MAX_ARRAY_SIZE) {109return cache.getCacheBucket(length).getArray();110}111if (DO_STATS) {112cache.stats.oversize++;113}114if (DO_LOG_OVERSIZE) {115logInfo(getLogPrefix(clean) + "ByteArrayCache: "116+ "getArray[oversize]: length=\t" + length);117}118return createArray(length);119}120121byte[] widenArray(final byte[] array, final int usedSize,122final int needSize)123{124final int length = array.length;125if (DO_CHECKS && length >= needSize) {126return array;127}128if (DO_STATS) {129cache.stats.resize++;130}131132// maybe change bucket:133// ensure getNewSize() > newSize:134final byte[] res = getArray(ArrayCacheConst.getNewSize(usedSize, needSize));135136// use wrapper to ensure proper copy:137System.arraycopy(array, 0, res, 0, usedSize); // copy only used elements138139// maybe return current array:140putArray(array, 0, usedSize); // ensure array is cleared141142if (DO_LOG_WIDEN_ARRAY) {143logInfo(getLogPrefix(clean) + "ByteArrayCache: "144+ "widenArray[" + res.length145+ "]: usedSize=\t" + usedSize + "\tlength=\t" + length146+ "\tneeded length=\t" + needSize);147}148return res;149}150151byte[] putArray(final byte[] array)152{153// dirty array helper:154return putArray(array, 0, array.length);155}156157byte[] putArray(final byte[] array, final int fromIndex,158final int toIndex)159{160if (array.length <= MAX_ARRAY_SIZE) {161if ((clean || DO_CLEAN_DIRTY) && (toIndex != 0)) {162// clean-up array of dirty part[fromIndex; toIndex[163fill(array, fromIndex, toIndex, (byte)0);164}165// ensure to never store initial arrays in cache:166if (array != initial) {167cache.getCacheBucket(array.length).putArray(array);168}169}170return initial;171}172}173174static final class Bucket {175176private int tail = 0;177private final int arraySize;178private final boolean clean;179private final byte[][] arrays;180private final BucketStats stats;181182Bucket(final boolean clean, final int arraySize,183final int capacity, final BucketStats stats)184{185this.arraySize = arraySize;186this.clean = clean;187this.stats = stats;188this.arrays = new byte[capacity][];189}190191byte[] getArray() {192if (DO_STATS) {193stats.getOp++;194}195// use cache:196if (tail != 0) {197final byte[] array = arrays[--tail];198arrays[tail] = null;199return array;200}201if (DO_STATS) {202stats.createOp++;203}204return createArray(arraySize);205}206207void putArray(final byte[] array)208{209if (DO_CHECKS && (array.length != arraySize)) {210logInfo(getLogPrefix(clean) + "ByteArrayCache: "211+ "bad length = " + array.length);212return;213}214if (DO_STATS) {215stats.returnOp++;216}217// fill cache:218if (arrays.length > tail) {219arrays[tail++] = array;220221if (DO_STATS) {222stats.updateMaxSize(tail);223}224} else if (DO_CHECKS) {225logInfo(getLogPrefix(clean) + "ByteArrayCache: "226+ "array capacity exceeded !");227}228}229}230231static byte[] createArray(final int length) {232return new byte[length];233}234235static void fill(final byte[] array, final int fromIndex,236final int toIndex, final byte value)237{238// clear array data:239Arrays.fill(array, fromIndex, toIndex, value);240if (DO_CHECKS) {241check(array, fromIndex, toIndex, value);242}243}244245static void check(final byte[] array, final int fromIndex,246final int toIndex, final byte value)247{248if (DO_CHECKS) {249// check zero on full array:250for (int i = 0; i < array.length; i++) {251if (array[i] != value) {252logException("Invalid value at: " + i + " = " + array[i]253+ " from: " + fromIndex + " to: " + toIndex + "\n"254+ Arrays.toString(array), new Throwable());255256// ensure array is correctly filled:257Arrays.fill(array, value);258259return;260}261}262}263}264265static String getLogPrefix(final boolean clean) {266return (clean) ? "Clean" : "Dirty";267}268}269270271