jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java
changeset 40421 d5ee65e2b0fb
parent 39519 21bfc4452441
child 47126 188ef162f019
--- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java	Wed Aug 03 14:49:01 2016 +0530
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java	Wed Aug 03 22:53:38 2016 +0200
@@ -29,10 +29,8 @@
 import java.lang.ref.WeakReference;
 import java.util.concurrent.atomic.AtomicInteger;
 import sun.java2d.ReentrantContext;
-import sun.java2d.ReentrantContextProvider;
-import static sun.java2d.marlin.ArrayCache.*;
+import sun.java2d.marlin.ArrayCacheConst.CacheStats;
 import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator;
-import static sun.java2d.marlin.MarlinUtils.logInfo;
 
 /**
  * This class is a renderer context dedicated to a single thread
@@ -41,12 +39,6 @@
 
     // RendererContext creation counter
     private static final AtomicInteger CTX_COUNT = new AtomicInteger(1);
-    // RendererContext statistics
-    final RendererStats stats = (DO_STATS || DO_MONITORS)
-                                       ? RendererStats.getInstance(): null;
-
-    private static final boolean USE_CACHE_HARD_REF = DO_STATS
-        || (MarlinRenderingEngine.REF_TYPE == ReentrantContextProvider.REF_WEAK);
 
     /**
      * Create a new renderer context
@@ -54,25 +46,14 @@
      * @return new RendererContext instance
      */
     static RendererContext createContext() {
-        final RendererContext newCtx = new RendererContext("ctx"
-                    + Integer.toString(CTX_COUNT.getAndIncrement()));
-
-        if (DO_STATS || DO_MONITORS) {
-            RendererStats.ALL_CONTEXTS.add(newCtx);
-        }
-        return newCtx;
+        return new RendererContext("ctx"
+                       + Integer.toString(CTX_COUNT.getAndIncrement()));
     }
 
-    // context name (debugging purposes)
-    final String name;
     // Smallest object used as Cleaner's parent reference
-    final Object cleanerObj = new Object();
+    private final Object cleanerObj;
     // dirty flag indicating an exception occured during pipeline in pathTo()
     boolean dirty = false;
-    // dynamic array caches kept using weak reference (low memory footprint)
-    WeakReference<ArrayCachesHolder> refArrayCaches = null;
-    // hard reference to array caches (for statistics)
-    ArrayCachesHolder hardRefArrayCaches = null;
     // shared data
     final float[] float6 = new float[6];
     // shared curve (dirty) (Renderer / Stroker)
@@ -83,8 +64,8 @@
     final NormalizingPathIterator nPQPathIterator;
     // MarlinRenderingEngine.TransformingPathConsumer2D
     final TransformingPathConsumer2D transformerPC2D;
-    // recycled Path2D instance
-    Path2D.Float p2d = null;
+    // recycled Path2D instance (weak)
+    private WeakReference<Path2D.Float> refPath2D = null;
     final Renderer renderer;
     final Stroker stroker;
     // Simplifies out collinear lines
@@ -95,6 +76,19 @@
     // flag indicating the shape is stroked (1) or filled (0)
     int stroking = 0;
 
+    // Array caches:
+    /* clean int[] cache (zero-filled) = 5 refs */
+    private final IntArrayCache cleanIntCache = new IntArrayCache(true, 5);
+    /* dirty int[] cache = 4 refs */
+    private final IntArrayCache dirtyIntCache = new IntArrayCache(false, 4);
+    /* dirty float[] cache = 3 refs */
+    private final FloatArrayCache dirtyFloatCache = new FloatArrayCache(false, 3);
+    /* dirty byte[] cache = 1 ref */
+    private final ByteArrayCache dirtyByteCache = new ByteArrayCache(false, 1);
+
+    // RendererContext statistics
+    final RendererStats stats;
+
     /**
      * Constructor
      *
@@ -104,8 +98,18 @@
         if (LOG_CREATE_CONTEXT) {
             MarlinUtils.logInfo("new RendererContext = " + name);
         }
+        this.cleanerObj = new Object();
 
-        this.name = name;
+        // create first stats (needed by newOffHeapArray):
+        if (DO_STATS || DO_MONITORS) {
+            stats = RendererStats.createInstance(cleanerObj, name);
+            // push cache stats:
+            stats.cacheStats = new CacheStats[] { cleanIntCache.stats,
+                dirtyIntCache.stats, dirtyFloatCache.stats, dirtyByteCache.stats
+            };
+        } else {
+            stats = null;
+        }
 
         // NormalizingPathIterator instances:
         nPCPathIterator = new NormalizingPathIterator.NearestPixelCenter(float6);
@@ -128,11 +132,13 @@
      * clean up before reusing this context
      */
     void dispose() {
+        if (DO_STATS) {
+            if (stats.totalOffHeap > stats.totalOffHeapMax) {
+                stats.totalOffHeapMax = stats.totalOffHeap;
+            }
+            stats.totalOffHeap = 0L;
+        }
         stroking = 0;
-        // reset hard reference to array caches if needed:
-        if (!USE_CACHE_HARD_REF) {
-            hardRefArrayCaches = null;
-        }
         // if context is maked as DIRTY:
         if (dirty) {
             // may happen if an exception if thrown in the pipeline processing:
@@ -151,300 +157,43 @@
         }
     }
 
-    // Array caches
-    ArrayCachesHolder getArrayCachesHolder() {
-        // Use hard reference first (cached resolved weak reference):
-        ArrayCachesHolder holder = hardRefArrayCaches;
-        if (holder == null) {
-            // resolve reference:
-            holder = (refArrayCaches != null)
-                     ? refArrayCaches.get()
-                     : null;
-            // create a new ArrayCachesHolder if none is available
-            if (holder == null) {
-                if (LOG_CREATE_CONTEXT) {
-                    MarlinUtils.logInfo("new ArrayCachesHolder for "
-                                        + "RendererContext = " + name);
-                }
-
-                holder = new ArrayCachesHolder();
-
-                if (USE_CACHE_HARD_REF) {
-                    // update hard reference:
-                    hardRefArrayCaches = holder;
-                } else {
-                    // update weak reference:
-                    refArrayCaches = new WeakReference<ArrayCachesHolder>(holder);
-                }
-            }
-        }
-        return holder;
-    }
+    Path2D.Float getPath2D() {
+        // resolve reference:
+        Path2D.Float p2d
+            = (refPath2D != null) ? refPath2D.get() : null;
 
-    // dirty byte array cache
-    ByteArrayCache getDirtyByteArrayCache(final int length) {
-        final int bucket = ArrayCache.getBucketDirtyBytes(length);
-        return getArrayCachesHolder().dirtyByteArrayCaches[bucket];
-    }
-
-    byte[] getDirtyByteArray(final int length) {
-        if (length <= MAX_DIRTY_BYTE_ARRAY_SIZE) {
-            return getDirtyByteArrayCache(length).getArray();
-        }
-
-        if (DO_STATS) {
-            incOversize();
-        }
-
-        if (DO_LOG_OVERSIZE) {
-            logInfo("getDirtyByteArray[oversize]: length=\t" + length);
-        }
+        // create a new Path2D ?
+        if (p2d == null) {
+            p2d = new Path2D.Float(Path2D.WIND_NON_ZERO, INITIAL_EDGES_COUNT); // 32K
 
-        return new byte[length];
-    }
-
-    void putDirtyByteArray(final byte[] array) {
-        final int length = array.length;
-        // odd sized array are non-cached arrays (initial arrays)
-        // ensure to never store initial arrays in cache:
-        if (((length & 0x1) == 0) && (length <= MAX_DIRTY_BYTE_ARRAY_SIZE)) {
-            getDirtyByteArrayCache(length).putDirtyArray(array, length);
-        }
-    }
-
-    byte[] widenDirtyByteArray(final byte[] in,
-                               final int usedSize, final int needSize)
-    {
-        final int length = in.length;
-        if (DO_CHECKS && length >= needSize) {
-            return in;
+            // update weak reference:
+            refPath2D = new WeakReference<Path2D.Float>(p2d);
         }
-        if (DO_STATS) {
-            incResizeDirtyByte();
-        }
-
-        // maybe change bucket:
-        // ensure getNewSize() > newSize:
-        final byte[] res = getDirtyByteArray(getNewSize(usedSize, needSize));
-
-        System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
-
-        // maybe return current array:
-        // NO clean-up of array data = DIRTY ARRAY
-        putDirtyByteArray(in);
-
-        if (DO_LOG_WIDEN_ARRAY) {
-            logInfo("widenDirtyByteArray[" + res.length + "]: usedSize=\t"
-                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
-                    + needSize);
-        }
-        return res;
-    }
-
-    // int array cache
-    IntArrayCache getIntArrayCache(final int length) {
-        final int bucket = ArrayCache.getBucket(length);
-        return getArrayCachesHolder().intArrayCaches[bucket];
-    }
-
-    int[] getIntArray(final int length) {
-        if (length <= MAX_ARRAY_SIZE) {
-            return getIntArrayCache(length).getArray();
-        }
-
-        if (DO_STATS) {
-            incOversize();
-        }
-
-        if (DO_LOG_OVERSIZE) {
-            logInfo("getIntArray[oversize]: length=\t" + length);
-        }
-
-        return new int[length];
-    }
-
-    // unused
-    int[] widenIntArray(final int[] in, final int usedSize,
-                        final int needSize, final int clearTo)
-    {
-        final int length = in.length;
-        if (DO_CHECKS && length >= needSize) {
-            return in;
-        }
-        if (DO_STATS) {
-            incResizeInt();
-        }
-
-        // maybe change bucket:
-        // ensure getNewSize() > newSize:
-        final int[] res = getIntArray(getNewSize(usedSize, needSize));
-
-        System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
-
-        // maybe return current array:
-        putIntArray(in, 0, clearTo); // ensure all array is cleared (grow-reduce algo)
-
-        if (DO_LOG_WIDEN_ARRAY) {
-            logInfo("widenIntArray[" + res.length + "]: usedSize=\t"
-                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
-                    + needSize);
-        }
-        return res;
+        // reset the path anyway:
+        p2d.reset();
+        return p2d;
     }
 
-    void putIntArray(final int[] array, final int fromIndex,
-                     final int toIndex)
-    {
-        final int length = array.length;
-        // odd sized array are non-cached arrays (initial arrays)
-        // ensure to never store initial arrays in cache:
-        if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {
-            getIntArrayCache(length).putArray(array, length, fromIndex, toIndex);
+    OffHeapArray newOffHeapArray(final long initialSize) {
+        if (DO_STATS) {
+            stats.totalOffHeapInitial += initialSize;
         }
-    }
-
-    // dirty int array cache
-    IntArrayCache getDirtyIntArrayCache(final int length) {
-        final int bucket = ArrayCache.getBucket(length);
-        return getArrayCachesHolder().dirtyIntArrayCaches[bucket];
-    }
-
-    int[] getDirtyIntArray(final int length) {
-        if (length <= MAX_ARRAY_SIZE) {
-            return getDirtyIntArrayCache(length).getArray();
-        }
-
-        if (DO_STATS) {
-            incOversize();
-        }
-
-        if (DO_LOG_OVERSIZE) {
-            logInfo("getDirtyIntArray[oversize]: length=\t" + length);
-        }
-
-        return new int[length];
+        return new OffHeapArray(cleanerObj, initialSize);
     }
 
-    int[] widenDirtyIntArray(final int[] in,
-                             final int usedSize, final int needSize)
-    {
-        final int length = in.length;
-        if (DO_CHECKS && length >= needSize) {
-            return in;
-        }
-        if (DO_STATS) {
-            incResizeDirtyInt();
-        }
-
-        // maybe change bucket:
-        // ensure getNewSize() > newSize:
-        final int[] res = getDirtyIntArray(getNewSize(usedSize, needSize));
-
-        System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
-
-        // maybe return current array:
-        // NO clean-up of array data = DIRTY ARRAY
-        putDirtyIntArray(in);
-
-        if (DO_LOG_WIDEN_ARRAY) {
-            logInfo("widenDirtyIntArray[" + res.length + "]: usedSize=\t"
-                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
-                    + needSize);
-        }
-        return res;
-    }
-
-    void putDirtyIntArray(final int[] array) {
-        final int length = array.length;
-        // odd sized array are non-cached arrays (initial arrays)
-        // ensure to never store initial arrays in cache:
-        if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {
-            getDirtyIntArrayCache(length).putDirtyArray(array, length);
-        }
-    }
-
-    // dirty float array cache
-    FloatArrayCache getDirtyFloatArrayCache(final int length) {
-        final int bucket = ArrayCache.getBucket(length);
-        return getArrayCachesHolder().dirtyFloatArrayCaches[bucket];
+    IntArrayCache.Reference newCleanIntArrayRef(final int initialSize) {
+        return cleanIntCache.createRef(initialSize);
     }
 
-    float[] getDirtyFloatArray(final int length) {
-        if (length <= MAX_ARRAY_SIZE) {
-            return getDirtyFloatArrayCache(length).getArray();
-        }
-
-        if (DO_STATS) {
-            incOversize();
-        }
-
-        if (DO_LOG_OVERSIZE) {
-            logInfo("getDirtyFloatArray[oversize]: length=\t" + length);
-        }
-
-        return new float[length];
+    IntArrayCache.Reference newDirtyIntArrayRef(final int initialSize) {
+        return dirtyIntCache.createRef(initialSize);
     }
 
-    float[] widenDirtyFloatArray(final float[] in,
-                                 final int usedSize, final int needSize)
-    {
-        final int length = in.length;
-        if (DO_CHECKS && length >= needSize) {
-            return in;
-        }
-        if (DO_STATS) {
-            incResizeDirtyFloat();
-        }
-
-        // maybe change bucket:
-        // ensure getNewSize() > newSize:
-        final float[] res = getDirtyFloatArray(getNewSize(usedSize, needSize));
-
-        System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
-
-        // maybe return current array:
-        // NO clean-up of array data = DIRTY ARRAY
-        putDirtyFloatArray(in);
-
-        if (DO_LOG_WIDEN_ARRAY) {
-            logInfo("widenDirtyFloatArray[" + res.length + "]: usedSize=\t"
-                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
-                    + needSize);
-        }
-        return res;
+    FloatArrayCache.Reference newDirtyFloatArrayRef(final int initialSize) {
+        return dirtyFloatCache.createRef(initialSize);
     }
 
-    void putDirtyFloatArray(final float[] array) {
-        final int length = array.length;
-        // odd sized array are non-cached arrays (initial arrays)
-        // ensure to never store initial arrays in cache:
-        if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {
-            getDirtyFloatArrayCache(length).putDirtyArray(array, length);
-        }
-    }
-
-    /* class holding all array cache instances */
-    static final class ArrayCachesHolder {
-        // zero-filled int array cache:
-        final IntArrayCache[] intArrayCaches;
-        // dirty array caches:
-        final IntArrayCache[] dirtyIntArrayCaches;
-        final FloatArrayCache[] dirtyFloatArrayCaches;
-        final ByteArrayCache[] dirtyByteArrayCaches;
-
-        ArrayCachesHolder() {
-            intArrayCaches = new IntArrayCache[BUCKETS];
-            dirtyIntArrayCaches = new IntArrayCache[BUCKETS];
-            dirtyFloatArrayCaches = new FloatArrayCache[BUCKETS];
-            dirtyByteArrayCaches = new ByteArrayCache[BUCKETS];
-
-            for (int i = 0; i < BUCKETS; i++) {
-                intArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]);
-                // dirty array caches:
-                dirtyIntArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]);
-                dirtyFloatArrayCaches[i] = new FloatArrayCache(ARRAY_SIZES[i]);
-                dirtyByteArrayCaches[i] = new ByteArrayCache(DIRTY_BYTE_ARRAY_SIZES[i]);
-            }
-        }
+    ByteArrayCache.Reference newDirtyByteArrayRef(final int initialSize) {
+        return dirtyByteCache.createRef(initialSize);
     }
 }