--- a/meth.patch Mon Sep 29 19:33:33 2008 -0700
+++ b/meth.patch Wed Oct 08 22:38:47 2008 -0700
@@ -1,3 +1,24 @@ diff --git a/src/share/classes/com/sun/t
+diff --git a/src/share/classes/com/sun/tools/classfile/OpCodes.java b/src/share/classes/com/sun/tools/classfile/OpCodes.java
+--- a/src/share/classes/com/sun/tools/classfile/OpCodes.java
++++ b/src/share/classes/com/sun/tools/classfile/OpCodes.java
+@@ -293,7 +293,7 @@
+ public static final int opc_invokespecial = 183;
+ public static final int opc_invokestatic = 184;
+ public static final int opc_invokeinterface = 185;
+-// public static final int opc_xxxunusedxxx = 186;
++ public static final int opc_invokedynamic = 186;
+ public static final int opc_new = 187;
+ public static final int opc_newarray = 188;
+ public static final int opc_anewarray = 189;
+@@ -526,7 +526,7 @@
+ "invokespecial", // was "invokenonvirtual",
+ "invokestatic",
+ "invokeinterface",
+- "bytecode 186", //"xxxunusedxxx",
++ "invokedynamic", // JSR 292
+ "new",
+ "newarray",
+ "anewarray",
diff --git a/src/share/classes/com/sun/tools/javac/code/Symtab.java b/src/share/classes/com/sun/tools/javac/code/Symtab.java
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java
+++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java
@@ -53,28 +74,165 @@ diff --git a/src/share/classes/com/sun/t
synthesizeBoxTypeIfMissing(doubleType);
synthesizeBoxTypeIfMissing(floatType);
-diff --git a/src/share/classes/com/sun/tools/javac/code/Types.java b/src/share/classes/com/sun/tools/javac/code/Types.java
---- a/src/share/classes/com/sun/tools/javac/code/Types.java
-+++ b/src/share/classes/com/sun/tools/javac/code/Types.java
-@@ -874,6 +874,9 @@
+diff --git a/src/share/classes/com/sun/tools/javac/comp/Attr.java b/src/share/classes/com/sun/tools/javac/comp/Attr.java
+--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java
++++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java
+@@ -118,6 +118,7 @@
+ relax = (options.get("-retrofit") != null ||
+ options.get("-relax") != null);
+ useBeforeDeclarationWarning = options.get("useBeforeDeclarationWarning") != null;
++ allowInvokedynamic = options.get("invokedynamic") != null;
+ }
+
+ /** Switch: relax some constraints for retrofit mode.
+@@ -148,6 +149,10 @@
+ * objects during constructor call?
*/
- public boolean isCastable(Type t, Type s, Warner warn) {
- if (t == s)
-+ return true;
-+
-+ if (s == syms.dynamicType && (allowBoxing || !s.isPrimitive()))
- return true;
-
- if (t.isPrimitive() != s.isPrimitive())
+ boolean allowAnonOuterThis;
++
++ /** Switch: allow invokedynamic syntax
++ */
++ boolean allowInvokedynamic;
+
+ /**
+ * Switch: warn about use of variable before declaration?
+@@ -438,14 +443,22 @@
+ }
+
+ /** Attribute a type argument list, returning a list of types.
++ * Caller is responsible for calling checkRefTypes.
+ */
+- List<Type> attribTypes(List<JCExpression> trees, Env<AttrContext> env) {
++ List<Type> attribAnyTypes(List<JCExpression> trees, Env<AttrContext> env) {
+ ListBuffer<Type> argtypes = new ListBuffer<Type>();
+ for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail)
+- argtypes.append(chk.checkRefType(l.head.pos(), attribType(l.head, env)));
++ argtypes.append(attribType(l.head, env));
+ return argtypes.toList();
+ }
+
++ /** Attribute a type argument list, returning a list of types.
++ * Check that all the types are references.
++ */
++ List<Type> attribTypes(List<JCExpression> trees, Env<AttrContext> env) {
++ List<Type> types = attribAnyTypes(trees, env);
++ return chk.checkRefTypes(trees, types);
++ }
+
+ /**
+ * Attribute type variables (of generic classes or methods).
+@@ -1194,6 +1207,7 @@
+
+ // The types of the actual method type arguments.
+ List<Type> typeargtypes = null;
++ boolean typeargtypesNonRefOK = false;
+
+ Name methName = TreeInfo.name(tree.meth);
+
+@@ -1281,7 +1295,8 @@
+ // Otherwise, we are seeing a regular method call.
+ // Attribute the arguments, yielding list of argument types, ...
+ argtypes = attribArgs(tree.args, localEnv);
+- typeargtypes = attribTypes(tree.typeargs, localEnv);
++ typeargtypes = attribAnyTypes(tree.typeargs, localEnv);
++ boolean nonRefsOK = false;
+
+ // ... and attribute the method using as a prototype a methodtype
+ // whose formal argument types is exactly the list of actual
+@@ -1316,6 +1331,20 @@
+ BoundKind.EXTENDS,
+ syms.boundClass)),
+ restype.tsym);
++ }
++
++ // as a special case, MethodHandle.<T>invoke(abc) and Dynamic.<T>foo(abc)
++ // has type <T>, and T can be a primitive type.
++ if (tree.meth.getTag() == JCTree.SELECT && !typeargtypes.isEmpty()) {
++ Type selt = ((JCFieldAccess) tree.meth).selected.type;
++ if ((selt == syms.methodHandleType && methName == names.invoke) || selt == syms.dynamicType) {
++ assert types.isSameType(restype, typeargtypes.head) : mtype;
++ typeargtypesNonRefOK = true;
++ }
++ }
++
++ if (!typeargtypesNonRefOK) {
++ chk.checkRefTypes(tree.typeargs, typeargtypes);
+ }
+
+ // Check that value of resulting type is admissible in the
+@@ -1919,7 +1948,8 @@
+ // Check if type-qualified fields or methods are static (JLS)
+ if ((sym.flags() & STATIC) == 0 &&
+ sym.name != names._super &&
+- (sym.kind == VAR || sym.kind == MTH)) {
++ (sym.kind == VAR || sym.kind == MTH) &&
++ !(allowInvokedynamic && sym.owner == syms.dynamicType.tsym)) {
+ rs.access(rs.new StaticError(sym),
+ tree.pos(), site, sym.name, true);
+ }
+diff --git a/src/share/classes/com/sun/tools/javac/comp/Check.java b/src/share/classes/com/sun/tools/javac/comp/Check.java
+--- a/src/share/classes/com/sun/tools/javac/comp/Check.java
++++ b/src/share/classes/com/sun/tools/javac/comp/Check.java
+@@ -207,6 +207,12 @@
+ * @param found The type that was found.
+ */
+ Type typeTagError(DiagnosticPosition pos, Object required, Object found) {
++ // this error used to be raised by the parser,
++ // but has been delayed to this point:
++ if (found instanceof Type && ((Type)found).tag == VOID) {
++ log.error(pos, "illegal.start.of.type");
++ return syms.errType;
++ }
+ log.error(pos, "type.found.req", found, required);
+ return syms.errType;
+ }
+@@ -545,6 +551,20 @@
+ diags.fragment("type.req.ref"),
+ t);
+ }
++ }
++
++ /** Check that each type is a reference type, i.e. a class, interface or array type
++ * or a type variable.
++ * @param trees Original trees, used for error reporting.
++ * @param types The types to be checked.
++ */
++ List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
++ List<JCExpression> tl = trees;
++ for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
++ l.head = checkRefType(tl.head.pos(), l.head);
++ tl = tl.tail;
++ }
++ return types;
+ }
+
+ /** Check that type is a null or reference type.
diff --git a/src/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/share/classes/com/sun/tools/javac/comp/Resolve.java
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java
-@@ -852,6 +852,62 @@
+@@ -62,6 +62,7 @@
+ JCDiagnostic.Factory diags;
+ public final boolean boxingEnabled; // = source.allowBoxing();
+ public final boolean varargsEnabled; // = source.allowVarargs();
++ public final String invokedynamicString; // = options.get("invokedynamic");
+ private final boolean debugResolve;
+
+ public static Resolve instance(Context context) {
+@@ -99,6 +100,7 @@
+ varargsEnabled = source.allowVarargs();
+ Options options = Options.instance(context);
+ debugResolve = options.get("debugresolve") != null;
++ invokedynamicString = options.get("invokedynamic");
+ }
+
+ /** error symbols, which are returned when resolution fails
+@@ -852,6 +854,83 @@
return bestSoFar;
}
+ /** Find or create an implicit method of exactly the given type (after erasure).
+ * Searches in a side table, not the main scope of the site.
++ * This emulates the lookup process required by JSR 292 in JVM.
+ * @param env The current environment.
+ * @param site The original type from where the selection
+ * takes place.
@@ -87,29 +245,49 @@ diff --git a/src/share/classes/com/sun/t
+ Name name,
+ List<Type> argtypes,
+ List<Type> typeargtypes) {
++ assert invokedynamicString != null;
+ assert site == syms.dynamicType || (site == syms.methodHandleType && name == names.invoke);
++ boolean isTransitionalStatic = (site == syms.dynamicType && invokedynamicString.equals("invokestatic"));
+ ClassSymbol c = (ClassSymbol) site.tsym;
+ Scope implicit = c.members().next;
-+ if (implicit == null)
++ if (implicit == null) {
+ c.members().next = implicit = new Scope(c);
-+ MethodType mtype = new MethodType(Type.map(argtypes, implicitArgType),
-+ syms.objectType,
++ }
++ Type restype;
++ if (typeargtypes.isEmpty()) {
++ restype = syms.objectType;
++ } else {
++ restype = typeargtypes.head;
++ if (!typeargtypes.tail.isEmpty())
++ return methodNotFound;
++ }
++ List<Type> paramtypes = Type.map(argtypes, implicitArgType);
++ if (site == syms.dynamicType && invokedynamicString.equals("invokeinterface")) {
++ // force leading arg to object, so it can act as receiver
++ if (paramtypes.isEmpty())
++ return methodNotFound;
++ paramtypes.head = syms.objectType;
++ }
++ MethodType mtype = new MethodType(paramtypes,
++ restype,
+ List.<Type>nil(),
+ syms.methodClass);
++ int flags = PUBLIC | ABSTRACT | (isTransitionalStatic ? STATIC : 0);
+ Symbol m = null;
+ for (Scope.Entry e = implicit.lookup(name);
+ e.scope != null;
+ e = e.next()) {
+ Symbol sym = e.sym;
+ assert sym.kind == MTH;
-+ if (types.isSameType(mtype, sym.type)) {
++ if (types.isSameType(mtype, sym.type)
++ && (sym.flags() & STATIC) == (flags & STATIC)) {
+ m = sym;
+ break;
+ }
+ }
+ if (m == null) {
+ // create the desired method
-+ m = new MethodSymbol(PUBLIC | ABSTRACT, name, mtype, c);
++ m = new MethodSymbol(flags, name, mtype, c);
+ implicit.enter(m);
+ }
+ assert argumentsAcceptable(argtypes, types.memberType(site, m).getParameterTypes(),
@@ -132,13 +310,14 @@ diff --git a/src/share/classes/com/sun/t
/** Load toplevel or member class with given fully qualified name and
* verify that it is accessible.
* @param env The current environment.
-@@ -1226,6 +1282,13 @@
+@@ -1226,6 +1305,14 @@
sym = findMethod(env, site, name, argtypes, typeargtypes, true,
env.info.varArgs=true, false);
}
+ if (sym.kind >= AMBIGUOUS &&
++ invokedynamicString != null &&
+ (site == syms.dynamicType ||
-+ (site == syms.methodHandleType && name == names.invoke))) {
++ 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;
@@ -146,17 +325,240 @@ diff --git a/src/share/classes/com/sun/t
if (sym.kind >= AMBIGUOUS) {
sym = access(sym, pos, site, name, true, argtypes, typeargtypes);
}
+diff --git a/src/share/classes/com/sun/tools/javac/jvm/ByteCodes.java b/src/share/classes/com/sun/tools/javac/jvm/ByteCodes.java
+--- a/src/share/classes/com/sun/tools/javac/jvm/ByteCodes.java
++++ b/src/share/classes/com/sun/tools/javac/jvm/ByteCodes.java
+@@ -225,7 +225,7 @@
+ invokespecial = 183,
+ invokestatic = 184,
+ invokeinterface = 185,
+- // ___unused___ = 186,
++ invokedynamic = 186,
+ new_ = 187,
+ newarray = 188,
+ anewarray = 189,
+diff --git a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
+--- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
++++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
+@@ -474,6 +474,7 @@
+ if (value instanceof MethodSymbol) {
+ MethodSymbol m = (MethodSymbol)value;
+ poolbuf.appendByte((m.owner.flags() & INTERFACE) != 0
++ && (m.flags() & STATIC) == 0 // JSR 292, transitional
+ ? CONSTANT_InterfaceMethodref
+ : CONSTANT_Methodref);
+ poolbuf.appendChar(pool.put(m.owner));
+diff --git a/src/share/classes/com/sun/tools/javac/jvm/Code.java b/src/share/classes/com/sun/tools/javac/jvm/Code.java
+--- a/src/share/classes/com/sun/tools/javac/jvm/Code.java
++++ b/src/share/classes/com/sun/tools/javac/jvm/Code.java
+@@ -453,6 +453,21 @@
+ if (!alive) return;
+ emit2(meth);
+ state.pop(argsize + 1);
++ state.push(mtype.getReturnType());
++ }
++
++ /** Emit an invokedynamic instruction.
++ */
++ public void emitInvokedynamic(int meth, Type mtype) {
++ // N.B. this format is totally speculative
++ // current plan of record is to introduce invokedynamic in a way that
++ // does not break the verifier (via invokeinterface or invokestatic)
++ int argsize = width(mtype.getParameterTypes());
++ emitop(invokedynamic);
++ if (!alive) return;
++ emit2(meth);
++ emit2(0);
++ state.pop(argsize);
+ state.push(mtype.getReturnType());
+ }
+
diff --git a/src/share/classes/com/sun/tools/javac/jvm/Gen.java b/src/share/classes/com/sun/tools/javac/jvm/Gen.java
--- a/src/share/classes/com/sun/tools/javac/jvm/Gen.java
+++ b/src/share/classes/com/sun/tools/javac/jvm/Gen.java
-@@ -2057,6 +2057,7 @@
- // For basic types, the coerce(...) in genExpr(...) will do
- // the conversion.
- if (tree.clazz.type.tag > lastBaseTag &&
-+ !types.isSameType(tree.clazz.type, syms.dynamicType) &&
- types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) {
- code.emitop2(checkcast, makeRef(tree.pos(), tree.clazz.type));
+@@ -119,6 +119,7 @@
+ : options.get("-g:vars") != null;
+ genCrt = options.get("-Xjcov") != null;
+ debugCode = options.get("debugcode") != null;
++ invokedynamicString = options.get("invokedynamic");
+
+ generateIproxies =
+ target.requiresIproxy() ||
+@@ -155,6 +156,7 @@
+ private final boolean varDebugInfo;
+ private final boolean genCrt;
+ private final boolean debugCode;
++ private final String invokedynamicString;
+
+ /** Default limit of (approximate) size of finalizer to inline.
+ * Zero means always use jsr. 100 or greater means never use
+@@ -2140,6 +2142,24 @@
+ }
+ result = items.
+ makeImmediateItem(sym.type, ((VarSymbol) sym).getConstValue());
++ } else if (invokedynamicString != null && sym.kind == MTH && ssym == syms.dynamicType.tsym) {
++ System.out.println("invokedynamic "+sym);//@@
++ base.drop();
++ if (invokedynamicString.equals("invokedynamic")) {
++ // native form
++ result = items.makeDynamicItem(sym);
++ } else if (invokedynamicString.equals("invokestatic")) {
++ // invokestatic transitional encoding
++ result = items.makeStaticItem(sym);
++ } else if (invokedynamicString.equals("invokeinterface")) {
++ // invokeinterface transitional encoding
++ Symbol sym1 = sym.clone(sym.owner);
++ MethodType type1 = (MethodType) sym1.type.clone();
++ type1.argtypes = type1.argtypes.tail; // drop receiver from type
++ sym1.type = type1;
++ result = items.makeMemberItem(sym1, false);
++ } else
++ assert false : invokedynamicString;
+ } else {
+ if (!accessSuper)
+ sym = binaryQualifier(sym, tree.selected.type);
+diff --git a/src/share/classes/com/sun/tools/javac/jvm/Items.java b/src/share/classes/com/sun/tools/javac/jvm/Items.java
+--- a/src/share/classes/com/sun/tools/javac/jvm/Items.java
++++ b/src/share/classes/com/sun/tools/javac/jvm/Items.java
+@@ -139,6 +139,13 @@
+ */
+ Item makeStaticItem(Symbol member) {
+ return new StaticItem(member);
++ }
++
++ /** Make an item representing a dynamically invoked method.
++ * @param member The represented symbol.
++ */
++ Item makeDynamicItem(Symbol member) {
++ return new DynamicItem(member);
+ }
+
+ /** Make an item representing an instance variable or method.
+@@ -460,6 +467,37 @@
+ return "static(" + member + ")";
}
+ }
++
++ /** An item representing a dynamic call site.
++ */
++ class DynamicItem extends StaticItem {
++ DynamicItem(Symbol member) {
++ super(member);
++ assert member.owner == syms.dynamicType.tsym;
++ }
++
++ Item load() {
++ assert false;
++ return null;
++ }
++
++ void store() {
++ assert false;
++ }
++
++ Item invoke() {
++ // assert target.hasNativeInvokeDynamic();
++ MethodType mtype = (MethodType)member.erasure(types);
++ int rescode = Code.typecode(mtype.restype);
++ code.emitInvokedynamic(pool.put(member), mtype);
++ return stackItem[rescode];
++ }
++
++ public String toString() {
++ return "dynamic(" + member + ")";
++ }
++ }
++
+
+ /** An item representing an instance variable or method.
+ */
+diff --git a/src/share/classes/com/sun/tools/javac/jvm/Target.java b/src/share/classes/com/sun/tools/javac/jvm/Target.java
+--- a/src/share/classes/com/sun/tools/javac/jvm/Target.java
++++ b/src/share/classes/com/sun/tools/javac/jvm/Target.java
+@@ -62,6 +62,11 @@
+
+ /** JDK 6. */
+ JDK1_6("1.6", 50, 0),
++
++ /** Support for the JSR292 prototype compiler (targeting 1.7 VMs
++ * augmented with a few support classes). This is a transitional
++ * option that will not be supported in the product. */
++ JSR292("jsr292", 50, 0),
+
+ /** JDK 7. */
+ JDK1_7("1.7", 51, 0);
+@@ -253,6 +258,18 @@
+ return compareTo(JDK1_5) >= 0;
+ }
+
++ /** Does the VM support method handles and at least emulated invokedynamic?
++ */
++ public boolean hasMethodHandles() {
++ return compareTo(JSR292) >= 0;
++ }
++
++ /** Does the VM support a native invokedynamic instruction?
++ */
++ public boolean hasNativeInvokeDynamic() {
++ return compareTo(JDK1_7) >= 0;
++ }
++
+ /** Although we may not have support for class literals, should we
+ * avoid initializing the class that the literal refers to?
+ * See 4468823
+diff --git a/src/share/classes/com/sun/tools/javac/main/Main.java b/src/share/classes/com/sun/tools/javac/main/Main.java
+--- a/src/share/classes/com/sun/tools/javac/main/Main.java
++++ b/src/share/classes/com/sun/tools/javac/main/Main.java
+@@ -267,13 +267,21 @@
+ }
+ return null;
+ } else {
+- options.put("-target", source.requiredTarget().name);
++ target = source.requiredTarget();
++ options.put("-target", target.name);
+ }
+ } else {
+ if (targetString == null && !source.allowGenerics()) {
+- options.put("-target", Target.JDK1_4.name);
++ target = Target.JDK1_4;
++ options.put("-target", target.name);
+ }
+ }
++ }
++ if (target.hasMethodHandles() && options.get("invokedynamic") == null) {
++ if (target.hasNativeInvokeDynamic())
++ options.put("invokedynamic", "invokedynamic");
++ else
++ options.put("invokedynamic", "invokestatic"); // transitional form
+ }
+ return filenames.toList();
+ }
+diff --git a/src/share/classes/com/sun/tools/javac/parser/Parser.java b/src/share/classes/com/sun/tools/javac/parser/Parser.java
+--- a/src/share/classes/com/sun/tools/javac/parser/Parser.java
++++ b/src/share/classes/com/sun/tools/javac/parser/Parser.java
+@@ -331,6 +331,7 @@
+ */
+ JCExpression illegal(int pos) {
+ setErrorEndPos(S.pos());
++ Thread.dumpStack();//@@
+ if ((mode & EXPR) != 0)
+ return syntaxError(pos, "illegal.start.of.expr");
+ else
+@@ -1067,7 +1068,13 @@
+ return illegal(pos);
+ }
+ } else {
+- return illegal();
++ // Support the corner case of myMethodHandle.<void>invoke() by passing
++ // a void type (like other primitive types) to the next phase.
++ // The error will be reported in Attr.attribTypes or Attr.visitApply.
++ JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTags.VOID));
++ S.nextToken();
++ return ti;
++ //return illegal();
+ }
+ break;
+ default:
diff --git a/src/share/classes/com/sun/tools/javac/util/Name.java b/src/share/classes/com/sun/tools/javac/util/Name.java
--- a/src/share/classes/com/sun/tools/javac/util/Name.java
+++ b/src/share/classes/com/sun/tools/javac/util/Name.java
@@ -194,6 +596,17 @@ diff --git a/src/share/classes/com/sun/t
public final Name TYPE;
public final Name FIELD;
+diff --git a/src/share/classes/com/sun/tools/javap/CodeWriter.java b/src/share/classes/com/sun/tools/javap/CodeWriter.java
+--- a/src/share/classes/com/sun/tools/javap/CodeWriter.java
++++ b/src/share/classes/com/sun/tools/javap/CodeWriter.java
+@@ -256,6 +256,7 @@
+ return 3;
+ }
+ case opc_invokeinterface:
++ case opc_invokedynamic:
+ {
+ int index = attr.getUnsignedShort(pc + 1);
+ int nargs = attr.getUnsignedByte(pc + 3);
diff --git a/test/tools/javac/meth/InvokeDyn.java b/test/tools/javac/meth/InvokeDyn.java
new file mode 100644
--- /dev/null
@@ -224,7 +637,7 @@ new file mode 100644
+
+/*
+ * @test
-+ * @bug 0000000
++ * @bug 6754038
+ * @summary Generate call sites for method handle
+ * @author jrose
+ *
@@ -246,19 +659,19 @@ new file mode 100644
+public class InvokeDyn {
+ void test() {
+ Object x = "hello";
-+ ((Dynamic)x).greet("world", 123);
-+ ((Dynamic)x).greet("mundus", 456);
-+ ((Dynamic)x).greet("kosmos", 789);
-+ ((Dynamic)10.11121).cogitate(3.14);
-+ ((Dynamic)null).#"yow: what I mean to say is, please treat this one specially"(null);
-+ ((Dynamic)"goodbye").invoke();
++ Dynamic.greet(x, "world", 123);
++ Dynamic.greet(x, "mundus", 456);
++ Dynamic.greet(x, "kosmos", 789);
++ Dynamic.<String>cogitate(10.11121, 3.14);
++ Dynamic.<void>#"yow: what I mean to say is, please treat this one specially"(null);
++ Dynamic.<int>invoke("goodbye");
+ }
+}
diff --git a/test/tools/javac/meth/InvokeMH.java b/test/tools/javac/meth/InvokeMH.java
new file mode 100644
--- /dev/null
+++ b/test/tools/javac/meth/InvokeMH.java
-@@ -0,0 +1,52 @@
+@@ -0,0 +1,73 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -284,7 +697,7 @@ new file mode 100644
+
+/*
+ * @test
-+ * @bug 0000000
++ * @bug 6754038
+ * @summary Generate call sites for method handle
+ * @author jrose
+ *
@@ -296,7 +709,7 @@ new file mode 100644
+ * $ javap -c -classpath dist meth.InvokeMH
+ * </code>
+ *
-+ * @run main meth.InvokeMH
++ * @compile InvokeMH.java
+ */
+
+package meth;
@@ -304,10 +717,132 @@ new file mode 100644
+import java.dyn.MethodHandle;
+
+public class InvokeMH {
-+ void test(MethodHandle mh) {
-+ mh.invoke("world", 123);
-+ mh.invoke("mundus", 456);
-+ mh.invoke("kosmos", 789);
-+ mh.invoke();
++ void test(MethodHandle mh_SiO,
++ MethodHandle mh_vS,
++ MethodHandle mh_vi,
++ MethodHandle mh_vv) {
++ Object o; String s; int i; // for return type testing
++
++ // next five must have sig = (String,int)Object
++ mh_SiO.invoke("world", 123);
++ mh_SiO.invoke("mundus", 456);
++ Object k = "kosmos";
++ mh_SiO.invoke((String)k, 789);
++ o = mh_SiO.invoke((String)null, 000);
++ o = mh_SiO.<Object>invoke("arda", -123);
++
++ // sig = ()String
++ s = mh_vS.<String>invoke();
++
++ // sig = ()int
++ i = mh_vi.<int>invoke();
++ o = mh_vi.<int>invoke();
++ //s = mh_vi.<int>invoke(); //BAD
++ mh_vi.<int>invoke();
++
++ // sig = ()void
++ //o = mh_vv.<void>invoke(); //BAD
++ mh_vv.<void>invoke();
+ }
+}
+diff --git a/test/tools/javac/meth/MakeNegTests.sh b/test/tools/javac/meth/MakeNegTests.sh
+new file mode 100644
+--- /dev/null
++++ b/test/tools/javac/meth/MakeNegTests.sh
+@@ -0,0 +1,96 @@
++#!/bin/sh
++
++#
++# Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
++# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++#
++# This code is free software; you can redistribute it and/or modify it
++# under the terms of the GNU General Public License version 2 only, as
++# published by the Free Software Foundation.
++#
++# This code is distributed in the hope that it will be useful, but WITHOUT
++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++# version 2 for more details (a copy is included in the LICENSE file that
++# accompanied this code).
++#
++# You should have received a copy of the GNU General Public License version
++# 2 along with this work; if not, write to the Free Software Foundation,
++# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++#
++# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
++# CA 95054 USA or visit www.sun.com if you need additional information or
++# have any questions.
++#
++
++# @test
++# @bug 6754038
++# @summary Verify correct rejection of strongly typed return values
++# @run shell MakeNegTests.sh
++
++default_template=InvokeMH.java
++javacflags='-target 7'
++# the rest of this file is a generic "//BAD"-line tester
++
++: ${TESTSRC=.} ${TESTCLASSES=.}
++javac="${TESTJAVA+${TESTJAVA}/bin/}javac"
++
++verbose=false quiet=false
++
++main() {
++ case "${@-}" in
++ *.java*)
++ for template; do
++ expand_and_test "$template"
++ done;;
++ *) expand_and_test "${TESTSRC}/$default_template";;
++ esac
++}
++
++expand_and_test() {
++ template=$1
++ expand "$@"
++ testneg "$@"
++}
++
++expand() {
++ template=$1
++ badlines=` grep -n < "$template" '//BAD' `
++ badcount=` echo "$badlines" | wc -l `
++ [ $badcount -gt 0 ] || { echo "No negative test cases in $template"; exit 1; }
++ $quiet || echo "Expanding $badcount negative test cases from $template:"
++ $quiet || echo "$badlines"
++ badnums=` echo "$badlines" | sed 's/:.*//' `
++ casestem=` getcasestem "$template" `
++ tclassname=` basename "$template" .java `
++ rm -f "$casestem"*.java
++ for badnum in $badnums; do
++ casefile="$casestem"${badnum}.java
++ cclassname=` basename "$casefile" .java `
++ sed < "$template" > "$casefile" "
++ ${badnum}s:^ *[/*]*: :
++ s/${tclassname}/${cclassname}/g
++ "
++ $verbose && diff -u "$template" "$casefile"
++ done
++}
++
++getcasestem() {
++ echo "$1" | sed 's/\.java$//;s/_BAD[0-9]*$//;s/$/_BAD/'
++}
++
++testneg() {
++ template=$1
++ for casefile in ` getcasestem "$template" `*.java; do
++ $quiet || echo -------- $javac $javacflags "$casefile"
++ $javac $javacflags "$casefile" > "$casefile".errlog 2>&1 && {
++ echo "*** Compilation unexpectedly succeeded: $casefile"
++ exit 1
++ }
++ $quiet || echo "Compilation failed as expected"
++ $quiet || head ` $verbose || echo -3 ` < "$casefile".errlog
++ rm "$casefile".errlog
++ done
++}
++
++main "$@"