changeset 63:79557a2bd213

indy-bsm: rebase, adjust annotation resolution
author jrose
date Thu, 12 Aug 2010 14:36:12 -0700
parents d1667dc5ddcf
children e25df59bd472
files indy-bsm-6964498.patch
diffstat 1 files changed, 130 insertions(+), 100 deletions(-) [+]
line wrap: on
line diff
--- a/indy-bsm-6964498.patch	Thu Aug 12 14:31:54 2010 -0700
+++ b/indy-bsm-6964498.patch	Thu Aug 12 14:36:12 2010 -0700
@@ -302,7 +302,7 @@
 diff --git a/src/share/classes/com/sun/tools/javac/code/Symbol.java b/src/share/classes/com/sun/tools/javac/code/Symbol.java
 --- a/src/share/classes/com/sun/tools/javac/code/Symbol.java
 +++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java
-@@ -1318,6 +1318,40 @@
+@@ -1318,6 +1318,43 @@
          }
      }
  
@@ -338,6 +338,9 @@
 +
 +        public MemberReferenceSymbol getBootstrapMethod() { return bootstrapMethod; }
 +        public MethodSymbol getCallMethod() { return (MethodSymbol) other; }
++        public InvokeDynamicSymbol changeCallMethod(MethodSymbol callMethod) {
++            return new InvokeDynamicSymbol(bootstrapMethod, callMethod);
++        }
 +    }
 +
      /** A class for predefined operators.
@@ -346,7 +349,7 @@
 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
-@@ -119,9 +119,12 @@
+@@ -119,9 +119,11 @@
      public final Type stringBuilderType;
      public final Type cloneableType;
      public final Type serializableType;
@@ -355,11 +358,10 @@
      public final Type polymorphicSignatureType;
      public final Type invokeDynamicType;
 +    public final Type bootstrapMethodType;
-+    public final Type callSiteType;
      public final Type throwableType;
      public final Type errorType;
      public final Type illegalArgumentExceptionType;
-@@ -408,9 +411,12 @@
+@@ -408,9 +410,11 @@
          cloneableType = enterClass("java.lang.Cloneable");
          throwableType = enterClass("java.lang.Throwable");
          serializableType = enterClass("java.io.Serializable");
@@ -368,11 +370,10 @@
          polymorphicSignatureType = enterClass("java.dyn.MethodHandle$PolymorphicSignature");
          invokeDynamicType = enterClass("java.dyn.InvokeDynamic");
 +        bootstrapMethodType = enterClass("java.dyn.BootstrapMethod");
-+        callSiteType = enterClass("java.dyn.CallSite");
          errorType = enterClass("java.lang.Error");
          illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException");
          exceptionType = enterClass("java.lang.Exception");
-@@ -448,6 +454,7 @@
+@@ -448,6 +452,7 @@
          synthesizeEmptyInterfaceIfMissing(cloneableType);
          synthesizeEmptyInterfaceIfMissing(serializableType);
          synthesizeEmptyInterfaceIfMissing(polymorphicSignatureType);
@@ -383,66 +384,31 @@
 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
-@@ -1373,24 +1373,40 @@
-                               restype.tsym);
+@@ -1380,6 +1380,23 @@
              }
  
--            // 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)
--                  ||
--                  (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;
--                  assert mfield.selected.type == syms.methodHandleType
--                      || mfield.selected.type == syms.invokeDynamicType;
--                  typeargtypesNonRefOK = true;
--              }
-+            // Special case logic for JSR 292 types.
-+            if (tree.meth.getTag() == JCTree.SELECT) {
+             // Special case logic for JSR 292 types.
++            if (rs.recognizeInvokeDynamic && tree.meth.getTag() == JCTree.SELECT) {
 +                JCFieldAccess mfield = (JCFieldAccess) tree.meth;
-+                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)) {
-+
-+                    // MethodHandle.<T>invoke(abc) and InvokeDynamic.<T>foo(abc)
-+                    // has type <T>, and T can be a primitive type.
-+                    if (!typeargtypes.isEmpty()) {
-+                        assert types.isSameType(restype, typeargtypes.head) : mtype;
-+                        assert mfield.selected.type == syms.methodHandleType
-+                            || mfield.selected.type == syms.invokeDynamicType;
-+                        typeargtypesNonRefOK = true;
-+                    }
-+
-+                    // InvokeDynamic requires a type annotation @BootstrapMethod.
-+                    if (mfield.selected.type == syms.invokeDynamicType) {
-+                        MemberReferenceSymbol bsm = resolveBootstrapMethod(tree);
-+                        if (bsm == null) {
-+                            if (allowTransitionalJSR292)
++                // InvokeDynamic requires an enclosing annotation @BootstrapMethod.
++                if (mfield.selected.type == syms.invokeDynamicType) {
++                    Symbol bsm = resolveBootstrapMethod(tree);
++                    if (!(bsm instanceof MemberReferenceSymbol)) {
++                        if (!bsm.type.isErroneous()) {
++                            if (rs.allowTransitionalJSR292)
 +                                log.warning(tree.pos(), "invokedynamic.must.have.bootstrap.method");
 +                            else
 +                                log.error(tree.pos(), "invokedynamic.must.have.bootstrap.method");
 +                        }
-+                        mfield.sym = new InvokeDynamicSymbol(bsm, (MethodSymbol) mfield.sym);
++                        bsm = null;
 +                    }
++                    mfield.sym = new InvokeDynamicSymbol((MemberReferenceSymbol) bsm, (MethodSymbol) mfield.sym);
 +                }
-             }
- 
-             if (!typeargtypesNonRefOK) {
-@@ -1429,6 +1445,129 @@
++            }
+             if (rs.allowTransitionalJSR292 && tree.meth.getTag() == JCTree.SELECT && !typeargtypes.isEmpty()) {
+                 JCFieldAccess mfield = (JCFieldAccess) tree.meth;
+                 // MethodHandle.<T>invoke(abc) and InvokeDynamic.<T>foo(abc)
+@@ -1430,6 +1447,121 @@
              return (typeargtypes == null) ? mt : (Type)new ForAll(typeargtypes, mt);
          }
  
@@ -450,12 +416,12 @@
 +     * Resolve the bootstrap method for an invokedynamic site.
 +     * The method is specified by @BootstrapMethod annotation on the
 +     * InvokeDynamic's type parameter, or else on an enclosing definition.
++     * Return noSymbol or errSymbol on failure.
 +     */
-+    MemberReferenceSymbol resolveBootstrapMethod(JCMethodInvocation tree) {
-+        Attribute.Compound bsm = findBootstrapMethod(tree);
-+        if (bsm == null)
-+            bsm = findBootstrapMethod(env);  // look it up in the environment
-+        if (bsm == null)  return null;
++    Symbol resolveBootstrapMethod(JCMethodInvocation tree) {
++        assert rs.recognizeInvokeDynamic;
++        Attribute.Compound bsm = findBootstrapMethod(env);  // look it up in the environment
++        if (bsm == null)  return syms.noSymbol;
 +        assert bsm.type.tsym == syms.bootstrapMethodType.tsym;
 +        int bsmPos = tree.pos;  //FIXME: put this on the @BootstrapMethod anno.
 +
@@ -464,7 +430,7 @@
 +        // - name of bootstrap method (or null string, for new & <init>)
 +        // - argument types of bootstrap method
 +        MethodSymbol[] attrSyms = bootstrapMethodAnnotationSyms();
-+        if (attrSyms == null)  return null;  // no structure to decode
++        if (attrSyms == null)  return syms.noSymbol;  // no structure to decode
 +        Object[] values = new Object[attrSyms.length];
 +        for (int i = 0; i < attrSyms.length; i++) {
 +            Attribute m = bsm.member(attrSyms[i].name);
@@ -496,7 +462,7 @@
 +            if (buf != null)  sampleArgs = buf.toList();
 +        }
 +        if (classValue == null || methName == null || sampleArgs == null)
-+            return null;
++            return syms.noSymbol;
 +        boolean isConstructor = (methName == names.init);
 +        JCExpression bootm;
 +        if (!isConstructor)
@@ -509,24 +475,29 @@
 +                                             sampleArgs, null);
 +        Env<AttrContext> localEnv = env.enclosing(JCTree.CLASSDEF);
 +        localEnv = localEnv.dup(tree, localEnv.info.dup());
-+        Type bsmtype = attribExpr(make.TypeCast(syms.callSiteType, bootm), localEnv);
-+        if (bsmtype.isErroneous())  return null;
++        Type bsmtype = attribExpr(make.TypeCast(syms.objectType, bootm), localEnv);
++        if (bsmtype.isErroneous())  return syms.errSymbol;
 +        Symbol bootsym;
 +        if (!isConstructor)
 +            bootsym = TreeInfo.symbol(((JCMethodInvocation)bootm).meth);
 +        else
 +            bootsym = ((JCNewClass)bootm).constructor;
-+        if (!(bootsym instanceof MethodSymbol))  return null;
++        if (!(bootsym instanceof MethodSymbol))  return bootsym;
 +        //System.out.println("resolved bsm: "+bootsym);
 +        assert isConstructor == bootsym.isConstructor();
 +        int refKind = isConstructor ? ClassFile.REF_newInvokeSpecial : ClassFile.REF_invokeStatic;
 +        return new MemberReferenceSymbol(refKind, bootsym);
 +    }
-+    /** Find a default @BootstrapMethod on an enclosing method or class. */
++    /** Find a default @BootstrapMethod on an enclosing declaration, method, or class. */
 +    private Attribute.Compound findBootstrapMethod(Env<AttrContext> innerEnv) {
++        assert rs.recognizeInvokeDynamic;
 +        // Look in the enclosing scopes for a default @BootstrapMethod annotation.
 +        for (Env<AttrContext> env = innerEnv; env.outer != null; env = env.outer) {
 +            Attribute.Compound bsm;
++            if (env.tree.getTag() == JCTree.VARDEF) {
++                bsm = ((JCVariableDecl) env.tree).sym.attribute(syms.bootstrapMethodType.tsym);
++                if (bsm != null)  return bsm;
++            }
 +            if (env.enclMethod != null) {
 +                bsm = env.enclMethod.sym.attribute(syms.bootstrapMethodType.tsym);
 +                if (bsm != null)  return bsm;
@@ -536,22 +507,9 @@
 +        }
 +        return null;
 +    }
-+    /** Search the type annotations of an InvokeDynamic call to find a @BootstrapMethod. */
-+    private Attribute.Compound findBootstrapMethod(JCMethodInvocation tree) {
-+        JCExpression rtype = tree.typeargs.head;  // defaults to null, if no type args
-+        if (rtype != null && rtype.getTag() == JCTree.ANNOTATED_TYPE) {
-+            // By convention, the annotation local to this particular call
-+            // is placed on the return type parameter.
-+            for (JCTypeAnnotation a : ((JCAnnotatedType)rtype).annotations) {
-+                if (a.attribute_field.type.tsym == syms.bootstrapMethodType.tsym) {
-+                    return a.attribute_field;
-+                }
-+            }
-+        }
-+        return null;
-+    }
 +    /** Symbols needed for destructuring a @BootstrapMethod annotation. */
 +    private MethodSymbol[] bootstrapMethodAnnotationSyms() {
++        assert rs.recognizeInvokeDynamic;
 +        if (bootstrapMethodAnnotationSyms == null) {
 +            Scope members = syms.bootstrapMethodType.tsym.members();
 +            Name[] elems = { names.value, names._name, names.arguments };
@@ -572,6 +530,33 @@
      public void visitNewClass(JCNewClass tree) {
          Type owntype = types.createErrorType(tree.type);
  
+@@ -1964,14 +2096,24 @@
+             if (meth.getTag() == JCTree.SELECT) {
+                 JCFieldAccess methsel = (JCFieldAccess)meth;
+                 if (rs.isPolymorphicSignatureInstance(methsel.sym)) {
+-                    MethodSymbol sym = (MethodSymbol) methsel.sym;
++                    MethodSymbol sym;
++                    InvokeDynamicSymbol indysym = null;
++                    if (methsel.sym instanceof InvokeDynamicSymbol)
++                        indysym = (InvokeDynamicSymbol)methsel.sym;
++                    if (indysym != null)
++                        sym = indysym.getCallMethod();
++                    else
++                        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;
++                    if (indysym != null)
++                        methsel.sym = indysym.changeCallMethod((MethodSymbol) newSym);
++                    else
++                        methsel.sym = (MethodSymbol) newSym;
+                 }
+             }
+         }
 diff --git a/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java b/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java
 --- a/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java
 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java
@@ -709,7 +694,7 @@
 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
-@@ -2194,7 +2194,8 @@
+@@ -2200,7 +2200,8 @@
                  makeImmediateItem(sym.type, ((VarSymbol) sym).getConstValue());
          } else if (allowInvokedynamic && sym.kind == MTH && ssym == syms.invokeDynamicType.tsym) {
              base.drop();
@@ -991,12 +976,25 @@
          }
      }
  }
+diff --git a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
+--- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
++++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
+@@ -1177,8 +1177,7 @@
+                     return illegal(pos);
+                 }
+             } else {
+-                // Support the corner case of myMethodHandle.<void>invoke() by passing
+-                // a void type (like other primitive types) to the next phase.
++                // Treat void like a primitive type in the parser.
+                 // The error will be reported in Attr.attribTypes or Attr.visitApply.
+                 JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTags.VOID));
+                 S.nextToken();
 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
+@@ -127,6 +127,11 @@
+ compiler.warn.wrong.target.for.polymorphic.signature=\
+     MethodHandle invocations work correctly only on -target 7 runtimes and better
  
 +compiler.err.invokedynamic.must.have.bootstrap.method=\
 +    InvokeDynamic calls must be in scope of a @BootstrapMethod annotation
@@ -1009,7 +1007,7 @@
 diff --git a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java
 --- a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java
 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java
-@@ -738,6 +738,27 @@
+@@ -744,6 +744,27 @@
          return result;
      }
  
@@ -1164,7 +1162,7 @@
 new file mode 100644
 --- /dev/null
 +++ b/test/tools/javac/meth/IndyLocalBootstrap.java
-@@ -0,0 +1,112 @@
+@@ -0,0 +1,144 @@
 +/*
 + * Copyright 2010 Sun Microsystems, Inc.  All Rights Reserved.
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -1213,34 +1211,37 @@
 +
 +import java.dyn.*;
 +
-+@BootstrapMethod(value=IndyLocalBootstrap.class, name="classBSM")
 +class IndyLocalBootstrap {
 +    public static void main(String... args) throws Throwable {
 +        new IndyLocalBootstrap().run(args);
 +    }
 +    void run(String... args) throws Throwable {
 +        System.out.println("starting");
-+        doFoo1();
++        Foo.doFoo1();
 +        System.out.println("one test done");
-+        Object x = InvokeDynamic.foo2(2); //use classBSM
-+        System.out.println("one more test");
++        Foo.doFoo2();
++        System.out.println("last one");
 +        doFoo3();
 +        System.out.println("all done");
++        if (args.length > 0)
++            BadCases.doBad1();
 +    }
 +
-+    //@BootstrapMethod(FancySite.class, name="make")
-+    private static Object doFoo1() throws Throwable {
-+        return InvokeDynamic.<@BootstrapMethod(value=FancySite.class, name="make") Object>foo1();
-+    }
++    @BootstrapMethod(value=IndyLocalBootstrap.class, name="classBSM")
++    static class Foo {
++        static Object doFoo1() throws Throwable {
++            return InvokeDynamic.foo2(2); //use classBSM
++        }
 +
-+    @BootstrapMethod(FancySite.class)
-+    private static void doFoo3() throws Throwable {
-+        InvokeDynamic.<void>foo3("three"); //use FancySite
++        @BootstrapMethod(FancySite.class)
++        static void doFoo2() throws Throwable {
++            InvokeDynamic.<void>foo2("three"); //use FancySite
++        }
 +    }
 +
 +    // /* //BAD
 +    static //*/
-+    Object classBSM(Object caller, Object name, Object type) {
++    private Object classBSM(Object caller, Object name, Object type) {
 +        return new FancySite((Class)caller, (String)name, (MethodType)type, "IndyLocalBootstrap.classBSM");
 +    }
 +
@@ -1276,4 +1277,33 @@
 +            return new FancySite(caller, name, type, "FancySite.make");
 +        }
 +    }
++
++    static Object doFoo3() throws Throwable {
++        @BootstrapMethod(value=IndyLocalBootstrap.FancySite.class, name="make")
++        Object junk = InvokeDynamic.foo3();
++        return junk;
++    }
++
++    @BootstrapMethod(value=IndyLocalBootstrap.class, name="classBSM")
++    static class BadCases {
++        static Object doBad1() throws Throwable {
++            try {
++                @BootstrapMethod(value=java.util.Arrays.class, name="asList")
++                Object junk = InvokeDynamic.bad1();
++                throw new RuntimeException("unexpected return: "+junk);
++            } catch (ClassCastException ex) {
++                return ex;  // should reach here!
++            }
++        }
++
++        //@BootstrapMethod(value=String.class, name="no.such.method") //BAD
++        static void doBad2() throws Throwable {
++            InvokeDynamic.bad2();
++        }
++
++        //@BootstrapMethod(value=String.class, name="toString") //BAD
++        static void doBad3() throws Throwable {
++            InvokeDynamic.bad3();
++        }
++    }
 +}