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;
+ 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 ****
// 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,1422 ----
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 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();
}
--- 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_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 = ",";
--- 1531,1552 ----
}
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?
--- 1557,1577 ----
}
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.
--- 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 ****
}
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);
--- 1679,1694 ----
}
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*/
--- 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 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 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 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 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 {
! 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[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 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
--- 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;
*/
! 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