--- old/src/share/classes/java/lang/invoke/LambdaForm.java 2014-04-01 17:49:44.000000000 +0400 +++ new/src/share/classes/java/lang/invoke/LambdaForm.java 2014-04-01 17:49:43.000000000 +0400 @@ -30,14 +30,14 @@ 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. @@ -130,13 +130,119 @@ 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 = BasicType.values(); + static final BasicType[] ARG_TYPES = Arrays.copyOf(ALL_TYPES, ALL_TYPES.length-1); + + static final int ARG_TYPE_LIMIT = ARG_TYPES.length; + static final int TYPE_LIMIT = ALL_TYPES.length; + + 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> 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; + } + + static { assert(checkBasicType()); } + private static boolean checkBasicType() { + for (int i = 0; i < ARG_TYPE_LIMIT; i++) { + assert ARG_TYPES[i].ordinal() == i; + assert ARG_TYPES[i] == ALL_TYPES[i]; + } + for (int i = 0; i < TYPE_LIMIT; i++) { + assert ALL_TYPES[i].ordinal() == i; + } + assert ALL_TYPES[TYPE_LIMIT - 1] == V_TYPE; + assert !Arrays.asList(ARG_TYPES).contains(V_TYPE); + return true; + } + } + 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; + this.debugName = fixDebugName(debugName); normalize(); } @@ -168,12 +274,12 @@ // 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())); + assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature(); } private static Name[] buildEmptyNames(int arity, String basicTypeSignature) { @@ -181,24 +287,55 @@ 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 = VOID_RESULT; 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]; @@ -294,14 +431,14 @@ // } /** 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; } @@ -319,15 +456,15 @@ 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(); + 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('_'); @@ -339,27 +476,15 @@ 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); } @@ -543,21 +668,21 @@ 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])); + 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; @@ -736,7 +861,7 @@ * 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); @@ -782,8 +907,8 @@ 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); + 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, @@ -874,7 +999,7 @@ 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; @@ -895,13 +1020,10 @@ } LambdaForm addArguments(int pos, List> 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); + return addArguments(pos, basicTypes(types)); } - 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; @@ -960,7 +1082,7 @@ 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++) { @@ -1044,7 +1166,7 @@ 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); @@ -1134,7 +1256,7 @@ MethodHandle mh2 = typeForm.namedFunctionInvoker; if (mh2 != null) return mh2; // benign race if (!mh.type().equals(INVOKER_METHOD_TYPE)) - throw new InternalError(mh.debugString()); + throw newInternalError(mh.debugString()); return typeForm.namedFunctionInvoker = mh; } @@ -1193,11 +1315,6 @@ return true; } - String basicTypeSignature() { - //return LambdaForm.basicTypeSignature(resolvedHandle.type()); - return LambdaForm.basicTypeSignature(methodType()); - } - MethodType methodType() { if (resolvedHandle != null) return resolvedHandle.type(); @@ -1224,18 +1341,15 @@ 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(); - //if (!member.isStatic()) siglen += 1; - //return siglen; return methodType().parameterCount(); } @@ -1243,44 +1357,63 @@ 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 static char[] basicTypes(List> types) { - char[] btypes = new char[types.size()]; - for (int i = 0; i < btypes.length; i++) { - btypes[i] = basicType(types.get(i)); + public boolean isConstantZero() { + return this.equals(constantZero(returnType())); } - 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++] = basicTypeChar(pt); } sig[sigp++] = '_'; - sig[sigp++] = basicType(type.returnType()); + 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; @@ -1292,7 +1425,7 @@ } 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); @@ -1303,14 +1436,14 @@ 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) { @@ -1319,7 +1452,9 @@ } return true; } - + char typeChar() { + return type.btChar; + } void resolve() { if (function != null) @@ -1397,18 +1532,18 @@ 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))+":"+type; + 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 = ""; @@ -1423,17 +1558,17 @@ 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; } @@ -1510,7 +1645,7 @@ @Override public int hashCode() { if (isParam()) - return index | (type << 8); + return index | (type.ordinal() << 8); return function.hashCode() ^ Arrays.hashCode(arguments); } } @@ -1545,10 +1680,12 @@ } 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; @@ -1590,56 +1727,118 @@ 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; + + 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; + + 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. @@ -1690,7 +1889,21 @@ static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable; */ - static { NamedFunction.initializeInvokers(); } + private static final HashMap 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.