Skip to content

Commit bf47a47

Browse files
committedFeb 11, 2021
8261282: Lazy initialization of built-in ICC_Profile/ColorSpace classes is too lazy
Reviewed-by: azvegint
1 parent f4cfd75 commit bf47a47

File tree

6 files changed

+219
-199
lines changed

6 files changed

+219
-199
lines changed
 

‎src/java.desktop/share/classes/java/awt/color/ColorSpace.java

+30-87
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@
3939
import java.io.Serializable;
4040
import java.lang.annotation.Native;
4141

42-
import sun.java2d.cmm.CMSManager;
43-
4442
/**
4543
* This abstract class is used to serve as a color space tag to identify the
4644
* specific color space of a {@code Color} object or, via a {@code ColorModel}
@@ -112,12 +110,22 @@ public abstract class ColorSpace implements Serializable {
112110
private final int numComponents;
113111
private transient String [] compName = null;
114112

115-
// Cache of singletons for the predefined color spaces.
116-
private static ColorSpace sRGBspace;
117-
private static ColorSpace XYZspace;
118-
private static ColorSpace PYCCspace;
119-
private static ColorSpace GRAYspace;
120-
private static ColorSpace LINEAR_RGBspace;
113+
/**
114+
* The lazy cache of singletons for the predefined built-in color spaces.
115+
*/
116+
private interface BuiltInSpace {
117+
118+
ColorSpace SRGB = new ICC_ColorSpace(ICC_Profile.getInstance(CS_sRGB));
119+
120+
ColorSpace LRGB =
121+
new ICC_ColorSpace(ICC_Profile.getInstance(CS_LINEAR_RGB));
122+
123+
ColorSpace XYZ = new ICC_ColorSpace(ICC_Profile.getInstance(CS_CIEXYZ));
124+
125+
ColorSpace PYCC = new ICC_ColorSpace(ICC_Profile.getInstance(CS_PYCC));
126+
127+
ColorSpace GRAY = new ICC_ColorSpace(ICC_Profile.getInstance(CS_GRAY));
128+
}
121129

122130
/**
123131
* Any of the family of XYZ color spaces.
@@ -289,88 +297,24 @@ protected ColorSpace(int type, int numComponents) {
289297
* Returns a {@code ColorSpace} representing one of the specific predefined
290298
* color spaces.
291299
*
292-
* @param colorspace a specific color space identified by one of the
293-
* predefined class constants (e.g. {@code CS_sRGB},
294-
* {@code CS_LINEAR_RGB}, {@code CS_CIEXYZ}, {@code CS_GRAY}, or
295-
* {@code CS_PYCC})
300+
* @param cspace a specific color space identified by one of the predefined
301+
* class constants (e.g. {@code CS_sRGB}, {@code CS_LINEAR_RGB},
302+
* {@code CS_CIEXYZ}, {@code CS_GRAY}, or {@code CS_PYCC})
296303
* @return the requested {@code ColorSpace} object
297304
*/
298305
// NOTE: This method may be called by privileged threads.
299306
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
300-
public static ColorSpace getInstance (int colorspace)
301-
{
302-
ColorSpace theColorSpace;
303-
304-
switch (colorspace) {
305-
case CS_sRGB:
306-
synchronized(ColorSpace.class) {
307-
if (sRGBspace == null) {
308-
ICC_Profile theProfile = ICC_Profile.getInstance (CS_sRGB);
309-
sRGBspace = new ICC_ColorSpace (theProfile);
310-
}
311-
312-
theColorSpace = sRGBspace;
307+
public static ColorSpace getInstance(int cspace) {
308+
return switch (cspace) {
309+
case CS_sRGB -> BuiltInSpace.SRGB;
310+
case CS_LINEAR_RGB -> BuiltInSpace.LRGB;
311+
case CS_CIEXYZ -> BuiltInSpace.XYZ;
312+
case CS_PYCC -> BuiltInSpace.PYCC;
313+
case CS_GRAY -> BuiltInSpace.GRAY;
314+
default -> {
315+
throw new IllegalArgumentException("Unknown color space");
313316
}
314-
break;
315-
316-
case CS_CIEXYZ:
317-
synchronized(ColorSpace.class) {
318-
if (XYZspace == null) {
319-
ICC_Profile theProfile =
320-
ICC_Profile.getInstance (CS_CIEXYZ);
321-
XYZspace = new ICC_ColorSpace (theProfile);
322-
}
323-
324-
theColorSpace = XYZspace;
325-
}
326-
break;
327-
328-
case CS_PYCC:
329-
synchronized(ColorSpace.class) {
330-
if (PYCCspace == null) {
331-
ICC_Profile theProfile = ICC_Profile.getInstance (CS_PYCC);
332-
PYCCspace = new ICC_ColorSpace (theProfile);
333-
}
334-
335-
theColorSpace = PYCCspace;
336-
}
337-
break;
338-
339-
340-
case CS_GRAY:
341-
synchronized(ColorSpace.class) {
342-
if (GRAYspace == null) {
343-
ICC_Profile theProfile = ICC_Profile.getInstance (CS_GRAY);
344-
GRAYspace = new ICC_ColorSpace (theProfile);
345-
/* to allow access from java.awt.ColorModel */
346-
CMSManager.GRAYspace = GRAYspace;
347-
}
348-
349-
theColorSpace = GRAYspace;
350-
}
351-
break;
352-
353-
354-
case CS_LINEAR_RGB:
355-
synchronized(ColorSpace.class) {
356-
if (LINEAR_RGBspace == null) {
357-
ICC_Profile theProfile =
358-
ICC_Profile.getInstance(CS_LINEAR_RGB);
359-
LINEAR_RGBspace = new ICC_ColorSpace (theProfile);
360-
/* to allow access from java.awt.ColorModel */
361-
CMSManager.LINEAR_RGBspace = LINEAR_RGBspace;
362-
}
363-
364-
theColorSpace = LINEAR_RGBspace;
365-
}
366-
break;
367-
368-
369-
default:
370-
throw new IllegalArgumentException ("Unknown color space");
371-
}
372-
373-
return theColorSpace;
317+
};
374318
}
375319

376320
/**
@@ -380,8 +324,7 @@ public static ColorSpace getInstance (int colorspace)
380324
* {@code false} if it is not
381325
*/
382326
public boolean isCS_sRGB () {
383-
/* REMIND - make sure we know sRGBspace exists already */
384-
return (this == sRGBspace);
327+
return this == BuiltInSpace.SRGB;
385328
}
386329

387330
/**

‎src/java.desktop/share/classes/java/awt/color/ICC_Profile.java

+40-95
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,31 @@ public class ICC_Profile implements Serializable {
9494
private transient volatile Profile cmmProfile;
9595
private transient volatile ProfileDeferralInfo deferralInfo;
9696

97-
// Registry of singleton profile objects for specific color spaces
98-
// defined in the ColorSpace class (e.g. CS_sRGB), see
99-
// getInstance(int cspace) factory method.
100-
private static ICC_Profile sRGBprofile;
101-
private static ICC_Profile XYZprofile;
102-
private static ICC_Profile PYCCprofile;
103-
private static ICC_Profile GRAYprofile;
104-
private static ICC_Profile LINEAR_RGBprofile;
97+
/**
98+
* The lazy registry of singleton profile objects for specific built-in
99+
* color spaces defined in the ColorSpace class (e.g. CS_sRGB),
100+
* see getInstance(int cspace) factory method.
101+
*/
102+
private interface BuiltInProfile {
103+
/*
104+
* Deferral is only used for standard profiles. Enabling the appropriate
105+
* access privileges is handled at a lower level.
106+
*/
107+
ICC_Profile SRGB = new ICC_ProfileRGB(new ProfileDeferralInfo(
108+
"sRGB.pf", ColorSpace.TYPE_RGB, 3, CLASS_DISPLAY));
109+
110+
ICC_Profile LRGB = new ICC_ProfileRGB(new ProfileDeferralInfo(
111+
"LINEAR_RGB.pf", ColorSpace.TYPE_RGB, 3, CLASS_DISPLAY));
112+
113+
ICC_Profile XYZ = new ICC_Profile(new ProfileDeferralInfo(
114+
"CIEXYZ.pf", ColorSpace.TYPE_XYZ, 3, CLASS_ABSTRACT));
115+
116+
ICC_Profile PYCC = new ICC_Profile(new ProfileDeferralInfo(
117+
"PYCC.pf", ColorSpace.TYPE_3CLR, 3, CLASS_COLORSPACECONVERSION));
118+
119+
ICC_Profile GRAY = new ICC_ProfileGray(new ProfileDeferralInfo(
120+
"GRAY.pf", ColorSpace.TYPE_GRAY, 1, CLASS_DISPLAY));
121+
}
105122

106123
/**
107124
* Profile class is input.
@@ -818,89 +835,17 @@ else if ((getColorSpaceType (p) == ColorSpace.TYPE_RGB) &&
818835
* @throws IllegalArgumentException If {@code cspace} is not one of the
819836
* predefined color space types
820837
*/
821-
public static ICC_Profile getInstance (int cspace) {
822-
ICC_Profile thisProfile = null;
823-
switch (cspace) {
824-
case ColorSpace.CS_sRGB:
825-
synchronized(ICC_Profile.class) {
826-
if (sRGBprofile == null) {
827-
/*
828-
* Deferral is only used for standard profiles.
829-
* Enabling the appropriate access privileges is handled
830-
* at a lower level.
831-
*/
832-
ProfileDeferralInfo pdi =
833-
new ProfileDeferralInfo("sRGB.pf",
834-
ColorSpace.TYPE_RGB, 3,
835-
CLASS_DISPLAY);
836-
sRGBprofile = new ICC_ProfileRGB(pdi);
837-
}
838-
thisProfile = sRGBprofile;
839-
}
840-
841-
break;
842-
843-
case ColorSpace.CS_CIEXYZ:
844-
synchronized(ICC_Profile.class) {
845-
if (XYZprofile == null) {
846-
ProfileDeferralInfo pdi =
847-
new ProfileDeferralInfo("CIEXYZ.pf",
848-
ColorSpace.TYPE_XYZ, 3,
849-
CLASS_ABSTRACT);
850-
XYZprofile = new ICC_Profile(pdi);
851-
}
852-
thisProfile = XYZprofile;
853-
}
854-
855-
break;
856-
857-
case ColorSpace.CS_PYCC:
858-
synchronized(ICC_Profile.class) {
859-
if (PYCCprofile == null) {
860-
ProfileDeferralInfo pdi =
861-
new ProfileDeferralInfo("PYCC.pf",
862-
ColorSpace.TYPE_3CLR, 3,
863-
CLASS_COLORSPACECONVERSION);
864-
PYCCprofile = new ICC_Profile(pdi);
865-
}
866-
thisProfile = PYCCprofile;
867-
}
868-
869-
break;
870-
871-
case ColorSpace.CS_GRAY:
872-
synchronized(ICC_Profile.class) {
873-
if (GRAYprofile == null) {
874-
ProfileDeferralInfo pdi =
875-
new ProfileDeferralInfo("GRAY.pf",
876-
ColorSpace.TYPE_GRAY, 1,
877-
CLASS_DISPLAY);
878-
GRAYprofile = new ICC_ProfileGray(pdi);
879-
}
880-
thisProfile = GRAYprofile;
881-
}
882-
883-
break;
884-
885-
case ColorSpace.CS_LINEAR_RGB:
886-
synchronized(ICC_Profile.class) {
887-
if (LINEAR_RGBprofile == null) {
888-
ProfileDeferralInfo pdi =
889-
new ProfileDeferralInfo("LINEAR_RGB.pf",
890-
ColorSpace.TYPE_RGB, 3,
891-
CLASS_DISPLAY);
892-
LINEAR_RGBprofile = new ICC_ProfileRGB(pdi);
893-
}
894-
thisProfile = LINEAR_RGBprofile;
838+
public static ICC_Profile getInstance(int cspace) {
839+
return switch (cspace) {
840+
case ColorSpace.CS_sRGB -> BuiltInProfile.SRGB;
841+
case ColorSpace.CS_LINEAR_RGB -> BuiltInProfile.LRGB;
842+
case ColorSpace.CS_CIEXYZ -> BuiltInProfile.XYZ;
843+
case ColorSpace.CS_PYCC -> BuiltInProfile.PYCC;
844+
case ColorSpace.CS_GRAY -> BuiltInProfile.GRAY;
845+
default -> {
846+
throw new IllegalArgumentException("Unknown color space");
895847
}
896-
897-
break;
898-
899-
default:
900-
throw new IllegalArgumentException("Unknown color space");
901-
}
902-
903-
return thisProfile;
848+
};
904849
}
905850

906851
/**
@@ -1803,15 +1748,15 @@ private void writeObject(ObjectOutputStream s)
18031748
s.defaultWriteObject();
18041749

18051750
String csName = null;
1806-
if (this == sRGBprofile) {
1751+
if (this == BuiltInProfile.SRGB) {
18071752
csName = "CS_sRGB";
1808-
} else if (this == XYZprofile) {
1753+
} else if (this == BuiltInProfile.XYZ) {
18091754
csName = "CS_CIEXYZ";
1810-
} else if (this == PYCCprofile) {
1755+
} else if (this == BuiltInProfile.PYCC) {
18111756
csName = "CS_PYCC";
1812-
} else if (this == GRAYprofile) {
1757+
} else if (this == BuiltInProfile.GRAY) {
18131758
csName = "CS_GRAY";
1814-
} else if (this == LINEAR_RGBprofile) {
1759+
} else if (this == BuiltInProfile.LRGB) {
18151760
csName = "CS_LINEAR_RGB";
18161761
}
18171762

‎src/java.desktop/share/classes/java/awt/image/ColorModel.java

+3-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1705,15 +1705,11 @@ static int getDefaultTransferType(int pixel_bits) {
17051705
static Map<ICC_ColorSpace, short[]> lg16Toog16Map = null; // 16-bit linear to 16-bit "other" gray
17061706

17071707
static boolean isLinearRGBspace(ColorSpace cs) {
1708-
// Note: CMM.LINEAR_RGBspace will be null if the linear
1709-
// RGB space has not been created yet.
1710-
return (cs == CMSManager.LINEAR_RGBspace);
1708+
return cs == ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB);
17111709
}
17121710

17131711
static boolean isLinearGRAYspace(ColorSpace cs) {
1714-
// Note: CMM.GRAYspace will be null if the linear
1715-
// gray space has not been created yet.
1716-
return (cs == CMSManager.GRAYspace);
1712+
return cs == ColorSpace.getInstance(ColorSpace.CS_GRAY);
17171713
}
17181714

17191715
static byte[] getLinearRGB8TosRGB8LUT() {

‎src/java.desktop/share/classes/sun/java2d/cmm/CMSManager.java

+2-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -26,20 +26,12 @@
2626
package sun.java2d.cmm;
2727

2828
import java.awt.color.CMMException;
29-
import java.awt.color.ColorSpace;
3029
import java.awt.color.ICC_Profile;
3130
import java.security.AccessController;
3231

3332
import sun.security.action.GetPropertyAction;
3433

35-
public class CMSManager {
36-
public static ColorSpace GRAYspace; // These two fields allow access
37-
public static ColorSpace LINEAR_RGBspace; // to java.awt.color.ColorSpace
38-
// private fields from other
39-
// packages. The fields are set
40-
// by java.awt.color.ColorSpace
41-
// and read by
42-
// java.awt.image.ColorModel.
34+
public final class CMSManager {
4335

4436
private static PCMM cmmImpl = null;
4537

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.awt.color.ColorSpace;
25+
import java.awt.color.ICC_ColorSpace;
26+
import java.awt.color.ICC_Profile;
27+
import java.util.Arrays;
28+
import java.util.Set;
29+
30+
import static java.awt.color.ColorSpace.*;
31+
32+
/**
33+
* @test
34+
* @bug 8261282
35+
* @summary Checks that all built-in profiles and data are different.
36+
*/
37+
public final class BuiltInDataVariation {
38+
39+
public static void main(String[] args) {
40+
testColorProfiles();
41+
testColorSpaces();
42+
}
43+
44+
private static void testColorProfiles() {
45+
ICC_Profile srgb = ICC_Profile.getInstance(CS_sRGB);
46+
ICC_Profile lrgb = ICC_Profile.getInstance(CS_LINEAR_RGB);
47+
ICC_Profile xyz = ICC_Profile.getInstance(CS_CIEXYZ);
48+
ICC_Profile pycc = ICC_Profile.getInstance(CS_PYCC);
49+
ICC_Profile gray = ICC_Profile.getInstance(CS_GRAY);
50+
51+
test(srgb, lrgb, xyz, pycc, gray);
52+
test(Arrays.hashCode(srgb.getData()), Arrays.hashCode(lrgb.getData()),
53+
Arrays.hashCode(xyz.getData()), Arrays.hashCode(pycc.getData()),
54+
Arrays.hashCode(gray.getData()));
55+
}
56+
57+
private static void testColorSpaces() {
58+
var srgb = (ICC_ColorSpace) ColorSpace.getInstance(CS_sRGB);
59+
var lrgb = (ICC_ColorSpace) ColorSpace.getInstance(CS_LINEAR_RGB);
60+
var xyz = (ICC_ColorSpace) ColorSpace.getInstance(CS_CIEXYZ);
61+
var pycc = (ICC_ColorSpace) ColorSpace.getInstance(CS_PYCC);
62+
var gray = (ICC_ColorSpace) ColorSpace.getInstance(CS_GRAY);
63+
64+
test(srgb, lrgb, xyz, pycc, gray);
65+
test(srgb.getProfile(), lrgb.getProfile(), xyz.getProfile(),
66+
pycc.getProfile(), gray.getProfile());
67+
test(Arrays.hashCode(srgb.getProfile().getData()),
68+
Arrays.hashCode(lrgb.getProfile().getData()),
69+
Arrays.hashCode(xyz.getProfile().getData()),
70+
Arrays.hashCode(pycc.getProfile().getData()),
71+
Arrays.hashCode(gray.getProfile().getData()));
72+
}
73+
74+
private static void test(Object srgb, Object lrgb, Object xyz,
75+
Object pycc, Object gray) {
76+
Set.of(srgb, lrgb, xyz, pycc, gray);
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.awt.color.ColorSpace;
25+
import java.awt.color.ICC_Profile;
26+
27+
import static java.awt.color.ColorSpace.CS_CIEXYZ;
28+
import static java.awt.color.ColorSpace.CS_GRAY;
29+
import static java.awt.color.ColorSpace.CS_LINEAR_RGB;
30+
import static java.awt.color.ColorSpace.CS_PYCC;
31+
import static java.awt.color.ColorSpace.CS_sRGB;
32+
33+
/**
34+
* @test
35+
* @bug 8261282
36+
* @summary Checks static locks in the ColorSpace/ICC_Profile classes.
37+
*/
38+
public final class HotStaticLocks {
39+
40+
public static void main(String[] args) throws Exception {
41+
testICCProfile();
42+
testColorSpace();
43+
}
44+
45+
private static void testICCProfile() throws Exception {
46+
int[] spaces = {CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ, CS_PYCC, CS_GRAY};
47+
for (int cs : spaces) {
48+
synchronized (ICC_Profile.class) {
49+
Thread t = new Thread(() -> ICC_Profile.getInstance(cs));
50+
t.start();
51+
t.join();
52+
}
53+
}
54+
}
55+
56+
private static void testColorSpace() throws Exception {
57+
int[] spaces = {CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ, CS_PYCC, CS_GRAY};
58+
for (int cs : spaces) {
59+
synchronized (ColorSpace.class) {
60+
Thread t = new Thread(() -> ColorSpace.getInstance(cs));
61+
t.start();
62+
t.join();
63+
}
64+
}
65+
}
66+
}

1 commit comments

Comments
 (1)

openjdk-notifier[bot] commented on Feb 11, 2021

@openjdk-notifier[bot]
Please sign in to comment.