changeset 62:d1667dc5ddcf

meth: update EDR fix to favor cast-based target typing
author jrose
date Thu, 12 Aug 2010 14:31:54 -0700
parents 2356cadfea90
children 79557a2bd213
files meth-edrfix.patch
diffstat 1 files changed, 295 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/meth-edrfix.patch	Thu Aug 12 14:31:19 2010 -0700
+++ b/meth-edrfix.patch	Thu Aug 12 14:31:54 2010 -0700
@@ -1,77 +1,260 @@
 Allow new versions of javac to compile old versions of JSR 292 code.
-This patch can go away when the old versions of JSR 292 code have gone away.
-Hopefully, it won't be needed at all.
+Allow new versions of the JSR 292 code to omit type parameters from polymorphic signatures.
+Instead, casts will perform the same function, with a clearer meaning and cleaner syntax.
+When the old versions of JSR 292 code have gone away, we will kill the flag 'allowTransitionalJSR292'.
 
 Local definitions:
  "new version of javac" = version which requires @PolymorphicSignature annotations in java.dyn.MethodHandle.
- "old version of JSR 292 code" = version in which java.dyn.MethodHandle lacks @PolymorphicSignature annotations.
+ "old version of JSR 292 code" = version in which java.dyn.MethodHandle lacks @PolymorphicSignature annotations or uses type parameters.
 
-diff --git a/src/share/classes/com/sun/tools/javac/code/Source.java b/src/share/classes/com/sun/tools/javac/code/Source.java
---- a/src/share/classes/com/sun/tools/javac/code/Source.java
-+++ b/src/share/classes/com/sun/tools/javac/code/Source.java
-@@ -172,6 +172,10 @@
-     public boolean allowPolymorphicSignature() {
-         return compareTo(JDK1_7) >= 0;
-     }
-+    public boolean allowTransitionalJSR292() {
-+        // FIXME: Get rid of this after spec. is finalized and transitional code is gone.
-+        return allowPolymorphicSignature();
-+    }
-     public static SourceVersion toSourceVersion(Source source) {
-         switch(source) {
-         case JDK1_2:
 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 @@
-         allowCovariantReturns = source.allowCovariantReturns();
-         allowAnonOuterThis = source.allowAnonOuterThis();
-         allowStringsInSwitch = source.allowStringsInSwitch();
-+        allowTransitionalJSR292 = source.allowTransitionalJSR292();
-         sourceName = source.name;
-         relax = (options.get("-retrofit") != null ||
-                  options.get("-relax") != null);
-@@ -171,6 +172,9 @@
-      */
-     boolean allowStringsInSwitch;
+@@ -1121,6 +1121,7 @@
  
-+    /** Transitional before JSR 292 final. */
-+    boolean allowTransitionalJSR292;
+     public void visitExec(JCExpressionStatement tree) {
+         attribExpr(tree.expr, env);
++        pushTargetType(syms.voidType, tree.expr);
+         result = null;
+     }
+ 
+@@ -1378,23 +1379,22 @@
+                               restype.tsym);
+             }
+ 
+-            // as a special case, MethodHandle.<T>invoke(abc) and InvokeDynamic.<T>foo(abc)
+-            // has type <T>, and T can be a primitive type.
+-            if (tree.meth.getTag() == JCTree.SELECT && !typeargtypes.isEmpty()) {
+-              JCFieldAccess mfield = (JCFieldAccess) tree.meth;
+-              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 mfield.selected.type == syms.methodHandleType
+-                      || mfield.selected.type == syms.invokeDynamicType;
+-                  typeargtypesNonRefOK = true;
+-              }
++            // Special case logic for JSR 292 types.
++            if (rs.allowTransitionalJSR292 && tree.meth.getTag() == JCTree.SELECT && !typeargtypes.isEmpty()) {
++                JCFieldAccess mfield = (JCFieldAccess) tree.meth;
++                // MethodHandle.<T>invoke(abc) and InvokeDynamic.<T>foo(abc)
++                // has type <T>, and T can be a primitive type.
++                if (mfield.selected.type.tsym == syms.invokeDynamicType.tsym && rs.recognizeInvokeDynamic) {
++                    typeargtypesNonRefOK = true;
++                } else if (mfield.selected.type.tsym == syms.methodHandleType.tsym && rs.recognizeMethodHandles) {
++                    if (mfield.sym != null && rs.isPolymorphicSignatureInstance(mfield.sym))
++                        typeargtypesNonRefOK = true;  // invokeExact, invokeGeneric
++                    else if (methName == names.invoke)
++                        typeargtypesNonRefOK = true;  // older logic that doesn't use annotations
++                }
+             }
+ 
+-            if (!typeargtypesNonRefOK) {
++            if (!(rs.allowTransitionalJSR292 && typeargtypesNonRefOK)) {
+                 chk.checkRefTypes(tree.typeargs, typeargtypes);
+             }
+ 
+@@ -1949,12 +1949,34 @@
+         Type clazztype = attribType(tree.clazz, env);
+         chk.validate(tree.clazz, env);
+         Type exprtype = attribExpr(tree.expr, env, Infer.anyPoly);
++        pushTargetType(clazztype, tree.expr);
+         Type owntype = chk.checkCastable(tree.expr.pos(), exprtype, clazztype);
+         if (exprtype.constValue() != null)
+             owntype = cfolder.coerce(exprtype, owntype);
+         result = check(tree, capture(owntype), VAL, pkind, pt);
+     }
+ 
++    // A cast or occurrence as an expression statement can affect the linkage of some method calls.
++    void pushTargetType(Type targetType, JCExpression expr) {
++        // JSR 292:  Link some calls according to return type as indicated by a cast.
++        if (expr.getTag() == JCTree.APPLY) {
++            JCExpression meth = ((JCMethodInvocation)expr).meth;
++            if (meth.getTag() == JCTree.SELECT) {
++                JCFieldAccess methsel = (JCFieldAccess)meth;
++                if (rs.isPolymorphicSignatureInstance(methsel.sym)) {
++                    MethodSymbol sym = (MethodSymbol) methsel.sym;
++                    MethodType oldType = sym.type.asMethodType();
++                    Symbol newSym = rs.findPolymorphicSignatureInstance(sym.owner.type, sym.name, sym,
++                                                                        targetType,
++                                                                        oldType.argtypes);
++                    if (!rs.isPolymorphicSignatureInstance(newSym))
++                        throw new AssertionError("can't split poly sym: "+sym);
++                    methsel.sym = newSym;
++                }
++            }
++        }
++    }
 +
-     /**
-      * Switch: name of source level; used for error reporting.
-      */
-@@ -1376,6 +1380,10 @@
-               if ((mfield.selected.type.tsym != null &&
-                    (mfield.selected.type.tsym.flags() & POLYMORPHIC_SIGNATURE) != 0)
-                   ||
-+                  (allowTransitionalJSR292 &&  // old logic that doesn't use annotations
-+                   ((mfield.selected.type == syms.methodHandleType && methName == names.invoke)
-+                    || mfield.selected.type == syms.invokeDynamicType))
-+                  ||
-                   (mfield.sym != null &&
-                    (mfield.sym.flags() & POLYMORPHIC_SIGNATURE) != 0)) {
-                   assert types.isSameType(restype, typeargtypes.head) : mtype;
+     public void visitTypeTest(JCInstanceOf tree) {
+         Type exprtype = chk.checkNullOrRefType(
+             tree.expr.pos(), attribExpr(tree.expr, env));
 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
-@@ -68,6 +68,7 @@
+@@ -67,7 +67,9 @@
+     JCDiagnostic.Factory diags;
      public final boolean boxingEnabled; // = source.allowBoxing();
      public final boolean varargsEnabled; // = source.allowVarargs();
-     public final boolean allowPolymorphicSignature;
+-    public final boolean allowPolymorphicSignature;
++    public final boolean recognizeMethodHandles;
++    public final boolean recognizeInvokeDynamic;
 +    public final boolean allowTransitionalJSR292;
      private final boolean debugResolve;
  
      public static Resolve instance(Context context) {
-@@ -106,6 +107,7 @@
+@@ -105,7 +107,10 @@
+         varargsEnabled = source.allowVarargs();
          Options options = Options.instance(context);
          debugResolve = options.get("debugresolve") != null;
-         allowPolymorphicSignature = source.allowPolymorphicSignature() || options.get("invokedynamic") != null;
-+        allowTransitionalJSR292 = source.allowTransitionalJSR292();
+-        allowPolymorphicSignature = source.allowPolymorphicSignature() || options.get("invokedynamic") != null;
++        allowTransitionalJSR292 = options.get("allowTransitionalJSR292") != null;
++        Target target = Target.instance(context);
++        recognizeMethodHandles = allowTransitionalJSR292 || target.hasMethodHandles();
++        recognizeInvokeDynamic = allowTransitionalJSR292 || target.hasInvokedynamic() && source.allowPolymorphicSignature();
      }
  
      /** error symbols, which are returned when resolution fails
-@@ -1365,6 +1367,14 @@
+@@ -301,7 +306,7 @@
+                         boolean useVarargs,
+                         Warner warn)
+         throws Infer.InferenceException {
+-        assert ((m.flags() & (POLYMORPHIC_SIGNATURE|HYPOTHETICAL)) != POLYMORPHIC_SIGNATURE);
++        assert !isPolymorphicSignatureGeneric(m);
+         if (useVarargs && (m.flags() & VARARGS) == 0) return null;
+         Type mt = types.memberType(site, m);
+ 
+@@ -578,13 +583,16 @@
+         if (sym.kind == ERR) return bestSoFar;
+         if (!sym.isInheritedIn(site.tsym, types)) return bestSoFar;
+         assert sym.kind < AMBIGUOUS;
+-        if ((sym.flags() & POLYMORPHIC_SIGNATURE) != 0 && allowPolymorphicSignature) {
++        if (isPolymorphicSignatureGeneric(sym) && recognizeMethodHandles) {
+             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);
++            Type restype = syms.objectType;
++            if (allowTransitionalJSR292)  restype = resultTypeParameter(env, typeargtypes);
++            sym = findPolymorphicSignatureInstance(sym.owner.type, sym.name, (MethodSymbol) sym, restype, argtypes);
++            assert null != instantiate(env, site, sym, argtypes, typeargtypes, false, false, Warner.noWarnings);
+         }
+         try {
+             if (rawInstantiate(env, site, sym, argtypes, typeargtypes,
+@@ -757,12 +765,14 @@
+                       boolean useVarargs,
+                       boolean operator) {
+         Symbol bestSoFar = methodNotFound;
+-        if ((site.tsym.flags() & POLYMORPHIC_SIGNATURE) != 0 &&
+-            allowPolymorphicSignature &&
++        if (isPolymorphicSignatureGeneric(site.tsym) && recognizeInvokeDynamic &&
+             site.tag == CLASS &&
+             !(useVarargs | allowBoxing | operator)) {
+             // supply an exactly-typed implicit method in java.dyn.InvokeDynamic
+-            bestSoFar = findPolymorphicSignatureInstance(env, site, name, null, argtypes, typeargtypes);
++            Type restype = syms.objectType;
++            if (allowTransitionalJSR292)  restype = resultTypeParameter(env, typeargtypes);
++            bestSoFar = findPolymorphicSignatureInstance(site, name, null, restype, argtypes);
++            assert null != instantiate(env, site, bestSoFar, argtypes, typeargtypes, false, false, Warner.noWarnings);
+         }
+         return findMethod(env,
+                           site,
+@@ -908,43 +918,35 @@
+     /** 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.
++     *  @param site      The original type from where the selection takes place.
+      *  @param name      The method's name.
+-     *  @param argtypes  The method's value arguments.
+-     *  @param typeargtypes The method's type arguments
++     *  @param spMethod  A template for the implicit method, or null.
++     *  @param restype   The required return type.
++     *  @param argtypes  The required argument types.
+      */
+-    Symbol findPolymorphicSignatureInstance(Env<AttrContext> env,
+-                                            Type site,
++    Symbol findPolymorphicSignatureInstance(Type site,
+                                             Name name,
+                                             MethodSymbol spMethod,  // sig. poly. method or null if none
+-                                            List<Type> argtypes,
+-                                            List<Type> typeargtypes) {
+-        assert allowPolymorphicSignature;
++                                            Type restype,
++                                            List<Type> argtypes) {
++        assert (recognizeMethodHandles || recognizeInvokeDynamic);
+         //assert site == syms.invokeDynamicType || site == syms.methodHandleType : site;
+         ClassSymbol c = (ClassSymbol) site.tsym;
+         Scope implicit = c.members().next;
+         if (implicit == null) {
+             c.members().next = implicit = new Scope(c);
+         }
+-        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);
+         long flags;
+         List<Type> exType;
+         if (spMethod != null) {
++            assert spMethod.owner == site.tsym;
+             exType = spMethod.getThrownTypes();
+             flags = spMethod.flags() & AccessFlags;
+         } else {
+             // make it throw all exceptions
+-            //assert(site == syms.invokeDynamicType);
++            assert recognizeInvokeDynamic;
++            assert site == syms.invokeDynamicType;
+             exType = List.of(syms.throwableType);
+             flags = PUBLIC | STATIC;
+         }
+@@ -972,7 +974,7 @@
+         }
+         assert argumentsAcceptable(argtypes, types.memberType(site, m).getParameterTypes(),
+                                    false, false, Warner.noWarnings);
+-        assert null != instantiate(env, site, m, argtypes, typeargtypes, false, false, Warner.noWarnings);
++        assert isPolymorphicSignatureInstance(m);
+         return m;
+     }
+     //where
+@@ -989,6 +991,26 @@
+             return argType;
+         }
+ 
++    /** Recognize if this symbol was marked @PolymorphicSignature in the source. */
++    public boolean isPolymorphicSignatureGeneric(Symbol sym) {
++        return ((sym.flags() & (POLYMORPHIC_SIGNATURE | HYPOTHETICAL)) == POLYMORPHIC_SIGNATURE);
++    }
++    /** Recognize if this symbol was split from a @PolymorphicSignature symbol in the source. */
++    public boolean isPolymorphicSignatureInstance(Symbol sym) {
++        return ((sym.flags() & (POLYMORPHIC_SIGNATURE | HYPOTHETICAL)) == (POLYMORPHIC_SIGNATURE | HYPOTHETICAL));
++    }
++
++    /** Decode <T> in foo.<T>invoke(bar), for JSR 292 EDR only. */
++    Type resultTypeParameter(Env<AttrContext> env, List<Type> typeargtypes) {
++        assert allowTransitionalJSR292;
++        if (typeargtypes.isEmpty()) {
++            return syms.objectType;
++        } else {
++            log.warning(env.tree.pos, "type.parameter.on.polymorphic.signature");
++            return typeargtypes.head;
++        }
++    }
++
+     /** Load toplevel or member class with given fully qualified name and
+      *  verify that it is accessible.
+      *  @param env       The current environment.
+@@ -1367,6 +1389,14 @@
              methodResolutionCache.put(steps.head, sym);
              steps = steps.tail;
          }
@@ -80,12 +263,73 @@
 +            (site == syms.invokeDynamicType ||
 +             site == syms.methodHandleType && name == names.invoke)) {
 +            // lookup failed; supply an exactly-typed implicit method
-+            sym = findPolymorphicSignatureInstance(env, site, name, null, argtypes, typeargtypes);
++            sym = findPolymorphicSignatureInstance(site, name, null, resultTypeParameter(env, typeargtypes), argtypes);
 +            env.info.varArgs = false;
 +        }
          if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
              MethodResolutionPhase errPhase =
                      firstErroneousResolutionPhase();
+@@ -1374,6 +1404,10 @@
+                     pos, site, name, true, argtypes, typeargtypes);
+             env.info.varArgs = errPhase.isVarargsRequired;
+         }
++        if (isPolymorphicSignatureGeneric(sym)) {
++            // Should have expanded this sym already.  Oops.
++            log.warning(pos, "wrong.target.for.polymorphic.signature");
++        }
+         return sym;
+     }
+ 
+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
+@@ -259,6 +259,14 @@
+         return compareTo(JDK1_7) >= 0;
+     }
+ 
++    /** Does the VM support polymorphic method handle invocation?
++     *  Affects the linkage information output to the classfile.
++     *  An alias for {@code hasInvokedynamic}, since all the JSR 292 features appear together.
++     */
++    public boolean hasMethodHandles() {
++        return hasInvokedynamic();
++    }
++
+     /** 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
+@@ -282,6 +282,13 @@
+             }
+         }
+ 
++        // phase this out with JSR 292 PFD
++        if ("no".equals(options.get("allowTransitionalJSR292"))) {
++            options.put("allowTransitionalJSR292", null);
++        } else if (target.hasInvokedynamic() && options.get("allowTransitionalJSR292") == null) {
++            options.put("allowTransitionalJSR292", "allowTransitionalJSR292");
++        }
++
+         // handle this here so it works even if no other options given
+         String showClass = options.get("showClass");
+         if (showClass != null) {
+diff --git a/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/share/classes/com/sun/tools/javac/resources/compiler.properties
+--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties
++++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties
+@@ -124,6 +124,11 @@
+ compiler.err.no.superclass=\
+     {0} has no superclass
+ 
++compiler.warn.type.parameter.on.polymorphic.signature\
++    change obsolete notation for MethodHandle invocations from x.<T>invoke(y) to (T)x.invoke(y)
++compiler.warn.wrong.target.for.polymorphic.signature=\
++    MethodHandle invocations work correctly only on -target 7 runtimes and better
++
+ compiler.err.concrete.inheritance.conflict=\
+     methods {0} from {1} and {2} from {3} are inherited with the same signature
+ 
 diff --git a/src/share/classes/com/sun/tools/javac/util/Names.java b/src/share/classes/com/sun/tools/javac/util/Names.java
 --- a/src/share/classes/com/sun/tools/javac/util/Names.java
 +++ b/src/share/classes/com/sun/tools/javac/util/Names.java