8141446: Cache Class.forName for permanently loaded classes
Reviewed-by: hannesw, mhaupt, sundar
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java Thu Nov 05 12:15:40 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java Thu Nov 05 15:02:36 2015 +0100
@@ -53,7 +53,6 @@
import java.io.IOException;
import java.io.Serializable;
import java.lang.invoke.CallSite;
-import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Collections;
@@ -246,7 +245,7 @@
* @return Nashorn type
*/
@SuppressWarnings("fallthrough")
- static Type typeFor(final jdk.internal.org.objectweb.asm.Type itype) {
+ private static Type typeFor(final jdk.internal.org.objectweb.asm.Type itype) {
switch (itype.getSort()) {
case jdk.internal.org.objectweb.asm.Type.BOOLEAN:
return BOOLEAN;
@@ -260,11 +259,13 @@
if (Context.isStructureClass(itype.getClassName())) {
return SCRIPT_OBJECT;
}
- try {
- return Type.typeFor(Class.forName(itype.getClassName()));
- } catch(final ClassNotFoundException e) {
- throw new AssertionError(e);
- }
+ return cacheByName.computeIfAbsent(itype.getClassName(), (name) -> {
+ try {
+ return Type.typeFor(Class.forName(name));
+ } catch(final ClassNotFoundException e) {
+ throw new AssertionError(e);
+ }
+ });
case jdk.internal.org.objectweb.asm.Type.VOID:
return null;
case jdk.internal.org.objectweb.asm.Type.ARRAY:
@@ -785,19 +786,10 @@
* @return the Type representing this class
*/
public static Type typeFor(final Class<?> clazz) {
- final Type type = cache.get(clazz);
- if(type != null) {
- return type;
- }
- assert !clazz.isPrimitive() || clazz == void.class;
- final Type newType;
- if (clazz.isArray()) {
- newType = new ArrayType(clazz);
- } else {
- newType = new ObjectType(clazz);
- }
- final Type existingType = cache.putIfAbsent(clazz, newType);
- return existingType == null ? newType : existingType;
+ return cache.computeIfAbsent(clazz, (keyClass) -> {
+ assert !keyClass.isPrimitive() || keyClass == void.class;
+ return keyClass.isArray() ? new ArrayType(keyClass) : new ObjectType(keyClass);
+ });
}
@Override
@@ -902,6 +894,7 @@
/** Mappings between java classes and their Type singletons */
private static final ConcurrentMap<Class<?>, Type> cache = new ConcurrentHashMap<>();
+ private static final ConcurrentMap<String, Type> cacheByName = new ConcurrentHashMap<>();
/**
* This is the boolean singleton, used for all boolean types
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Thu Nov 05 12:15:40 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Thu Nov 05 15:02:36 2015 +0100
@@ -64,13 +64,14 @@
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Level;
-import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.ClassWriter;
@@ -525,6 +526,7 @@
private static final ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader;
+ private static final ConcurrentMap<String, Class<?>> structureClasses = new ConcurrentHashMap<>();
/*package-private*/ @SuppressWarnings("static-method")
ClassLoader getSharedLoader() {
@@ -1056,7 +1058,13 @@
if (System.getSecurityManager() != null && !StructureLoader.isStructureClass(fullName)) {
throw new ClassNotFoundException(fullName);
}
- return (Class<? extends ScriptObject>)Class.forName(fullName, true, sharedLoader);
+ return (Class<? extends ScriptObject>)structureClasses.computeIfAbsent(fullName, (name) -> {
+ try {
+ return Class.forName(name, true, sharedLoader);
+ } catch (final ClassNotFoundException e) {
+ throw new AssertionError(e);
+ }
+ });
}
/**