changeset 2996:156d2dfb901f

Enhancement: add support for cross-specialization boundaries accessors. * retain generic info associated with accessors in Lower * simulate accessors in specialzied classes * add heuristics to detect cross-specialization boundaries * add flag to mark specializable synthetic symbols * add specialization support for invokestatic/getstatic/putstatic * add smoke tests (contributed by Jan Lahoda)
author mcimadamore
date Fri, 05 Jun 2015 15:03:30 +0100
parents 52d2779ddd19
children 9a9deb54d415
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/IndifierTranslator.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.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/Code.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java test/tools/javac/valhalla/typespec/SpecializedAccessors.java test/tools/javac/valhalla/typespec/SpecializedAccessors2.java test/tools/javac/valhalla/typespec/SpecializedAccessors2Aux.java test/tools/javac/valhalla/typespec/SpecializedAccessors3.java
diffstat 15 files changed, 246 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Wed Jun 03 14:10:17 2015 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Fri Jun 05 15:03:30 2015 +0100
@@ -298,6 +298,11 @@
      */
     public static final long PEELED = 1L<<53;
 
+    /**
+     * Flag to mark specializable (synthetic) symbols
+     */
+    public static final long SPECIALIZABLE = 1L<<54;
+
 
 
     /* Type-variable declaration flags - since standard Java flags are not supported on type
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/IndifierTranslator.java	Wed Jun 03 14:10:17 2015 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/IndifierTranslator.java	Fri Jun 05 15:03:30 2015 +0100
@@ -85,12 +85,12 @@
     protected JCMethodInvocation makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
                                         List<BootstrapArgument<?>> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
                                         Name methName) {
-        return makeIndyCall(pos, syms.noSymbol, site, bsmName, staticArgs, indyType, indyArgs, methName);
+        return makeIndyCall(pos, syms.noSymbol, site, bsmName, staticArgs, indyType, indyArgs, methName, null);
     }
 
     protected JCMethodInvocation makeIndyCall(DiagnosticPosition pos, Symbol owner, Type site, Name bsmName,
                                       List<BootstrapArgument<?>> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
-                                      Name methName) {
+                                      Name methName, Symbol baseSymbol) {
         List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
                 syms.stringType,
                 syms.methodTypeType).appendList(staticArgs.map(a -> a.kind.asType(syms)));
@@ -103,7 +103,12 @@
                 referenceKind(bsm),
                 (MethodSymbol)bsm,
                 indyType,
-                staticArgs.toArray(new BootstrapArgument<?>[staticArgs.length()]));
+                staticArgs.toArray(new BootstrapArgument<?>[staticArgs.length()])) {
+            @Override
+            public Symbol baseSymbol() {
+               return baseSymbol == null ? this : baseSymbol;
+            }
+        };
         int prevPos = make.pos;
         try {
             make.at(pos);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed Jun 03 14:10:17 2015 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Jun 05 15:03:30 2015 +0100
@@ -35,15 +35,12 @@
 import com.sun.tools.javac.tree.TreeMaker;
 import com.sun.tools.javac.tree.TreeTranslator;
 import com.sun.tools.javac.code.Attribute;
-import com.sun.tools.javac.code.Kinds;
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
-import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
 import com.sun.tools.javac.code.Symbol.MethodSymbol;
 import com.sun.tools.javac.code.Symbol.TypeSymbol;
 import com.sun.tools.javac.code.Symbol.VarSymbol;
-import com.sun.tools.javac.code.Symtab;
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.code.Type.MethodType;
 import com.sun.tools.javac.code.Type.TypeVar;
@@ -1891,7 +1888,7 @@
                 // Lambda methods are private synthetic.
                 // Inherit ACC_STRICT from the enclosing method, or, for clinit,
                 // from the class.
-                translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
+                translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD | SPECIALIZABLE |
                         owner.flags_field & STRICTFP |
                         owner.owner.flags_field & STRICTFP |
                         PRIVATE |
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Wed Jun 03 14:10:17 2015 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Jun 05 15:03:30 2015 +0100
@@ -30,6 +30,8 @@
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Kinds.KindSelector;
 import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol.BootstrapArgument;
+import com.sun.tools.javac.comp.SpecializeTypes.SpecializedVarSymbol;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.main.Option.PkgInfo;
 import com.sun.tools.javac.tree.*;
@@ -83,6 +85,7 @@
     private final ConstFold cfolder;
     private final Target target;
     private final Source source;
+    private final SpecializeTypes specializeTypes;
     private final TypeEnvs typeEnvs;
     private final Name dollarAssertionsDisabled;
     private final Name classDollar;
@@ -104,6 +107,7 @@
         cfolder = ConstFold.instance(context);
         target = Target.instance(context);
         source = Source.instance(context);
+        specializeTypes = SpecializeTypes.instance(context);
         typeEnvs = TypeEnvs.instance(context);
         dollarAssertionsDisabled = names.
             fromString(target.syntheticNameChar() + "assertionsDisabled");
@@ -967,6 +971,16 @@
      */
     MethodSymbol accessSymbol(Symbol sym, JCTree tree, JCTree enclOp,
                               boolean protAccess, boolean refSuper) {
+        Symbol specialized = sym.specialized();
+        Symbol baseAcc = null;
+        if (sym != specialized) {
+            baseAcc = accessSymbol(sym.baseSymbol(), tree, enclOp, protAccess, refSuper);
+            if (sym.baseSymbol().isStatic()) {
+                return (MethodSymbol)baseAcc;
+            }
+            sym = specialized;
+        }
+
         ClassSymbol accOwner = refSuper && protAccess
             // For access via qualified super (T.super.x), place the
             // access symbol on T.
@@ -1006,16 +1020,16 @@
                 else
                     argtypes = operator.type.getParameterTypes().tail;
             } else if (acode == ASSIGNcode)
-                argtypes = List.of(vsym.erasure(types));
+                argtypes = List.of(vsym.type);
             else
                 argtypes = List.nil();
-            restype = vsym.erasure(types);
+            restype = vsym.type;
             thrown = List.nil();
             break;
         case MTH:
             acode = DEREFcode;
-            argtypes = vsym.erasure(types).getParameterTypes();
-            restype = vsym.erasure(types).getReturnType();
+            argtypes = vsym.type.getParameterTypes();
+            restype = vsym.type.getReturnType();
             thrown = vsym.type.getThrownTypes();
             break;
         default:
@@ -1031,16 +1045,30 @@
         // of the type containing the accessed symbol, not the class
         // containing the access method.
         if ((vsym.flags() & STATIC) == 0) {
-            argtypes = argtypes.prepend(vsym.owner.erasure(types));
+            argtypes = argtypes.prepend(vsym.owner.type);
         }
         MethodSymbol[] accessors = accessSyms.get(vsym);
         MethodSymbol accessor = accessors[acode];
+        Symbol baseSymbol = sym;
         if (accessor == null) {
             accessor = new MethodSymbol(
-                STATIC | SYNTHETIC | (accOwner.isInterface() ? PUBLIC : 0),
-                accessName(anum.intValue(), acode),
+                (sym.isStatic() ? 0 : SPECIALIZABLE) | STATIC | SYNTHETIC | (accOwner.isInterface() ? PUBLIC : 0),
+                baseAcc != null ? baseAcc.name : accessName(anum.intValue(), acode),
                 new MethodType(argtypes, restype, thrown, syms.methodClass),
-                accOwner);
+                accOwner) {
+                @Override
+                public Symbol baseSymbol() {
+                    return baseSymbol;
+                }
+            };
+            if (sym.type.hasTag(FORALL)) {
+                ForAll fa = (ForAll)sym.type;
+                final Symbol accSym = accessor;
+                List<Type> newTvars = types.newInstances(fa.tvars).stream()
+                        .peek(t -> t.tsym.owner = accSym)
+                        .collect(List.collector());
+                accessor.type = new ForAll(newTvars, types.subst(accessor.type, fa.tvars, newTvars));
+            }
             enterSynthetic(tree.pos(), accessor, accOwner.members());
             accessors[acode] = accessor;
         }
@@ -1061,12 +1089,8 @@
     /** Do we need an access method to reference private symbol?
      */
     boolean needsPrivateAccess(Symbol sym) {
-        if ((sym.flags() & PRIVATE) != 0 &&
-                (sym.flags() & STATIC) != 0 &&
-                sym.enclClass().type.allparams().stream().anyMatch(types::isAnyTypeVar)) {
-            //always require accessor for private static access to specializable class
-            return true;
-        } else if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) {
+        if ((sym.flags() & PRIVATE) == 0 ||
+                (sym.owner == currentClass && !crossSpecializationBoundaries(sym))) {
             return false;
         } else if (sym.name == names.init && sym.owner.isLocal()) {
             // private constructor in local class: relax protection
@@ -1081,7 +1105,7 @@
      */
     boolean needsProtectedAccess(Symbol sym, JCTree tree) {
         if ((sym.flags() & PROTECTED) == 0 ||
-            sym.owner.owner == currentClass.owner || // fast special case
+            (sym.owner.owner == currentClass.owner && !crossSpecializationBoundaries(sym)) || // fast special case
             sym.packge() == currentClass.packge())
             return false;
         if (!currentClass.isSubClass(sym.owner, types))
@@ -1093,6 +1117,12 @@
         return !((JCFieldAccess) tree).selected.type.tsym.isSubClass(currentClass, types);
     }
 
+    boolean crossSpecializationBoundaries(Symbol sym) {
+        return sym.isStatic() ?
+                types.needsMangling(currentClass.type) :
+                !types.isSameType(currentClass.type, sym.specialized().owner.type);
+    }
+
     /** The class in which an access method for given symbol goes.
      *  @param sym        The access symbol
      *  @param protAccess Is access to a protected symbol in another
@@ -1175,7 +1205,13 @@
             break;
         case MTH: case VAR:
             if (sym.owner.kind == TYP) {
-
+                boolean specializedGenericCall = false;
+                Symbol inSym = sym;
+                if (sym instanceof DynamicMethodSymbol &&
+                        ((DynamicMethodSymbol)sym).bsm.owner == syms.genericMethodSpecialzer.tsym) {
+                    sym = sym.baseSymbol();
+                    specializedGenericCall = true;
+                }
                 // Access methods are required for
                 //  - private members,
                 //  - protected members in a superclass of an
@@ -1208,7 +1244,7 @@
                     // to their access methods.
                     if (accReq) {
                         List<JCExpression> args = List.nil();
-                        if ((sym.flags() & STATIC) == 0) {
+                        if (!specializedGenericCall && (sym.flags() & STATIC) == 0) {
                             // Instance access methods get instance
                             // as first parameter.
                             if (base == null)
@@ -1219,10 +1255,17 @@
                         Symbol access = accessSymbol(sym, tree,
                                                      enclOp, protAccess,
                                                      refSuper);
+                        if (specializedGenericCall) {
+                            //patch up indy
+                            DynamicMethodSymbol dynSym = (DynamicMethodSymbol)inSym;
+                            dynSym.staticArgs[1] = BootstrapArgument.MethodHandle(new Pool.MethodHandle(ClassFile.REF_invokeStatic, access, types));
+                            access = dynSym;
+                        }
                         JCExpression receiver = make.Select(
                             base != null ? base : make.QualIdent(access.owner),
                             access);
-                        return make.App(receiver, args);
+
+                        return make.App(receiver, args).setType(access.erasure(types).getReturnType());
 
                     // Other accesses to members of outer classes get a
                     // qualifier.
@@ -1307,8 +1350,10 @@
      */
     void makeAccessible(Symbol sym) {
         JCClassDecl cdef = classDef(sym.owner.enclClass());
-        if (cdef == null) Assert.error("class def not found: " + sym + " in " + sym.owner);
-        if (sym.name == names.init) {
+        if (cdef == null) {
+            Assert.check((sym.owner.enclClass().flags() & SPECIALIZED_CLASS) != 0,
+                    () -> "class def not found: " + sym + " in " + sym.owner);
+        } else if (sym.name == names.init) {
             cdef.defs = cdef.defs.prepend(
                 accessConstructorDef(cdef.pos, sym, accessConstrs.get(sym)));
         } else {
@@ -1379,7 +1424,7 @@
             ref = make.Ident(sym);
             args = make.Idents(md.params);
         } else {
-            JCExpression site = make.Ident(md.params.head);
+            JCExpression site = make.Ident(md.params.head).setType(md.params.head.sym.erasure(types));
             if (acode % 2 != 0) {
                 //odd access codes represent qualified super accesses - need to
                 //emit reference to the direct superclass, even if the refered
@@ -1410,10 +1455,18 @@
                     treeTag(binaryAccessOperator(acode1)), ref, args.head);
                 ((JCAssignOp) expr).operator = binaryAccessOperator(acode1);
             }
-            stat = make.Return(expr.setType(sym.type));
+            stat = make.Return(expr.setType(sym.erasure(types)));
         } else {
             stat = make.Call(make.App(ref, args));
         }
+
+        if (sym.type.hasTag(FORALL)) {
+            JCMethodInvocation app = stat.hasTag(EXEC) ?
+                    (JCMethodInvocation)((JCExpressionStatement)stat).expr :
+                    (JCMethodInvocation)((JCReturn)stat).expr;
+            stat = make.Call(specializeTypes.specializeGenericMethodCallIfNeeded(sym, app, ((ForAll)sym.type).tvars));
+        }
+
         md.body = make.Block(0, List.of(stat));
 
         // Make sure all parameters, result types and thrown exceptions
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/SpecializeTypes.java	Wed Jun 03 14:10:17 2015 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/SpecializeTypes.java	Fri Jun 05 15:03:30 2015 +0100
@@ -75,7 +75,6 @@
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
@@ -153,6 +152,12 @@
      */
     JCExpression specializeGenericMethodCallIfNeeded(JCMethodInvocation tree) {
         Symbol msym = TreeInfo.symbol(tree.meth);
+        return specializeGenericMethodCallIfNeeded(msym, tree, tree.typeargs.nonEmpty() ?
+                        TreeInfo.types(tree.typeargs) :
+                        inferredTypeargs(tree.meth.type, msym));
+    }
+
+    JCExpression specializeGenericMethodCallIfNeeded(Symbol msym, JCMethodInvocation tree, List<Type> inferredTypeargs) {
         JCExpression receiverExpr = null;
         if (!msym.isStatic()) {
             receiverExpr = tree.meth.hasTag(Tag.SELECT) ?
@@ -164,9 +169,7 @@
                 msym,
                 TreeInfo.args(tree),
                 receiverExpr,
-                tree.typeargs.nonEmpty() ?
-                        TreeInfo.types(tree.typeargs) :
-                        inferredTypeargs(tree.meth.type, msym),
+                inferredTypeargs,
                 msym.isStatic() ? msym.owner.type : receiverExpr.type,
                 tree.varargsElement);
     }
@@ -262,7 +265,7 @@
                 }
 
                 JCMethodInvocation methInv = makeIndyCall(tree, msym.owner, syms.genericMethodSpecialzer,
-                        names.metafactory, staticArgs, (MethodType)indyType, args, msym.name);
+                        names.metafactory, staticArgs, (MethodType)indyType, args, msym.name, msym);
                 methInv.varargsElement = varargsElement;
 
                 //set type to be inferred type (instead of indy return type). This will cause
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Wed Jun 03 14:10:17 2015 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Fri Jun 05 15:03:30 2015 +0100
@@ -263,7 +263,7 @@
 
         // Create a bridge method symbol and a bridge definition without a body.
         Type bridgeType = meth.erasure(types);
-        long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE |
+        long flags = impl.flags() & AccessFlags | SPECIALIZABLE | SYNTHETIC | BRIDGE |
                 (origin.isInterface() ? DEFAULT : 0);
         if (hypothetical) flags |= HYPOTHETICAL;
         MethodSymbol bridge = new MethodSymbol(flags,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Wed Jun 03 14:10:17 2015 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Fri Jun 05 15:03:30 2015 +0100
@@ -630,13 +630,15 @@
                     names.Signature :
                     names.SpecializerSignature;
 
-            // note that a local class with captured variables
-            // will get a signature attribute
-            int alenIdx = writeAttr(sigName);
+            if (regularSig || (sym.flags() & SPECIALIZABLE) != 0) {
+                // note that a local class with captured variables
+                // will get a signature attribute
+                int alenIdx = writeAttr(sigName);
 
-            databuf.appendChar(pool.put(typeSig(sym.type, regularSig ? SigMode.NORMAL : SigMode.SPECIALIZER)));
-            endAttr(alenIdx);
-            acount++;
+                databuf.appendChar(pool.put(typeSig(sym.type, regularSig ? SigMode.NORMAL : SigMode.SPECIALIZER)));
+                endAttr(alenIdx);
+                acount++;
+            }
         }
         acount += writeJavaAnnotations(sym.getRawAttributes());
         acount += writeTypeAnnotations(sym.getRawTypeAttributes(), false);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Wed Jun 03 14:10:17 2015 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Fri Jun 05 15:03:30 2015 +0100
@@ -2310,6 +2310,9 @@
             case new_:
             case getfield:
             case putfield:
+            case getstatic:
+            case putstatic:
+            case invokestatic:
             case invokevirtual:
             case invokeinterface:
             case invokespecial:
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Jun 03 14:10:17 2015 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Jun 05 15:03:30 2015 +0100
@@ -1791,6 +1791,18 @@
         // the parameters of the method's external type (that is, any implicit
         // outer instance of a super(...) call appears as first parameter).
         MethodSymbol msym = (MethodSymbol)TreeInfo.symbol(tree.meth);
+        if (msym.name.toString().startsWith("access$") &&
+                m.isAny() && !msym.baseSymbol().isStatic() &&
+                tree.args.head.unerasedType != null) {
+            //patch up any item
+            AnyMemberItem anyItem = (AnyMemberItem)m;
+            List<Type> from = anyItem.ownerType.allparams();
+            List<Type> to = tree.args.head.unerasedType.allparams();
+            m = items.new AnyMemberItem(anyItem.delegatedItem,
+                    types.subst(anyItem.originalType, from, to),
+                    types.subst(anyItem.ownerType, from, to),
+                    types.subst(anyItem.memberType, from, to));
+        }
         genArgs(tree.args,
                 msym.externalType(types).getParameterTypes());
         if (!msym.isDynamic()) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Wed Jun 03 14:10:17 2015 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Fri Jun 05 15:03:30 2015 +0100
@@ -29,17 +29,14 @@
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol.BootstrapArgument;
 import com.sun.tools.javac.code.Type.*;
-import com.sun.tools.javac.code.Types.UnaryVisitor;
 import com.sun.tools.javac.jvm.Code.*;
 import com.sun.tools.javac.jvm.Gen.BinarySymbol;
-import com.sun.tools.javac.jvm.Pool.MethodHandle;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.util.Assert;
 import com.sun.tools.javac.util.ListBuffer;
 import com.sun.tools.javac.util.Name;
 import com.sun.tools.javac.util.Names;
 
-import java.util.Optional;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
@@ -164,15 +161,14 @@
      *  @param member       The represented symbol.
      */
     Item makeStaticMethodItem(Symbol member) {
-        //TODO: this should probably be wrapped too
-        return new StaticMethodItem(member);
+        return wrapStaticIfNeeded(new StaticMethodItem(member), t -> t.getReturnType());
     }
 
     /** Make an item representing an static variable.
      *  @param member       The represented symbol.
      */
     Item makeStaticFieldItem(Symbol member) {
-        return new StaticFieldItem(member);
+        return wrapStaticIfNeeded(new StaticFieldItem(member), t -> t);
     }
 
     /** Make an item representing an internal method call.
@@ -316,6 +312,23 @@
         return result;
     }
 
+    private Item wrapStaticIfNeeded(StaticItem staticItem, Function<Type, Type> typeFunc) {
+        Symbol staticSym = staticItem.member;
+        if ((staticItem.member.flags() & Flags.SPECIALIZABLE) != 0 &&
+                (types.containsSpecializableTvars(staticSym.type) ||
+                types.containsSpecializableTvars(staticSym.owner.type))) {
+            Type ty = staticSym.type;
+            if (ty.hasTag(TypeTag.FORALL)) {
+                ForAll fa = (ForAll)ty;
+                ty = types.subst(ty.asMethodType(), fa.tvars, types.erasure(fa.tvars));
+            }
+            return new AnyMemberItem(staticItem, typeFunc.apply(ty), staticSym.owner.type,
+                    ty);
+        } else {
+            return staticItem;
+        }
+    }
+
     /** The base class of all items, which implements default behavior.
      */
     abstract class Item {
@@ -612,6 +625,9 @@
             switch (opcode) {
                 case getfield:
                 case putfield:
+                case getstatic:
+                case putstatic:
+                case invokestatic:
                 case invokevirtual:
                 case invokeinterface:
                 case invokespecial:
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Wed Jun 03 14:10:17 2015 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Jun 05 15:03:30 2015 +0100
@@ -696,6 +696,7 @@
         case DOUBLE: case BOOLEAN: case VOID:
             tp = TypeIdent(t.getTag());
             break;
+        case ANY_BOUND:
         case TYPEVAR:
             tp = Ident(t.tsym);
             break;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/typespec/SpecializedAccessors.java	Fri Jun 05 15:03:30 2015 +0100
@@ -0,0 +1,23 @@
+/**
+ * @test
+ * @clean .*
+ * @compile SpecializedAccessors.java
+ * @run main SpecializedAccessors
+ */
+public final class SpecializedAccessors<any T> {
+
+    private T t;
+
+    public static void main(String[] args) {
+        Nested.main(args);
+    }
+
+    public static class Nested {
+        public static void main(String[] args) {
+            SpecializedAccessors<int> v = new SpecializedAccessors<>();
+
+            System.err.println(v.t);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/typespec/SpecializedAccessors2.java	Fri Jun 05 15:03:30 2015 +0100
@@ -0,0 +1,31 @@
+/**
+ * @test
+ * @clean .*
+ * @compile SpecializedAccessors2.java
+ * @compile SpecializedAccessors2Aux.java
+ * @run main SpecializedAccessors2
+ */
+public final class SpecializedAccessors2<T> {
+
+    private static <Z1, Z2> Pair<Z1, Z2> combine(Z1 z1, Z2 z2) {
+        return new Pair<>(z1, z2);
+    }
+
+    public static void main(String[] args) {
+        Pair.of("", "");
+    }
+
+    public static class Pair<Z1, Z2> {
+        final Z1 z1;
+        final Z2 z2;
+        public Pair(Z1 z1, Z2 z2) {
+            this.z1 = z1;
+            this.z2 = z2;
+        }
+
+        public static <Z1, Z2> Pair<Z1, Z2> of(Z1 z1, Z2 z2) {
+            return SpecializedAccessors2.combine(z1, z2);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/typespec/SpecializedAccessors2Aux.java	Fri Jun 05 15:03:30 2015 +0100
@@ -0,0 +1,3 @@
+public class SpecializedAccessors2Aux {
+    SpecializedAccessors2 a;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/typespec/SpecializedAccessors3.java	Fri Jun 05 15:03:30 2015 +0100
@@ -0,0 +1,45 @@
+/**
+ * @test
+ * @clean .*
+ * @compile SpecializedAccessors3.java
+ * @run main SpecializedAccessors3
+ */
+public final class SpecializedAccessors3<any T> {
+
+    private T t;
+
+    private <Z> Pair<T, Z> combine(Z z) {
+        return new Pair<>(t, z);
+    }
+
+    private <any Z> Pair<T, Z> combineAny(Z z) {
+        return new Pair<>(t, z);
+    }
+
+    public static void main(String[] args) {
+        SpecializedAccessors3<int> v = new SpecializedAccessors3<>();
+
+        Pair.of(v, "");
+
+        Pair.ofAny(v, "");
+        Pair.ofAny(v, 2L);
+    }
+
+    public static class Pair<any U, any V> {
+        final U u;
+        final V v;
+        public Pair(U u, V v) {
+            this.u = u;
+            this.v = v;
+        }
+
+        public static <any Z1, Z2> Pair<Z1, Z2> of(SpecializedAccessors3<Z1> a, Z2 z2) {
+            return a.combine(z2);
+        }
+
+        public static <any Z1, any Z2> Pair<Z1, Z2> ofAny(SpecializedAccessors3<Z1> a, Z2 z2) {
+            return a.combineAny(z2);
+        }
+    }
+
+}