8024635: Caching MethodType's descriptor string improves lambda linkage performance
authorjrose
Sat, 02 Nov 2013 20:08:10 -0700
changeset 21604 2ad6b165b7d8
parent 21603 e88919c55dac
child 21605 d32edf24ffcb
8024635: Caching MethodType's descriptor string improves lambda linkage performance Summary: Better interpreted and compiled performance of operations in MethodType important to LambdaMetafactory. Reviewed-by: jrose, twisti, mchung Contributed-by: sergey.kuksenko@oracle.com
jdk/src/share/classes/java/lang/invoke/MethodType.java
--- a/jdk/src/share/classes/java/lang/invoke/MethodType.java	Fri Nov 01 14:40:03 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodType.java	Sat Nov 02 20:08:10 2013 -0700
@@ -32,6 +32,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ConcurrentHashMap;
 import sun.invoke.util.BytecodeDescriptor;
@@ -98,14 +99,26 @@
     private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
     private @Stable MethodType wrapAlt;  // alternative wrapped/unwrapped version
     private @Stable Invokers invokers;   // cache of handy higher-order adapters
+    private @Stable String methodDescriptor;  // cache for toMethodDescriptorString
 
     /**
      * Check the given parameters for validity and store them into the final fields.
      */
-    private MethodType(Class<?> rtype, Class<?>[] ptypes) {
+    private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
         checkRtype(rtype);
         checkPtypes(ptypes);
         this.rtype = rtype;
+        // defensively copy the array passed in by the user
+        this.ptypes = trusted ? ptypes : Arrays.copyOf(ptypes, ptypes.length);
+    }
+
+    /**
+     * Construct a temporary unchecked instance of MethodType for use only as a key to the intern table.
+     * Does not check the given parameters for validity, and must be discarded after it is used as a searching key.
+     * The parameters are reversed for this constructor, so that is is not accidentally used.
+     */
+    private MethodType(Class<?>[] ptypes, Class<?> rtype) {
+        this.rtype = rtype;
         this.ptypes = ptypes;
     }
 
@@ -146,20 +159,21 @@
     /*non-public*/ static final int MAX_MH_INVOKER_ARITY = MAX_MH_ARITY-1;  // deduct one more for invoker
 
     private static void checkRtype(Class<?> rtype) {
-        rtype.equals(rtype);  // null check
+        Objects.requireNonNull(rtype);
     }
-    private static int checkPtype(Class<?> ptype) {
-        ptype.getClass();  //NPE
+    private static void checkPtype(Class<?> ptype) {
+        Objects.requireNonNull(ptype);
         if (ptype == void.class)
             throw newIllegalArgumentException("parameter type cannot be void");
-        if (ptype == double.class || ptype == long.class)  return 1;
-        return 0;
     }
     /** Return number of extra slots (count of long/double args). */
     private static int checkPtypes(Class<?>[] ptypes) {
         int slots = 0;
         for (Class<?> ptype : ptypes) {
-            slots += checkPtype(ptype);
+            checkPtype(ptype);
+            if (ptype == double.class || ptype == long.class) {
+                slots++;
+            }
         }
         checkSlotCount(ptypes.length + slots);
         return slots;
@@ -284,20 +298,16 @@
      */
     /*trusted*/ static
     MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
+        MethodType mt = internTable.get(new MethodType(ptypes, rtype));
+        if (mt != null)
+            return mt;
         if (ptypes.length == 0) {
             ptypes = NO_PTYPES; trusted = true;
         }
-        MethodType mt1 = new MethodType(rtype, ptypes);
-        MethodType mt0 = internTable.get(mt1);
-        if (mt0 != null)
-            return mt0;
-        if (!trusted)
-            // defensively copy the array passed in by the user
-            mt1 = new MethodType(rtype, ptypes.clone());
+        mt = new MethodType(rtype, ptypes, trusted);
         // promote the object to the Real Thing, and reprobe
-        MethodTypeForm form = MethodTypeForm.findForm(mt1);
-        mt1.form = form;
-        return internTable.add(mt1);
+        mt.form = MethodTypeForm.findForm(mt);
+        return internTable.add(mt);
     }
     private static final MethodType[] objectOnlyTypes = new MethodType[20];
 
@@ -919,7 +929,12 @@
      * @return the bytecode type descriptor representation
      */
     public String toMethodDescriptorString() {
-        return BytecodeDescriptor.unparse(this);
+        String desc = methodDescriptor;
+        if (desc == null) {
+            desc = BytecodeDescriptor.unparse(this);
+            methodDescriptor = desc;
+        }
+        return desc;
     }
 
     /*non-public*/ static String toFieldDescriptorString(Class<?> cls) {