Skip to content

Commit

Permalink
6995195: Static initialization deadlock in sun.java2d.loops.Blit and …
Browse files Browse the repository at this point in the history
…GraphicsPrimitiveMgr

Reviewed-by: serb, aivanov
  • Loading branch information
Dmitry Cherepanov committed Apr 27, 2023
1 parent 748476f commit de0c05d
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 42 deletions.
3 changes: 2 additions & 1 deletion src/java.desktop/share/classes/sun/java2d/loops/Blit.java
Expand Up @@ -36,6 +36,7 @@
import sun.java2d.SurfaceData;
import sun.java2d.pipe.Region;
import sun.java2d.pipe.SpanIterator;
import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives;

/**
* Blit
Expand Down Expand Up @@ -111,7 +112,7 @@ public native void Blit(SurfaceData src, SurfaceData dst,
int width, int height);

static {
GraphicsPrimitiveMgr.registerGeneral(new Blit(null, null, null));
GeneralPrimitives.register(new Blit(null, null, null));
}

protected GraphicsPrimitive makePrimitive(SurfaceType srctype,
Expand Down
3 changes: 2 additions & 1 deletion src/java.desktop/share/classes/sun/java2d/loops/BlitBg.java
Expand Up @@ -37,6 +37,7 @@
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.pipe.Region;
import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives;

/**
* BlitBg
Expand Down Expand Up @@ -114,7 +115,7 @@ public native void BlitBg(SurfaceData src, SurfaceData dst,
int width, int height);

static {
GraphicsPrimitiveMgr.registerGeneral(new BlitBg(null, null, null));
GeneralPrimitives.register(new BlitBg(null, null, null));
}

protected GraphicsPrimitive makePrimitive(SurfaceType srctype,
Expand Down
Expand Up @@ -29,6 +29,7 @@
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.pipe.Region;
import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives;

/**
* DrawGlyphList - loops for SolidTextRenderer pipe.
Expand Down Expand Up @@ -73,7 +74,7 @@ public native void DrawGlyphList(SunGraphics2D sg2d, SurfaceData dest,

// This instance is used only for lookup.
static {
GraphicsPrimitiveMgr.registerGeneral(
GeneralPrimitives.register(
new DrawGlyphList(null, null, null));
}

Expand Down
Expand Up @@ -29,6 +29,7 @@
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.pipe.Region;
import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives;

/**
* DrawGlyphListAA - loops for AATextRenderer pipe
Expand Down Expand Up @@ -71,7 +72,7 @@ public native void DrawGlyphListAA(SunGraphics2D sg2d, SurfaceData dest,
int fromGlyph, int toGlyph);

static {
GraphicsPrimitiveMgr.registerGeneral(
GeneralPrimitives.register(
new DrawGlyphListAA(null, null, null));
}

Expand Down
Expand Up @@ -29,6 +29,7 @@
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.pipe.Region;
import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives;

import java.awt.*;

Expand Down Expand Up @@ -67,7 +68,7 @@ public void DrawGlyphListColor(SunGraphics2D sg2d, SurfaceData dest,

// This instance is used only for lookup.
static {
GraphicsPrimitiveMgr.registerGeneral(
GeneralPrimitives.register(
new DrawGlyphListColor(null, null, null));
}

Expand Down
Expand Up @@ -31,6 +31,7 @@

import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives;

/**
* FillRect
Expand Down Expand Up @@ -75,7 +76,7 @@ public native void FillRect(SunGraphics2D sg2d, SurfaceData dest,
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,
Expand Down
Expand Up @@ -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,
Expand Down Expand Up @@ -121,24 +120,6 @@ public static synchronized void register(GraphicsPrimitive[] newPrimitives)
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)
{
Expand All @@ -165,7 +146,7 @@ public static synchronized GraphicsPrimitive locate(int primTypeID,

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) {
Expand Down Expand Up @@ -218,20 +199,6 @@ public static synchronized GraphicsPrimitive locate(int primTypeID,
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) {
Expand Down Expand Up @@ -274,6 +241,46 @@ private static void writeLog(String str) {
}
}

/**
* 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
Expand Down
Expand Up @@ -30,6 +30,7 @@

import sun.java2d.SurfaceData;
import sun.java2d.pipe.Region;
import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives;

/**
* MaskBlit
Expand Down Expand Up @@ -109,7 +110,7 @@ public native void MaskBlit(SurfaceData src, SurfaceData dst,
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,
Expand Down
Expand Up @@ -32,6 +32,7 @@
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.pipe.Region;
import sun.java2d.loops.GraphicsPrimitiveMgr.GeneralPrimitives;

/**
* MaskFill
Expand Down Expand Up @@ -141,7 +142,7 @@ public boolean canDoParallelograms() {
}

static {
GraphicsPrimitiveMgr.registerGeneral(new MaskFill(null, null, null));
GeneralPrimitives.register(new MaskFill(null, null, null));
}

protected GraphicsPrimitive makePrimitive(SurfaceType srctype,
Expand Down
70 changes: 70 additions & 0 deletions 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);
}
}
}

1 comment on commit de0c05d

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.