6995195: Static initialization deadlock in sun.java2d.loops.Blit and GraphicsPrimitiveMgr

Reviewed-by: serb, aivanov
This commit is contained in:
Dmitry Cherepanov 2023-04-27 07:06:24 +00:00
parent 748476fd80
commit de0c05da07
10 changed files with 127 additions and 42 deletions

@ -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,

@ -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,

@ -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));
}

@ -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));
}

@ -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));
}

@ -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,

@ -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

@ -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,

@ -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,

@ -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);
}
}
}