src/share/classes/java/lang/invoke/LambdaForm.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File jdk Cdiff src/share/classes/java/lang/invoke/LambdaForm.java

src/share/classes/java/lang/invoke/LambdaForm.java

Print this page
rev 9490 : 8037210: Get rid of char-based descriptions 'J' of basic types
Reviewed-by: ?

*** 28,45 **** import java.lang.annotation.*; import java.lang.reflect.Method; import java.util.Map; import java.util.List; import java.util.Arrays; - import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import sun.invoke.util.Wrapper; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleNatives.Constants.*; - import java.lang.reflect.Field; - import java.util.Objects; /** * The symbolic, non-executable form of a method handle's invocation semantics. * It consists of a series of names. * The first N (N=arity) names are parameters, --- 28,45 ---- import java.lang.annotation.*; import java.lang.reflect.Method; import java.util.Map; import java.util.List; import java.util.Arrays; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import sun.invoke.util.Wrapper; + import java.lang.reflect.Field; + + import static java.lang.invoke.LambdaForm.BasicType.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleNatives.Constants.*; /** * The symbolic, non-executable form of a method handle's invocation semantics. * It consists of a series of names. * The first N (N=arity) names are parameters,
*** 128,144 **** // Caches for common structural transforms: LambdaForm[] bindCache; public static final int VOID_RESULT = -1, LAST_RESULT = -2; LambdaForm(String debugName, int arity, Name[] names, int result) { assert(namesOK(arity, names)); this.arity = arity; this.result = fixResult(result, names); this.names = names.clone(); ! this.debugName = debugName; normalize(); } LambdaForm(String debugName, int arity, Name[] names) { --- 128,236 ---- // Caches for common structural transforms: LambdaForm[] bindCache; public static final int VOID_RESULT = -1, LAST_RESULT = -2; + public enum BasicType { + L_TYPE('L', Object.class, Wrapper.OBJECT), // all reference types + I_TYPE('I', int.class, Wrapper.INT), + J_TYPE('J', long.class, Wrapper.LONG), + F_TYPE('F', float.class, Wrapper.FLOAT), + D_TYPE('D', double.class, Wrapper.DOUBLE), // all primitive types + V_TYPE('V', void.class, Wrapper.VOID); // not valid in all contexts + + public static final BasicType[] ALL_TYPES = { L_TYPE, I_TYPE, J_TYPE, F_TYPE, D_TYPE, V_TYPE }; + public static final BasicType[] ARG_TYPES = { L_TYPE, I_TYPE, J_TYPE, F_TYPE, D_TYPE }; + + public static final int ARG_TYPE_LIMIT = V_TYPE.ordinal(); + public static final int TYPE_LIMIT = ARG_TYPE_LIMIT+1; + + private final char btChar; + private final Class<?> btClass; + private final Wrapper btWrapper; + + private BasicType(char btChar, Class<?> btClass, Wrapper wrapper) { + this.btChar = btChar; + this.btClass = btClass; + this.btWrapper = wrapper; + } + + public char basicTypeChar() { + return btChar; + } + public Class<?> basicTypeClass() { + return btClass; + } + public Wrapper basicTypeWrapper() { + return btWrapper; + } + public int basicTypeSlots() { + return btWrapper.stackSlots(); + } + + public static BasicType basicType(byte type) { + return ALL_TYPES[type]; + } + public static BasicType basicType(char type) { + switch (type) { + case 'L': return L_TYPE; + case 'I': return I_TYPE; + case 'J': return J_TYPE; + case 'F': return F_TYPE; + case 'D': return D_TYPE; + case 'V': return V_TYPE; + // all subword types are represented as ints + case 'Z': + case 'B': + case 'S': + case 'C': + return I_TYPE; + default: + throw newInternalError("Unknown type char: '"+type+"'"); + } + } + public static BasicType basicType(Wrapper type) { + char c = type.basicTypeChar(); + return basicType(c); + } + public static BasicType basicType(Class<?> type) { + if (!type.isPrimitive()) return L_TYPE; + return basicType(Wrapper.forPrimitiveType(type)); + } + + public static char basicTypeChar(Class<?> type) { + return basicType(type).btChar; + } + public static BasicType[] basicTypes(List<Class<?>> types) { + BasicType[] btypes = new BasicType[types.size()]; + for (int i = 0; i < btypes.length; i++) { + btypes[i] = basicType(types.get(i)); + } + return btypes; + } + public static BasicType[] basicTypes(String types) { + BasicType[] btypes = new BasicType[types.length()]; + for (int i = 0; i < btypes.length; i++) { + btypes[i] = basicType(types.charAt(i)); + } + return btypes; + } + public static boolean isBasicTypeChar(char c) { + return "LIJFDV".indexOf(c) >= 0; + } + public static boolean isArgBasicTypeChar(char c) { + return "LIJFD".indexOf(c) >= 0; + } + } + LambdaForm(String debugName, int arity, Name[] names, int result) { assert(namesOK(arity, names)); this.arity = arity; this.result = fixResult(result, names); this.names = names.clone(); ! this.debugName = fixDebugName(debugName); normalize(); } LambdaForm(String debugName, int arity, Name[] names) {
*** 166,206 **** // Make a blank lambda form, which returns a constant zero or null. // It is used as a template for managing the invocation of similar forms that are non-empty. // Called only from getPreparedForm. assert(isValidSignature(sig)); this.arity = signatureArity(sig); ! this.result = (signatureReturn(sig) == 'V' ? -1 : arity); this.names = buildEmptyNames(arity, sig); this.debugName = "LF.zero"; assert(nameRefsAreLegal()); assert(isEmpty()); ! assert(sig.equals(basicTypeSignature())); } private static Name[] buildEmptyNames(int arity, String basicTypeSignature) { assert(isValidSignature(basicTypeSignature)); int resultPos = arity + 1; // skip '_' if (arity < 0 || basicTypeSignature.length() != resultPos+1) throw new IllegalArgumentException("bad arity for "+basicTypeSignature); ! int numRes = (basicTypeSignature.charAt(resultPos) == 'V' ? 0 : 1); Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity)); for (int i = 0; i < numRes; i++) { ! names[arity + i] = constantZero(arity + i, basicTypeSignature.charAt(resultPos + i)); } return names; } private static int fixResult(int result, Name[] names) { ! if (result >= 0) { ! if (names[result].type == 'V') ! return -1; ! } else if (result == LAST_RESULT) { ! return names.length - 1; ! } return result; } private static boolean namesOK(int arity, Name[] names) { for (int i = 0; i < names.length; i++) { Name n = names[i]; assert(n != null) : "n is null"; if (i < arity) --- 258,329 ---- // Make a blank lambda form, which returns a constant zero or null. // It is used as a template for managing the invocation of similar forms that are non-empty. // Called only from getPreparedForm. assert(isValidSignature(sig)); this.arity = signatureArity(sig); ! this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity); this.names = buildEmptyNames(arity, sig); this.debugName = "LF.zero"; assert(nameRefsAreLegal()); assert(isEmpty()); ! assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature(); } private static Name[] buildEmptyNames(int arity, String basicTypeSignature) { assert(isValidSignature(basicTypeSignature)); int resultPos = arity + 1; // skip '_' if (arity < 0 || basicTypeSignature.length() != resultPos+1) throw new IllegalArgumentException("bad arity for "+basicTypeSignature); ! int numRes = (basicType(basicTypeSignature.charAt(resultPos)) == V_TYPE ? 0 : 1); Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity)); for (int i = 0; i < numRes; i++) { ! Name zero = new Name(constantZero(basicType(basicTypeSignature.charAt(resultPos + i)))); ! names[arity + i] = zero.newIndex(arity + i); } return names; } private static int fixResult(int result, Name[] names) { ! if (result == LAST_RESULT) ! result = names.length - 1; // might still be void ! if (result >= 0 && names[result].type == V_TYPE) ! result = -1; return result; } + private static String fixDebugName(String debugName) { + if (DEBUG_NAME_COUNTERS != null) { + int under = debugName.indexOf('_'); + int length = debugName.length(); + if (under < 0) under = length; + String debugNameStem = debugName.substring(0, under); + Integer ctr; + synchronized (DEBUG_NAME_COUNTERS) { + ctr = DEBUG_NAME_COUNTERS.get(debugNameStem); + if (ctr == null) ctr = 0; + DEBUG_NAME_COUNTERS.put(debugNameStem, ctr+1); + } + StringBuilder buf = new StringBuilder(debugNameStem); + buf.append('_'); + int leadingZero = buf.length(); + buf.append((int) ctr); + for (int i = buf.length() - leadingZero; i < 3; i++) + buf.insert(leadingZero, '0'); + if (under < length) { + ++under; // skip "_" + while (under < length && Character.isDigit(debugName.charAt(under))) { + ++under; + } + if (under < length && debugName.charAt(under) == '_') ++under; + if (under < length) + buf.append('_').append(debugName, under, length); + } + return buf.toString(); + } + return debugName; + } + private static boolean namesOK(int arity, Name[] names) { for (int i = 0; i < names.length; i++) { Name n = names[i]; assert(n != null) : "n is null"; if (i < arity)
*** 292,309 **** // // NYI: fit this into the fast path? // return interpretWithArguments(args); // } /** Report the return type. */ ! char returnType() { ! if (result < 0) return 'V'; Name n = names[result]; return n.type; } /** Report the N-th argument type. */ ! char parameterType(int n) { assert(n < arity); return names[n].type; } /** Report the arity. */ --- 415,432 ---- // // NYI: fit this into the fast path? // return interpretWithArguments(args); // } /** Report the return type. */ ! BasicType returnType() { ! if (result < 0) return V_TYPE; Name n = names[result]; return n.type; } /** Report the N-th argument type. */ ! BasicType parameterType(int n) { assert(n < arity); return names[n].type; } /** Report the arity. */
*** 317,335 **** } /** Return ABC_Z, where the ABC are parameter type characters, and Z is the return type character. */ final String basicTypeSignature() { StringBuilder buf = new StringBuilder(arity() + 3); for (int i = 0, a = arity(); i < a; i++) ! buf.append(parameterType(i)); ! return buf.append('_').append(returnType()).toString(); } static int signatureArity(String sig) { assert(isValidSignature(sig)); return sig.indexOf('_'); } ! static char signatureReturn(String sig) { ! return sig.charAt(signatureArity(sig)+1); } static boolean isValidSignature(String sig) { int arity = sig.indexOf('_'); if (arity < 0) return false; // must be of the form *_* int siglen = sig.length(); --- 440,458 ---- } /** Return ABC_Z, where the ABC are parameter type characters, and Z is the return type character. */ final String basicTypeSignature() { StringBuilder buf = new StringBuilder(arity() + 3); for (int i = 0, a = arity(); i < a; i++) ! buf.append(parameterType(i).basicTypeChar()); ! return buf.append('_').append(returnType().basicTypeChar()).toString(); } static int signatureArity(String sig) { assert(isValidSignature(sig)); return sig.indexOf('_'); } ! static BasicType signatureReturn(String sig) { ! return basicType(sig.charAt(signatureArity(sig)+1)); } static boolean isValidSignature(String sig) { int arity = sig.indexOf('_'); if (arity < 0) return false; // must be of the form *_* int siglen = sig.length();
*** 337,367 **** for (int i = 0; i < siglen; i++) { if (i == arity) continue; // skip '_' char c = sig.charAt(i); if (c == 'V') return (i == siglen - 1 && arity == siglen - 2); ! if (ALL_TYPES.indexOf(c) < 0) return false; // must be [LIJFD] } return true; // [LIJFD]*_[LIJFDV] } - static Class<?> typeClass(char t) { - switch (t) { - case 'I': return int.class; - case 'J': return long.class; - case 'F': return float.class; - case 'D': return double.class; - case 'L': return Object.class; - case 'V': return void.class; - default: assert false; - } - return null; - } static MethodType signatureType(String sig) { Class<?>[] ptypes = new Class<?>[signatureArity(sig)]; for (int i = 0; i < ptypes.length; i++) ! ptypes[i] = typeClass(sig.charAt(i)); ! Class<?> rtype = typeClass(signatureReturn(sig)); return MethodType.methodType(rtype, ptypes); } /* * Code generation issues: --- 460,478 ---- for (int i = 0; i < siglen; i++) { if (i == arity) continue; // skip '_' char c = sig.charAt(i); if (c == 'V') return (i == siglen - 1 && arity == siglen - 2); ! if (!isArgBasicTypeChar(c)) return false; // must be [LIJFD] } return true; // [LIJFD]*_[LIJFDV] } static MethodType signatureType(String sig) { Class<?>[] ptypes = new Class<?>[signatureArity(sig)]; for (int i = 0; i < ptypes.length; i++) ! ptypes[i] = basicType(sig.charAt(i)).btClass; ! Class<?> rtype = signatureReturn(sig).btClass; return MethodType.methodType(rtype, ptypes); } /* * Code generation issues:
*** 541,565 **** MethodHandle mh = (MethodHandle) av[0]; MethodType mt = mh.type(); assert(mt.parameterCount() == arity-1); for (int i = 0; i < av.length; i++) { Class<?> pt = (i == 0 ? MethodHandle.class : mt.parameterType(i-1)); ! assert(valueMatches(sig.charAt(i), pt, av[i])); } return true; } ! private static boolean valueMatches(char tc, Class<?> type, Object x) { // The following line is needed because (...)void method handles can use non-void invokers ! if (type == void.class) tc = 'V'; // can drop any kind of value assert tc == basicType(type) : tc + " == basicType(" + type + ")=" + basicType(type); switch (tc) { ! case 'I': assert checkInt(type, x) : "checkInt(" + type + "," + x +")"; break; ! case 'J': assert x instanceof Long : "instanceof Long: " + x; break; ! case 'F': assert x instanceof Float : "instanceof Float: " + x; break; ! case 'D': assert x instanceof Double : "instanceof Double: " + x; break; ! case 'L': assert checkRef(type, x) : "checkRef(" + type + "," + x + ")"; break; ! case 'V': break; // allow anything here; will be dropped default: assert(false); } return true; } private static boolean returnTypesMatch(String sig, Object[] av, Object res) { --- 652,676 ---- MethodHandle mh = (MethodHandle) av[0]; MethodType mt = mh.type(); assert(mt.parameterCount() == arity-1); for (int i = 0; i < av.length; i++) { Class<?> pt = (i == 0 ? MethodHandle.class : mt.parameterType(i-1)); ! assert(valueMatches(basicType(sig.charAt(i)), pt, av[i])); } return true; } ! private static boolean valueMatches(BasicType tc, Class<?> type, Object x) { // The following line is needed because (...)void method handles can use non-void invokers ! if (type == void.class) tc = V_TYPE; // can drop any kind of value assert tc == basicType(type) : tc + " == basicType(" + type + ")=" + basicType(type); switch (tc) { ! case I_TYPE: assert checkInt(type, x) : "checkInt(" + type + "," + x +")"; break; ! case J_TYPE: assert x instanceof Long : "instanceof Long: " + x; break; ! case F_TYPE: assert x instanceof Float : "instanceof Float: " + x; break; ! case D_TYPE: assert x instanceof Double : "instanceof Double: " + x; break; ! case L_TYPE: assert checkRef(type, x) : "checkRef(" + type + "," + x + ")"; break; ! case V_TYPE: break; // allow anything here; will be dropped default: assert(false); } return true; } private static boolean returnTypesMatch(String sig, Object[] av, Object res) {
*** 734,744 **** /** * Apply immediate binding for a Name in this form indicated by its position relative to the form. * The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not * accepted as valid. */ ! LambdaForm bindImmediate(int pos, char basicType, Object value) { // must be an argument, and the types must match assert pos > 0 && pos < arity && names[pos].type == basicType && Name.typesMatch(basicType, value); int arity2 = arity - 1; Name[] names2 = new Name[names.length - 1]; --- 845,855 ---- /** * Apply immediate binding for a Name in this form indicated by its position relative to the form. * The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not * accepted as valid. */ ! LambdaForm bindImmediate(int pos, BasicType basicType, Object value) { // must be an argument, and the types must match assert pos > 0 && pos < arity && names[pos].type == basicType && Name.typesMatch(basicType, value); int arity2 = arity - 1; Name[] names2 = new Name[names.length - 1];
*** 780,791 **** return new LambdaForm(debugName, arity2, names2, result2); } LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) { Name name = names[namePos]; ! BoundMethodHandle.SpeciesData newData = oldData.extendWithType(name.type); ! return bind(name, newData.getterName(names[0], oldData.fieldCount()), oldData, newData); } LambdaForm bind(Name name, Name binding, BoundMethodHandle.SpeciesData oldData, BoundMethodHandle.SpeciesData newData) { int pos = name.index; --- 891,902 ---- return new LambdaForm(debugName, arity2, names2, result2); } LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) { Name name = names[namePos]; ! BoundMethodHandle.SpeciesData newData = oldData.extendWith(name.type); ! return bind(name, new Name(newData.getterFunction(oldData.fieldCount()), names[0]), oldData, newData); } LambdaForm bind(Name name, Name binding, BoundMethodHandle.SpeciesData oldData, BoundMethodHandle.SpeciesData newData) { int pos = name.index;
*** 872,882 **** return true; } return false; } ! LambdaForm addArguments(int pos, char... types) { assert(pos <= arity); int length = names.length; int inTypes = types.length; Name[] names2 = Arrays.copyOf(names, length + inTypes); int arity2 = arity + inTypes; --- 983,993 ---- return true; } return false; } ! LambdaForm addArguments(int pos, BasicType... types) { assert(pos <= arity); int length = names.length; int inTypes = types.length; Name[] names2 = Arrays.copyOf(names, length + inTypes); int arity2 = arity + inTypes;
*** 893,909 **** } return new LambdaForm(debugName, arity2, names2, result2); } LambdaForm addArguments(int pos, List<Class<?>> types) { ! char[] basicTypes = new char[types.size()]; for (int i = 0; i < basicTypes.length; i++) basicTypes[i] = basicType(types.get(i)); return addArguments(pos, basicTypes); } ! LambdaForm permuteArguments(int skip, int[] reorder, char[] types) { // Note: When inArg = reorder[outArg], outArg is fed by a copy of inArg. // The types are the types of the new (incoming) arguments. int length = names.length; int inTypes = types.length; int outArgs = reorder.length; --- 1004,1020 ---- } return new LambdaForm(debugName, arity2, names2, result2); } LambdaForm addArguments(int pos, List<Class<?>> types) { ! BasicType[] basicTypes = new BasicType[types.size()]; for (int i = 0; i < basicTypes.length; i++) basicTypes[i] = basicType(types.get(i)); return addArguments(pos, basicTypes); } ! LambdaForm permuteArguments(int skip, int[] reorder, BasicType[] types) { // Note: When inArg = reorder[outArg], outArg is fed by a copy of inArg. // The types are the types of the new (incoming) arguments. int length = names.length; int inTypes = types.length; int outArgs = reorder.length;
*** 958,968 **** } } return new LambdaForm(debugName, arity2, names2, result2); } ! static boolean permutedTypesMatch(int[] reorder, char[] types, Name[] names, int skip) { int inTypes = types.length; int outArgs = reorder.length; for (int i = 0; i < outArgs; i++) { assert(names[skip+i].isParam()); assert(names[skip+i].type == types[reorder[i]]); --- 1069,1079 ---- } } return new LambdaForm(debugName, arity2, names2, result2); } ! static boolean permutedTypesMatch(int[] reorder, BasicType[] types, Name[] names, int skip) { int inTypes = types.length; int outArgs = reorder.length; for (int i = 0; i < outArgs; i++) { assert(names[skip+i].isParam()); assert(names[skip+i].type == types[reorder[i]]);
*** 1042,1052 **** if (type.equals(INVOKER_METHOD_TYPE) && m.getName().startsWith("invoke_")) { String sig = m.getName().substring("invoke_".length()); int arity = LambdaForm.signatureArity(sig); MethodType srcType = MethodType.genericMethodType(arity); ! if (LambdaForm.signatureReturn(sig) == 'V') srcType = srcType.changeReturnType(void.class); MethodTypeForm typeForm = srcType.form(); typeForm.namedFunctionInvoker = DirectMethodHandle.make(m); } } --- 1153,1163 ---- if (type.equals(INVOKER_METHOD_TYPE) && m.getName().startsWith("invoke_")) { String sig = m.getName().substring("invoke_".length()); int arity = LambdaForm.signatureArity(sig); MethodType srcType = MethodType.genericMethodType(arity); ! if (LambdaForm.signatureReturn(sig) == V_TYPE) srcType = srcType.changeReturnType(void.class); MethodTypeForm typeForm = srcType.form(); typeForm.namedFunctionInvoker = DirectMethodHandle.make(m); } }
*** 1132,1142 **** MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm); // this could take a while mh = DirectMethodHandle.make(invoker); MethodHandle mh2 = typeForm.namedFunctionInvoker; if (mh2 != null) return mh2; // benign race if (!mh.type().equals(INVOKER_METHOD_TYPE)) ! throw new InternalError(mh.debugString()); return typeForm.namedFunctionInvoker = mh; } @Hidden Object invokeWithArguments(Object... arguments) throws Throwable { --- 1243,1253 ---- MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm); // this could take a while mh = DirectMethodHandle.make(invoker); MethodHandle mh2 = typeForm.namedFunctionInvoker; if (mh2 != null) return mh2; // benign race if (!mh.type().equals(INVOKER_METHOD_TYPE)) ! throw newInternalError(mh.debugString()); return typeForm.namedFunctionInvoker = mh; } @Hidden Object invokeWithArguments(Object... arguments) throws Throwable {
*** 1222,1236 **** Class<?> memberDeclaringClassOrNull() { return (member == null) ? null : member.getDeclaringClass(); } ! char returnType() { return basicType(methodType().returnType()); } ! char parameterType(int n) { return basicType(methodType().parameterType(n)); } int arity() { //int siglen = member.getMethodType().parameterCount(); --- 1333,1347 ---- Class<?> memberDeclaringClassOrNull() { return (member == null) ? null : member.getDeclaringClass(); } ! BasicType returnType() { return basicType(methodType().returnType()); } ! BasicType parameterType(int n) { return basicType(methodType().parameterType(n)); } int arity() { //int siglen = member.getMethodType().parameterCount();
*** 1241,1288 **** public String toString() { if (member == null) return String.valueOf(resolvedHandle); return member.getDeclaringClass().getSimpleName()+"."+member.getName(); } - } ! void resolve() { ! for (Name n : names) n.resolve(); } ! public static char basicType(Class<?> type) { ! char c = Wrapper.basicTypeChar(type); ! if ("ZBSC".indexOf(c) >= 0) c = 'I'; ! assert("LIJFDV".indexOf(c) >= 0); ! return c; } - public static char[] basicTypes(List<Class<?>> types) { - char[] btypes = new char[types.size()]; - for (int i = 0; i < btypes.length; i++) { - btypes[i] = basicType(types.get(i)); } ! return btypes; } public static String basicTypeSignature(MethodType type) { char[] sig = new char[type.parameterCount() + 2]; int sigp = 0; for (Class<?> pt : type.parameterList()) { ! sig[sigp++] = basicType(pt); } sig[sigp++] = '_'; ! sig[sigp++] = basicType(type.returnType()); assert(sigp == sig.length); return String.valueOf(sig); } static final class Name { ! final char type; private short index; final NamedFunction function; @Stable final Object[] arguments; ! private Name(int index, char type, NamedFunction function, Object[] arguments) { this.index = (short)index; this.type = type; this.function = function; this.arguments = arguments; assert(this.index == index); --- 1352,1444 ---- public String toString() { if (member == null) return String.valueOf(resolvedHandle); return member.getDeclaringClass().getSimpleName()+"."+member.getName(); } ! public boolean isIdentity() { ! return this.equals(identity(returnType())); } ! public boolean isConstantZero() { ! return this.equals(constantZero(returnType())); } } ! ! void resolve() { ! for (Name n : names) n.resolve(); } + public static String basicTypeSignature(MethodType type) { char[] sig = new char[type.parameterCount() + 2]; int sigp = 0; for (Class<?> pt : type.parameterList()) { ! sig[sigp++] = basicTypeChar(pt); } sig[sigp++] = '_'; ! sig[sigp++] = basicTypeChar(type.returnType()); assert(sigp == sig.length); return String.valueOf(sig); } + public static String shortenSignature(String signature) { + // Hack to make signatures more readable when they show up in method names. + final int NO_CHAR = -1, MIN_RUN = 3; + int c0, c1 = NO_CHAR, c1reps = 0; + StringBuilder buf = null; + int len = signature.length(); + if (len < MIN_RUN) return signature; + for (int i = 0; i <= len; i++) { + // shift in the next char: + c0 = c1; c1 = (i == len ? NO_CHAR : signature.charAt(i)); + if (c1 == c0) { ++c1reps; continue; } + // shift in the next count: + int c0reps = c1reps; c1reps = 1; + // end of a character run + if (c0reps < MIN_RUN) { + if (buf != null) { + while (--c0reps >= 0) + buf.append((char)c0); + } + continue; + } + // found three or more in a row + if (buf == null) + buf = new StringBuilder().append(signature, 0, i - c0reps); + buf.append((char)c0).append(c0reps); + } + return (buf == null) ? signature : buf.toString(); + } + static void testShortenSignature() { + for (String s : new String[] { + // invariant strings: + "L", "LL", "ILL", "LIL", "LLI", "IILL", "ILIL", "ILLI", + // a few mappings: + "LLL=L3", "LLLL=L4", "LLLLLLLLLL=L10", + "IIIDDD=I3D3", "IDDD=ID3", "IIDDD=IID3", "IIID=I3D", "IIIDD=I3DD" + }) { + String s2 = s.substring(s.indexOf('=')+1); + String s1 = s.equals(s2) ? s : s.substring(0, s.length() - s2.length() - 1); + // mix the above cases with before and after reps of Z* + for (int k = -3; k <= 3; k++) { + String beg = (k < 0 ? "ZZZZ".substring(-k) : ""); + String end = (k > 0 ? "ZZZZ".substring(+k) : ""); + String ks1 = beg+s1+end; + String ks2 = shortenSignature(beg)+s2+shortenSignature(end); + String ks3 = shortenSignature(ks1); + if (!ks3.equals(ks2)) System.out.println(Arrays.asList(ks1, ks2, ks3)); + assert(ks3.equals(ks2)) : Arrays.asList(ks1, ks2, ks3); + } + } + } static final class Name { ! final BasicType type; private short index; final NamedFunction function; @Stable final Object[] arguments; ! private Name(int index, BasicType type, NamedFunction function, Object[] arguments) { this.index = (short)index; this.type = type; this.function = function; this.arguments = arguments; assert(this.index == index);
*** 1290,1327 **** Name(MethodHandle function, Object... arguments) { this(new NamedFunction(function), arguments); } Name(MethodType functionType, Object... arguments) { this(new NamedFunction(functionType), arguments); ! assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == 'L'); } Name(MemberName function, Object... arguments) { this(new NamedFunction(function), arguments); } Name(NamedFunction function, Object... arguments) { this(-1, function.returnType(), function, arguments = arguments.clone()); assert(arguments.length == function.arity()) : "arity mismatch: arguments.length=" + arguments.length + " == function.arity()=" + function.arity() + " in " + debugString(); for (int i = 0; i < arguments.length; i++) assert(typesMatch(function.parameterType(i), arguments[i])) : "types don't match: function.parameterType(" + i + ")=" + function.parameterType(i) + ", arguments[" + i + "]=" + arguments[i] + " in " + debugString(); } ! Name(int index, char type) { this(index, type, null, null); } ! Name(char type) { ! this(-1, type); ! } ! char type() { return type; } int index() { return index; } boolean initIndex(int i) { if (index != i) { if (index != -1) return false; index = (short)i; } return true; } ! void resolve() { if (function != null) function.resolve(); } --- 1446,1485 ---- Name(MethodHandle function, Object... arguments) { this(new NamedFunction(function), arguments); } Name(MethodType functionType, Object... arguments) { this(new NamedFunction(functionType), arguments); ! assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == L_TYPE); } Name(MemberName function, Object... arguments) { this(new NamedFunction(function), arguments); } Name(NamedFunction function, Object... arguments) { this(-1, function.returnType(), function, arguments = arguments.clone()); assert(arguments.length == function.arity()) : "arity mismatch: arguments.length=" + arguments.length + " == function.arity()=" + function.arity() + " in " + debugString(); for (int i = 0; i < arguments.length; i++) assert(typesMatch(function.parameterType(i), arguments[i])) : "types don't match: function.parameterType(" + i + ")=" + function.parameterType(i) + ", arguments[" + i + "]=" + arguments[i] + " in " + debugString(); } ! /** Create a raw parameter of the given type, with an expected index. */ ! Name(int index, BasicType type) { this(index, type, null, null); } ! /** Create a raw parameter of the given type. */ ! Name(BasicType type) { this(-1, type); } ! BasicType type() { return type; } int index() { return index; } boolean initIndex(int i) { if (index != i) { if (index != -1) return false; index = (short)i; } return true; } ! char typeChar() { ! return type.btChar; ! } void resolve() { if (function != null) function.resolve(); }
*** 1395,1416 **** } boolean isParam() { return function == null; } boolean isConstantZero() { ! return !isParam() && arguments.length == 0 && function.equals(constantZero(0, type).function); } public String toString() { ! return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+type; } public String debugString() { String s = toString(); return (function == null) ? s : s + "=" + exprString(); } public String exprString() { ! if (function == null) return "null"; StringBuilder buf = new StringBuilder(function.toString()); buf.append("("); String cma = ""; for (Object a : arguments) { buf.append(cma); cma = ","; --- 1553,1574 ---- } boolean isParam() { return function == null; } boolean isConstantZero() { ! return !isParam() && arguments.length == 0 && function.isConstantZero(); } public String toString() { ! return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+typeChar(); } public String debugString() { String s = toString(); return (function == null) ? s : s + "=" + exprString(); } public String exprString() { ! if (function == null) return toString(); StringBuilder buf = new StringBuilder(function.toString()); buf.append("("); String cma = ""; for (Object a : arguments) { buf.append(cma); cma = ",";
*** 1421,1441 **** } buf.append(")"); return buf.toString(); } ! private static boolean typesMatch(char parameterType, Object object) { if (object instanceof Name) { return ((Name)object).type == parameterType; } switch (parameterType) { ! case 'I': return object instanceof Integer; ! case 'J': return object instanceof Long; ! case 'F': return object instanceof Float; ! case 'D': return object instanceof Double; } ! assert(parameterType == 'L'); return true; } /** * Does this Name precede the given binding node in some canonical order? --- 1579,1599 ---- } buf.append(")"); return buf.toString(); } ! static boolean typesMatch(BasicType parameterType, Object object) { if (object instanceof Name) { return ((Name)object).type == parameterType; } switch (parameterType) { ! case I_TYPE: return object instanceof Integer; ! case J_TYPE: return object instanceof Long; ! case F_TYPE: return object instanceof Float; ! case D_TYPE: return object instanceof Double; } ! assert(parameterType == L_TYPE); return true; } /** * Does this Name precede the given binding node in some canonical order?
*** 1508,1518 **** return x instanceof Name && equals((Name)x); } @Override public int hashCode() { if (isParam()) ! return index | (type << 8); return function.hashCode() ^ Arrays.hashCode(arguments); } } /** Return the index of the last name which contains n as an argument. --- 1666,1676 ---- return x instanceof Name && equals((Name)x); } @Override public int hashCode() { if (isParam()) ! return index | (type.ordinal() << 8); return function.hashCode() ^ Arrays.hashCode(arguments); } } /** Return the index of the last name which contains n as an argument.
*** 1543,1556 **** } return count; } static Name argument(int which, char type) { ! int tn = ALL_TYPES.indexOf(type); ! if (tn < 0 || which >= INTERNED_ARGUMENT_LIMIT) return new Name(which, type); ! return INTERNED_ARGUMENTS[tn][which]; } static Name internArgument(Name n) { assert(n.isParam()) : "not param: " + n; assert(n.index < INTERNED_ARGUMENT_LIMIT); return argument(n.index, n.type); --- 1701,1716 ---- } return count; } static Name argument(int which, char type) { ! return argument(which, basicType(type)); ! } ! static Name argument(int which, BasicType type) { ! if (which >= INTERNED_ARGUMENT_LIMIT) return new Name(which, type); ! return INTERNED_ARGUMENTS[type.ordinal()][which]; } static Name internArgument(Name n) { assert(n.isParam()) : "not param: " + n; assert(n.index < INTERNED_ARGUMENT_LIMIT); return argument(n.index, n.type);
*** 1588,1647 **** Name[] names = new Name[length + extra]; for (int i = 0; i < length; i++) names[i] = argument(i, basicType(types.parameterType(i))); return names; } - static final String ALL_TYPES = "LIJFD"; // omit V, not an argument type static final int INTERNED_ARGUMENT_LIMIT = 10; private static final Name[][] INTERNED_ARGUMENTS ! = new Name[ALL_TYPES.length()][INTERNED_ARGUMENT_LIMIT]; static { ! for (int tn = 0; tn < ALL_TYPES.length(); tn++) { ! for (int i = 0; i < INTERNED_ARGUMENTS[tn].length; i++) { ! char type = ALL_TYPES.charAt(tn); ! INTERNED_ARGUMENTS[tn][i] = new Name(i, type); } } } private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(); ! static Name constantZero(int which, char type) { ! return CONSTANT_ZERO[ALL_TYPES.indexOf(type)].newIndex(which); } ! private static final Name[] CONSTANT_ZERO ! = new Name[ALL_TYPES.length()]; ! static { ! for (int tn = 0; tn < ALL_TYPES.length(); tn++) { ! char bt = ALL_TYPES.charAt(tn); ! Wrapper wrap = Wrapper.forBasicType(bt); ! MemberName zmem = new MemberName(LambdaForm.class, "zero"+bt, MethodType.methodType(wrap.primitiveType()), REF_invokeStatic); try { ! zmem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zmem, null, NoSuchMethodException.class); } catch (IllegalAccessException|NoSuchMethodException ex) { throw newInternalError(ex); } ! NamedFunction zcon = new NamedFunction(zmem); ! Name n = new Name(zcon).newIndex(0); ! assert(n.type == ALL_TYPES.charAt(tn)); ! CONSTANT_ZERO[tn] = n; ! assert(n.isConstantZero()); } } // Avoid appealing to ValueConversions at bootstrap time: ! private static int zeroI() { return 0; } ! private static long zeroJ() { return 0; } ! private static float zeroF() { return 0; } ! private static double zeroD() { return 0; } ! private static Object zeroL() { return null; } ! ! // Put this last, so that previous static inits can run before. ! static { ! if (USE_PREDEFINED_INTERPRET_METHODS) ! PREPARED_FORMS.putAll(computeInitialPreparedForms()); ! } /** * Internal marker for byte-compiled LambdaForms. */ /*non-public*/ --- 1748,1871 ---- Name[] names = new Name[length + extra]; for (int i = 0; i < length; i++) names[i] = argument(i, basicType(types.parameterType(i))); return names; } static final int INTERNED_ARGUMENT_LIMIT = 10; private static final Name[][] INTERNED_ARGUMENTS ! = new Name[ARG_TYPE_LIMIT][INTERNED_ARGUMENT_LIMIT]; static { ! for (BasicType type : BasicType.ARG_TYPES) { ! int id = type.ordinal(); ! for (int i = 0; i < INTERNED_ARGUMENTS[id].length; i++) { ! INTERNED_ARGUMENTS[id][i] = new Name(i, type); } } } private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(); ! static LambdaForm identityForm(BasicType type) { ! return LF_identityForm[type.ordinal()]; } ! static LambdaForm zeroForm(BasicType type) { ! return LF_zeroForm[type.ordinal()]; ! } ! static NamedFunction identity(BasicType type) { ! return NF_identity[type.ordinal()]; ! } ! static NamedFunction constantZero(BasicType type) { ! return NF_zero[type.ordinal()]; ! } ! private static final LambdaForm[] LF_identityForm = new LambdaForm[TYPE_LIMIT]; ! private static final LambdaForm[] LF_zeroForm = new LambdaForm[TYPE_LIMIT]; ! private static final NamedFunction[] NF_identity = new NamedFunction[TYPE_LIMIT]; ! private static final NamedFunction[] NF_zero = new NamedFunction[TYPE_LIMIT]; ! private static void createIdentityForms() { ! for (BasicType type : BasicType.ALL_TYPES) { ! int btId = type.ordinal(); ! char btChar = type.basicTypeChar(); ! boolean isVoid = (type == V_TYPE); ! Class<?> btClass = type.btClass; ! MethodType zeType = MethodType.methodType(btClass); ! MethodType idType = isVoid ? zeType : zeType.appendParameterTypes(btClass); ! ! // Look up some symbolic names. It might not be necessary to have these, ! // but if we need to emit direct references to bytecodes, it helps. ! // Zero is built from a call to an identity function with a constant zero input. ! MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic); ! MemberName zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic); try { ! zeMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zeMem, null, NoSuchMethodException.class); ! idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class); } catch (IllegalAccessException|NoSuchMethodException ex) { throw newInternalError(ex); } ! ! NamedFunction idFun = new NamedFunction(idMem); ! LambdaForm idForm; ! if (isVoid) { ! Name[] idNames = new Name[] { argument(0, L_TYPE) }; ! idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT); ! } else { ! Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) }; ! idForm = new LambdaForm(idMem.getName(), 2, idNames, 1); ! } ! LF_identityForm[btId] = idForm; ! NF_identity[btId] = idFun; ! //idFun.resolvedHandle = SimpleMethodHandle.make(idMem.getInvocationType(), idForm); ! ! NamedFunction zeFun = new NamedFunction(zeMem); ! LambdaForm zeForm; ! if (isVoid) { ! zeForm = idForm; ! } else { ! Object zeValue = Wrapper.forBasicType(btChar).zero(); ! Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) }; ! zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1); ! } ! LF_zeroForm[btId] = zeForm; ! NF_zero[btId] = zeFun; ! //zeFun.resolvedHandle = SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm); ! ! assert(idFun.isIdentity()); ! assert(zeFun.isConstantZero()); ! assert(new Name(zeFun).isConstantZero()); ! } ! ! // Do this in a separate pass, so that SimpleMethodHandle.make can see the tables. ! for (BasicType type : BasicType.ALL_TYPES) { ! int btId = type.ordinal(); ! NamedFunction idFun = NF_identity[btId]; ! LambdaForm idForm = LF_identityForm[btId]; ! MemberName idMem = idFun.member; ! idFun.resolvedHandle = SimpleMethodHandle.make(idMem.getInvocationType(), idForm); ! ! NamedFunction zeFun = NF_zero[btId]; ! LambdaForm zeForm = LF_zeroForm[btId]; ! MemberName zeMem = zeFun.member; ! zeFun.resolvedHandle = SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm); ! ! assert(idFun.isIdentity()); ! assert(zeFun.isConstantZero()); ! assert(new Name(zeFun).isConstantZero()); } } // Avoid appealing to ValueConversions at bootstrap time: ! private static int identity_I(int x) { return x; } ! private static long identity_J(long x) { return x; } ! private static float identity_F(float x) { return x; } ! private static double identity_D(double x) { return x; } ! private static Object identity_L(Object x) { return x; } ! private static void identity_V() { return; } // same as zeroV, but that's OK ! private static int zero_I() { return 0; } ! private static long zero_J() { return 0; } ! private static float zero_F() { return 0; } ! private static double zero_D() { return 0; } ! private static Object zero_L() { return null; } ! private static void zero_V() { return; } /** * Internal marker for byte-compiled LambdaForms. */ /*non-public*/
*** 1688,1698 **** static final native Object linkToVirtual(Object x1, MemberName mn) throws Throwable; static final native Object linkToSpecial(Object x1, MemberName mn) throws Throwable; static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable; */ ! static { NamedFunction.initializeInvokers(); } // The following hack is necessary in order to suppress TRACE_INTERPRETER // during execution of the static initializes of this class. // Turning on TRACE_INTERPRETER too early will cause // stack overflows and other misbehavior during attempts to trace events --- 1912,1936 ---- static final native Object linkToVirtual(Object x1, MemberName mn) throws Throwable; static final native Object linkToSpecial(Object x1, MemberName mn) throws Throwable; static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable; */ ! private static final HashMap<String,Integer> DEBUG_NAME_COUNTERS; ! static { ! if (debugEnabled()) ! DEBUG_NAME_COUNTERS = new HashMap<>(); ! else ! DEBUG_NAME_COUNTERS = null; ! } ! ! // Put this last, so that previous static inits can run before. ! static { ! createIdentityForms(); ! if (USE_PREDEFINED_INTERPRET_METHODS) ! PREPARED_FORMS.putAll(computeInitialPreparedForms()); ! NamedFunction.initializeInvokers(); ! } // The following hack is necessary in order to suppress TRACE_INTERPRETER // during execution of the static initializes of this class. // Turning on TRACE_INTERPRETER too early will cause // stack overflows and other misbehavior during attempts to trace events
src/share/classes/java/lang/invoke/LambdaForm.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File