src/share/classes/java/lang/invoke/LambdaForm.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File
*** old/src/share/classes/java/lang/invoke/LambdaForm.java	Sat Mar 22 02:03:05 2014
--- new/src/share/classes/java/lang/invoke/LambdaForm.java	Sat Mar 22 02:03:04 2014

*** 28,45 **** --- 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 java.lang.reflect.Field; + + import static java.lang.invoke.LambdaForm.BasicType.*; 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,
*** 128,144 **** --- 128,236 ---- // Caches for common structural transforms: LambdaForm[] bindCache; public static final int VOID_RESULT = -1, LAST_RESULT = -2; + 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 + + static final BasicType[] ALL_TYPES = { L_TYPE, I_TYPE, J_TYPE, F_TYPE, D_TYPE, V_TYPE }; + static final BasicType[] ARG_TYPES = { L_TYPE, I_TYPE, J_TYPE, F_TYPE, D_TYPE }; + + static final int ARG_TYPE_LIMIT = V_TYPE.ordinal(); + 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; + } + + char basicTypeChar() { + return btChar; + } + Class<?> basicTypeClass() { + return btClass; + } + Wrapper basicTypeWrapper() { + return btWrapper; + } + int basicTypeSlots() { + return btWrapper.stackSlots(); + } + + static BasicType basicType(byte type) { + return ALL_TYPES[type]; + } + 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+"'"); + } + } + static BasicType basicType(Wrapper type) { + char c = type.basicTypeChar(); + return basicType(c); + } + static BasicType basicType(Class<?> type) { + if (!type.isPrimitive()) return L_TYPE; + return basicType(Wrapper.forPrimitiveType(type)); + } + + static char basicTypeChar(Class<?> type) { + return basicType(type).btChar; + } + 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; + } + 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; + } + static boolean isBasicTypeChar(char c) { + return "LIJFDV".indexOf(c) >= 0; + } + 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 **** --- 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' ? -1 : arity); ! 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 = (basicTypeSignature.charAt(resultPos) == 'V' ? 0 : 1); ! 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++) { ! names[arity + i] = constantZero(arity + i, basicTypeSignature.charAt(resultPos + 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 >= 0) { if (names[result].type == 'V') return -1; } else if (result == LAST_RESULT) { return names.length - 1; } ! 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 **** --- 415,432 ---- // // NYI: fit this into the fast path? // return interpretWithArguments(args); // } /** Report the return type. */ ! char returnType() { ! if (result < 0) return 'V'; ! BasicType returnType() { ! if (result < 0) return V_TYPE; Name n = names[result]; return n.type; } /** Report the N-th argument type. */ ! char parameterType(int n) { ! BasicType parameterType(int n) { assert(n < arity); return names[n].type; } /** Report the arity. */
*** 317,335 **** --- 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 char signatureReturn(String sig) { ! return sig.charAt(signatureArity(sig)+1); ! 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 **** --- 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 (ALL_TYPES.indexOf(c) < 0) return false; // must be [LIJFD] ! if (!isArgBasicTypeChar(c)) 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)); ! ptypes[i] = basicType(sig.charAt(i)).btClass; ! Class<?> rtype = signatureReturn(sig).btClass; return MethodType.methodType(rtype, ptypes); } /* * Code generation issues:
*** 541,565 **** --- 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(char tc, Class<?> type, Object x) { ! 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'; // can drop any kind of value ! 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': 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 ! 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 **** --- 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, char basicType, Object value) { ! 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 **** --- 891,902 ---- 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); ! 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 **** --- 983,993 ---- return true; } return false; } ! LambdaForm addArguments(int pos, char... types) { ! 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 **** --- 1004,1020 ---- } return new LambdaForm(debugName, arity2, names2, result2); } LambdaForm addArguments(int pos, List<Class<?>> types) { ! char[] basicTypes = new char[types.size()]; ! 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, char[] types) { ! 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 **** --- 1069,1079 ---- } } return new LambdaForm(debugName, arity2, names2, result2); } ! static boolean permutedTypesMatch(int[] reorder, char[] types, Name[] names, int skip) { ! 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 **** --- 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') ! if (LambdaForm.signatureReturn(sig) == V_TYPE) srcType = srcType.changeReturnType(void.class); MethodTypeForm typeForm = srcType.form(); typeForm.namedFunctionInvoker = DirectMethodHandle.make(m); } }
*** 1132,1142 **** --- 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 new InternalError(mh.debugString()); return typeForm.namedFunctionInvoker = mh; } @Hidden Object invokeWithArguments(Object... arguments) throws Throwable {
*** 1222,1236 **** --- 1333,1347 ---- Class<?> memberDeclaringClassOrNull() { return (member == null) ? null : member.getDeclaringClass(); } ! char returnType() { ! BasicType returnType() { return basicType(methodType().returnType()); } ! char parameterType(int n) { ! BasicType parameterType(int n) { return basicType(methodType().parameterType(n)); } int arity() { //int siglen = member.getMethodType().parameterCount();
*** 1241,1288 **** --- 1352,1422 ---- 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 boolean isIdentity() { ! return this.equals(identity(returnType())); } ! 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 boolean isConstantZero() { ! return this.equals(constantZero(returnType())); } 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; + + 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 final class Name { ! final char type; ! final BasicType type; private short index; final NamedFunction function; @Stable final Object[] arguments; ! private Name(int index, char type, NamedFunction function, 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 **** --- 1424,1463 ---- 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'); ! 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(); } Name(int index, char type) { + /** Create a raw parameter of the given type, with an expected index. */ + Name(int index, BasicType type) { this(index, type, null, null); } Name(char type) { this(-1, type); } + /** Create a raw parameter of the given type. */ + Name(BasicType type) { this(-1, type); } ! char type() { return 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 **** --- 1531,1552 ---- } boolean isParam() { return function == null; } boolean isConstantZero() { ! return !isParam() && arguments.length == 0 && function.equals(constantZero(0, type).function); ! 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 "null"; ! 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 **** --- 1557,1577 ---- } buf.append(")"); return buf.toString(); } ! private static boolean typesMatch(char parameterType, Object object) { ! static boolean typesMatch(BasicType 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; ! 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'); ! assert(parameterType == L_TYPE); return true; } /** * Does this Name precede the given binding node in some canonical order?
*** 1508,1518 **** --- 1644,1654 ---- 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 **** --- 1679,1694 ---- } return count; } static Name argument(int which, char type) { ! int tn = ALL_TYPES.indexOf(type); if (tn < 0 || which >= INTERNED_ARGUMENT_LIMIT) ! 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[tn][which]; ! 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 **** --- 1726,1849 ---- 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]; ! = new Name[ARG_TYPE_LIMIT][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); ! for (BasicType type : BasicType.ARG_TYPES) { + int ord = type.ordinal(); + for (int i = 0; i < INTERNED_ARGUMENTS[ord].length; i++) { ! INTERNED_ARGUMENTS[ord][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); ! static LambdaForm identityForm(BasicType type) { ! return LF_identityForm[type.ordinal()]; } 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); + 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 ord = 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 { ! zmem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zmem, null, NoSuchMethodException.class); ! 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 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()); + ! 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[ord] = idForm; + NF_identity[ord] = 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[ord] = zeForm; + NF_zero[ord] = 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 ord = type.ordinal(); + NamedFunction idFun = NF_identity[ord]; + LambdaForm idForm = LF_identityForm[ord]; + MemberName idMem = idFun.member; + idFun.resolvedHandle = SimpleMethodHandle.make(idMem.getInvocationType(), idForm); + + NamedFunction zeFun = NF_zero[ord]; + LambdaForm zeForm = LF_zeroForm[ord]; + 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 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()); ! } ! 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 **** --- 1890,1914 ---- 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(); } + 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