6939134: JSR 292 adjustments to method handle invocation

Split MethodHandle.invoke into invokeExact and invokeGeneric

Reviewed-by: twisti
This commit is contained in:
John R Rose 2010-05-01 15:05:39 -07:00
parent 9329c4986e
commit a56ce23775
13 changed files with 126 additions and 68 deletions

View File

@ -230,6 +230,12 @@ public class Flags {
*/ */
public static final long PROPRIETARY = 1L<<38; public static final long PROPRIETARY = 1L<<38;
/**
* Flag that marks a signature-polymorphic invoke method.
* (These occur inside java.dyn.MethodHandle.)
*/
public static final long POLYMORPHIC_SIGNATURE = 1L<<39;
/** Modifier masks. /** Modifier masks.
*/ */
public static final int public static final int

View File

@ -168,6 +168,10 @@ public enum Source {
public boolean allowStringsInSwitch() { public boolean allowStringsInSwitch() {
return compareTo(JDK1_7) >= 0; return compareTo(JDK1_7) >= 0;
} }
// JSR 292: recognize @PolymorphicSignature on java/dyn names
public boolean allowPolymorphicSignature() {
return compareTo(JDK1_7) >= 0;
}
public static SourceVersion toSourceVersion(Source source) { public static SourceVersion toSourceVersion(Source source) {
switch(source) { switch(source) {
case JDK1_2: case JDK1_2:

View File

@ -120,6 +120,7 @@ public class Symtab {
public final Type cloneableType; public final Type cloneableType;
public final Type serializableType; public final Type serializableType;
public final Type methodHandleType; public final Type methodHandleType;
public final Type polymorphicSignatureType;
public final Type invokeDynamicType; public final Type invokeDynamicType;
public final Type throwableType; public final Type throwableType;
public final Type errorType; public final Type errorType;
@ -291,24 +292,6 @@ public class Symtab {
} }
} }
public void synthesizeMHTypeIfMissing(final Type type) {
final Completer completer = type.tsym.completer;
if (completer != null) {
type.tsym.completer = new Completer() {
public void complete(Symbol sym) throws CompletionFailure {
try {
completer.complete(sym);
} catch (CompletionFailure e) {
sym.flags_field |= (PUBLIC | ABSTRACT);
((ClassType) sym.type).supertype_field = objectType;
// do not bother to create MH.type if not visibly declared
// this sym just accumulates invoke(...) methods
}
}
};
}
}
public void synthesizeBoxTypeIfMissing(final Type type) { public void synthesizeBoxTypeIfMissing(final Type type) {
ClassSymbol sym = reader.enterClass(boxedName[type.tag]); ClassSymbol sym = reader.enterClass(boxedName[type.tag]);
final Completer completer = sym.completer; final Completer completer = sym.completer;
@ -426,6 +409,7 @@ public class Symtab {
throwableType = enterClass("java.lang.Throwable"); throwableType = enterClass("java.lang.Throwable");
serializableType = enterClass("java.io.Serializable"); serializableType = enterClass("java.io.Serializable");
methodHandleType = enterClass("java.dyn.MethodHandle"); methodHandleType = enterClass("java.dyn.MethodHandle");
polymorphicSignatureType = enterClass("java.dyn.MethodHandle$PolymorphicSignature");
invokeDynamicType = enterClass("java.dyn.InvokeDynamic"); invokeDynamicType = enterClass("java.dyn.InvokeDynamic");
errorType = enterClass("java.lang.Error"); errorType = enterClass("java.lang.Error");
illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException"); illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException");
@ -463,8 +447,7 @@ public class Symtab {
synthesizeEmptyInterfaceIfMissing(cloneableType); synthesizeEmptyInterfaceIfMissing(cloneableType);
synthesizeEmptyInterfaceIfMissing(serializableType); synthesizeEmptyInterfaceIfMissing(serializableType);
synthesizeMHTypeIfMissing(methodHandleType); synthesizeEmptyInterfaceIfMissing(polymorphicSignatureType);
synthesizeMHTypeIfMissing(invokeDynamicType);
synthesizeBoxTypeIfMissing(doubleType); synthesizeBoxTypeIfMissing(doubleType);
synthesizeBoxTypeIfMissing(floatType); synthesizeBoxTypeIfMissing(floatType);
synthesizeBoxTypeIfMissing(voidType); synthesizeBoxTypeIfMissing(voidType);

View File

@ -122,7 +122,6 @@ public class Attr extends JCTree.Visitor {
relax = (options.get("-retrofit") != null || relax = (options.get("-retrofit") != null ||
options.get("-relax") != null); options.get("-relax") != null);
useBeforeDeclarationWarning = options.get("useBeforeDeclarationWarning") != null; useBeforeDeclarationWarning = options.get("useBeforeDeclarationWarning") != null;
allowInvokedynamic = options.get("invokedynamic") != null;
enableSunApiLintControl = options.get("enableSunApiLintControl") != null; enableSunApiLintControl = options.get("enableSunApiLintControl") != null;
} }
@ -155,10 +154,6 @@ public class Attr extends JCTree.Visitor {
*/ */
boolean allowAnonOuterThis; boolean allowAnonOuterThis;
/** Switch: allow invokedynamic syntax
*/
boolean allowInvokedynamic;
/** /**
* Switch: warn about use of variable before declaration? * Switch: warn about use of variable before declaration?
* RFE: 6425594 * RFE: 6425594
@ -1377,9 +1372,15 @@ public class Attr extends JCTree.Visitor {
// as a special case, MethodHandle.<T>invoke(abc) and InvokeDynamic.<T>foo(abc) // as a special case, MethodHandle.<T>invoke(abc) and InvokeDynamic.<T>foo(abc)
// has type <T>, and T can be a primitive type. // has type <T>, and T can be a primitive type.
if (tree.meth.getTag() == JCTree.SELECT && !typeargtypes.isEmpty()) { if (tree.meth.getTag() == JCTree.SELECT && !typeargtypes.isEmpty()) {
Type selt = ((JCFieldAccess) tree.meth).selected.type; JCFieldAccess mfield = (JCFieldAccess) tree.meth;
if ((selt == syms.methodHandleType && methName == names.invoke) || selt == syms.invokeDynamicType) { if ((mfield.selected.type.tsym != null &&
(mfield.selected.type.tsym.flags() & POLYMORPHIC_SIGNATURE) != 0)
||
(mfield.sym != null &&
(mfield.sym.flags() & POLYMORPHIC_SIGNATURE) != 0)) {
assert types.isSameType(restype, typeargtypes.head) : mtype; assert types.isSameType(restype, typeargtypes.head) : mtype;
assert mfield.selected.type == syms.methodHandleType
|| mfield.selected.type == syms.invokeDynamicType;
typeargtypesNonRefOK = true; typeargtypesNonRefOK = true;
} }
} }

View File

@ -768,6 +768,12 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
&& s.owner.kind != MTH && s.owner.kind != MTH
&& types.isSameType(c.type, syms.deprecatedType)) && types.isSameType(c.type, syms.deprecatedType))
s.flags_field |= Flags.DEPRECATED; s.flags_field |= Flags.DEPRECATED;
// Internally to java.dyn, a @PolymorphicSignature annotation
// translates to a classfile attribute.
if (!c.type.isErroneous()
&& types.isSameType(c.type, syms.polymorphicSignatureType)) {
s.flags_field |= Flags.POLYMORPHIC_SIGNATURE;
}
if (!annotated.add(a.type.tsym)) if (!annotated.add(a.type.tsym))
log.error(a.pos, "duplicate.annotation"); log.error(a.pos, "duplicate.annotation");
} }

View File

@ -67,7 +67,7 @@ public class Resolve {
JCDiagnostic.Factory diags; JCDiagnostic.Factory diags;
public final boolean boxingEnabled; // = source.allowBoxing(); public final boolean boxingEnabled; // = source.allowBoxing();
public final boolean varargsEnabled; // = source.allowVarargs(); public final boolean varargsEnabled; // = source.allowVarargs();
public final boolean allowInvokedynamic; // = options.get("invokedynamic"); public final boolean allowPolymorphicSignature;
private final boolean debugResolve; private final boolean debugResolve;
public static Resolve instance(Context context) { public static Resolve instance(Context context) {
@ -105,7 +105,7 @@ public class Resolve {
varargsEnabled = source.allowVarargs(); varargsEnabled = source.allowVarargs();
Options options = Options.instance(context); Options options = Options.instance(context);
debugResolve = options.get("debugresolve") != null; debugResolve = options.get("debugresolve") != null;
allowInvokedynamic = options.get("invokedynamic") != null; allowPolymorphicSignature = source.allowPolymorphicSignature() || options.get("invokedynamic") != null;
} }
/** error symbols, which are returned when resolution fails /** error symbols, which are returned when resolution fails
@ -301,6 +301,7 @@ public class Resolve {
boolean useVarargs, boolean useVarargs,
Warner warn) Warner warn)
throws Infer.InferenceException { throws Infer.InferenceException {
assert ((m.flags() & (POLYMORPHIC_SIGNATURE|HYPOTHETICAL)) != POLYMORPHIC_SIGNATURE);
if (useVarargs && (m.flags() & VARARGS) == 0) return null; if (useVarargs && (m.flags() & VARARGS) == 0) return null;
Type mt = types.memberType(site, m); Type mt = types.memberType(site, m);
@ -575,6 +576,14 @@ public class Resolve {
if (sym.kind == ERR) return bestSoFar; if (sym.kind == ERR) return bestSoFar;
if (!sym.isInheritedIn(site.tsym, types)) return bestSoFar; if (!sym.isInheritedIn(site.tsym, types)) return bestSoFar;
assert sym.kind < AMBIGUOUS; assert sym.kind < AMBIGUOUS;
if ((sym.flags() & POLYMORPHIC_SIGNATURE) != 0 && allowPolymorphicSignature) {
assert(site.tag == CLASS);
// Never match a MethodHandle.invoke directly.
if (useVarargs | allowBoxing | operator)
return bestSoFar;
// Supply an exactly-typed implicit method instead.
sym = findPolymorphicSignatureInstance(env, sym.owner.type, sym.name, (MethodSymbol) sym, argtypes, typeargtypes);
}
try { try {
if (rawInstantiate(env, site, sym, argtypes, typeargtypes, if (rawInstantiate(env, site, sym, argtypes, typeargtypes,
allowBoxing, useVarargs, Warner.noWarnings) == null) { allowBoxing, useVarargs, Warner.noWarnings) == null) {
@ -745,6 +754,14 @@ public class Resolve {
boolean allowBoxing, boolean allowBoxing,
boolean useVarargs, boolean useVarargs,
boolean operator) { boolean operator) {
Symbol bestSoFar = methodNotFound;
if ((site.tsym.flags() & POLYMORPHIC_SIGNATURE) != 0 &&
allowPolymorphicSignature &&
site.tag == CLASS &&
!(useVarargs | allowBoxing | operator)) {
// supply an exactly-typed implicit method in java.dyn.InvokeDynamic
bestSoFar = findPolymorphicSignatureInstance(env, site, name, null, argtypes, typeargtypes);
}
return findMethod(env, return findMethod(env,
site, site,
name, name,
@ -752,7 +769,7 @@ public class Resolve {
typeargtypes, typeargtypes,
site.tsym.type, site.tsym.type,
true, true,
methodNotFound, bestSoFar,
allowBoxing, allowBoxing,
useVarargs, useVarargs,
operator); operator);
@ -896,13 +913,14 @@ public class Resolve {
* @param argtypes The method's value arguments. * @param argtypes The method's value arguments.
* @param typeargtypes The method's type arguments * @param typeargtypes The method's type arguments
*/ */
Symbol findImplicitMethod(Env<AttrContext> env, Symbol findPolymorphicSignatureInstance(Env<AttrContext> env,
Type site, Type site,
Name name, Name name,
List<Type> argtypes, MethodSymbol spMethod, // sig. poly. method or null if none
List<Type> typeargtypes) { List<Type> argtypes,
assert allowInvokedynamic; List<Type> typeargtypes) {
assert site == syms.invokeDynamicType || (site == syms.methodHandleType && name == names.invoke); assert allowPolymorphicSignature;
//assert site == syms.invokeDynamicType || site == syms.methodHandleType : site;
ClassSymbol c = (ClassSymbol) site.tsym; ClassSymbol c = (ClassSymbol) site.tsym;
Scope implicit = c.members().next; Scope implicit = c.members().next;
if (implicit == null) { if (implicit == null) {
@ -917,12 +935,22 @@ public class Resolve {
return methodNotFound; return methodNotFound;
} }
List<Type> paramtypes = Type.map(argtypes, implicitArgType); List<Type> paramtypes = Type.map(argtypes, implicitArgType);
long flags;
List<Type> exType;
if (spMethod != null) {
exType = spMethod.getThrownTypes();
flags = spMethod.flags() & AccessFlags;
} else {
// make it throw all exceptions
//assert(site == syms.invokeDynamicType);
exType = List.of(syms.throwableType);
flags = PUBLIC | STATIC;
}
MethodType mtype = new MethodType(paramtypes, MethodType mtype = new MethodType(paramtypes,
restype, restype,
List.<Type>nil(), exType,
syms.methodClass); syms.methodClass);
int flags = PUBLIC | ABSTRACT; flags |= ABSTRACT | HYPOTHETICAL | POLYMORPHIC_SIGNATURE;
if (site == syms.invokeDynamicType) flags |= STATIC;
Symbol m = null; Symbol m = null;
for (Scope.Entry e = implicit.lookup(name); for (Scope.Entry e = implicit.lookup(name);
e.scope != null; e.scope != null;
@ -1337,14 +1365,6 @@ public class Resolve {
methodResolutionCache.put(steps.head, sym); methodResolutionCache.put(steps.head, sym);
steps = steps.tail; steps = steps.tail;
} }
if (sym.kind >= AMBIGUOUS &&
allowInvokedynamic &&
(site == syms.invokeDynamicType ||
site == syms.methodHandleType && name == names.invoke)) {
// lookup failed; supply an exactly-typed implicit method
sym = findImplicitMethod(env, site, name, argtypes, typeargtypes);
env.info.varArgs = false;
}
if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
MethodResolutionPhase errPhase = MethodResolutionPhase errPhase =
firstErroneousResolutionPhase(); firstErroneousResolutionPhase();

View File

@ -1098,6 +1098,12 @@ public class ClassReader implements Completer {
} }
}, },
new AttributeReader(names.PolymorphicSignature, V45_3/*S.B.V51*/, CLASS_OR_MEMBER_ATTRIBUTE) {
void read(Symbol sym, int attrLen) {
sym.flags_field |= POLYMORPHIC_SIGNATURE;
}
},
// The following attributes for a Code attribute are not currently handled // The following attributes for a Code attribute are not currently handled
// StackMapTable // StackMapTable

View File

@ -651,6 +651,13 @@ public class ClassWriter extends ClassFile {
endAttr(alenIdx); endAttr(alenIdx);
acount++; acount++;
} }
if ((flags & POLYMORPHIC_SIGNATURE) != 0) {
if (target.majorVersion < 51)
throw new AssertionError("PolymorphicSignature attributes in java/dyn must be written with -target 7 (required major version is 51, current is"+target.majorVersion+")");
int alenIdx = writeAttr(names.PolymorphicSignature);
endAttr(alenIdx);
acount++;
}
return acount; return acount;
} }

View File

@ -121,7 +121,7 @@ public class Gen extends JCTree.Visitor {
: options.get("-g:vars") != null; : options.get("-g:vars") != null;
genCrt = options.get("-Xjcov") != null; genCrt = options.get("-Xjcov") != null;
debugCode = options.get("debugcode") != null; debugCode = options.get("debugcode") != null;
allowInvokedynamic = options.get("invokedynamic") != null; allowInvokedynamic = target.hasInvokedynamic() || options.get("invokedynamic") != null;
generateIproxies = generateIproxies =
target.requiresIproxy() || target.requiresIproxy() ||

View File

@ -281,9 +281,6 @@ public class Main {
} }
} }
} }
if (target.hasInvokedynamic()) {
options.put("invokedynamic", "invokedynamic");
}
// handle this here so it works even if no other options given // handle this here so it works even if no other options given
String showClass = options.get("showClass"); String showClass = options.get("showClass");

View File

@ -103,6 +103,7 @@ public class Names {
public final Name RuntimeInvisibleTypeAnnotations; public final Name RuntimeInvisibleTypeAnnotations;
public final Name RuntimeVisibleParameterAnnotations; public final Name RuntimeVisibleParameterAnnotations;
public final Name RuntimeInvisibleParameterAnnotations; public final Name RuntimeInvisibleParameterAnnotations;
public final Name PolymorphicSignature;
public final Name Value; public final Name Value;
public final Name EnclosingMethod; public final Name EnclosingMethod;
public final Name desiredAssertionStatus; public final Name desiredAssertionStatus;
@ -115,7 +116,6 @@ public class Names {
public final Name value; public final Name value;
public final Name getMessage; public final Name getMessage;
public final Name getClass; public final Name getClass;
public final Name invoke;
public final Name TYPE; public final Name TYPE;
public final Name TYPE_USE; public final Name TYPE_USE;
public final Name TYPE_PARAMETER; public final Name TYPE_PARAMETER;
@ -213,6 +213,7 @@ public class Names {
RuntimeInvisibleTypeAnnotations = fromString("RuntimeInvisibleTypeAnnotations"); RuntimeInvisibleTypeAnnotations = fromString("RuntimeInvisibleTypeAnnotations");
RuntimeVisibleParameterAnnotations = fromString("RuntimeVisibleParameterAnnotations"); RuntimeVisibleParameterAnnotations = fromString("RuntimeVisibleParameterAnnotations");
RuntimeInvisibleParameterAnnotations = fromString("RuntimeInvisibleParameterAnnotations"); RuntimeInvisibleParameterAnnotations = fromString("RuntimeInvisibleParameterAnnotations");
PolymorphicSignature = fromString("PolymorphicSignature");
Value = fromString("Value"); Value = fromString("Value");
EnclosingMethod = fromString("EnclosingMethod"); EnclosingMethod = fromString("EnclosingMethod");
@ -227,7 +228,6 @@ public class Names {
value = fromString("value"); value = fromString("value");
getMessage = fromString("getMessage"); getMessage = fromString("getMessage");
getClass = fromString("getClass"); getClass = fromString("getClass");
invoke = fromString("invoke");
TYPE = fromString("TYPE"); TYPE = fromString("TYPE");
TYPE_USE = fromString("TYPE_USE"); TYPE_USE = fromString("TYPE_USE");

View File

@ -47,7 +47,7 @@ package meth;
import java.dyn.InvokeDynamic; import java.dyn.InvokeDynamic;
public class InvokeDyn { public class InvokeDyn {
void test() { void test() throws Throwable {
Object x = "hello"; Object x = "hello";
InvokeDynamic.greet(x, "world", 123); InvokeDynamic.greet(x, "world", 123);
InvokeDynamic.greet(x, "mundus", 456); InvokeDynamic.greet(x, "mundus", 456);

View File

@ -48,28 +48,56 @@ public class InvokeMH {
void test(MethodHandle mh_SiO, void test(MethodHandle mh_SiO,
MethodHandle mh_vS, MethodHandle mh_vS,
MethodHandle mh_vi, MethodHandle mh_vi,
MethodHandle mh_vv) { MethodHandle mh_vv) throws Throwable {
Object o; String s; int i; // for return type testing Object o; String s; int i; // for return type testing
// next five must have sig = (String,int)Object // next five must have sig = (String,int)Object
mh_SiO.invoke("world", 123); mh_SiO.invokeExact("world", 123);
mh_SiO.invoke("mundus", 456); mh_SiO.invokeExact("mundus", 456);
Object k = "kosmos"; Object k = "kosmos";
mh_SiO.invoke((String)k, 789); mh_SiO.invokeExact((String)k, 789);
o = mh_SiO.invoke((String)null, 000); o = mh_SiO.invokeExact((String)null, 000);
o = mh_SiO.<Object>invoke("arda", -123); o = mh_SiO.<Object>invokeExact("arda", -123);
// sig = ()String // sig = ()String
s = mh_vS.<String>invoke(); s = mh_vS.<String>invokeExact();
// sig = ()int // sig = ()int
i = mh_vi.<int>invoke(); i = mh_vi.<int>invokeExact();
o = mh_vi.<int>invoke(); o = mh_vi.<int>invokeExact();
//s = mh_vi.<int>invoke(); //BAD //s = mh_vi.<int>invokeExact(); //BAD
mh_vi.<int>invoke(); mh_vi.<int>invokeExact();
// sig = ()void // sig = ()void
//o = mh_vv.<void>invoke(); //BAD //o = mh_vv.<void>invokeExact(); //BAD
mh_vv.<void>invoke(); mh_vv.<void>invokeExact();
}
void testGen(MethodHandle mh_SiO,
MethodHandle mh_vS,
MethodHandle mh_vi,
MethodHandle mh_vv) throws Throwable {
Object o; String s; int i; // for return type testing
// next five must have sig = (*,*)*
mh_SiO.invokeGeneric((Object)"world", (Object)123);
mh_SiO.<void>invokeGeneric((Object)"mundus", (Object)456);
Object k = "kosmos";
mh_SiO.invokeGeneric(k, 789);
o = mh_SiO.invokeGeneric(null, 000);
o = mh_SiO.<Object>invokeGeneric("arda", -123);
// sig = ()String
o = mh_vS.invokeGeneric();
// sig = ()int
i = mh_vi.<int>invokeGeneric();
o = mh_vi.invokeGeneric();
//s = mh_vi.<int>invokeGeneric(); //BAD
mh_vi.<void>invokeGeneric();
// sig = ()void
//o = mh_vv.<void>invokeGeneric(); //BAD
o = mh_vv.invokeGeneric();
} }
} }