提交 fbfd2d29 编写于 作者: V vlivanov

8050052: Small cleanups in java.lang.invoke code

Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
上级 301e0094
...@@ -50,9 +50,9 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -50,9 +50,9 @@ import jdk.internal.org.objectweb.asm.Type;
* *
* All bound arguments are encapsulated in dedicated species. * All bound arguments are encapsulated in dedicated species.
*/ */
/* non-public */ abstract class BoundMethodHandle extends MethodHandle { /*non-public*/ abstract class BoundMethodHandle extends MethodHandle {
/* non-public */ BoundMethodHandle(MethodType type, LambdaForm form) { /*non-public*/ BoundMethodHandle(MethodType type, LambdaForm form) {
super(type, form); super(type, form);
} }
...@@ -66,15 +66,15 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -66,15 +66,15 @@ import jdk.internal.org.objectweb.asm.Type;
switch (xtype) { switch (xtype) {
case L_TYPE: case L_TYPE:
if (true) return bindSingle(type, form, x); // Use known fast path. if (true) return bindSingle(type, form, x); // Use known fast path.
return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(L_TYPE).constructor[0].invokeBasic(type, form, x); return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(L_TYPE).constructor().invokeBasic(type, form, x);
case I_TYPE: case I_TYPE:
return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x)); return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor().invokeBasic(type, form, ValueConversions.widenSubword(x));
case J_TYPE: case J_TYPE:
return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(J_TYPE).constructor[0].invokeBasic(type, form, (long) x); return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(J_TYPE).constructor().invokeBasic(type, form, (long) x);
case F_TYPE: case F_TYPE:
return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(F_TYPE).constructor[0].invokeBasic(type, form, (float) x); return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(F_TYPE).constructor().invokeBasic(type, form, (float) x);
case D_TYPE: case D_TYPE:
return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(D_TYPE).constructor[0].invokeBasic(type, form, (double) x); return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(D_TYPE).constructor().invokeBasic(type, form, (double) x);
default : throw newInternalError("unexpected xtype: " + xtype); default : throw newInternalError("unexpected xtype: " + xtype);
} }
} catch (Throwable t) { } catch (Throwable t) {
...@@ -139,8 +139,8 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -139,8 +139,8 @@ import jdk.internal.org.objectweb.asm.Type;
/*non-public*/ abstract int fieldCount(); /*non-public*/ abstract int fieldCount();
@Override @Override
final Object internalProperties() { Object internalProperties() {
return "/BMH="+internalValues(); return "\n& BMH="+internalValues();
} }
@Override @Override
...@@ -219,7 +219,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -219,7 +219,7 @@ import jdk.internal.org.objectweb.asm.Type;
@Override @Override
/*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) { /*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
try { try {
return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg); return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) { } catch (Throwable ex) {
throw uncaughtException(ex); throw uncaughtException(ex);
} }
...@@ -227,7 +227,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -227,7 +227,7 @@ import jdk.internal.org.objectweb.asm.Type;
@Override @Override
/*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) { /*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
try { try {
return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg); return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) { } catch (Throwable ex) {
throw uncaughtException(ex); throw uncaughtException(ex);
} }
...@@ -235,7 +235,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -235,7 +235,7 @@ import jdk.internal.org.objectweb.asm.Type;
@Override @Override
/*non-public*/ final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) { /*non-public*/ final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
try { try {
return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg); return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) { } catch (Throwable ex) {
throw uncaughtException(ex); throw uncaughtException(ex);
} }
...@@ -243,7 +243,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -243,7 +243,7 @@ import jdk.internal.org.objectweb.asm.Type;
@Override @Override
/*non-public*/ final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) { /*non-public*/ final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
try { try {
return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg); return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) { } catch (Throwable ex) {
throw uncaughtException(ex); throw uncaughtException(ex);
} }
...@@ -251,7 +251,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -251,7 +251,7 @@ import jdk.internal.org.objectweb.asm.Type;
@Override @Override
/*non-public*/ final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) { /*non-public*/ final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
try { try {
return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg); return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) { } catch (Throwable ex) {
throw uncaughtException(ex); throw uncaughtException(ex);
} }
...@@ -268,18 +268,20 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -268,18 +268,20 @@ import jdk.internal.org.objectweb.asm.Type;
* The fields are immutable; their values are fully specified at object construction. * The fields are immutable; their values are fully specified at object construction.
* Each BMH type supplies an array of getter functions which may be used in lambda forms. * Each BMH type supplies an array of getter functions which may be used in lambda forms.
* A BMH is constructed by cloning a shorter BMH and adding one or more new field values. * A BMH is constructed by cloning a shorter BMH and adding one or more new field values.
* As a degenerate and common case, the "shorter BMH" can be missing, and contributes zero prior fields. * The shortest possible BMH has zero fields; its class is SimpleMethodHandle.
* BMH species are not interrelated by subtyping, even though it would appear that
* a shorter BMH could serve as a supertype of a longer one which extends it.
*/ */
static class SpeciesData { static class SpeciesData {
final String typeChars; private final String typeChars;
final BasicType[] typeCodes; private final BasicType[] typeCodes;
final Class<? extends BoundMethodHandle> clazz; private final Class<? extends BoundMethodHandle> clazz;
// Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH // Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
// Therefore, we need a non-final link in the chain. Use array elements. // Therefore, we need a non-final link in the chain. Use array elements.
final MethodHandle[] constructor; @Stable private final MethodHandle[] constructor;
final MethodHandle[] getters; @Stable private final MethodHandle[] getters;
final NamedFunction[] nominalGetters; @Stable private final NamedFunction[] nominalGetters;
final SpeciesData[] extensions; @Stable private final SpeciesData[] extensions;
/*non-public*/ int fieldCount() { /*non-public*/ int fieldCount() {
return typeCodes.length; return typeCodes.length;
...@@ -290,9 +292,14 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -290,9 +292,14 @@ import jdk.internal.org.objectweb.asm.Type;
/*non-public*/ char fieldTypeChar(int i) { /*non-public*/ char fieldTypeChar(int i) {
return typeChars.charAt(i); return typeChars.charAt(i);
} }
Object fieldSignature() {
return typeChars;
}
public Class<? extends BoundMethodHandle> fieldHolder() {
return clazz;
}
public String toString() { public String toString() {
return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+typeChars+"]"; return "SpeciesData<"+fieldSignature()+">";
} }
/** /**
...@@ -301,7 +308,20 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -301,7 +308,20 @@ import jdk.internal.org.objectweb.asm.Type;
* getter. * getter.
*/ */
NamedFunction getterFunction(int i) { NamedFunction getterFunction(int i) {
return nominalGetters[i]; NamedFunction nf = nominalGetters[i];
assert(nf.memberDeclaringClassOrNull() == fieldHolder());
assert(nf.returnType() == fieldType(i));
return nf;
}
NamedFunction[] getterFunctions() {
return nominalGetters;
}
MethodHandle[] getterHandles() { return getters; }
MethodHandle constructor() {
return constructor[0];
} }
static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class); static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
...@@ -324,7 +344,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -324,7 +344,7 @@ import jdk.internal.org.objectweb.asm.Type;
private void initForBootstrap() { private void initForBootstrap() {
assert(!INIT_DONE); assert(!INIT_DONE);
if (constructor[0] == null) { if (constructor() == null) {
String types = typeChars; String types = typeChars;
Factory.makeCtors(clazz, types, this.constructor); Factory.makeCtors(clazz, types, this.constructor);
Factory.makeGetters(clazz, types, this.getters); Factory.makeGetters(clazz, types, this.getters);
...@@ -508,19 +528,19 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -508,19 +528,19 @@ import jdk.internal.org.objectweb.asm.Type;
* return new Species_LLI(mt, lf, argL0, argL1, argI2); * return new Species_LLI(mt, lf, argL0, argL1, argI2);
* } * }
* final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) { * final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
* return SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * return SPECIES_DATA.extendWith(L_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* } * }
* final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) { * final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
* return SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * return SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* } * }
* final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) { * final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
* return SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * return SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* } * }
* final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) { * final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
* return SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * return SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* } * }
* public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) { * public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
* return SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * return SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* } * }
* } * }
* </pre> * </pre>
...@@ -653,16 +673,14 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -653,16 +673,14 @@ import jdk.internal.org.objectweb.asm.Type;
char btChar = type.basicTypeChar(); char btChar = type.basicTypeChar();
mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE); mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE);
mv.visitCode(); mv.visitCode();
// return SPECIES_DATA.extendWith(t).constructor[0].invokeBasic(mt, lf, argL0, ..., narg) // return SPECIES_DATA.extendWith(t).constructor().invokeBasic(mt, lf, argL0, ..., narg)
// obtain constructor // obtain constructor
mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG); mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
int iconstInsn = ICONST_0 + ord; int iconstInsn = ICONST_0 + ord;
assert(iconstInsn <= ICONST_5); assert(iconstInsn <= ICONST_5);
mv.visitInsn(iconstInsn); mv.visitInsn(iconstInsn);
mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false); mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false);
mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG); mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "constructor", "()" + MH_SIG, false);
mv.visitInsn(ICONST_0);
mv.visitInsn(AALOAD);
// load mt, lf // load mt, lf
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 2);
......
...@@ -319,7 +319,7 @@ public class CallSite { ...@@ -319,7 +319,7 @@ public class CallSite {
throw new ClassCastException("bootstrap method failed to produce a CallSite"); throw new ClassCastException("bootstrap method failed to produce a CallSite");
} }
if (!site.getTarget().type().equals(type)) if (!site.getTarget().type().equals(type))
throw new WrongMethodTypeException("wrong type: "+site.getTarget()); throw wrongTargetType(site.getTarget(), type);
} catch (Throwable ex) { } catch (Throwable ex) {
BootstrapMethodError bex; BootstrapMethodError bex;
if (ex instanceof BootstrapMethodError) if (ex instanceof BootstrapMethodError)
......
...@@ -59,6 +59,7 @@ class DirectMethodHandle extends MethodHandle { ...@@ -59,6 +59,7 @@ class DirectMethodHandle extends MethodHandle {
MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind()); MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind());
m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null); m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null);
if (m != null && m.isPublic()) { if (m != null && m.isPublic()) {
assert(member.getReferenceKind() == m.getReferenceKind()); // else this.form is wrong
member = m; member = m;
} }
} }
...@@ -127,7 +128,7 @@ class DirectMethodHandle extends MethodHandle { ...@@ -127,7 +128,7 @@ class DirectMethodHandle extends MethodHandle {
@Override @Override
String internalProperties() { String internalProperties() {
return "/DMH="+member.toString(); return "\n& DMH.MN="+internalMemberName();
} }
//// Implementation methods. //// Implementation methods.
......
...@@ -308,7 +308,7 @@ class Invokers { ...@@ -308,7 +308,7 @@ class Invokers {
: Arrays.asList(mtype, customized, which, nameCursor, names.length); : Arrays.asList(mtype, customized, which, nameCursor, names.length);
if (MTYPE_ARG >= INARG_LIMIT) { if (MTYPE_ARG >= INARG_LIMIT) {
assert(names[MTYPE_ARG] == null); assert(names[MTYPE_ARG] == null);
NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0); NamedFunction getter = BoundMethodHandle.speciesData_L().getterFunction(0);
names[MTYPE_ARG] = new Name(getter, names[THIS_MH]); names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
// else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM) // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
} }
...@@ -360,9 +360,6 @@ class Invokers { ...@@ -360,9 +360,6 @@ class Invokers {
Object checkGenericType(Object mhObj, Object expectedObj) { Object checkGenericType(Object mhObj, Object expectedObj) {
MethodHandle mh = (MethodHandle) mhObj; MethodHandle mh = (MethodHandle) mhObj;
MethodType expected = (MethodType) expectedObj; MethodType expected = (MethodType) expectedObj;
if (mh.type() == expected) return mh;
MethodHandle atc = mh.asTypeCache;
if (atc != null && atc.type() == expected) return atc;
return mh.asType(expected); return mh.asType(expected);
/* Maybe add more paths here. Possible optimizations: /* Maybe add more paths here. Possible optimizations:
* for (R)MH.invoke(a*), * for (R)MH.invoke(a*),
...@@ -436,24 +433,25 @@ class Invokers { ...@@ -436,24 +433,25 @@ class Invokers {
} }
// Local constant functions: // Local constant functions:
private static final NamedFunction NF_checkExactType; private static final NamedFunction
private static final NamedFunction NF_checkGenericType; NF_checkExactType,
private static final NamedFunction NF_asType; NF_checkGenericType,
private static final NamedFunction NF_getCallSiteTarget; NF_getCallSiteTarget;
static { static {
try { try {
NamedFunction nfs[] = {
NF_checkExactType = new NamedFunction(Invokers.class NF_checkExactType = new NamedFunction(Invokers.class
.getDeclaredMethod("checkExactType", Object.class, Object.class)); .getDeclaredMethod("checkExactType", Object.class, Object.class)),
NF_checkGenericType = new NamedFunction(Invokers.class NF_checkGenericType = new NamedFunction(Invokers.class
.getDeclaredMethod("checkGenericType", Object.class, Object.class)); .getDeclaredMethod("checkGenericType", Object.class, Object.class)),
NF_asType = new NamedFunction(MethodHandle.class
.getDeclaredMethod("asType", MethodType.class));
NF_getCallSiteTarget = new NamedFunction(Invokers.class NF_getCallSiteTarget = new NamedFunction(Invokers.class
.getDeclaredMethod("getCallSiteTarget", Object.class)); .getDeclaredMethod("getCallSiteTarget", Object.class))
NF_checkExactType.resolve(); };
NF_checkGenericType.resolve(); for (NamedFunction nf : nfs) {
NF_getCallSiteTarget.resolve(); // Each nf must be statically invocable or we get tied up in our bootstraps.
// bound assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
nf.resolve();
}
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
throw newInternalError(ex); throw newInternalError(ex);
} }
......
...@@ -327,10 +327,6 @@ import java.util.Objects; ...@@ -327,10 +327,6 @@ import java.util.Objects;
assert(getReferenceKind() == oldKind); assert(getReferenceKind() == oldKind);
assert(MethodHandleNatives.refKindIsValid(refKind)); assert(MethodHandleNatives.refKindIsValid(refKind));
flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT); flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT);
// if (isConstructor() && refKind != REF_newInvokeSpecial)
// flags += (IS_METHOD - IS_CONSTRUCTOR);
// else if (refKind == REF_newInvokeSpecial && isMethod())
// flags += (IS_CONSTRUCTOR - IS_METHOD);
return this; return this;
} }
...@@ -344,9 +340,11 @@ import java.util.Objects; ...@@ -344,9 +340,11 @@ import java.util.Objects;
return !testFlags(mask, 0); return !testFlags(mask, 0);
} }
/** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */ /** Utility method to query if this member is a method handle invocation (invoke or invokeExact).
* Also returns true for the non-public MH.invokeBasic.
*/
public boolean isMethodHandleInvoke() { public boolean isMethodHandleInvoke() {
final int bits = MH_INVOKE_MODS; final int bits = MH_INVOKE_MODS &~ Modifier.PUBLIC;
final int negs = Modifier.STATIC; final int negs = Modifier.STATIC;
if (testFlags(bits | negs, bits) && if (testFlags(bits | negs, bits) &&
clazz == MethodHandle.class) { clazz == MethodHandle.class) {
...@@ -355,7 +353,14 @@ import java.util.Objects; ...@@ -355,7 +353,14 @@ import java.util.Objects;
return false; return false;
} }
public static boolean isMethodHandleInvokeName(String name) { public static boolean isMethodHandleInvokeName(String name) {
return name.equals("invoke") || name.equals("invokeExact"); switch (name) {
case "invoke":
case "invokeExact":
case "invokeBasic": // internal sig-poly method
return true;
default:
return false;
}
} }
private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC; private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC;
...@@ -720,16 +725,8 @@ import java.util.Objects; ...@@ -720,16 +725,8 @@ import java.util.Objects;
init(defClass, name, type, flagsMods(IS_FIELD, 0, refKind)); init(defClass, name, type, flagsMods(IS_FIELD, 0, refKind));
initResolved(false); initResolved(false);
} }
/** Create a field or type name from the given components: Declaring class, name, type. /** Create a method or constructor name from the given components:
* The declaring class may be supplied as null if this is to be a bare name and type. * Declaring class, name, type, reference kind.
* The modifier flags default to zero.
* The resulting name will in an unresolved state.
*/
public MemberName(Class<?> defClass, String name, Class<?> type, Void unused) {
this(defClass, name, type, REF_NONE);
initResolved(false);
}
/** Create a method or constructor name from the given components: Declaring class, name, type, modifiers.
* It will be a constructor if and only if the name is {@code "&lt;init&gt;"}. * It will be a constructor if and only if the name is {@code "&lt;init&gt;"}.
* The declaring class may be supplied as null if this is to be a bare name and type. * The declaring class may be supplied as null if this is to be a bare name and type.
* The last argument is optional, a boolean which requests REF_invokeSpecial. * The last argument is optional, a boolean which requests REF_invokeSpecial.
......
...@@ -762,11 +762,19 @@ public abstract class MethodHandle { ...@@ -762,11 +762,19 @@ public abstract class MethodHandle {
return this; return this;
} }
// Return 'this.asTypeCache' if the conversion is already memoized. // Return 'this.asTypeCache' if the conversion is already memoized.
MethodHandle atc = asTypeCached(newType);
if (atc != null) {
return atc;
}
return asTypeUncached(newType);
}
private MethodHandle asTypeCached(MethodType newType) {
MethodHandle atc = asTypeCache; MethodHandle atc = asTypeCache;
if (atc != null && newType == atc.type) { if (atc != null && newType == atc.type) {
return atc; return atc;
} }
return asTypeUncached(newType); return null;
} }
/** Override this to change asType behavior. */ /** Override this to change asType behavior. */
...@@ -991,8 +999,11 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123)); ...@@ -991,8 +999,11 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123));
return MethodHandles.collectArguments(target, collectArgPos, collector); return MethodHandles.collectArguments(target, collectArgPos, collector);
} }
// private API: return true if last param exactly matches arrayType /**
private boolean asCollectorChecks(Class<?> arrayType, int arrayLength) { * See if {@code asCollector} can be validly called with the given arguments.
* Return false if the last parameter is not an exact match to arrayType.
*/
/*non-public*/ boolean asCollectorChecks(Class<?> arrayType, int arrayLength) {
spreadArrayChecks(arrayType, arrayLength); spreadArrayChecks(arrayType, arrayLength);
int nargs = type().parameterCount(); int nargs = type().parameterCount();
if (nargs != 0) { if (nargs != 0) {
...@@ -1154,7 +1165,7 @@ assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0))); ...@@ -1154,7 +1165,7 @@ assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
* @see #asFixedArity * @see #asFixedArity
*/ */
public MethodHandle asVarargsCollector(Class<?> arrayType) { public MethodHandle asVarargsCollector(Class<?> arrayType) {
Class<?> arrayElement = arrayType.getComponentType(); arrayType.getClass(); // explicit NPE
boolean lastMatch = asCollectorChecks(arrayType, 0); boolean lastMatch = asCollectorChecks(arrayType, 0);
if (isVarargsCollector() && lastMatch) if (isVarargsCollector() && lastMatch)
return this; return this;
...@@ -1283,14 +1294,17 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); ...@@ -1283,14 +1294,17 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
*/ */
@Override @Override
public String toString() { public String toString() {
if (DEBUG_METHOD_HANDLE_NAMES) return debugString(); if (DEBUG_METHOD_HANDLE_NAMES) return "MethodHandle"+debugString();
return standardString(); return standardString();
} }
String standardString() { String standardString() {
return "MethodHandle"+type; return "MethodHandle"+type;
} }
/** Return a string with a several lines describing the method handle structure.
* This string would be suitable for display in an IDE debugger.
*/
String debugString() { String debugString() {
return standardString()+"/LF="+internalForm()+internalProperties(); return type+" : "+internalForm()+internalProperties();
} }
//// Implementation methods. //// Implementation methods.
...@@ -1302,15 +1316,13 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); ...@@ -1302,15 +1316,13 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
/*non-public*/ /*non-public*/
MethodHandle setVarargs(MemberName member) throws IllegalAccessException { MethodHandle setVarargs(MemberName member) throws IllegalAccessException {
if (!member.isVarargs()) return this; if (!member.isVarargs()) return this;
int argc = type().parameterCount(); Class<?> arrayType = type().lastParameterType();
if (argc != 0) {
Class<?> arrayType = type().parameterType(argc-1);
if (arrayType.isArray()) { if (arrayType.isArray()) {
return MethodHandleImpl.makeVarargsCollector(this, arrayType); return MethodHandleImpl.makeVarargsCollector(this, arrayType);
} }
}
throw member.makeAccessException("cannot make variable arity", null); throw member.makeAccessException("cannot make variable arity", null);
} }
/*non-public*/ /*non-public*/
MethodHandle viewAsType(MethodType newType) { MethodHandle viewAsType(MethodType newType) {
// No actual conversions, just a new view of the same method. // No actual conversions, just a new view of the same method.
...@@ -1361,7 +1373,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); ...@@ -1361,7 +1373,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
/*non-public*/ /*non-public*/
Object internalProperties() { Object internalProperties() {
// Override to something like "/FOO=bar" // Override to something to follow this.form, like "\n& FOO=bar"
return ""; return "";
} }
...@@ -1469,6 +1481,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); ...@@ -1469,6 +1481,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
/*non-public*/ /*non-public*/
void updateForm(LambdaForm newForm) { void updateForm(LambdaForm newForm) {
if (form == newForm) return; if (form == newForm) return;
assert(this instanceof DirectMethodHandle && this.internalMemberName().isStatic());
// ISSUE: Should we have a memory fence here? // ISSUE: Should we have a memory fence here?
UNSAFE.putObject(this, FORM_OFFSET, newForm); UNSAFE.putObject(this, FORM_OFFSET, newForm);
this.form.prepare(); // as in MethodHandle.<init> this.form.prepare(); // as in MethodHandle.<init>
......
...@@ -357,7 +357,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -357,7 +357,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static class AsVarargsCollector extends MethodHandle { static class AsVarargsCollector extends MethodHandle {
private final MethodHandle target; private final MethodHandle target;
private final Class<?> arrayType; private final Class<?> arrayType;
private /*@Stable*/ MethodHandle asCollectorCache; private @Stable MethodHandle asCollectorCache;
AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) { AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
super(type, reinvokerForm(target)); super(type, reinvokerForm(target));
...@@ -534,7 +534,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -534,7 +534,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static final MethodHandle MH_castReference; static final MethodHandle MH_castReference;
static final MethodHandle MH_copyAsPrimitiveArray; static final MethodHandle MH_copyAsPrimitiveArray;
static final MethodHandle MH_copyAsReferenceArray;
static final MethodHandle MH_fillNewTypedArray; static final MethodHandle MH_fillNewTypedArray;
static final MethodHandle MH_fillNewArray; static final MethodHandle MH_fillNewArray;
static final MethodHandle MH_arrayIdentity; static final MethodHandle MH_arrayIdentity;
...@@ -557,8 +556,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -557,8 +556,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodType.methodType(Object.class, Class.class, Object.class)); MethodType.methodType(Object.class, Class.class, Object.class));
MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray", MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
MethodType.methodType(Object.class, Wrapper.class, Object[].class)); MethodType.methodType(Object.class, Wrapper.class, Object[].class));
MH_copyAsReferenceArray = IMPL_LOOKUP.findStatic(MHI, "copyAsReferenceArray",
MethodType.methodType(Object[].class, Class.class, Object[].class));
MH_arrayIdentity = IMPL_LOOKUP.findStatic(MHI, "identity", MH_arrayIdentity = IMPL_LOOKUP.findStatic(MHI, "identity",
MethodType.methodType(Object[].class, Object[].class)); MethodType.methodType(Object[].class, Object[].class));
MH_fillNewArray = IMPL_LOOKUP.findStatic(MHI, "fillNewArray", MH_fillNewArray = IMPL_LOOKUP.findStatic(MHI, "fillNewArray",
...@@ -758,7 +755,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -758,7 +755,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
BoundMethodHandle mh; BoundMethodHandle mh;
try { try {
mh = (BoundMethodHandle) mh = (BoundMethodHandle)
data.constructor[0].invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher, data.constructor().invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher,
(Object) collectArgs, (Object) unboxResult); (Object) collectArgs, (Object) unboxResult);
} catch (Throwable ex) { } catch (Throwable ex) {
throw uncaughtException(ex); throw uncaughtException(ex);
...@@ -1095,6 +1092,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1095,6 +1092,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} }
private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) { private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) {
Object[] a = Arrays.copyOf(example, len); Object[] a = Arrays.copyOf(example, len);
assert(a.getClass() != Object[].class);
fillWithArguments(a, 0, args); fillWithArguments(a, 0, args);
return a; return a;
} }
...@@ -1143,9 +1141,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1143,9 +1141,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} }
private static final MethodHandle[] FILL_ARRAYS = makeFillArrays(); private static final MethodHandle[] FILL_ARRAYS = makeFillArrays();
private static Object[] copyAsReferenceArray(Class<? extends Object[]> arrayType, Object... a) {
return Arrays.copyOf(a, a.length, arrayType);
}
private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) { private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
Object a = w.makeArray(boxes.length); Object a = w.makeArray(boxes.length);
w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length); w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
...@@ -1265,8 +1260,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1265,8 +1260,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
if (nargs >= MAX_JVM_ARITY/2 - 1) { if (nargs >= MAX_JVM_ARITY/2 - 1) {
int slots = nargs; int slots = nargs;
final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH
if (arrayType == double[].class || arrayType == long[].class) if (slots <= MAX_ARRAY_SLOTS && elemType.isPrimitive())
slots *= 2; slots *= Wrapper.forPrimitiveType(elemType).stackSlots();
if (slots > MAX_ARRAY_SLOTS) if (slots > MAX_ARRAY_SLOTS)
throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs); throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs);
} }
...@@ -1276,16 +1271,18 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1276,16 +1271,18 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle cache[] = TYPED_COLLECTORS.get(elemType); MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
MethodHandle mh = nargs < cache.length ? cache[nargs] : null; MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
if (mh != null) return mh; if (mh != null) return mh;
if (elemType.isPrimitive()) { if (nargs == 0) {
Object example = java.lang.reflect.Array.newInstance(arrayType.getComponentType(), 0);
mh = MethodHandles.constant(arrayType, example);
} else if (elemType.isPrimitive()) {
MethodHandle builder = Lazy.MH_fillNewArray; MethodHandle builder = Lazy.MH_fillNewArray;
MethodHandle producer = buildArrayProducer(arrayType); MethodHandle producer = buildArrayProducer(arrayType);
mh = buildVarargsArray(builder, producer, nargs); mh = buildVarargsArray(builder, producer, nargs);
} else { } else {
@SuppressWarnings("unchecked") Class<? extends Object[]> objArrayType = arrayType.asSubclass(Object[].class);
Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType;
Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType); Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
MethodHandle builder = Lazy.MH_fillNewTypedArray.bindTo(example); MethodHandle builder = Lazy.MH_fillNewTypedArray.bindTo(example);
MethodHandle producer = Lazy.MH_arrayIdentity; MethodHandle producer = Lazy.MH_arrayIdentity; // must be weakly typed
mh = buildVarargsArray(builder, producer, nargs); mh = buildVarargsArray(builder, producer, nargs);
} }
mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType))); mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
...@@ -1297,9 +1294,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1297,9 +1294,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
private static MethodHandle buildArrayProducer(Class<?> arrayType) { private static MethodHandle buildArrayProducer(Class<?> arrayType) {
Class<?> elemType = arrayType.getComponentType(); Class<?> elemType = arrayType.getComponentType();
if (elemType.isPrimitive()) assert(elemType.isPrimitive());
return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType)); return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType));
else
return Lazy.MH_copyAsReferenceArray.bindTo(arrayType);
} }
} }
...@@ -33,6 +33,7 @@ import java.util.ArrayList; ...@@ -33,6 +33,7 @@ import java.util.ArrayList;
import sun.reflect.CallerSensitive; import sun.reflect.CallerSensitive;
import sun.reflect.Reflection; import sun.reflect.Reflection;
import sun.reflect.misc.ReflectUtil; import sun.reflect.misc.ReflectUtil;
import static java.lang.invoke.MethodHandleStatics.*;
/** /**
* This class consists exclusively of static methods that help adapt * This class consists exclusively of static methods that help adapt
...@@ -148,7 +149,7 @@ public class MethodHandleProxies { ...@@ -148,7 +149,7 @@ public class MethodHandleProxies {
public static public static
<T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) { <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers())) if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
throw new IllegalArgumentException("not a public interface: "+intfc.getName()); throw newIllegalArgumentException("not a public interface", intfc.getName());
final MethodHandle mh; final MethodHandle mh;
if (System.getSecurityManager() != null) { if (System.getSecurityManager() != null) {
final Class<?> caller = Reflection.getCallerClass(); final Class<?> caller = Reflection.getCallerClass();
...@@ -165,7 +166,7 @@ public class MethodHandleProxies { ...@@ -165,7 +166,7 @@ public class MethodHandleProxies {
} }
final Method[] methods = getSingleNameMethods(intfc); final Method[] methods = getSingleNameMethods(intfc);
if (methods == null) if (methods == null)
throw new IllegalArgumentException("not a single-method interface: "+intfc.getName()); throw newIllegalArgumentException("not a single-method interface", intfc.getName());
final MethodHandle[] vaTargets = new MethodHandle[methods.length]; final MethodHandle[] vaTargets = new MethodHandle[methods.length];
for (int i = 0; i < methods.length; i++) { for (int i = 0; i < methods.length; i++) {
Method sm = methods[i]; Method sm = methods[i];
...@@ -189,7 +190,7 @@ public class MethodHandleProxies { ...@@ -189,7 +190,7 @@ public class MethodHandleProxies {
return getArg(method.getName()); return getArg(method.getName());
if (isObjectMethod(method)) if (isObjectMethod(method))
return callObjectMethod(proxy, method, args); return callObjectMethod(proxy, method, args);
throw new InternalError("bad proxy method: "+method); throw newInternalError("bad proxy method: "+method);
} }
}; };
...@@ -240,7 +241,7 @@ public class MethodHandleProxies { ...@@ -240,7 +241,7 @@ public class MethodHandleProxies {
return (WrapperInstance) x; return (WrapperInstance) x;
} catch (ClassCastException ex) { } catch (ClassCastException ex) {
} }
throw new IllegalArgumentException("not a wrapper instance"); throw newIllegalArgumentException("not a wrapper instance");
} }
/** /**
......
...@@ -45,7 +45,7 @@ import sun.misc.Unsafe; ...@@ -45,7 +45,7 @@ import sun.misc.Unsafe;
static final boolean DUMP_CLASS_FILES; static final boolean DUMP_CLASS_FILES;
static final boolean TRACE_INTERPRETER; static final boolean TRACE_INTERPRETER;
static final boolean TRACE_METHOD_LINKAGE; static final boolean TRACE_METHOD_LINKAGE;
static final Integer COMPILE_THRESHOLD; static final int COMPILE_THRESHOLD;
static final int PROFILE_LEVEL; static final int PROFILE_LEVEL;
static { static {
...@@ -56,7 +56,7 @@ import sun.misc.Unsafe; ...@@ -56,7 +56,7 @@ import sun.misc.Unsafe;
values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES"); values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES");
values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER"); values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER");
values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE"); values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD"); values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 30);
values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0); values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
return null; return null;
} }
...@@ -131,7 +131,10 @@ import sun.misc.Unsafe; ...@@ -131,7 +131,10 @@ import sun.misc.Unsafe;
/*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj, Object obj2) { /*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj, Object obj2) {
return new IllegalArgumentException(message(message, obj, obj2)); return new IllegalArgumentException(message(message, obj, obj2));
} }
/** Propagate unchecked exceptions and errors, but wrap anything checked and throw that instead. */
/*non-public*/ static Error uncaughtException(Throwable ex) { /*non-public*/ static Error uncaughtException(Throwable ex) {
if (ex instanceof Error) throw (Error) ex;
if (ex instanceof RuntimeException) throw (RuntimeException) ex;
throw newInternalError("uncaught exception", ex); throw newInternalError("uncaught exception", ex);
} }
static Error NYI() { static Error NYI() {
......
...@@ -863,6 +863,8 @@ assertEquals("", (String) MH_newString.invokeExact()); ...@@ -863,6 +863,8 @@ assertEquals("", (String) MH_newString.invokeExact());
return invoker(type); return invoker(type);
if ("invokeExact".equals(name)) if ("invokeExact".equals(name))
return exactInvoker(type); return exactInvoker(type);
if ("invokeBasic".equals(name))
return basicInvoker(type);
assert(!MemberName.isMethodHandleInvokeName(name)); assert(!MemberName.isMethodHandleInvokeName(name));
return null; return null;
} }
...@@ -1880,7 +1882,7 @@ return invoker; ...@@ -1880,7 +1882,7 @@ return invoker;
static public static public
MethodHandle spreadInvoker(MethodType type, int leadingArgCount) { MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
if (leadingArgCount < 0 || leadingArgCount > type.parameterCount()) if (leadingArgCount < 0 || leadingArgCount > type.parameterCount())
throw new IllegalArgumentException("bad argument count "+leadingArgCount); throw newIllegalArgumentException("bad argument count", leadingArgCount);
return type.invokers().spreadInvoker(leadingArgCount); return type.invokers().spreadInvoker(leadingArgCount);
} }
...@@ -1965,7 +1967,7 @@ return invoker; ...@@ -1965,7 +1967,7 @@ return invoker;
static /*non-public*/ static /*non-public*/
MethodHandle basicInvoker(MethodType type) { MethodHandle basicInvoker(MethodType type) {
return type.form().basicInvoker(); return type.invokers().basicInvoker();
} }
/// method handle modification (creation from other method handles) /// method handle modification (creation from other method handles)
......
...@@ -907,7 +907,7 @@ class MethodType implements java.io.Serializable { ...@@ -907,7 +907,7 @@ class MethodType implements java.io.Serializable {
if (!descriptor.startsWith("(") || // also generates NPE if needed if (!descriptor.startsWith("(") || // also generates NPE if needed
descriptor.indexOf(')') < 0 || descriptor.indexOf(')') < 0 ||
descriptor.indexOf('.') >= 0) descriptor.indexOf('.') >= 0)
throw new IllegalArgumentException("not a method descriptor: "+descriptor); throw newIllegalArgumentException("not a method descriptor: "+descriptor);
List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader); List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
Class<?> rtype = types.remove(types.size() - 1); Class<?> rtype = types.remove(types.size() - 1);
checkSlotCount(types.size()); checkSlotCount(types.size());
......
...@@ -47,14 +47,10 @@ final class MethodTypeForm { ...@@ -47,14 +47,10 @@ final class MethodTypeForm {
final int[] argToSlotTable, slotToArgTable; final int[] argToSlotTable, slotToArgTable;
final long argCounts; // packed slot & value counts final long argCounts; // packed slot & value counts
final long primCounts; // packed prim & double counts final long primCounts; // packed prim & double counts
final int vmslots; // total number of parameter slots
final MethodType erasedType; // the canonical erasure final MethodType erasedType; // the canonical erasure
final MethodType basicType; // the canonical erasure, with primitives simplified final MethodType basicType; // the canonical erasure, with primitives simplified
// Cached adapter information: // Cached adapter information:
@Stable String typeString; // argument type signature characters
@Stable MethodHandle genericInvoker; // JVM hook for inexact invoke
@Stable MethodHandle basicInvoker; // cached instance of MH.invokeBasic
@Stable MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction @Stable MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction
// Cached lambda form information, for basic types only: // Cached lambda form information, for basic types only:
...@@ -70,24 +66,40 @@ final class MethodTypeForm { ...@@ -70,24 +66,40 @@ final class MethodTypeForm {
LF_INTERPRET = 6, // LF interpreter LF_INTERPRET = 6, // LF interpreter
LF_COUNTER = 7, // CMH wrapper LF_COUNTER = 7, // CMH wrapper
LF_REINVOKE = 8, // other wrapper LF_REINVOKE = 8, // other wrapper
LF_EX_LINKER = 9, // invokeExact_MT LF_EX_LINKER = 9, // invokeExact_MT (for invokehandle)
LF_EX_INVOKER = 10, // invokeExact MH LF_EX_INVOKER = 10, // MHs.invokeExact
LF_GEN_LINKER = 11, LF_GEN_LINKER = 11, // generic invoke_MT (for invokehandle)
LF_GEN_INVOKER = 12, LF_GEN_INVOKER = 12, // generic MHs.invoke
LF_CS_LINKER = 13, // linkToCallSite_CS LF_CS_LINKER = 13, // linkToCallSite_CS
LF_MH_LINKER = 14, // linkToCallSite_MH LF_MH_LINKER = 14, // linkToCallSite_MH
LF_GWC = 15, LF_GWC = 15, // guardWithCatch (catchException)
LF_LIMIT = 16; LF_LIMIT = 16;
/** Return the type corresponding uniquely (1-1) to this MT-form.
* It might have any primitive returns or arguments, but will have no references except Object.
*/
public MethodType erasedType() { public MethodType erasedType() {
return erasedType; return erasedType;
} }
/** Return the basic type derived from the erased type of this MT-form.
* A basic type is erased (all references Object) and also has all primitive
* types (except int, long, float, double, void) normalized to int.
* Such basic types correspond to low-level JVM calling sequences.
*/
public MethodType basicType() { public MethodType basicType() {
return basicType; return basicType;
} }
private boolean assertIsBasicType() {
// primitives must be flattened also
assert(erasedType == basicType)
: "erasedType: " + erasedType + " != basicType: " + basicType;
return true;
}
public LambdaForm cachedLambdaForm(int which) { public LambdaForm cachedLambdaForm(int which) {
assert(assertIsBasicType());
return lambdaForms[which]; return lambdaForms[which];
} }
...@@ -98,28 +110,6 @@ final class MethodTypeForm { ...@@ -98,28 +110,6 @@ final class MethodTypeForm {
return lambdaForms[which] = form; return lambdaForms[which] = form;
} }
public MethodHandle basicInvoker() {
assert(erasedType == basicType) : "erasedType: " + erasedType + " != basicType: " + basicType; // primitives must be flattened also
MethodHandle invoker = basicInvoker;
if (invoker != null) return invoker;
invoker = DirectMethodHandle.make(invokeBasicMethod(basicType));
basicInvoker = invoker;
return invoker;
}
// This next one is called from LambdaForm.NamedFunction.<init>.
/*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
assert(basicType == basicType.basicType());
try {
// Do approximately the same as this public API call:
// Lookup.findVirtual(MethodHandle.class, name, type);
// But bypass access and corner case checks, since we know exactly what we need.
return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
} catch (ReflectiveOperationException ex) {
throw newInternalError("JVM cannot find invoker for "+basicType, ex);
}
}
/** /**
* Build an MTF for a given type, which must have all references erased to Object. * Build an MTF for a given type, which must have all references erased to Object.
* This MTF will stand for that type and all un-erased variations. * This MTF will stand for that type and all un-erased variations.
...@@ -172,6 +162,15 @@ final class MethodTypeForm { ...@@ -172,6 +162,15 @@ final class MethodTypeForm {
this.basicType = erasedType; this.basicType = erasedType;
} else { } else {
this.basicType = MethodType.makeImpl(bt, bpts, true); this.basicType = MethodType.makeImpl(bt, bpts, true);
// fill in rest of data from the basic type:
MethodTypeForm that = this.basicType.form();
assert(this != that);
this.primCounts = that.primCounts;
this.argCounts = that.argCounts;
this.argToSlotTable = that.argToSlotTable;
this.slotToArgTable = that.slotToArgTable;
this.lambdaForms = null;
return;
} }
if (lac != 0) { if (lac != 0) {
int slot = ptypeCount + lac; int slot = ptypeCount + lac;
...@@ -187,10 +186,14 @@ final class MethodTypeForm { ...@@ -187,10 +186,14 @@ final class MethodTypeForm {
argToSlotTab[1+i] = slot; argToSlotTab[1+i] = slot;
} }
assert(slot == 0); // filled the table assert(slot == 0); // filled the table
} } else if (pac != 0) {
this.primCounts = pack(lrc, prc, lac, pac); // have primitives but no long primitives; share slot counts with generic
this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount); assert(ptypeCount == pslotCount);
if (slotToArgTab == null) { MethodTypeForm that = MethodType.genericMethodType(ptypeCount).form();
assert(this != that);
slotToArgTab = that.slotToArgTable;
argToSlotTab = that.argToSlotTable;
} else {
int slot = ptypeCount; // first arg is deepest in stack int slot = ptypeCount; // first arg is deepest in stack
slotToArgTab = new int[slot+1]; slotToArgTab = new int[slot+1];
argToSlotTab = new int[1+ptypeCount]; argToSlotTab = new int[1+ptypeCount];
...@@ -201,19 +204,16 @@ final class MethodTypeForm { ...@@ -201,19 +204,16 @@ final class MethodTypeForm {
argToSlotTab[1+i] = slot; argToSlotTab[1+i] = slot;
} }
} }
this.primCounts = pack(lrc, prc, lac, pac);
this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
this.argToSlotTable = argToSlotTab; this.argToSlotTable = argToSlotTab;
this.slotToArgTable = slotToArgTab; this.slotToArgTable = slotToArgTab;
if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments"); if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments");
// send a few bits down to the JVM: // Initialize caches, but only for basic types
this.vmslots = parameterSlotCount(); assert(basicType == erasedType);
this.lambdaForms = new LambdaForm[LF_LIMIT];
if (basicType == erasedType) {
lambdaForms = new LambdaForm[LF_LIMIT];
} else {
lambdaForms = null; // could be basicType.form().lambdaForms;
}
} }
private static long pack(int a, int b, int c, int d) { private static long pack(int a, int b, int c, int d) {
...@@ -300,7 +300,7 @@ final class MethodTypeForm { ...@@ -300,7 +300,7 @@ final class MethodTypeForm {
*/ */
public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) { public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
Class<?>[] ptypes = mt.ptypes(); Class<?>[] ptypes = mt.ptypes();
Class<?>[] ptc = MethodTypeForm.canonicalizes(ptypes, howArgs); Class<?>[] ptc = MethodTypeForm.canonicalizeAll(ptypes, howArgs);
Class<?> rtype = mt.returnType(); Class<?> rtype = mt.returnType();
Class<?> rtc = MethodTypeForm.canonicalize(rtype, howRet); Class<?> rtc = MethodTypeForm.canonicalize(rtype, howRet);
if (ptc == null && rtc == null) { if (ptc == null && rtc == null) {
...@@ -368,7 +368,7 @@ final class MethodTypeForm { ...@@ -368,7 +368,7 @@ final class MethodTypeForm {
/** Canonicalize each param type in the given array. /** Canonicalize each param type in the given array.
* Return null if all types are already canonicalized. * Return null if all types are already canonicalized.
*/ */
static Class<?>[] canonicalizes(Class<?>[] ts, int how) { static Class<?>[] canonicalizeAll(Class<?>[] ts, int how) {
Class<?>[] cs = null; Class<?>[] cs = null;
for (int imax = ts.length, i = 0; i < imax; i++) { for (int imax = ts.length, i = 0; i < imax; i++) {
Class<?> c = canonicalize(ts[i], how); Class<?> c = canonicalize(ts[i], how);
......
...@@ -2160,15 +2160,23 @@ public class MethodHandlesTest { ...@@ -2160,15 +2160,23 @@ public class MethodHandlesTest {
else else
type = type.changeParameterType(j, argType); type = type.changeParameterType(j, argType);
if (done.add(type)) if (done.add(type))
testInvokers(type); testInvokersWithCatch(type);
MethodType vtype = type.changeReturnType(void.class); MethodType vtype = type.changeReturnType(void.class);
if (done.add(vtype)) if (done.add(vtype))
testInvokers(vtype); testInvokersWithCatch(vtype);
} }
} }
} }
} }
public void testInvokersWithCatch(MethodType type) throws Throwable {
try {
testInvokers(type);
} catch (Throwable ex) {
System.out.println("*** testInvokers on "+type+" => ");
ex.printStackTrace(System.out);
}
}
public void testInvokers(MethodType type) throws Throwable { public void testInvokers(MethodType type) throws Throwable {
if (verbosity >= 3) if (verbosity >= 3)
System.out.println("test invokers for "+type); System.out.println("test invokers for "+type);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册