8141446: Cache Class.forName for permanently loaded classes
authorattila
Thu, 05 Nov 2015 15:02:36 +0100
changeset 33538 82c57d427fa1
parent 33537 2d7055bf79a8
child 33539 59fdb1bb8199
8141446: Cache Class.forName for permanently loaded classes Reviewed-by: hannesw, mhaupt, sundar
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
--- 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);
+            }
+        });
     }
 
     /**