changeset 3297:3700d512c76d

Fix: descriptors should not mention type-variables that are not in scope when using -XDgenericClassFile
author mcimadamore
date Fri, 29 Jan 2016 15:57:10 +0000
parents ee3dd386c16b
children 776432d52150
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/SpecializeTypes.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolWriter.java test/tools/javac/valhalla/typespec/GenericMethod01.java test/tools/javac/valhalla/typespec/GenericMethod02.java
diffstat 8 files changed, 71 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Thu Jan 28 17:46:46 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Fri Jan 29 15:57:10 2016 +0000
@@ -304,6 +304,11 @@
      */
     public static final long VIRTUAL = 1L << 55;
 
+    /**
+     * Flag to mark generic method bridges (using alt translation method)
+     */
+    public static final long GENERIC_METHOD_BRIDGE = 1L << 55;
+
 
 
     /* Type-variable declaration flags - since standard Java flags are not supported on type
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Thu Jan 28 17:46:46 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Fri Jan 29 15:57:10 2016 +0000
@@ -2541,6 +2541,7 @@
             for (Symbol sym2 : ct.tsym.members().getSymbolsByName(sym.name, NON_RECURSIVE)) {
                 // VM allows methods and variables with differing types
                 if (sym.kind == sym2.kind &&
+                    (sym.flags() & GENERIC_METHOD_BRIDGE) == (sym2.flags() & GENERIC_METHOD_BRIDGE) &&
                     types.isSameType(sym.erasure(types), sym2.erasure(types)) &&
                     sym != sym2 &&
                     (sym.flags() & Flags.SYNTHETIC) != (sym2.flags() & Flags.SYNTHETIC) &&
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/SpecializeTypes.java	Thu Jan 28 17:46:46 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/SpecializeTypes.java	Fri Jan 29 15:57:10 2016 +0000
@@ -159,6 +159,9 @@
     /** enclosing operation. */
     JCExpression enclOp;
 
+    /** translation map for non specialized generic method calls */
+    Map<Symbol, Symbol> genericMethodBridgeMap = new HashMap<>();
+
     /**
      * Specialize a generic constructor call (if needed).
      */
@@ -351,6 +354,10 @@
                 //set type to be inferred type (instead of indy return type). This will cause
                 //usual checkcast to be generated during TransTypes (where required).
                 return (E)methInv.setType(tree.type);
+            } else if (desugarGenericMethods && !msym.isConstructor() &&
+                    msym.type.getTypeArguments().stream().anyMatch(types::isAnyTypeVar)) {
+                //generic constructors not supported in this scheme
+                TreeInfo.setSymbol(((JCMethodInvocation)tree).meth, genericMethodBridgeSym(msym));
             }
         }
         return tree;
@@ -820,6 +827,9 @@
 
         types.substBounds(newTypeParams, oldTypeParams, newTypeParams);
 
+        //init bridge
+        MethodSymbol bridgeSym = (MethodSymbol)genericMethodBridgeSym(msym);
+
         //init generic inner class type
         genMethodClassSym.type = new ClassType(msym.isStatic() ? Type.noType : currentClass.type,
                 newTypeParams,
@@ -874,20 +884,28 @@
         translate(desugaredClassDecl);
 
         //create bridge
-        JCMethodDecl bridgeDecl = make.MethodDef(msym, null);
+        bridgeSym.type = types.subst(msym.type,
+                        oldTypeParams,
+                        oldTypeParams.stream().map(types::erasure).collect(List.collector())).asMethodType();
+        JCMethodDecl bridgeDecl = make.MethodDef(bridgeSym, null);
         JCNewClass newClazz = make.NewClass(null, List.nil(), make.Ident(genMethodClassSym), List.nil(), null);
         newClazz.constructor = defaultConstr;
         newClazz.constructorType = defaultConstr.type;
-        newClazz.type = genMethodClassSym.type;
-        JCFieldAccess bridgedCall = make.Select(newClazz, msym.name);
-        bridgedCall.type = types.erasure(desugaredMethod.type);
+        newClazz.type = newClazz.clazz.type = types.subst(genMethodClassSym.type,
+                newTypeParams,
+                newTypeParams.stream().map(types::erasure).collect(List.collector()));
+        JCFieldAccess bridgedCall = make.Select(newClazz, bridgeSym.name);
+        bridgedCall.type = types.memberType(newClazz.type, desugaredMethod);
         bridgedCall.sym = desugaredMethod;
         List<JCExpression> args = bridgeDecl.params.stream()
                 .map(p -> make.Ident(p.sym)).collect(List.collector());
-        JCStatement stat = msym.type.getReturnType().hasTag(VOID) ?
+        JCStatement stat = bridgeSym.type.getReturnType().hasTag(VOID) ?
                 make.Exec(make.App(bridgedCall, args).setType(syms.voidType)) :
-                make.Return(make.App(bridgedCall, args).setType(types.erasure(msym.type.getReturnType())));
+                make.Return(make.App(bridgedCall, args).setType(bridgeSym.getReturnType()));
         bridgeDecl.body = make.Block(0, List.of(stat));
+
+        msym.flags_field |= Flags.HYPOTHETICAL;
+
         return bridgeDecl;
     }
     //where
@@ -1018,6 +1036,18 @@
             return names.fromString(String.valueOf(Math.abs(params.hashCode())));
         }
 
+        private Symbol genericMethodBridgeSym(Symbol msym) {
+            Symbol bridgeSym = genericMethodBridgeMap.get(msym);
+            if (bridgeSym == null) {
+                bridgeSym = msym.clone(msym.owner);
+                bridgeSym.flags_field |= Flags.SYNTHETIC | Flags.SPECIALIZABLE |
+                        Flags.GENERIC_METHOD_BRIDGE; //this is a trick to fixup method name when writing the class
+                msym.enclClass().members().enter(bridgeSym);
+                genericMethodBridgeMap.put(msym, bridgeSym);
+            }
+            return bridgeSym;
+        }
+
     /**
      * Generate a tree corresponding to a virtual (synthetic) interface. Such an interface contains
      * two things: (i) boxing getters/setters for the anyfied class fields; (ii) boxing bridges for
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Thu Jan 28 17:46:46 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Fri Jan 29 15:57:10 2016 +0000
@@ -560,6 +560,7 @@
         // Check that we do not introduce a name clash by erasing types.
         for (Symbol sym : tree.sym.owner.members().getSymbolsByName(tree.name)) {
             if (sym != tree.sym &&
+                (sym.flags() & GENERIC_METHOD_BRIDGE) == (tree.sym.flags() & GENERIC_METHOD_BRIDGE) &&
                 types.isSameType(erasure(sym.type), tree.type)) {
                 log.error(tree.pos(),
                           "name.clash.same.erasure", tree.sym,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Thu Jan 28 17:46:46 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Fri Jan 29 15:57:10 2016 +0000
@@ -474,7 +474,19 @@
      */
     int writeMemberAttrs(Symbol sym) {
         int acount = writeFlagAttrs(sym.flags());
+        acount += writeSignatureIfNeeded(sym);
+
+        acount += writeJavaAnnotations(sym.getRawAttributes());
+        acount += writeTypeAnnotations(sym.getRawTypeAttributes(), false);
+        return acount;
+    }
+
+    int writeSignatureIfNeeded(Symbol sym) {
+        int acount = 0;
         long flags = sym.flags();
+        if ((flags & GENERIC_METHOD_BRIDGE) != 0) {
+            return writeSignatureIfNeeded(sym.baseSymbol());
+        }
         if (needsMemberSignature(sym)) {
 
             //if member is synthetic, pick SpecialzierSignature instead
@@ -504,9 +516,6 @@
                 acount++;
             }
         }
-
-        acount += writeJavaAnnotations(sym.getRawAttributes());
-        acount += writeTypeAnnotations(sym.getRawTypeAttributes(), false);
         return acount;
     }
 
@@ -944,6 +953,9 @@
      * TypeVariableMap attribute. If the input type-variable list is empty, no attribute is added.
      */
     private int writeTypeVariablesMapIfNeeded(Symbol sym) {
+        if ((sym.flags() & GENERIC_METHOD_BRIDGE) != 0) {
+            return writeTypeVariablesMapIfNeeded(sym.baseSymbol());
+        }
         if (sym.kind == MTH && sym.type.getTypeArguments().isEmpty()) {
             //do not generate tvars mapping for non-generic method
             return 0;
@@ -1790,6 +1802,8 @@
             result |= ACC_VARARGS;
         if ((flags & DEFAULT) != 0)
             result &= ~ABSTRACT;
+        if ((flags & GENERIC_METHOD_BRIDGE) != 0)
+            result &= ~SYNTHETIC;
         return result;
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolWriter.java	Thu Jan 28 17:46:46 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolWriter.java	Fri Jan 29 15:57:10 2016 +0000
@@ -59,7 +59,6 @@
 import com.sun.tools.javac.jvm.Pool.TypeVariable;
 import com.sun.tools.javac.util.Assert;
 import com.sun.tools.javac.util.ByteBuffer;
-import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.Name;
 import com.sun.tools.javac.util.Tuple.Tuple2;
 
@@ -109,9 +108,11 @@
         this.pool = new Pool();
         this.types = types;
         this.genericClassFile = genericClassFile;
-        this.typeVarsByOwner = types.typeVarsByOwner(poolClass).stream()
+        if (genericClassFile) {
+            this.typeVarsByOwner = types.typeVarsByOwner(poolClass).stream()
                     .flatMap(t -> t.elem1.stream())
                     .toArray(Type[]::new);
+        }
     }
 
     /**
@@ -285,7 +286,10 @@
         }
         
         private Entry visitDescriptor(Descriptor d) {
-            ClassRef cref = makeClass(d.site);
+            boolean simpleSite = genericClassFile && d.isStatic();
+            ClassRef cref = simpleSite ?
+                    (ClassRef)visit(d.site.tsym, null) :
+                    makeClass(d.site);
             NameAndType nt = makeNameAndType(d.name, d.externalType(types));
             Entry e = new MemberRef(memberTag(d.site, d), cref, nt, d);
             return pool.put(e);
@@ -429,6 +433,7 @@
             useNewCPForms = true;
             int adr = 0;
             for (; adr < typeVarsByOwner.length && typeVarsByOwner[adr].tsym != tv.tsym ; adr++ );
+            Assert.check(tv.tsym.owner.kind == TYP && adr < typeVarsByOwner.length);
             Entry erasure = typeArgPosition ?
                     makeConstant(types.names.fromString("_")) :
                     visit(types.getBounds(tv).head, typeNameFunc);
--- a/test/tools/javac/valhalla/typespec/GenericMethod01.java	Thu Jan 28 17:46:46 2016 +0000
+++ b/test/tools/javac/valhalla/typespec/GenericMethod01.java	Fri Jan 29 15:57:10 2016 +0000
@@ -30,10 +30,10 @@
  * @compile GenericMethod01.java
  * @run main GenericMethod01 *
  * @clean .*
- * @compile -XDuseUnsharedTable -XDdesugarGenericMethods GenericMethod01.java
+ * @compile -XDdesugarGenericMethods GenericMethod01.java
  * @run main GenericMethod01
  * @clean .*
- * @compile -XDuseUnsharedTable -XDgenericClassFile GenericMethod01.java
+ * @compile -XDgenericClassFile GenericMethod01.java
  */
 public class GenericMethod01 {
 
--- a/test/tools/javac/valhalla/typespec/GenericMethod02.java	Thu Jan 28 17:46:46 2016 +0000
+++ b/test/tools/javac/valhalla/typespec/GenericMethod02.java	Fri Jan 29 15:57:10 2016 +0000
@@ -30,7 +30,7 @@
  * @compile -XDdesugarGenericMethods GenericMethod02.java
  * @run main GenericMethod02
  * @clean .*
- * @compile -XDgenericClassFile GenericMethod01.java
+ * @compile -XDgenericClassFile GenericMethod02.java
  */
 public class GenericMethod02 {