Skip to content

Commit fc1d2a1

Browse files
committed
8259065: Optimize MessageDigest.getInstance
Reviewed-by: valeriep
1 parent 712014c commit fc1d2a1

File tree

4 files changed

+258
-136
lines changed

4 files changed

+258
-136
lines changed

src/java.base/share/classes/java/security/MessageDigest.java

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.io.PrintStream;
3131
import java.nio.ByteBuffer;
3232

33+
import sun.security.jca.GetInstance;
3334
import sun.security.util.Debug;
3435
import sun.security.util.MessageDigestSpi2;
3536

@@ -176,30 +177,27 @@ private MessageDigest(String algorithm, Provider p) {
176177
* @see Provider
177178
*/
178179
public static MessageDigest getInstance(String algorithm)
179-
throws NoSuchAlgorithmException {
180+
throws NoSuchAlgorithmException
181+
{
180182
Objects.requireNonNull(algorithm, "null algorithm name");
181-
try {
182-
MessageDigest md;
183-
Object[] objs = Security.getImpl(algorithm, "MessageDigest",
184-
(String)null);
185-
if (objs[0] instanceof MessageDigest) {
186-
md = (MessageDigest)objs[0];
187-
md.provider = (Provider)objs[1];
188-
} else {
189-
md = Delegate.of((MessageDigestSpi)objs[0], algorithm,
190-
(Provider) objs[1]);
191-
}
192-
193-
if (!skipDebug && pdebug != null) {
194-
pdebug.println("MessageDigest." + algorithm +
195-
" algorithm from: " + md.provider.getName());
196-
}
183+
MessageDigest md;
197184

198-
return md;
185+
GetInstance.Instance instance = GetInstance.getInstance("MessageDigest",
186+
MessageDigestSpi.class, algorithm);
187+
if (instance.impl instanceof MessageDigest messageDigest) {
188+
md = messageDigest;
189+
md.provider = instance.provider;
190+
} else {
191+
md = Delegate.of((MessageDigestSpi)instance.impl, algorithm,
192+
instance.provider);
193+
}
199194

200-
} catch(NoSuchProviderException e) {
201-
throw new NoSuchAlgorithmException(algorithm + " not found");
195+
if (!skipDebug && pdebug != null) {
196+
pdebug.println("MessageDigest." + algorithm +
197+
" algorithm from: " + md.provider.getName());
202198
}
199+
200+
return md;
203201
}
204202

205203
/**
@@ -245,17 +243,18 @@ public static MessageDigest getInstance(String algorithm, String provider)
245243
Objects.requireNonNull(algorithm, "null algorithm name");
246244
if (provider == null || provider.isEmpty())
247245
throw new IllegalArgumentException("missing provider");
248-
Object[] objs = Security.getImpl(algorithm, "MessageDigest", provider);
249-
if (objs[0] instanceof MessageDigest) {
250-
MessageDigest md = (MessageDigest)objs[0];
251-
md.provider = (Provider)objs[1];
252-
return md;
246+
247+
MessageDigest md;
248+
GetInstance.Instance instance = GetInstance.getInstance("MessageDigest",
249+
MessageDigestSpi.class, algorithm, provider);
250+
if (instance.impl instanceof MessageDigest messageDigest) {
251+
md = messageDigest;
252+
md.provider = instance.provider;
253253
} else {
254-
MessageDigest delegate =
255-
Delegate.of((MessageDigestSpi)objs[0], algorithm,
256-
(Provider)objs[1]);
257-
return delegate;
254+
md = Delegate.of((MessageDigestSpi)instance.impl, algorithm,
255+
instance.provider);
258256
}
257+
return md;
259258
}
260259

261260
/**

src/java.base/share/classes/java/security/Provider.java

Lines changed: 99 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -147,44 +147,7 @@ public abstract class Provider extends Properties {
147147

148148
private transient boolean initialized;
149149

150-
private static Object newInstanceUtil(final Class<?> clazz,
151-
final Class<?> ctrParamClz, final Object ctorParamObj)
152-
throws Exception {
153-
if (ctrParamClz == null) {
154-
Constructor<?> con = clazz.getConstructor();
155-
return con.newInstance();
156-
} else {
157-
// Looking for the constructor with a params first and fallback
158-
// to one without if not found. This is to support the enhanced
159-
// SecureRandom where both styles of constructors are supported.
160-
// Before jdk9, there was no params support (only getInstance(alg))
161-
// and an impl only had the params-less constructor. Since jdk9,
162-
// there is getInstance(alg,params) and an impl can contain
163-
// an Impl(params) constructor.
164-
try {
165-
Constructor<?> con = clazz.getConstructor(ctrParamClz);
166-
return con.newInstance(ctorParamObj);
167-
} catch (NoSuchMethodException nsme) {
168-
// For pre-jdk9 SecureRandom implementations, they only
169-
// have params-less constructors which still works when
170-
// the input ctorParamObj is null.
171-
//
172-
// For other primitives using params, ctorParamObj should not
173-
// be null and nsme is thrown, just like before.
174-
if (ctorParamObj == null) {
175-
try {
176-
Constructor<?> con = clazz.getConstructor();
177-
return con.newInstance();
178-
} catch (NoSuchMethodException nsme2) {
179-
nsme.addSuppressed(nsme2);
180-
throw nsme;
181-
}
182-
} else {
183-
throw nsme;
184-
}
185-
}
186-
}
187-
}
150+
private static final Object[] EMPTY = new Object[0];
188151

189152
private static double parseVersionStr(String s) {
190153
try {
@@ -1106,16 +1069,15 @@ private ServiceKey(String type, String algorithm, boolean intern) {
11061069
this.algorithm = intern ? algorithm.intern() : algorithm;
11071070
}
11081071
public int hashCode() {
1109-
return Objects.hash(type, algorithm);
1072+
return type.hashCode() * 31 + algorithm.hashCode();
11101073
}
11111074
public boolean equals(Object obj) {
11121075
if (this == obj) {
11131076
return true;
11141077
}
1115-
if (!(obj instanceof ServiceKey)) {
1078+
if (!(obj instanceof ServiceKey other)) {
11161079
return false;
11171080
}
1118-
ServiceKey other = (ServiceKey)obj;
11191081
return this.type.equals(other.type)
11201082
&& this.algorithm.equals(other.algorithm);
11211083
}
@@ -1192,9 +1154,7 @@ private void parseLegacyPut(String name, String value) {
11921154
ServiceKey key = new ServiceKey(type, stdAlg, true);
11931155
Service s = legacyMap.get(key);
11941156
if (s == null) {
1195-
s = new Service(this);
1196-
s.type = type;
1197-
s.algorithm = stdAlg;
1157+
s = new Service(this, type, stdAlg);
11981158
legacyMap.put(key, s);
11991159
}
12001160
legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
@@ -1213,9 +1173,7 @@ private void parseLegacyPut(String name, String value) {
12131173
ServiceKey key = new ServiceKey(type, stdAlg, true);
12141174
Service s = legacyMap.get(key);
12151175
if (s == null) {
1216-
s = new Service(this);
1217-
s.type = type;
1218-
s.algorithm = stdAlg;
1176+
s = new Service(this, type, stdAlg);
12191177
legacyMap.put(key, s);
12201178
}
12211179
s.className = className;
@@ -1238,9 +1196,7 @@ private void parseLegacyPut(String name, String value) {
12381196
ServiceKey key = new ServiceKey(type, stdAlg, true);
12391197
Service s = legacyMap.get(key);
12401198
if (s == null) {
1241-
s = new Service(this);
1242-
s.type = type;
1243-
s.algorithm = stdAlg;
1199+
s = new Service(this, type, stdAlg);
12441200
legacyMap.put(key, s);
12451201
}
12461202
s.addAttribute(attributeName, attributeValue);
@@ -1673,14 +1629,24 @@ private static String getEngineName(String s) {
16731629
* @since 1.5
16741630
*/
16751631
public static class Service {
1676-
1677-
private String type, algorithm, className;
1632+
private final String type;
1633+
private final String algorithm;
1634+
private String className;
16781635
private final Provider provider;
16791636
private List<String> aliases;
16801637
private Map<UString,String> attributes;
1638+
private final EngineDescription engineDescription;
1639+
1640+
// Reference to the cached implementation Class object.
1641+
// Will be a Class if this service is loaded from the built-in
1642+
// classloader (unloading not possible), otherwise a WeakReference to a
1643+
// Class
1644+
private Object classCache;
16811645

1682-
// Reference to the cached implementation Class object
1683-
private volatile Reference<Class<?>> classRef;
1646+
// Will be a Constructor if this service is loaded from the built-in
1647+
// classloader (unloading not possible), otherwise a WeakReference to
1648+
// a Constructor
1649+
private Object constructorCache;
16841650

16851651
// flag indicating whether this service has its attributes for
16861652
// supportedKeyFormats or supportedKeyClasses set
@@ -1702,8 +1668,11 @@ public static class Service {
17021668
// this constructor and these methods are used for parsing
17031669
// the legacy string properties.
17041670

1705-
private Service(Provider provider) {
1671+
private Service(Provider provider, String type, String algorithm) {
17061672
this.provider = provider;
1673+
this.type = type;
1674+
this.algorithm = algorithm;
1675+
engineDescription = knownEngines.get(type);
17071676
aliases = Collections.<String>emptyList();
17081677
attributes = Collections.<UString,String>emptyMap();
17091678
}
@@ -1749,6 +1718,7 @@ public Service(Provider provider, String type, String algorithm,
17491718
}
17501719
this.provider = provider;
17511720
this.type = getEngineName(type);
1721+
engineDescription = knownEngines.get(type);
17521722
this.algorithm = algorithm;
17531723
this.className = className;
17541724
if (aliases == null) {
@@ -1863,7 +1833,7 @@ public Object newInstance(Object constructorParameter)
18631833
}
18641834
Class<?> ctrParamClz;
18651835
try {
1866-
EngineDescription cap = knownEngines.get(type);
1836+
EngineDescription cap = engineDescription;
18671837
if (cap == null) {
18681838
// unknown engine type, use generic code
18691839
// this is the code path future for non-core
@@ -1890,7 +1860,7 @@ public Object newInstance(Object constructorParameter)
18901860
}
18911861
}
18921862
// constructorParameter can be null if not provided
1893-
return newInstanceUtil(getImplClass(), ctrParamClz, constructorParameter);
1863+
return newInstanceUtil(ctrParamClz, constructorParameter);
18941864
} catch (NoSuchAlgorithmException e) {
18951865
throw e;
18961866
} catch (InvocationTargetException e) {
@@ -1906,11 +1876,59 @@ public Object newInstance(Object constructorParameter)
19061876
}
19071877
}
19081878

1879+
private Object newInstanceOf() throws Exception {
1880+
Constructor<?> con = getDefaultConstructor();
1881+
return con.newInstance(EMPTY);
1882+
}
1883+
1884+
private Object newInstanceUtil(Class<?> ctrParamClz, Object ctorParamObj)
1885+
throws Exception
1886+
{
1887+
if (ctrParamClz == null) {
1888+
return newInstanceOf();
1889+
} else {
1890+
// Looking for the constructor with a params first and fallback
1891+
// to one without if not found. This is to support the enhanced
1892+
// SecureRandom where both styles of constructors are supported.
1893+
// Before jdk9, there was no params support (only getInstance(alg))
1894+
// and an impl only had the params-less constructor. Since jdk9,
1895+
// there is getInstance(alg,params) and an impl can contain
1896+
// an Impl(params) constructor.
1897+
try {
1898+
Constructor<?> con = getImplClass().getConstructor(ctrParamClz);
1899+
return con.newInstance(ctorParamObj);
1900+
} catch (NoSuchMethodException nsme) {
1901+
// For pre-jdk9 SecureRandom implementations, they only
1902+
// have params-less constructors which still works when
1903+
// the input ctorParamObj is null.
1904+
//
1905+
// For other primitives using params, ctorParamObj should not
1906+
// be null and nsme is thrown, just like before.
1907+
if (ctorParamObj == null) {
1908+
try {
1909+
return newInstanceOf();
1910+
} catch (NoSuchMethodException nsme2) {
1911+
nsme.addSuppressed(nsme2);
1912+
throw nsme;
1913+
}
1914+
} else {
1915+
throw nsme;
1916+
}
1917+
}
1918+
}
1919+
}
1920+
19091921
// return the implementation Class object for this service
19101922
private Class<?> getImplClass() throws NoSuchAlgorithmException {
19111923
try {
1912-
Reference<Class<?>> ref = classRef;
1913-
Class<?> clazz = (ref == null) ? null : ref.get();
1924+
Object cache = classCache;
1925+
if (cache instanceof Class<?> clazz) {
1926+
return clazz;
1927+
}
1928+
Class<?> clazz = null;
1929+
if (cache instanceof WeakReference<?> ref){
1930+
clazz = (Class<?>)ref.get();
1931+
}
19141932
if (clazz == null) {
19151933
ClassLoader cl = provider.getClass().getClassLoader();
19161934
if (cl == null) {
@@ -1923,7 +1941,7 @@ private Class<?> getImplClass() throws NoSuchAlgorithmException {
19231941
("class configured for " + type + " (provider: " +
19241942
provider.getName() + ") is not public.");
19251943
}
1926-
classRef = new WeakReference<>(clazz);
1944+
classCache = (cl == null) ? clazz : new WeakReference<Class<?>>(clazz);
19271945
}
19281946
return clazz;
19291947
} catch (ClassNotFoundException e) {
@@ -1933,6 +1951,26 @@ private Class<?> getImplClass() throws NoSuchAlgorithmException {
19331951
}
19341952
}
19351953

1954+
private Constructor<?> getDefaultConstructor()
1955+
throws NoSuchAlgorithmException, NoSuchMethodException
1956+
{
1957+
Object cache = constructorCache;
1958+
if (cache instanceof Constructor<?> con) {
1959+
return con;
1960+
}
1961+
Constructor<?> con = null;
1962+
if (cache instanceof WeakReference<?> ref){
1963+
con = (Constructor<?>)ref.get();
1964+
}
1965+
if (con == null) {
1966+
Class<?> clazz = getImplClass();
1967+
con = clazz.getConstructor();
1968+
constructorCache = (clazz.getClassLoader() == null)
1969+
? con : new WeakReference<Constructor<?>>(con);
1970+
}
1971+
return con;
1972+
}
1973+
19361974
/**
19371975
* Test whether this Service can use the specified parameter.
19381976
* Returns false if this service cannot use the parameter. Returns
@@ -1960,7 +1998,7 @@ private Class<?> getImplClass() throws NoSuchAlgorithmException {
19601998
* used with this type of service
19611999
*/
19622000
public boolean supportsParameter(Object parameter) {
1963-
EngineDescription cap = knownEngines.get(type);
2001+
EngineDescription cap = engineDescription;
19642002
if (cap == null) {
19652003
// unknown engine type, return true by default
19662004
return true;

0 commit comments

Comments
 (0)