diff --git a/src/java.desktop/share/classes/sun/java2d/loops/Blit.java b/src/java.desktop/share/classes/sun/java2d/loops/Blit.java index 0d3a4ac4f24..c5d29bb3e9c 100644 --- a/src/java.desktop/share/classes/sun/java2d/loops/Blit.java +++ b/src/java.desktop/share/classes/sun/java2d/loops/Blit.java @@ -36,6 +36,7 @@ import java.lang.ref.WeakReference; import sun.java2d.SurfaceData; import sun.java2d.pipe.Region; import sun.java2d.pipe.SpanIterator; +import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives; /** * Blit @@ -111,7 +112,7 @@ public class Blit extends GraphicsPrimitive int width, int height); static { - GraphicsPrimitiveMgr.registerGeneral(new Blit(null, null, null)); + GeneralPrimitives.register(new Blit(null, null, null)); } protected GraphicsPrimitive makePrimitive(SurfaceType srctype, diff --git a/src/java.desktop/share/classes/sun/java2d/loops/BlitBg.java b/src/java.desktop/share/classes/sun/java2d/loops/BlitBg.java index ffe5901a57d..8531c2d429f 100644 --- a/src/java.desktop/share/classes/sun/java2d/loops/BlitBg.java +++ b/src/java.desktop/share/classes/sun/java2d/loops/BlitBg.java @@ -37,6 +37,7 @@ import sun.awt.image.BufImgSurfaceData; import sun.java2d.SunGraphics2D; import sun.java2d.SurfaceData; import sun.java2d.pipe.Region; +import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives; /** * BlitBg @@ -114,7 +115,7 @@ public class BlitBg extends GraphicsPrimitive int width, int height); static { - GraphicsPrimitiveMgr.registerGeneral(new BlitBg(null, null, null)); + GeneralPrimitives.register(new BlitBg(null, null, null)); } protected GraphicsPrimitive makePrimitive(SurfaceType srctype, diff --git a/src/java.desktop/share/classes/sun/java2d/loops/DrawGlyphList.java b/src/java.desktop/share/classes/sun/java2d/loops/DrawGlyphList.java index dfc4fa34928..35a3aa75bf6 100644 --- a/src/java.desktop/share/classes/sun/java2d/loops/DrawGlyphList.java +++ b/src/java.desktop/share/classes/sun/java2d/loops/DrawGlyphList.java @@ -29,6 +29,7 @@ import sun.font.GlyphList; import sun.java2d.SunGraphics2D; import sun.java2d.SurfaceData; import sun.java2d.pipe.Region; +import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives; /** * DrawGlyphList - loops for SolidTextRenderer pipe. @@ -73,7 +74,7 @@ public class DrawGlyphList extends GraphicsPrimitive { // This instance is used only for lookup. static { - GraphicsPrimitiveMgr.registerGeneral( + GeneralPrimitives.register( new DrawGlyphList(null, null, null)); } diff --git a/src/java.desktop/share/classes/sun/java2d/loops/DrawGlyphListAA.java b/src/java.desktop/share/classes/sun/java2d/loops/DrawGlyphListAA.java index dd1f2b3e8f9..e4b5b51661a 100644 --- a/src/java.desktop/share/classes/sun/java2d/loops/DrawGlyphListAA.java +++ b/src/java.desktop/share/classes/sun/java2d/loops/DrawGlyphListAA.java @@ -29,6 +29,7 @@ import sun.font.GlyphList; import sun.java2d.SunGraphics2D; import sun.java2d.SurfaceData; import sun.java2d.pipe.Region; +import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives; /** * DrawGlyphListAA - loops for AATextRenderer pipe @@ -71,7 +72,7 @@ public class DrawGlyphListAA extends GraphicsPrimitive { int fromGlyph, int toGlyph); static { - GraphicsPrimitiveMgr.registerGeneral( + GeneralPrimitives.register( new DrawGlyphListAA(null, null, null)); } diff --git a/src/java.desktop/share/classes/sun/java2d/loops/DrawGlyphListColor.java b/src/java.desktop/share/classes/sun/java2d/loops/DrawGlyphListColor.java index 55ceaf4ce4e..262a0c16b56 100644 --- a/src/java.desktop/share/classes/sun/java2d/loops/DrawGlyphListColor.java +++ b/src/java.desktop/share/classes/sun/java2d/loops/DrawGlyphListColor.java @@ -29,6 +29,7 @@ import sun.font.GlyphList; import sun.java2d.SunGraphics2D; import sun.java2d.SurfaceData; import sun.java2d.pipe.Region; +import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives; import java.awt.*; @@ -67,7 +68,7 @@ public class DrawGlyphListColor extends GraphicsPrimitive { // This instance is used only for lookup. static { - GraphicsPrimitiveMgr.registerGeneral( + GeneralPrimitives.register( new DrawGlyphListColor(null, null, null)); } diff --git a/src/java.desktop/share/classes/sun/java2d/loops/FillRect.java b/src/java.desktop/share/classes/sun/java2d/loops/FillRect.java index e12a05da0ab..0edf701c9f2 100644 --- a/src/java.desktop/share/classes/sun/java2d/loops/FillRect.java +++ b/src/java.desktop/share/classes/sun/java2d/loops/FillRect.java @@ -31,6 +31,7 @@ package sun.java2d.loops; import sun.java2d.SunGraphics2D; import sun.java2d.SurfaceData; +import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives; /** * FillRect @@ -75,7 +76,7 @@ public class FillRect extends GraphicsPrimitive int x, int y, int w, int h); static { - GraphicsPrimitiveMgr.registerGeneral(new FillRect(null, null, null)); + GeneralPrimitives.register(new FillRect(null, null, null)); } protected GraphicsPrimitive makePrimitive(SurfaceType srctype, diff --git a/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitiveMgr.java b/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitiveMgr.java index 5fb4e26f118..b029a437b35 100644 --- a/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitiveMgr.java +++ b/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitiveMgr.java @@ -42,7 +42,6 @@ public final class GraphicsPrimitiveMgr { private static final boolean debugTrace = false; private static GraphicsPrimitive[] primitives; - private static GraphicsPrimitive[] generalPrimitives; private static boolean needssort = true; private static native void initIDs(Class GP, Class ST, Class CT, @@ -121,24 +120,6 @@ public final class GraphicsPrimitiveMgr { primitives = temp; } - /** - * Registers the general loop which will be used to produce specific - * primitives by the {@link GraphicsPrimitive#makePrimitive} function. - * - * @param gen the graphics primitive to be registered as the general loop - */ - public static synchronized void registerGeneral(GraphicsPrimitive gen) { - if (generalPrimitives == null) { - generalPrimitives = new GraphicsPrimitive[] {gen}; - return; - } - int len = generalPrimitives.length; - GraphicsPrimitive[] newGen = new GraphicsPrimitive[len + 1]; - System.arraycopy(generalPrimitives, 0, newGen, 0, len); - newGen[len] = gen; - generalPrimitives = newGen; - } - public static synchronized GraphicsPrimitive locate(int primTypeID, SurfaceType dsttype) { @@ -165,7 +146,7 @@ public final class GraphicsPrimitiveMgr { if (prim == null) { //System.out.println("Trying general loop"); - prim = locateGeneral(primTypeID); + prim = GeneralPrimitives.locate(primTypeID); if (prim != null) { prim = prim.makePrimitive(srctype, comptype, dsttype); if (prim != null && GraphicsPrimitive.traceflags != 0) { @@ -218,20 +199,6 @@ public final class GraphicsPrimitiveMgr { return null; } - private static GraphicsPrimitive locateGeneral(int primTypeID) { - if (generalPrimitives == null) { - return null; - } - for (int i = 0; i < generalPrimitives.length; i++) { - GraphicsPrimitive prim = generalPrimitives[i]; - if (prim.getPrimTypeID() == primTypeID) { - return prim; - } - } - return null; - //throw new InternalError("No general handler registered for"+signature); - } - private static GraphicsPrimitive locate(PrimitiveSpec spec) { if (needssort) { if (GraphicsPrimitive.traceflags != 0) { @@ -274,6 +241,46 @@ public final class GraphicsPrimitiveMgr { } } + /** + * A holder for general primitives to avoid circular dependencies + * between GraphicsPrimitiveMgr and Blit/etc classes. + */ + final static class GeneralPrimitives { + + private static GraphicsPrimitive[] primitives; + + /** + * Registers the general loop which will be used to produce specific + * primitives by the {@link GraphicsPrimitive#makePrimitive} function. + * + * @param gen the graphics primitive to be registered as the general loop + */ + static synchronized void register(GraphicsPrimitive gen) { + if (primitives == null) { + primitives = new GraphicsPrimitive[]{gen}; + return; + } + int len = primitives.length; + GraphicsPrimitive[] newGen = new GraphicsPrimitive[len + 1]; + System.arraycopy(primitives, 0, newGen, 0, len); + newGen[len] = gen; + primitives = newGen; + } + + static synchronized GraphicsPrimitive locate(int primTypeID) { + if (primitives == null) { + return null; + } + for (int i = 0; i < primitives.length; i++) { + GraphicsPrimitive prim = primitives[i]; + if (prim.getPrimTypeID() == primTypeID) { + return prim; + } + } + return null; + } + } + /** * Test that all of the GraphicsPrimitiveProxy objects actually * resolve to something. Throws a RuntimeException if anything diff --git a/src/java.desktop/share/classes/sun/java2d/loops/MaskBlit.java b/src/java.desktop/share/classes/sun/java2d/loops/MaskBlit.java index 414e800dd1b..c80981184b8 100644 --- a/src/java.desktop/share/classes/sun/java2d/loops/MaskBlit.java +++ b/src/java.desktop/share/classes/sun/java2d/loops/MaskBlit.java @@ -30,6 +30,7 @@ import java.lang.ref.WeakReference; import sun.java2d.SurfaceData; import sun.java2d.pipe.Region; +import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives; /** * MaskBlit @@ -109,7 +110,7 @@ public class MaskBlit extends GraphicsPrimitive byte[] mask, int maskoff, int maskscan); static { - GraphicsPrimitiveMgr.registerGeneral(new MaskBlit(null, null, null)); + GeneralPrimitives.register(new MaskBlit(null, null, null)); } protected GraphicsPrimitive makePrimitive(SurfaceType srctype, diff --git a/src/java.desktop/share/classes/sun/java2d/loops/MaskFill.java b/src/java.desktop/share/classes/sun/java2d/loops/MaskFill.java index 108b235d585..9a04e34186f 100644 --- a/src/java.desktop/share/classes/sun/java2d/loops/MaskFill.java +++ b/src/java.desktop/share/classes/sun/java2d/loops/MaskFill.java @@ -32,6 +32,7 @@ import sun.awt.image.BufImgSurfaceData; import sun.java2d.SunGraphics2D; import sun.java2d.SurfaceData; import sun.java2d.pipe.Region; +import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives; /** * MaskFill @@ -141,7 +142,7 @@ public class MaskFill extends GraphicsPrimitive } static { - GraphicsPrimitiveMgr.registerGeneral(new MaskFill(null, null, null)); + GeneralPrimitives.register(new MaskFill(null, null, null)); } protected GraphicsPrimitive makePrimitive(SurfaceType srctype, diff --git a/test/jdk/sun/java2d/loops/GraphicsPrimitiveMgrTest.java b/test/jdk/sun/java2d/loops/GraphicsPrimitiveMgrTest.java new file mode 100644 index 00000000000..3dacf7083d2 --- /dev/null +++ b/test/jdk/sun/java2d/loops/GraphicsPrimitiveMgrTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023, Azul Systems, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.concurrent.CountDownLatch; + +/** + * @test + * @bug 6995195 + * @summary Verify that concurrent classloading of GraphicsPrimitiveMgr + * and Blit doesn't deadlock + * @run main/othervm/timeout=20 GraphicsPrimitiveMgrTest + */ +public class GraphicsPrimitiveMgrTest { + + private static volatile CountDownLatch latch; + + private static final String C1 = "sun.java2d.loops.GraphicsPrimitiveMgr"; + private static final String C2 = "sun.java2d.loops.Blit"; + + public static void main(final String[] args) + throws ClassNotFoundException, InterruptedException + { + // force loading awt library + Class.forName("java.awt.Toolkit"); + + latch = new CountDownLatch(2); + + Thread t1 = new Thread(() -> loadClass(C1)); + Thread t2 = new Thread(() -> loadClass(C2)); + + t1.start(); + t2.start(); + + t1.join(); + t2.join(); + } + + private static void loadClass(String className) { + System.out.println(Thread.currentThread().getName() + " loading " + className); + try { + latch.countDown(); + latch.await(); + Class.forName(className); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +}