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
--- 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) {