changeset 3270:2b24dfe17c16

Enhancement: type-specialization backend overhaul * preserve unerased types as much as possible across the compiler pipeline * push specialization logic into the backend * remove support for specialized class symbols * constant pool support rewrite * explicit symbolic representation for method type types and method handles * simplified Items classes (more to come)
author mcimadamore
date Tue, 08 Dec 2015 14:42:24 +0000
parents 6a8a8a94eaef
children e7cdaa508aea
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.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/ClassReader.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/jvm/Pool.java src/jdk.compiler/share/classes/com/sun/tools/javac/sym/CreateSymbols.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java test/tools/javac/lambda/TestInvokeDynamic.java test/tools/javac/scope/7046348/EagerInterfaceCompletionTest.java test/tools/javac/valhalla/typespec/ObjectMethods.out test/tools/javac/valhalla/typespec/items/tests/TestRespecialization.java test/tools/javap/MethodParameters.java
diffstat 23 files changed, 1168 insertions(+), 2000 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Tue Dec 08 14:42:24 2015 +0000
@@ -48,7 +48,7 @@
 import com.sun.tools.javac.comp.AttrContext;
 import com.sun.tools.javac.comp.Env;
 import com.sun.tools.javac.jvm.*;
-import com.sun.tools.javac.jvm.Pool.MethodHandle;
+import com.sun.tools.javac.jvm.Gen.Descriptor;
 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
@@ -376,10 +376,6 @@
              (owner.kind == TYP && owner.isLocal()));
     }
 
-    public Symbol specialized() {
-        return this;
-    }
-
     /** Has this symbol an empty name? This includes anonymous
      *  inner classes.
      */
@@ -663,6 +659,7 @@
         protected T other;
         public DelegatedSymbol(T other) {
             super(other.kind, other.flags_field, other.name, other.type, other.owner);
+            Assert.check(this instanceof Descriptor);
             this.other = other;
         }
         public String toString() { return other.toString(); }
@@ -994,9 +991,9 @@
          */
         public List<ClassSymbol> trans_local;
 
-        /** the constant pool of the class
+        /** the pool writer (shared between {@code Gen} and {@code ClassWriter}.
          */
-        public Pool pool;
+        public PoolWriter poolWriter;
 
         /** the annotation metadata attached to this class */
         private AnnotationTypeMetadata annotationTypeMetadata;
@@ -1008,7 +1005,7 @@
             this.flatname = formFlatName(name, owner);
             this.sourcefile = null;
             this.classfile = null;
-            this.pool = null;
+            this.poolWriter = null;
             this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
         }
 
@@ -1487,6 +1484,14 @@
             return false;
         }
 
+        public boolean isHandle() {
+            return false;
+        }
+
+        public MethodHandleSymbol asHandle() {
+            return new MethodHandleSymbol(this);
+        }
+
         /** find a symbol that this (proxy method) symbol implements.
          *  @param    c       The class whose members are searched for
          *                    implementations
@@ -1877,7 +1882,7 @@
                 FLOAT(Float.class),
                 DOUBLE(Double.class),
                 STRING(String.class),
-                METHOD_HANDLE(Pool.MethodHandle.class),
+                METHOD_HANDLE(MethodHandleSymbol.class),
                 METHOD_TYPE(MethodType.class);
 
                 final Class<?> clazz;
@@ -1930,7 +1935,7 @@
                     case CLASS:
                         return Optional.of(((Symbol)data).type);
                     case METHOD_HANDLE:
-                        return Optional.of(((MethodHandle)data).refSym.owner.type);
+                        return Optional.of(((MethodHandleSymbol)data).owner.type);
                     default:
                         return Optional.empty();
                 }
@@ -1944,7 +1949,7 @@
                     case CLASS:
                         return Optional.of(((Symbol)data));
                     case METHOD_HANDLE:
-                        return Optional.of(((MethodHandle)data).refSym);
+                        return Optional.of(((MethodHandleSymbol)data));
                     default:
                         return Optional.empty();
                 }
@@ -1956,8 +1961,8 @@
             public static BootstrapArgument<Float> Float(Float data) { return new BootstrapArgument<>(Kind.FLOAT, data); }
             public static BootstrapArgument<Double> Double(Double data) { return new BootstrapArgument<>(Kind.DOUBLE, data); }
             public static BootstrapArgument<String> String(String data) { return new BootstrapArgument<>(Kind.STRING, data); }
-            public static BootstrapArgument<Pool.MethodHandle> MethodHandle(Pool.MethodHandle data) { return new BootstrapArgument<>(Kind.METHOD_HANDLE, data); }
-            public static BootstrapArgument<MethodType> MethodType(MethodType data) { return new BootstrapArgument<>(Kind.METHOD_TYPE, data); }
+            public static BootstrapArgument<MethodHandleSymbol> MethodHandle(MethodSymbol data) { return new BootstrapArgument<>(Kind.METHOD_HANDLE, data.asHandle()); }
+            public static BootstrapArgument<MethodType> MethodType(MethodType data) { return new BootstrapArgument<>(Kind.METHOD_TYPE, data.asConstant()); }
         }
 
         public BootstrapArgument<?>[] staticArgs;
@@ -1977,6 +1982,47 @@
         }
     }
 
+    /** A class for method handles.
+     */
+    public static class MethodHandleSymbol extends MethodSymbol {
+
+        private MethodSymbol refSym;
+
+        public MethodHandleSymbol(MethodSymbol msym) {
+            super(msym.flags_field, msym.name, msym.type, msym.owner);
+            this.refSym = msym;
+        }
+
+        /**
+         * Returns the kind associated with this method handle.
+         */
+        public int referenceKind() {
+            if (refSym.isConstructor()) {
+                return ClassFile.REF_newInvokeSpecial;
+            } else {
+                if (refSym.isStatic()) {
+                    return ClassFile.REF_invokeStatic;
+                } else if ((refSym.flags() & PRIVATE) != 0) {
+                    return ClassFile.REF_invokeSpecial;
+                } else if (refSym.enclClass().isInterface()) {
+                    return ClassFile.REF_invokeInterface;
+                } else {
+                    return ClassFile.REF_invokeVirtual;
+                }
+            }
+        }
+
+        @Override
+        public Symbol baseSymbol() {
+            return refSym;
+        }
+
+        @Override
+        public boolean isHandle() {
+            return true;
+        }
+    }
+
     /** A class for predefined operators.
      */
     public static class OperatorSymbol extends MethodSymbol {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Tue Dec 08 14:42:24 2015 +0000
@@ -1497,6 +1497,32 @@
                 restype != null && restype.isErroneous();
         }
 
+        /**
+         * Is this the type of a method type constant (used as static argument in an invokedynamic
+         * call) ?
+         */
+        public boolean isConstant() {
+            return false;
+        }
+
+        /**
+         * Return a method type constant based on the contents of this method type.
+         */
+        public MethodType asConstant() {
+            Type outer = this;
+            return new MethodType(argtypes, restype, thrown, tsym) {
+                @Override
+                public boolean isConstant() {
+                    return true;
+                }
+
+                @Override
+                public Type baseType() {
+                    return outer;
+                }
+            };
+        }
+
         public boolean contains(Type elem) {
             return elem.equalsIgnoreMetadata(this) || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem);
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Tue Dec 08 14:42:24 2015 +0000
@@ -28,13 +28,13 @@
 import java.lang.ref.SoftReference;
 import java.util.HashSet;
 import java.util.HashMap;
-import java.util.LinkedHashMap;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.function.BiFunction;
 import java.util.function.BiPredicate;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.stream.Collector;
 import java.util.function.Function;
@@ -44,15 +44,12 @@
 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
 import com.sun.tools.javac.code.Lint.LintCategory;
 import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
-import com.sun.tools.javac.code.Type.UndetVar.*;
 import com.sun.tools.javac.code.Type.UndetVar.Flag;
 import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
-import com.sun.tools.javac.code.Types.SignatureGenerator.SigMode;
 import com.sun.tools.javac.comp.AttrContext;
 import com.sun.tools.javac.comp.Check;
 import com.sun.tools.javac.comp.Enter;
 import com.sun.tools.javac.comp.Env;
-import com.sun.tools.javac.comp.Infer.InferredMethodType;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.Tuple.Tuple2;
 
@@ -94,9 +91,10 @@
 
     public final Symtab syms;
     final JavacMessages messages;
-    final Names names;
+    public final Names names;
     final boolean allowObjectToPrimitiveCast;
     final boolean allowDefaultMethods;
+    final boolean allowTypeSpecialization;
     final Check chk;
     final Enter enter;
     JCDiagnostic.Factory diags;
@@ -121,6 +119,7 @@
         Source source = Source.instance(context);
         allowObjectToPrimitiveCast = source.allowObjectToPrimitiveCast();
         allowDefaultMethods = source.allowDefaultMethods();
+        allowTypeSpecialization = source.allowTypeSpecialization();
         chk = Check.instance(context);
         enter = Enter.instance(context);
         capturedName = names.fromString("<captured wildcard>");
@@ -307,6 +306,30 @@
     }
 
     /**
+     * Is the given type a specialized type - e.g. does it contain, either directly, or indirectly
+     * (through superclasses) any primitive parameterizations?
+     */
+    public boolean isSpecialized(Type t) {
+        if (!allowTypeSpecialization) {
+            return false;
+        } else {
+            switch (t.getTag()) {
+                case FORALL:
+                    return isSpecialized(t.asMethodType());
+                case METHOD:
+                    return t.getParameterTypes().prepend(t.getReturnType()).stream().anyMatch(this::isSpecialized);
+                case CLASS:
+                    return isVirtualizable((ClassType)t) || directSupertypes(t).stream().anyMatch(this::isSpecialized) ||
+                        t.allparams().stream().anyMatch(Type::isPrimitiveOrValue);
+                case ARRAY:
+                    return isSpecialized(elemtype(t));
+                default:
+                    return false;
+            }
+        }
+    }
+
+    /**
      * Is the given type a specializable type-variable?
      */
     public boolean isSpecializableTypeVar(Type t) {
@@ -1801,8 +1824,8 @@
 
                 if (s.hasTag(CLASS) || s.hasTag(ARRAY)) {
                     boolean upcast;
-                    if ((upcast = isSubtype(erasureSource(t), erasureSource(s)))
-                        || isSubtype(erasureSource(s), erasureSource(t))) {
+                    if ((upcast = isSubtype(erasure(t), erasure(s)))
+                        || isSubtype(erasure(s), erasure(t))) {
                         if (!upcast && s.hasTag(ARRAY)) {
                             if (!isReifiable(s))
                                 warnStack.head.warn(LintCategory.UNCHECKED);
@@ -2425,7 +2448,7 @@
                         if (ownerParams.nonEmpty()) {
                             if (baseParams.isEmpty()) {
                                 // then base is a raw type
-                                return erasureSource(sym.type);
+                                return erasure(sym.type);
                             } else {
                                 return subst(sym.type, ownerParams, baseParams);
                             }
@@ -2549,9 +2572,7 @@
 
             @Override
             public Type visitClassType(ClassType t, ErasureKind erasureKind) {
-                Type classToErase = t.tsym.completer == Completer.NULL_COMPLETER && erasureKind.shouldSpecialize() ?
-                        specialize(t) : t; // we cannot force completion at this stage!
-                Type erased = classToErase.tsym.erasure(Types.this);
+                Type erased = t.tsym.erasure(Types.this);
                 if (erasureKind.shouldRecurse()) {
                     erased = new ErasedClassType(erased.getEnclosingType(), erased.tsym, t.getMetadata().without(Kind.ANNOTATIONS));
                     return erased;
@@ -2571,10 +2592,6 @@
             }
         };
 
-    public Type erasureSource(Type t) {
-        return erasure(t, ErasureKind.SOURCE);
-    }
-
     public List<Type> erasure(List<Type> ts) {
         return erasure.visit(ts, ErasureKind.NORMAL);
     }
@@ -2591,10 +2608,6 @@
         return erasure(t, ErasureKind.REFERENCE_ONLY);
     }
 
-    public List<Type> erasureSource(List<Type> ts) {
-        return erasure.visit(ts, ErasureKind.SOURCE);
-    }
-
     public List<Type> erasureReference(List<Type> ts) {
         return erasure.visit(ts, ErasureKind.REFERENCE_ONLY);
     }
@@ -2618,12 +2631,7 @@
          * Reference erasure behavior. Class types are not recursively erased,
          * synthetic 'any' type is left untouched.
          */
-        REFERENCE_ONLY,
-        /**
-         * Source erasure behavior. Specialization/virtualization is not applied.
-         * Otherwise, behavior is same as with {@link com.sun.tools.javac.code.Types.ErasureKind##NORMAL}.
-         */
-        SOURCE;
+        REFERENCE_ONLY;
 
         boolean shouldRecurse() {
             return this == RECURSIVE;
@@ -2632,322 +2640,6 @@
         boolean shouldEraseAny() {
             return this != REFERENCE_ONLY;
         }
-
-        boolean shouldSpecialize() {
-            return this != SOURCE;
-        }
-    }
-    // </editor-fold>
-
-    // <editor-fold defaultstate="collapsed" desc="Specialization routines">
-
-    /** cache of specialized class symbols. */
-    HashMap<UniqueType, ClassSymbol> specializedSymbols = new HashMap<>();
-
-    /**
-     * Thsi visitor computes a specialized type from given type, if needed. For classes, this involves
-     * creating a supporting specialized symbol {@link Types#specializeSymbol(com.sun.tools.javac.code.Types.UniqueType, Type)},
-     * where value-based type-parameters are encoded as part of the symbol name.
-     */
-    MapVisitor<Void> specialize = new MapVisitor<Void>() {
-        @Override
-        public Type visitClassType(ClassType ct, Void aVoid) {
-            if (isVirtualizable(ct)) {
-                ClassSymbol virtualClass = virtualizeClass(ct.tsym);
-                return visitClassType((ClassType)subst(virtualClass.type, virtualClass.type.allparams(), ct.allparams()), null);
-            }
-            //compute specialization of enclosing type
-            Type specializedEncl = specialize(ct.getEnclosingType());
-
-            if (specializedEncl == ct.getEnclosingType() && !specializableClosureTypeArgs(ct)) {
-                //nothing to specialize - return
-                return ct;
-            } else {
-                if ((ct.tsym.flags() & Flags.SPECIALIZED_CLASS) != 0) {
-                    //base type already specialized - merge specializations
-                    return specialize(new ClassType(ct.getEnclosingType(),
-                            mergeTypeArguments(ct, ct.getTypeArguments()),
-                            (TypeSymbol)ct.tsym.baseSymbol()));
-                } else {
-                    UniqueType key = new UniqueType(referenceArgTypesAsFormals(ct), Types.this);
-                    ClassSymbol specializedClassSymbol = specializedSymbols.get(key);
-                    if (specializedClassSymbol == null) {
-                        specializedClassSymbol = specializeSymbol(key, specializedEncl);
-                    }
-                    //return new specialized type
-                    List<Type> nonSpecializedTypeArgs = ct.getTypeArguments().stream()
-                            .filter(targ -> !targ.isPrimitiveOrValue())
-                            .collect(List.collector());
-                    return nonSpecializedTypeArgs.isEmpty() ?
-                            specializedClassSymbol.type :
-                            new ClassType(
-                                specializedEncl,
-                                ct.getTypeArguments().stream()
-                                        .filter(targ -> !targ.isPrimitiveOrValue()).collect(List.collector()),
-                                specializedClassSymbol) {
-                                @Override
-                                public Type baseType() {
-                                    return ct.baseType();
-                                }
-                            };
-                }
-            }
-        }
-
-        @Override
-        public Type visitArrayType(ArrayType t, Void aVoid) {
-            return new ArrayType(specialize(elemtype(t)), syms.arrayClass, t.getMetadata());
-        }
-
-        @Override
-        public Type visitMethodType(MethodType t, Void aVoid) {
-            Type mt = createMethodTypeWithParameters(t,
-                    t.getParameterTypes().stream()
-                            .map(Types.this::specialize).collect(List.collector()));
-            Type specializedMethodType = createMethodTypeWithReturn(mt, specialize(mt.getReturnType()));
-            if (t instanceof InferredMethodType) {
-                //preserve inferred info
-                InferredMethodType inferredMethodType = (InferredMethodType)t;
-                return new InferredMethodType((MethodType)specializedMethodType,
-                        inferredMethodType.inferenceContext);
-            } else {
-                return specializedMethodType;
-            }
-        }
-
-        @Override
-        public Type visitForAll(ForAll fa, Void aVoid) {
-            return new ForAll(fa.tvars, specialize(fa.qtype));
-        }
-    };
-
-    /**
-     * Does given type 't', or any of its declared supertypes contain any specializable type argument?
-     */
-    boolean specializableClosureTypeArgs(Type t) {
-        return specializableClosureTypeArgsInternal(t, new HashSet<>());
-    }
-    //where
-        private boolean specializableClosureTypeArgsInternal(Type t, Set<TypeSymbol> seen) {
-            if (!t.hasTag(CLASS) || !seen.add(t.tsym)) {
-                return false;
-            }
-            ClassType ctype = (ClassType)t;
-            if (ctype.typarams_field != null &&
-                    ctype.typarams_field.stream().anyMatch(Type::isPrimitiveOrValue)) {
-                return true;
-            }
-            ClassType symType = (ClassType)t.tsym.type;
-            if (symType.supertype_field != null) {
-                if (specializableClosureTypeArgsInternal(symType.supertype_field, seen)) {
-                    return true;
-                }
-            }
-            if (symType.interfaces_field != null) {
-                for (Type i : symType.interfaces_field) {
-                    if (specializableClosureTypeArgsInternal(i, seen)) {
-                        return true;
-                    }
-                }
-            }
-            return false;
-        }
-
-    /**
-     * Main entry-point for type-specialization.
-     */
-    public Type specialize(Type t) {
-        return t == null ?
-                null : t.accept(specialize, null);
-    }
-
-    MapVisitor<Void> unspecialize = new MapVisitor<Void>() {
-        @Override
-        public Type visitClassType(ClassType ct, Void aVoid) {
-            return (ct.tsym.flags() & SPECIALIZED_CLASS) != 0 ?
-                    (ClassType)ct.baseType() : ct;
-        }
-
-        @Override
-        public Type visitArrayType(ArrayType t, Void aVoid) {
-            return new ArrayType(unspecialize(elemtype(t)), syms.arrayClass, t.getMetadata());
-        }
-
-        @Override
-        public Type visitMethodType(MethodType t, Void aVoid) {
-            Type mt = createMethodTypeWithParameters(t,
-                    t.getParameterTypes().stream()
-                            .map(Types.this::unspecialize).collect(List.collector()));
-            return createMethodTypeWithReturn(mt, unspecialize(mt.getReturnType()));
-        }
-
-        @Override
-        public Type visitForAll(ForAll fa, Void aVoid) {
-            return new ForAll(fa.tvars, unspecialize(fa.qtype));
-        }
-    };
-
-    public Type unspecialize(Type t) {
-        return t == null ?
-                null : t.accept(unspecialize, null);
-    }
-
-    private List<Type> mergeTypeArguments(ClassType specializedClass, List<Type> newArgs) {
-        List<Type> typeargsWithHoles =
-                referenceArgTypesAsFormals(specializedClass.baseType()).getTypeArguments();
-        ListBuffer<Type> mergedTypeArgs = new ListBuffer<>();
-        for (Type t : typeargsWithHoles) {
-            final Type mergedTypeArg;
-            if (!t.isPrimitiveOrValue()) {
-                mergedTypeArg = newArgs.head;
-                newArgs = newArgs.tail;
-            } else {
-                mergedTypeArg = t;
-            }
-            mergedTypeArgs.add(mergedTypeArg);
-        }
-        return mergedTypeArgs.toList();
-    }
-
-    /**
-     * Create and return a specialized class symbol.
-     */
-    ClassSymbol specializeSymbol(UniqueType key, Type specializedEncl) {
-        ClassType ct = (ClassType)key.type;
-        List<Type> typeargs = ct.getTypeArguments();
-
-        //compute offset of tvar indexes
-        int offset = specializedEncl.hasTag(CLASS) ?
-                specializedEncl.allparams().length() :
-                0;
-
-        //compute name string
-        List<String> specNames =
-                Tuple2.zip(List.range(offset, offset + typeargs.length()), typeargs).stream()
-                        .filter(p -> p.elem1.isPrimitiveOrValue())
-                        .map(p -> String.join("=", p.elem0.toString(), typeSig(p.elem1)))
-                        .collect(List.collector());
-
-        //compute name of specialized class symbol
-        Name specializedName = specNames.isEmpty() ?
-                ct.tsym.name :
-                names.fromString(ct.tsym.name + "${" + String.join(",", specNames) + "}");
-
-        //compute specialized class flags - note we need to remove UNATTRIBUTED as we might get here
-        //before referenced classes got fully attributed - which, together with caching will cause
-        //the synthetic class to be re-attributed, leading to crashes.
-        long specializedFlags = (ct.tsym.flags() | Flags.SPECIALIZED_CLASS) & ~Flags.UNATTRIBUTED;
-
-        //set owner
-        Symbol specializedOwner = null;
-        if (ct.tsym.owner.kind == MTH &&
-                specializedEncl.hasTag(CLASS) &&
-                (ct.tsym.owner.flags() & Flags.STATIC) == 0) {
-            //this is likely bogus
-            for (Symbol s : specializedEncl.tsym.members().getSymbols()) {
-                if (s == ct.tsym.owner) {
-                    specializedOwner = s;
-                    break;
-                }
-            }
-        } else if (specializedEncl.hasTag(CLASS)) {
-            specializedOwner = specializedEncl.tsym;
-        } else {
-            specializedOwner = ct.tsym.owner;
-        }
-        Assert.checkNonNull(specializedOwner);
-
-        if (specializedOwner.kind == MTH && specNames.isEmpty()) {
-            //local classes w/o specialized args should simply use existing symbol as that's already
-            //been specialized!
-            return (ClassSymbol)ct.tsym;
-        }
-
-        //compute specialized class symbol
-        ClassSymbol specializedClassSym =
-                new ClassSymbol(specializedFlags,
-                        specializedName, null, specializedOwner) {
-                    @Override
-                    public Symbol baseSymbol() {
-                        return ct.tsym;
-                    }
-                };
-
-        if (specializedOwner.kind == MTH) {
-            //local class
-            specializedClassSym.flatname = chk.localClassName(specializedClassSym);
-        }
-
-        //compute mapping from unspecialized tvars to specialized symbol tvars
-        Map<Type, Type> tvarsMap = new LinkedHashMap<>();
-        List<Type> encl_params = specializedEncl.allparams();
-        for (Type t : ct.allparams()) {
-            if (t.isPrimitiveOrValue()) {
-                continue;
-            } else if (t.tsym.owner == ct.tsym) {
-                TypeVariableSymbol tvsym =
-                        new TypeVariableSymbol(t.tsym.flags(),
-                                t.tsym.name,
-                                null,
-                                specializedClassSym);
-                Type tv = new TypeVar(tvsym, t.getUpperBound(), null);
-                tvsym.type = tv;
-                tvarsMap.put(t, tv);
-            } else {
-                tvarsMap.put(t, encl_params.head);
-                encl_params = encl_params.tail;
-            }
-        }
-
-        //compute actual type-parameters (mix of instantiated types and new tvars)
-        List<Type> actuals = Tuple2.zip(ct.tsym.type.allparams(), ct.allparams()).stream()
-                .map(p -> p.elem1.isPrimitiveOrValue() ? p.elem1 : tvarsMap.get(p.elem0))
-                .collect(List.collector());
-
-        //adjust bounds of specialized tvars by replacing old tvars for actuals (see above)
-        for (Type t : new HashSet<>(tvarsMap.values())) {
-            Type.TypeVar tv = (Type.TypeVar)t;
-            tv.bound = subst(tv.getBound(), ct.tsym.type.getTypeArguments(), actuals);
-        }
-
-        //finish specialized class symbol (set type, members, etc.)
-        specializedClassSym.type = new ClassType(
-                specialize(ct.getEnclosingType()),
-                tvarsMap.values().stream()
-                        .filter(t -> t.tsym.owner == specializedClassSym)
-                        .collect(List.collector()),
-                specializedClassSym) {
-            @Override
-            public Type baseType() {
-                return ct;
-            }
-        };
-
-        //add specialized symbol to the cache (we need to do this now to avoid loops)
-        specializedSymbols.put(key, specializedClassSym);
-
-        specializedClassSym.completer = (_unused) -> {
-                //add (specialized) members to the scope of the specialized symbol
-                specializedClassSym.members_field = Scope.WriteableScope.create(specializedClassSym);
-                for (Symbol m : ct.tsym.members().getSymbols()) {
-                    if (m.kind == TYP || m.isStatic()) continue; //skip nested types and statics
-                    Symbol m2 = m.clone(specializedClassSym);
-                    m2.type = subst(m.type, ct.tsym.type.allparams(), actuals);
-                    specializedClassSym.members().enter(m2);
-                }
-
-                //replace direct supertypes
-                ((ClassType)specializedClassSym.type).supertype_field =
-                        specialize(subst(supertype(ct.tsym.type), ct.tsym.type.allparams(), actuals));
-
-                ((ClassType)specializedClassSym.type).interfaces_field =
-                        interfaces(ct.tsym.type).stream()
-                                .map(t -> subst(t, ct.tsym.type.allparams(), actuals))
-                                .map(this::specialize)
-                                .collect(List.collector());
-            };
-
-        return specializedClassSym;
     }
     // </editor-fold>
 
@@ -3094,23 +2786,19 @@
      * type contains anyfied unbounded wildcards (in which case virtualization is necessary).
      */
     public Type asVirtualType(Type t) {
-        return asVirtualType(t, this::erasure);
-    }
-
-    public Type asVirtualType(Type t, Function<Type, Type> typeFunc) {
-        return t.map(virtualTypeMap, typeFunc);
-    }
-
-    public TypeMapping<Function<Type, Type>> virtualTypeMap = new TypeMapping<Function<Type, Type>>() {
+        return t.map(virtualTypeMap);
+    }
+
+    public TypeMapping<Void> virtualTypeMap = new TypeMapping<Void>() {
         @Override
-        public Type visitClassType(ClassType t, Function<Type, Type> typeFunc) {
+        public Type visitClassType(ClassType t, Void _unused) {
             return t.allparams().stream().anyMatch(ta -> isAnyTypeVar(ta) || isAnyUnboundTypeArgument(ta)) ?
-                    virtualizeClass(t.tsym).type : typeFunc.apply(t);
+                    virtualizeClass(t.tsym).type : t;
         }
 
         @Override
-        public Type visitTypeVar(TypeVar t, Function<Type, Type> typeFunc) {
-            return typeFunc.apply(t);
+        public Type visitTypeVar(TypeVar t, Void _unused) {
+            return t;
         }
     };
 
@@ -3154,7 +2842,8 @@
      * Should a given type be virtualized?
      */
     public boolean isVirtualizable(ClassType ctype) {
-        return ctype.allparams().stream().anyMatch(this::isAnyUnboundTypeArgument);
+        return allowTypeSpecialization &&
+                ctype.allparams().stream().anyMatch(this::isAnyUnboundTypeArgument);
     }
     //where
         private boolean isAnyUnboundTypeArgument(Type t) {
@@ -3336,7 +3025,7 @@
     // <editor-fold defaultstate="collapsed" desc="typeVarsByOwner">
     public List<Tuple2<Symbol, List<Type>>> typeVarsByOwner(Symbol sym) {
         return ownersClosure(sym).stream()
-                .filter(s -> (s.kind == MTH || s.kind == TYP) && s.type != null)
+                .filter(s -> (s.kind == MTH || s.kind == TYP) && s.type != null && s.type.getTypeArguments().nonEmpty())
                 .map(s -> new Tuple2<>(s, s.type.getTypeArguments()))
                 .collect(List.collector());
     }
@@ -5454,7 +5143,7 @@
 
         @Override
         public Type visitClassType(ClassType t, Type target) {
-            Type erased = erasureSource(target);
+            Type erased = erasure(target);
             return asSuper(t, erased.tsym, AsSuperKind.PARTIAL_ERASURE);
         }
 
@@ -5480,7 +5169,7 @@
                         new ArrayType(newElem, syms.arrayClass) :
                         t;
             } else {
-                Type erased = erasureSource(target);
+                Type erased = erasure(target);
                 return asSuper(t, erased.tsym);
             }
         }
@@ -5499,7 +5188,7 @@
 
         @Override
         public Type visitTypeVar(TypeVar t, Type target) {
-            Type erased = erasureSource(target);
+            Type erased = erasure(target);
             return isSpecializableTypeVar(t) ? t : asSuper(t, erased.tsym);
         }
     }
@@ -5854,11 +5543,6 @@
 
     public static abstract class SignatureGenerator {
 
-        public enum SigMode {
-            NORMAL,
-            SPECIALIZER
-        }
-
         private final Types types;
 
         protected abstract void append(char ch);
@@ -5871,21 +5555,13 @@
         }
 
         /**
-         * Assemble signature of given type in string buffer. This method is mainly kept for
-         * sake of compatibility with existing clients.
+         * Assemble signature of given type in string buffer.
          */
         public void assembleSig(Type type) {
-            assembleSig(type, SigMode.NORMAL);
-        }
-
-        /**
-         * Assemble signature of given type in string buffer.
-         */
-        public void assembleSig(Type type, SigMode mode) {
             switch (type.getTag()) {
                 case ANY_BOUND:
                     //for compatibility
-                    assembleSig(types.syms.objectType, mode);
+                    assembleSig(types.syms.objectType);
                     break;
                 case BYTE:
                     append('B');
@@ -5919,24 +5595,24 @@
                         append('Q');
                     else
                         append('L');
-                    assembleClassSig(type, mode);
+                    assembleClassSig(type);
                     append(';');
                     break;
                 case ARRAY:
                     ArrayType at = (ArrayType) type;
                     append('[');
-                    assembleSig(at.elemtype, mode);
+                    assembleSig(at.elemtype);
                     break;
                 case METHOD:
                     MethodType mt = (MethodType) type;
                     append('(');
-                    assembleSig(mt.argtypes, mode);
+                    assembleSig(mt.argtypes);
                     append(')');
-                    assembleSig(mt.restype, mode);
+                    assembleSig(mt.restype);
                     if (hasTypeVar(mt.thrown)) {
                         for (List<Type> l = mt.thrown; l.nonEmpty(); l = l.tail) {
                             append('^');
-                            assembleSig(l.head, mode);
+                            assembleSig(l.head);
                         }
                     }
                     break;
@@ -5945,11 +5621,11 @@
                     switch (ta.kind) {
                         case SUPER:
                             append('-');
-                            assembleSig(ta.type, mode);
+                            assembleSig(ta.type);
                             break;
                         case EXTENDS:
                             append('+');
-                            assembleSig(ta.type, mode);
+                            assembleSig(ta.type);
                             break;
                         case UNBOUND:
                             append('*');
@@ -5966,8 +5642,8 @@
                     break;
                 case FORALL:
                     Type.ForAll ft = (Type.ForAll) type;
-                    assembleParamsSig(ft.tvars, mode);
-                    assembleSig(ft.qtype, mode);
+                    assembleParamsSig(ft.tvars);
+                    assembleSig(ft.qtype);
                     break;
                 default:
                     throw new AssertionError("typeSig " + type.getTag());
@@ -5984,7 +5660,7 @@
             return false;
         }
 
-        public void assembleClassSig(Type type, SigMode mode) {
+        public void assembleClassSig(Type type) {
             ClassType ct = (ClassType) type;
             //Todo: this means that we cannot recover back info associated with Box<any>
             //from ClassReader, as exact info gets erased here (bytecode enhancemet needed)
@@ -5999,7 +5675,7 @@
                         c.name == types.names.empty; // or anonymous
                 assembleClassSig(rawOuter
                         ? types.erasure(outer)
-                        : outer, mode);
+                        : outer);
                 append(rawOuter ? '$' : '.');
                 Assert.check(c.flatname.startsWith(c.owner.enclClass().flatname));
                 append(rawOuter
@@ -6010,12 +5686,12 @@
             }
             if (!types.isVirtualizable(ct) && ct.getTypeArguments().nonEmpty()) {
                 append('<');
-                assembleSig(ct.getTypeArguments(), mode);
+                assembleSig(ct.getTypeArguments());
                 append('>');
             }
         }
 
-        public void assembleParamsSig(List<Type> typarams, SigMode mode) {
+        public void assembleParamsSig(List<Type> typarams) {
             append('<');
             for (List<Type> ts = typarams; ts.nonEmpty(); ts = ts.tail) {
                 Type.TypeVar tvar = (Type.TypeVar) ts.head;
@@ -6026,15 +5702,15 @@
                 }
                 for (List<Type> l = bounds; l.nonEmpty(); l = l.tail) {
                     append(':');
-                    assembleSig(l.head, mode);
+                    assembleSig(l.head);
                 }
             }
             append('>');
         }
 
-        private void assembleSig(List<Type> types, SigMode mode) {
+        private void assembleSig(List<Type> types) {
             for (List<Type> ts = types; ts.nonEmpty(); ts = ts.tail) {
-                assembleSig(ts.head, mode);
+                assembleSig(ts.head);
             }
         }
     }
@@ -6076,20 +5752,93 @@
      * Emit signature for a given type
      */
     public Name typeSig(Type type) {
-        return typeSigInternal(type, SigMode.NORMAL);
-   }
+        SignatureGenerator sg = new BuilderSignatureGenerator(this);
+        sg.assembleSig(type);
+        return names.fromString(sg.toString());
+    }
 
     /**
-     * Emit specializer version of signature for a given type
+     * Emit BMA signature for a given type (transitional)
      */
-    public Name specializerSig(Type type) {
-        return typeSigInternal(normalize(type), SigMode.SPECIALIZER);
-    }
-
-    private Name typeSigInternal(Type type, SigMode mode) {
-        SignatureGenerator sg = new BuilderSignatureGenerator(this);
-        sg.assembleSig(type, mode);
-        return names.fromString(sg.toString());
+    public Name bytecodeMappingSig(Type type) {
+        return typeSig(normalize(type));
+    }
+
+    /**
+     * Emit descriptor for a given type.
+     */
+    public Name typeDesc(Type t) {
+        return typeDesc(t, c -> {});
+    }
+
+    public Name typeDesc(Type t, Consumer<ClassSymbol> crefFunc) {
+        Types.BuilderSignatureGenerator bsg = new Types.BuilderSignatureGenerator(this) {
+
+            @Override
+            protected void append(byte[] ba) {
+                append(names.fromUtf(ba));
+            }
+
+            @Override
+            public void assembleSig(Type type) {
+                switch (type.getTag()) {
+                    case FORALL:
+                        super.assembleSig(createMethodTypeWithThrown(type, List.nil()).asMethodType());
+                        break;
+                    case METHOD:
+                        super.assembleSig(createMethodTypeWithThrown(type, List.nil()));
+                        break;
+                    case ARRAY:
+                    case CLASS:
+                        super.assembleSig(type);
+                        break;
+                    default:
+                        super.assembleSig(erasure(type));
+                }
+            }
+            @Override
+            public void assembleClassSig(Type type) {
+                if (type.hasTag(TypeTag.CLASS) && isVirtualizable((ClassType)type)) {
+                    super.assembleClassSig(type);
+                } else if (type.hasTag(TypeTag.CLASS) && isSpecialized(type)) {
+                    classReference((ClassSymbol)type.tsym);
+                    append(mangledName(type));
+                } else {
+                    super.assembleClassSig(erasure(type));
+                }
+            }
+
+            @Override
+            protected void classReference(ClassSymbol c) {
+                crefFunc.accept(c);
+            }
+
+            /**
+             * Mangle specialized type (transitional).
+             */
+            Name mangledName(Type type) {
+                List<Type> typeargs = type.getTypeArguments();
+                int offset = 0;
+
+                //compute name string
+                List<String> specNames =
+                        Tuple2.zip(List.range(offset, offset + typeargs.length()), typeargs).stream()
+                                .filter(p -> p.elem1.isPrimitiveOrValue())
+                                .map(p -> String.join("=", p.elem0.toString(), typeSig(p.elem1)))
+                                .collect(List.collector());
+
+                Name baseName = names.fromUtf(externalize(type.tsym.flatName()));
+
+                //compute name of specialized class symbol
+                Name specializedName = specNames.isEmpty() ?
+                        baseName :
+                        names.fromString(baseName + "${" + String.join(",", specNames) + "}");
+
+                return specializedName;
+            }
+        };
+        bsg.assembleSig(normalize(t));
+        return names.fromString(bsg.toString());
     }
 
     // </editor-fold>
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Dec 08 14:42:24 2015 +0000
@@ -3666,7 +3666,7 @@
         }
         //where
             private Symbol objectMethodsClass(Type site) {
-                ClassSymbol objectMethodClass = new ClassSymbol(PUBLIC, names.empty, syms.unnamedPackage);
+                ClassSymbol objectMethodClass = new ClassSymbol(PUBLIC, names.java_lang_Object, syms.unnamedPackage);
                 objectMethodClass.type = new ClassType(Type.noType, List.nil(), objectMethodClass);
                 WriteableScope objectMethodClassScope = objectMethodClass.members_field = WriteableScope.create(objectMethodClass);
                 for (Symbol s : syms.objectType.tsym.members().getSymbols(s -> s.kind == MTH)) {
@@ -4083,8 +4083,8 @@
                         sym.location());
                //Todo: this probably needs to be revised to take into account partially erased types
                owntype = new MethodType(owntype.getParameterTypes(),
-                       types.erasureSource(owntype.getReturnType()),
-                       types.erasureSource(owntype.getThrownTypes()),
+                       types.erasure(owntype.getReturnType()),
+                       types.erasure(owntype.getThrownTypes()),
                        syms.methodClass);
             }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Dec 08 14:42:24 2015 +0000
@@ -2542,7 +2542,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 &&
-                    types.isSameType(types.erasure(sym.type), types.erasure(sym2.type)) &&
+                    types.isSameType(sym.erasure(types), sym2.erasure(types)) &&
                     sym != sym2 &&
                     (sym.flags() & Flags.SYNTHETIC) != (sym2.flags() & Flags.SYNTHETIC) &&
                     (sym.flags() & BRIDGE) == 0 && (sym2.flags() & BRIDGE) == 0) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Tue Dec 08 14:42:24 2015 +0000
@@ -24,7 +24,6 @@
  */
 package com.sun.tools.javac.comp;
 
-import com.sun.tools.javac.code.Kinds;
 import com.sun.tools.javac.code.Kinds.KindSelector;
 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol.BootstrapArgument;
@@ -32,9 +31,7 @@
 import com.sun.tools.javac.code.Type.ForAll;
 import com.sun.tools.javac.code.Types.AsSuperKind;
 import com.sun.tools.javac.code.Types.BuilderSignatureGenerator;
-import com.sun.tools.javac.code.Types.SignatureGenerator.SigMode;
 import com.sun.tools.javac.code.Types.TypeVarContext;
-import com.sun.tools.javac.comp.Infer.InferredMethodType;
 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 import com.sun.tools.javac.tree.*;
@@ -46,7 +43,6 @@
 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;
@@ -770,8 +766,12 @@
     /**
      * Create new synthetic method with given flags, name, type, owner
      */
+    private MethodSymbol makeSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
+        return new MethodSymbol(flags | SYNTHETIC, name, type, owner);
+    }
+
     private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
-        return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner);
+        return makeSyntheticMethod(flags | PRIVATE, name, type, owner);
     }
 
     /**
@@ -944,15 +944,20 @@
         private JCExpression makeReceiver(VarSymbol rcvr) {
             if (rcvr == null) return null;
             JCExpression rcvrExpr = make.Ident(rcvr);
-            Type rcvrType = tree.sym.enclClass().type;
-            if (rcvrType == syms.arrayClass.type) {
+            rcvrExpr.unerasedType = TreeInfo.unerasedTypeOrType(tree.getQualifierExpression());
+            Type rcvrType;
+            if (tree.sym.enclClass().type == syms.arrayClass.type) {
                 // Map the receiver type to the actually type, not just "array"
-                rcvrType = tree.getQualifierExpression().type;
+                rcvrType = TreeInfo.unerasedTypeOrType(tree.getQualifierExpression());
+            } else {
+                 rcvrType = types.decorateDescriptor(TreeInfo.unerasedTypeOrType(tree.getQualifierExpression()),
+                         tree.sym.enclClass().type);
             }
             if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
                 rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
+                ((JCExpression)((JCTypeCast)rcvrExpr).clazz).unerasedType = rcvrType;
+                rcvrExpr.unerasedType = rcvrType;
             }
-            rcvrExpr.unerasedType = tree.getQualifierExpression().unerasedType;
             return rcvrExpr;
         }
 
@@ -980,7 +985,11 @@
             apply = transTypes.coerce(attrEnv, apply,
                     types.erasure(localContext.tree.referentType.getReturnType()));
 
-            apply.unerasedType = normalizedUnerasedReferentType.getReturnType();
+            if (apply.hasTag(TYPECAST)) {
+                ((JCExpression)((JCTypeCast)apply).clazz).unerasedType = normalizedUnerasedReferentType.getReturnType();
+            } else {
+                apply.unerasedType = normalizedUnerasedReferentType.getReturnType();
+            }
             setVarargsIfNeeded(apply, tree.varargsElement);
             return apply;
         }
@@ -1030,30 +1039,12 @@
     }
 
     private MethodType typeToMethodType(Type mt) {
-        Type type = types.erasure(mt);
-        return new MethodType(type.getParameterTypes(),
-                        type.getReturnType(),
-                        type.getThrownTypes(),
-                        syms.methodClass) {
-            @Override
-            public Type baseType() {
-                return mt;
-            }
-        };
+        return types.decorateDescriptor(mt, mt).asMethodType();
     }
 
     private MethodType erasedDescType(JCTree tree, Symbol desc, Type site) {
-        Type type = desc.erasure(types);
-        Type instType = types.memberType(types.specialize(site), desc, AsSuperKind.PARTIAL_ERASURE);
-        return new MethodType(type.getParameterTypes(),
-                type.getReturnType(),
-                type.getThrownTypes(),
-                syms.methodClass) {
-            @Override
-            public Type baseType() {
-                return instType;
-            }
-        };
+        Type instType = types.memberType(site, desc, AsSuperKind.PARTIAL_ERASURE);
+        return instType.asMethodType();
     }
 
     /**
@@ -1066,7 +1057,7 @@
         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
         List<BootstrapArgument<?>> staticArgs = List.of(
                 BootstrapArgument.MethodType(erasedDescType(tree, samSym, tree.targets.head)),
-                BootstrapArgument.MethodHandle(new Pool.MethodHandle(refKind, refSym, types)),
+                BootstrapArgument.MethodHandle((MethodSymbol)refSym),
                 BootstrapArgument.MethodType(typeToMethodType(tree.getDescriptorType(types))));
 
         //no need to have accessors for lambdas MH
@@ -1191,15 +1182,10 @@
                 return extractUnerasedType(((JCUnary)expr).arg);
             default:
                 return expr.unerasedType == null ?
-                        expr.type : types.decorateDescriptor(expr.unerasedType, unspecializeErased(expr.type));
+                        expr.type : types.decorateDescriptor(expr.unerasedType, expr.type);
         }
     }
 
-    Type unspecializeErased(Type t) {
-        return (t.tsym.flags() & SPECIALIZED_CLASS) != 0 ?
-                types.unspecialize(t.tsym.type) : t;
-    }
-
     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
     /**
      * This visitor collects information about translation of a lambda expression.
@@ -2244,7 +2230,7 @@
                 super(tree);
                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
                 this.sigPolySym = isSignaturePolymorphic()
-                        ? makePrivateSyntheticMethod(tree.sym.flags(),
+                        ? makeSyntheticMethod(tree.sym.flags(),
                                               tree.sym.name,
                                               bridgedRefSig(),
                                               tree.sym.enclClass())
@@ -2320,7 +2306,8 @@
              * reference mentions type variables in enclosing generic method.
              */
             boolean isAnyfiedReference() {
-                return types.containsSpecializableTvars(tree.sym.type);
+                return types.isSpecialized(tree.expr.unerasedType) ||
+                        types.containsSpecializableTvars(tree.sym.type);
             }
             /**
              * Does this reference need to be converted to a lambda
@@ -2371,13 +2358,13 @@
 
     private String typeSig(Type type) {
         BuilderSignatureGenerator sg = new BuilderSignatureGenerator(types);
-        sg.assembleSig(type, SigMode.NORMAL);
+        sg.assembleSig(type);
         return sg.toString();
     }
 
     private String classSig(Type type) {
         BuilderSignatureGenerator sg = new BuilderSignatureGenerator(types);
-        sg.assembleClassSig(type, SigMode.NORMAL);
+        sg.assembleClassSig(type);
         return sg.toString();
     }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Tue Dec 08 14:42:24 2015 +0000
@@ -32,9 +32,7 @@
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol.BootstrapArgument;
 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol.BootstrapArgument.Kind;
-import com.sun.tools.javac.comp.SpecializeTypes.SpecializedVarSymbol;
 import com.sun.tools.javac.jvm.*;
-import com.sun.tools.javac.jvm.Pool.MethodHandle;
 import com.sun.tools.javac.main.Option.PkgInfo;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
@@ -455,7 +453,7 @@
                 .fromString(target.syntheticNameChar() +
                             "SwitchMap" +
                             target.syntheticNameChar() +
-                            writer.xClassName(forEnum.type).toString()
+                            names.fromUtf(ClassFile.externalize(forEnum.flatName())).toString()
                             .replace('/', '.')
                             .replace('.', target.syntheticNameChar()));
             ClassSymbol outerCacheClass = outerCacheClass();
@@ -974,15 +972,7 @@
      */
     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
@@ -1148,9 +1138,6 @@
             } else if (base != null && base.hasTag(NEWCLASS)) {
                 //new Baz<...>() - the unerased type of the creatiomn expression is the receiver type
                 return ((JCNewClass)base).unerasedType;
-            } else if (sym.specialized() != sym) {
-                //no tree, but specialized symbol - fetch specialized receiver
-                return sym.specialized().owner.type.baseType();
             } else {
                 //defaults to symbol owner
                 return sym.owner.type;
@@ -1217,9 +1204,11 @@
                 return makeLit(sym.type, cv);
             }
             // Otherwise replace the variable by its proxy.
+            Type unerased = sym.type;
             sym = proxies.findFirst(proxyName(sym.name));
             Assert.check(sym != null && (sym.flags_field & FINAL) != 0);
             tree = make.at(tree.pos).Ident(sym);
+            tree.unerasedType = unerased;
         }
         JCExpression base = (tree.hasTag(SELECT)) ? ((JCFieldAccess) tree).selected : null;
         switch (sym.kind) {
@@ -1252,11 +1241,11 @@
                 for (int i = 0; i < dynSym.staticArgs.length ; i++) {
                     BootstrapArgument<?> bsmArg = dynSym.staticArgs[i];
                     if ((bsmArg.flags & BootstrapArgument.NEEDS_ACCESSORS) != 0 && bsmArg.kind == Kind.METHOD_HANDLE) {
-                        MethodHandle mh = (MethodHandle)bsmArg.data;
-                        Symbol accessor = getAccessorIfNeeded(refSuper, mh.refSym, tree);
+                        MethodHandleSymbol mh = (MethodHandleSymbol)bsmArg.data;
+                        Symbol accessor = getAccessorIfNeeded(refSuper, mh, tree);
                         if (accessor != null) {
                             //patch up indy arg
-                            BootstrapArgument<?>  newArg = BootstrapArgument.MethodHandle(new Pool.MethodHandle(ClassFile.REF_invokeStatic, accessor, types));
+                            BootstrapArgument<?>  newArg = BootstrapArgument.MethodHandle((MethodSymbol)accessor);
                             newArg.flags = bsmArg.flags;
                             dynSym.staticArgs[i] = newArg;
                         }
@@ -1289,6 +1278,9 @@
                     // to their access methods.
                     if (accessor != null) {
                         List<JCExpression> args = List.nil();
+                        Type unerasedSite = base != null ?
+                                base.unerasedType :
+                                types.asOuterSuper(currentClass.type, accessor.owner);
                         if ((sym.flags() & STATIC) == 0) {
                             // Instance access methods get instance
                             // as first parameter.
@@ -1297,9 +1289,11 @@
                             args = args.prepend(base);
                             base = null;   // so we don't duplicate code
                         }
-                        JCExpression receiver = make.Select(
-                            base != null ? base : make.QualIdent(accessor.owner),
-                            accessor);
+                        if (base == null) {
+                            base = make.QualIdent(accessor.owner);
+                            base.unerasedType = unerasedSite;
+                        }
+                        JCExpression receiver = make.Select(base, accessor);
 
                         JCMethodInvocation app = make.App(receiver, args).setType(accessor.erasure(types).getReturnType());
                         app.unerasedType = tree.unerasedType != null && tree.unerasedType.hasTag(METHOD) ?
@@ -1310,8 +1304,10 @@
                     // Other accesses to members of outer classes get a
                     // qualifier.
                     } else if (baseReq) {
-                        return make.at(tree.pos).Select(
+                        JCExpression sel = make.at(tree.pos).Select(
                             accessBase(tree.pos(), sym), sym).setType(tree.type);
+                        sel.unerasedType = tree.unerasedType;
+                        return sel;
                     }
                 }
             } else if (sym.owner.kind == MTH && lambdaTranslationMap != null) {
@@ -1372,19 +1368,15 @@
                         constr.type.getThrownTypes(),
                         syms.methodClass),
                     accOwner);
+                if (accOwner.hasOuterInstance()) {
+                    aconstr.extraParams = List.of(new VarSymbol(PARAMETER | SYNTHETIC, make.paramName(0),
+                            accOwner.enclClass().type.getEnclosingType(), aconstr));
+                }
                 enterSynthetic(tree, aconstr, accOwner.members());
                 accessConstrs.put(constr.baseSymbol(), aconstr);
                 accessed.append(constr);
             }
-            //patch up accessor if original symbol was specialized
-            if (constr.specialized() != constr) {
-                Symbol specializedClassSym = constr.specialized().owner;
-                Symbol aconstr2 = aconstr.clone(specializedClassSym);
-                aconstr2.type = types.subst(aconstr.type, constr.enclClass().type.allparams(), specializedClassSym.type.baseType().allparams());
-                return specializeTypes.makeSpecializedSymbol(aconstr2);
-            } else {
-                return aconstr;
-            }
+            return aconstr;
         } else {
             return constr;
         }
@@ -1558,6 +1550,7 @@
         JCIdent callee = make.Ident(names._this);
         callee.sym = constr;
         callee.type = constr.type;
+        callee.unerasedType = constr.type;
         md.body =
             make.Block(0, List.<JCStatement>of(
                 make.Call(
@@ -2203,10 +2196,10 @@
      *  @param clazz      The tree identifying type T.
      */
     private JCExpression classOf(JCTree clazz) {
-        return classOfType(clazz.type, clazz.pos());
+        return classOfType(clazz.type, TreeInfo.unerasedTypeOrType(clazz), clazz.pos());
     }
 
-    private JCExpression classOfType(Type type, DiagnosticPosition pos) {
+    private JCExpression classOfType(Type type, Type unerased, DiagnosticPosition pos) {
         switch (type.getTag()) {
         case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
         case DOUBLE: case BOOLEAN: case VOID:
@@ -2223,7 +2216,9 @@
                 VarSymbol sym = new VarSymbol(
                         STATIC | PUBLIC | FINAL, names._class,
                         syms.classType, type.tsym);
-                return make_at(pos).Select(make.Type(type), sym);
+                JCFieldAccess sel = (JCFieldAccess)make_at(pos).Select(make.Type(type), sym);
+                sel.selected.unerasedType = unerased;
+                return sel;
         default:
             throw new AssertionError();
         }
@@ -2276,7 +2271,7 @@
             JCClassDecl containerDef = classDef(container);
             make_at(containerDef.pos());
             JCExpression notStatus = makeUnary(NOT, make.App(make.Select(
-                    classOfType(types.erasure(outermostClass.type),
+                    classOfType(types.erasure(outermostClass.type), outermostClass.type,
                                 containerDef.pos()),
                     desiredAssertionStatusSym)));
             JCVariableDecl assertDisabledDef = make.VarDef(assertDisabledSym,
@@ -2601,7 +2596,7 @@
             tree.extending = make.Type(types.supertype(tree.type));
 
         // classOfType adds a cache field to tree.defs
-        JCExpression e_class = classOfType(tree.sym.type, tree.pos()).
+        JCExpression e_class = classOfType(tree.sym.type, tree.sym.type, tree.pos()).
             setType(types.erasure(syms.classType));
 
         // process each enumeration constant, adding implicit constructor parameters
@@ -2753,14 +2748,11 @@
             // Add "String $enum$name, int $enum$ordinal" to the beginning of the
             // argument list for each constructor of an enum.
             JCVariableDecl nameParam = make_at(tree.pos()).
-                Param(names.fromString(target.syntheticNameChar() +
-                                       "enum" + target.syntheticNameChar() + "name"),
+                Param(enumNameParameter(),
                       syms.stringType, tree.sym);
             nameParam.mods.flags |= SYNTHETIC; nameParam.sym.flags_field |= SYNTHETIC;
             JCVariableDecl ordParam = make.
-                Param(names.fromString(target.syntheticNameChar() +
-                                       "enum" + target.syntheticNameChar() +
-                                       "ordinal"),
+                Param(enumOrdinalParameter(),
                       syms.intType, tree.sym);
             ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
 
@@ -2788,6 +2780,17 @@
             currentMethodSym = prevMethodSym;
         }
     }
+
+        private Name enumNameParameter() {
+            return names.fromString(target.syntheticNameChar() +
+                    "enum" + target.syntheticNameChar() + "name");
+        }
+
+        private Name enumOrdinalParameter() {
+            return names.fromString(target.syntheticNameChar() +
+                    "enum" + target.syntheticNameChar() + "ordinal");
+        }
+
     //where
         private void checkVarShadowing(DiagnosticPosition pos, Symbol owner) {
             List<Tuple2<Symbol, List<Type>>> typeVarsByOwner = types.typeVarsByOwner(owner);
@@ -2844,11 +2847,11 @@
             if (fvs.nonEmpty()) {
                 List<Type> addedargtypes = List.nil();
                 for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
+                    final Name pName = proxyName(l.head.name);
+                    m.capturedLocals =
+                        m.capturedLocals.prepend((VarSymbol)
+                                                (proxies.findFirst(pName)));
                     if (TreeInfo.isInitialConstructor(tree)) {
-                        final Name pName = proxyName(l.head.name);
-                        m.capturedLocals =
-                            m.capturedLocals.append((VarSymbol)
-                                                    (proxies.findFirst(pName)));
                         added = added.prepend(
                           initField(tree.body.pos, pName));
                     }
@@ -2902,7 +2905,9 @@
         }
 
     public void visitTypeCast(JCTypeCast tree) {
+        Type unerasedClazz = TreeInfo.unerasedTypeOrType(tree.clazz);
         tree.clazz = translate(tree.clazz);
+        ((JCExpression)tree.clazz).unerasedType = unerasedClazz;
         if (tree.type.isPrimitive() != tree.expr.type.isPrimitive())
             tree.expr = translate(tree.expr, tree.type);
         else
@@ -2915,7 +2920,10 @@
 
         // Box arguments, if necessary
         boolean isEnum = (tree.constructor.owner.flags() & ENUM) != 0;
-        List<Type> argTypes = tree.constructor.specialized().type.getParameterTypes();
+        List<Type> argTypes = tree.constructorType != null ?
+                tree.constructorType.getParameterTypes() :
+                tree.constructor.type.getParameterTypes();
+
         if (isEnum) argTypes = argTypes.prepend(syms.intType).prepend(syms.stringType);
         tree.args = boxArgs(argTypes, tree.args, tree.varargsElement);
         tree.varargsElement = null;
@@ -3100,7 +3108,9 @@
 
     public void visitApply(JCMethodInvocation tree) {
         Symbol meth = TreeInfo.symbol(tree.meth);
-        List<Type> argtypes = meth.specialized().type.getParameterTypes();
+        List<Type> argtypes = tree.meth.unerasedType != null ?
+                tree.meth.unerasedType.getParameterTypes() :
+                meth.type.getParameterTypes();
         if (meth.name == names.init && meth.owner == syms.enumSym)
             argtypes = argtypes.tail.tail;
         tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
@@ -3211,14 +3221,16 @@
     /** Expand a boxing or unboxing conversion if needed. */
     @SuppressWarnings("unchecked") // XXX unchecked
     <T extends JCExpression> T boxIfNeeded(T tree, Type type) {
-        boolean havePrimitive = tree.type.isPrimitive();
+        boolean havePrimitive = TreeInfo.unerasedTypeOrType(tree).isPrimitive();
         if (havePrimitive == type.isPrimitive())
             return tree;
         if (havePrimitive) {
             Type unboxedTarget = types.unboxedType(type);
             if (!unboxedTarget.hasTag(NONE)) {
-                if (!types.isSubtype(tree.type, unboxedTarget)) //e.g. Character c = 89;
+                if (!types.isSubtype(tree.type, unboxedTarget)) {//e.g. Character c = 89;
                     tree.type = unboxedTarget.constType(tree.type.constValue());
+                    tree.unerasedType = tree.type;
+                }
                 return (T)boxPrimitive(tree, types.erasure(type));
             } else {
                 tree = (T)boxPrimitive(tree);
@@ -3231,7 +3243,7 @@
 
     /** Box up a single primitive expression. */
     JCExpression boxPrimitive(JCExpression tree) {
-        return boxPrimitive(tree, types.boxedClass(tree.type).type);
+        return boxPrimitive(tree, types.boxedClass(TreeInfo.unerasedTypeOrType(tree)).type);
     }
 
     /** Box up a single primitive expression. */
@@ -3241,7 +3253,7 @@
                                          names.valueOf,
                                          box,
                                          List.<Type>nil()
-                                         .prepend(tree.type));
+                                         .prepend(TreeInfo.unerasedTypeOrType(tree)));
         return make.App(make.QualIdent(valueOfSym), List.of(tree));
     }
 
@@ -3283,7 +3295,7 @@
 
     public void visitAssign(JCAssign tree) {
         tree.lhs = translate(tree.lhs, tree);
-        tree.rhs = translate(tree.rhs, tree.lhs.type);
+        tree.rhs = translate(tree.rhs, TreeInfo.unerasedTypeOrType(tree.lhs));
 
         // If translated left hand side is an Apply, we are
         // seeing an access method invocation. In this case, append
@@ -3916,14 +3928,9 @@
             tree.selected.hasTag(SELECT) &&
             TreeInfo.name(tree.selected) == names._super &&
             !types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass);
-        JCExpression prevSelected = tree.selected;
         tree.selected = translate(tree.selected);
         if (tree.name == names._class) {
             result = classOf(tree.selected);
-            if (result.hasTag(SELECT)) {
-                //preserve unerased type info
-                ((JCFieldAccess)result).selected.unerasedType = prevSelected.unerasedType;
-            }
         }
         else if (tree.name == names._super &&
                 types.isDirectSuperInterface(tree.selected.type.tsym, currentClass)) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/SpecializeTypes.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/SpecializeTypes.java	Tue Dec 08 14:42:24 2015 +0000
@@ -44,7 +44,6 @@
 import com.sun.tools.javac.code.WhereClause;
 import com.sun.tools.javac.comp.CompileStates.CompileState;
 import com.sun.tools.javac.comp.Infer.InferredMethodType;
-import com.sun.tools.javac.jvm.Pool.MethodHandle;
 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.JCArrayAccess;
@@ -56,7 +55,6 @@
 import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
 import com.sun.tools.javac.tree.JCTree.JCIdent;
 import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
-import com.sun.tools.javac.tree.JCTree.JCMemberReference;
 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
 import com.sun.tools.javac.tree.JCTree.JCNewArray;
@@ -149,16 +147,6 @@
     JCExpression enclOp;
 
     /**
-     * Return the specialized supertypes matching given symbol 'sym'.
-     */
-    Symbol asSpecializedSymbol(Type t, Symbol sym) {
-        Type specializedSuper = types.specialize(types.asOuterSuper(t, sym.owner));
-        return (specializedSuper != null && (specializedSuper.tsym.flags() & (Flags.SPECIALIZED_CLASS | Flags.VIRTUAL)) != 0) ?
-                specializedSuper.tsym.members().findFirst(sym.name, s -> s.baseSymbol() == sym) :
-                null;
-    }
-
-    /**
      * Specialize a generic constructor call (if needed).
      */
     JCExpression specializeGenericConstructorIfNeeded(JCNewClass tree) {
@@ -247,7 +235,7 @@
                 List<BootstrapArgument<?>> staticArgs = typeargs.stream()
                         .map(ta -> {
                             BootstrapArgument<String> bsmArg = new BootstrapArgument<String>(Kind.STRING, types.isTypeArgumentSpecializable(ta) ?
-                                    types.specializerSig(ta).toString() : "") {
+                                    types.bytecodeMappingSig(ta).toString() : "") {
                                 public Optional<Type> asType() {
                                     return Optional.of(ta);
                                 }
@@ -261,16 +249,16 @@
 
                 Symbol unspecializedMeth = msym.baseSymbol();
 
-                staticArgs = staticArgs.prepend(BootstrapArgument.MethodHandle(new MethodHandle(referenceKind(unspecializedMeth), unspecializedMeth, types)));
+                staticArgs = staticArgs.prepend(BootstrapArgument.MethodHandle((MethodSymbol)unspecializedMeth));
                 //structural info is not required for the generic specialized call case
                 //as there, we should leave the method handle unspecialized, as it should point
                 //to the original version of the method in the template class.
                 staticArgs.head.flags &= ~BootstrapArgument.SPECIALIZABLE;
-                Type specializedReceiver = types.specialize(receiverType);
-                staticArgs = staticArgs.prepend(new BootstrapArgument<String>(Kind.STRING, types.specializerSig(specializedReceiver).toString()) {
+                Type effFinalReceiverType = receiverType;
+                staticArgs = staticArgs.prepend(new BootstrapArgument<String>(Kind.STRING, types.bytecodeMappingSig(receiverType).toString()) {
                                                     @Override
                                                     public Optional<Type> asType() {
-                                                        return Optional.of(specializedReceiver);
+                                                        return Optional.of(effFinalReceiverType);
                                                     }
                                                 });
 
@@ -366,10 +354,8 @@
         if (tree.def != null) {
             tree.def = translate(tree.def);
         }
-        Symbol specializedConstructor = asSpecializedSymbol(tree.type, tree.constructor);
-        if (specializedConstructor != null) {
-            //fixup constructor symbol
-            tree.constructor = makeSpecializedSymbol(specializedConstructor);
+        if (tree.encl != null) {
+            tree.encl = translate(tree.encl);
         }
         result = withInferenceContext(tree.constructorType, () -> specializeGenericConstructorIfNeeded(tree));
     }
@@ -409,13 +395,6 @@
             tree.selected.unerasedType = tree.selected.type;
         }
         tree.selected = translate(tree.selected, null);
-        if (tree.sym != null && !tree.sym.isStatic()) {
-            Symbol specializedSymbol = asSpecializedSymbol(tree.selected.type, tree.sym);
-            if (specializedSymbol != null) {
-                //fixup select symbol
-                tree.sym = makeSpecializedSymbol(specializedSymbol);
-            }
-        }
         result = tree;
     }
 
@@ -559,27 +538,6 @@
     }
 
     @Override
-    public void visitIdent(JCIdent tree) {
-        if (tree.sym != null) {
-            if (tree.sym.name == names._super) {
-                Type specializedSuper =
-                        types.specialize(types.asSuper(currentClass.type, tree.sym.type.tsym));
-                if (specializedSuper != null) {
-                    //fixup type of synthetic (method-private) super symbol
-                    tree.sym.type = specializedSuper;
-                }
-            } else if (!tree.sym.isStatic()) {
-                Symbol specializedSymbol = asSpecializedSymbol(currentClass.type, tree.sym);
-                if (specializedSymbol != null) {
-                    //fixup ident symbol
-                    tree.sym = makeSpecializedSymbol(specializedSymbol);
-                }
-            }
-        }
-        result = tree;
-    }
-
-    @Override
     public void visitApply(JCMethodInvocation tree) {
         if (tree.typeargs != null) {
             tree.typeargs = translate(tree.typeargs);
@@ -588,6 +546,10 @@
         tree.args = withInferenceContext(tree.meth.type, () -> translate(tree.args));
         JCMethodInvocation call = withInferenceContext(tree.meth.type, () -> specializeGenericMethodCallIfNeeded(rewriteSuperCallIfNeeded(tree)));
         Symbol meth = TreeInfo.symbol(call.meth);
+        if (rs.polymorphicSignatureScope.includes(meth)) {
+            //patch unerased type for polysig methods
+            tree.meth.unerasedType = meth.type;
+        }
         if (!(meth instanceof DynamicMethodSymbol) &&
                 call.meth.hasTag(SELECT) &&
                 needsVirtualAccessor(((JCFieldAccess)call.meth).selected.type, meth)) {
@@ -770,7 +732,6 @@
 
     @Override
     public void visitTypeCast(JCTypeCast tree) {
-        tree.unerasedType = tree.clazz.type;
         tree.clazz = translate(tree.clazz);
         tree.expr = translate(tree.expr);
         result = tree;
@@ -778,7 +739,6 @@
 
     @Override
     public void visitTypeTest(JCInstanceOf tree) {
-        tree.unerasedType = tree.clazz.type;
         tree.clazz = translate(tree.clazz);
         tree.expr = translate(tree.expr);
         result = tree;
@@ -789,28 +749,6 @@
         //do nothing
     }
 
-    @Override
-    public void visitReference(JCMemberReference tree) {
-        tree.expr = translate(tree.expr);
-        switch(tree.kind) {
-            case BOUND:
-            case UNBOUND:
-            case TOPLEVEL:
-                Symbol specializedSymbol = asSpecializedSymbol(tree.getQualifierExpression().type, tree.sym);
-                if (specializedSymbol != null) {
-                    //fixup reference symbol
-                    tree.sym = makeSpecializedSymbol(specializedSymbol);
-                }
-                break;
-            case IMPLICIT_INNER:
-            case SUPER:
-            case ARRAY_CTOR:
-                //always desugared to lambdas - do nothing
-                break;
-        }
-        result = tree;
-    }
-
     /**
      * 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
@@ -880,9 +818,9 @@
      */
     void makeVirtualBridgeIfNeeded(MethodSymbol virtualMethod, Type site) {
         Symbol originalSymbol = virtualMethod.baseSymbol();
-        if (!types.isSameType(originalSymbol.erasure(types), virtualMethod.erasure(types))) {
+        if (!types.typeDesc(originalSymbol.type).equals(types.typeDesc(virtualMethod.type))) {
             MethodSymbol bridgeImpl = virtualMethod.clone(site.tsym);
-            bridgeImpl.type = types.asVirtualType(originalSymbol.type, t -> t);
+            bridgeImpl.type = types.asVirtualType(originalSymbol.type);
             bridgeImpl.flags_field &= ~Flags.ABSTRACT;
             bridgeImpl.flags_field |= Flags.BRIDGE; //synthetic/specialziable flags inherited from virtual symbol
             JCMethodDecl bridgeDef = make.MethodDef(bridgeImpl, null);
@@ -965,129 +903,12 @@
         //prepend receiver
         indyType = types.createMethodTypeWithParameters(indyType, indyType.getParameterTypes().prepend(sel.selected.type));
         List<BootstrapArgument<?>> static_args =
-                List.of(BootstrapArgument.MethodHandle(new MethodHandle(referenceKind(accessor), accessor, types)));
+                List.of(BootstrapArgument.MethodHandle((MethodSymbol)accessor));
         JCMethodInvocation methInv = makeIndyCall(sel, accessor.owner, syms.virtualAccess,
                 names.metafactory, static_args, (MethodType)indyType, args.prepend(sel.selected), accessor.name, accessor);
-        return methInv.setType(vk.asInvType.apply(sel.type));
+        Type res = vk.asInvType.apply(sel.type);
+        methInv.setType(res);
+        methInv.unerasedType = methInv.type;
+        return methInv;
     }
-
-    /**
-     * This is an helper class that defines some of the common capabilities of specialized symbols.
-     * This class exists solely as a means to avoid code duplication.
-     */
-    class SpecializedSymbolHolder<S extends Symbol> {
-        S specializedSym;
-
-        public SpecializedSymbolHolder(S specializedSym) {
-            this.specializedSym = specializedSym;
-        }
-
-        public Type erasure(Types types) {
-            return specializedSym.erasure(types);
-        }
-
-        public Symbol specialized() {
-            return specializedSym;
-        }
-
-        public Symbol baseSymbol() {
-            return specializedSym.baseSymbol();
-        }
-
-        public S clone(Symbol newOwner) {
-            @SuppressWarnings("unchecked")
-            S sym = (S)makeSpecializedSymbolInternal(specializedSym.clone(newOwner));
-            sym.owner = types.unspecialize(newOwner.type).tsym;
-            return sym;
-        }
-    }
-
-    /**
-     * The symbol of a specialized variable. The variable behaves essentially like its non specialized
-     * counterpart, except for low-level, bytecode-dependent behavior, in which the variable is allowed
-     * to show its specialized nature.
-     */
-    class SpecializedVarSymbol extends VarSymbol {
-        SpecializedSymbolHolder<VarSymbol> specialized_field;
-
-        public SpecializedVarSymbol(VarSymbol vsym) {
-            super(vsym.baseSymbol().flags_field, vsym.baseSymbol().name, vsym.baseSymbol().type, vsym.baseSymbol().owner);
-            specialized_field = new SpecializedSymbolHolder<>(vsym);
-        }
-
-        @Override
-        public Type erasure(Types types) {
-            return specialized_field.erasure(types);
-        }
-
-        @Override
-        public Symbol specialized() {
-            return specialized_field.specialized();
-        }
-
-        @Override
-        public Symbol baseSymbol() {
-            return specialized_field.baseSymbol();
-        }
-
-        @Override
-        public VarSymbol clone(Symbol newOwner) {
-            return specialized_field.clone(newOwner);
-        }
-    }
-
-    /**
-     * The symbol of a specialized method. The method behaves essentially like its non specialized
-     * counterpart, except for low-level, bytecode-dependent behavior, in which the method is allowed
-     * to show its specialized nature.
-     */
-    class SpecializedMethodSymbol extends MethodSymbol {
-        SpecializedSymbolHolder<MethodSymbol> specialized_field;
-
-        public SpecializedMethodSymbol(MethodSymbol msym) {
-            super(msym.baseSymbol().flags_field, msym.baseSymbol().name, msym.baseSymbol().type, msym.baseSymbol().owner);
-            specialized_field = new SpecializedSymbolHolder<>(msym);
-        }
-
-        @Override
-        public Type erasure(Types types) {
-            return specialized_field.erasure(types);
-        }
-
-        @Override
-        public Symbol specialized() {
-            return specialized_field.specialized();
-        }
-
-        @Override
-        public Symbol baseSymbol() {
-            return specialized_field.baseSymbol();
-        }
-
-        @Override
-        public MethodSymbol clone(Symbol newOwner) {
-            return specialized_field.clone(newOwner);
-        }
-    }
-
-    /**
-     * Helper factory method to create specialized symbols.
-     * Invariant: the inoput symbol must be a member of a specialized class.
-     */
-    Symbol makeSpecializedSymbol(Symbol s) {
-        Assert.check((s.owner.flags() & (Flags.SPECIALIZED_CLASS | Flags.VIRTUAL)) != 0);
-        return makeSpecializedSymbolInternal(s);
-    }
-    //where
-        private Symbol makeSpecializedSymbolInternal(Symbol s) {
-            switch (s.kind) {
-                case VAR:
-                    return new SpecializedVarSymbol((VarSymbol)s);
-                case MTH:
-                    return new SpecializedMethodSymbol((MethodSymbol)s);
-                default:
-                    Assert.error("Cannot get here");
-                    return s;
-            }
-        }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Tue Dec 08 14:42:24 2015 +0000
@@ -179,19 +179,19 @@
     JCExpression retype(JCExpression tree, Type erasedType, Type target) {
 //      System.err.println("retype " + tree + " to " + erasedType);//DEBUG
         if (!erasedType.isPrimitive()) {
+            if (target != null && target.isPrimitive()) {
+                target = erasure(tree.type);
+            }
             Type unerasedTarget = target;
             if (target instanceof ProtoType) {
                 unerasedTarget = ((ProtoType)target).unerasedType;
                 target = ((ProtoType)target).qtype;
             }
-            if (target != null && target.isPrimitive()) {
-                target = erasure(tree.type);
-            }
             tree.type = erasedType;
             if (target != null) {
                 JCExpression coercedExpr = coerce(tree, erasure(target));
-                if (unerasedTarget != null)
-                    coercedExpr.unerasedType = unerasedTarget;
+                if (coercedExpr != tree && unerasedTarget != null)
+                    coercedExpr.unerasedType = ((JCExpression)((JCTypeCast)coercedExpr).clazz).unerasedType = unerasedTarget;
                 return coercedExpr;
             }
         }
@@ -302,7 +302,7 @@
             JCExpression call =
                 make.Apply(
                            null,
-                           make.Select(receiver, impl).setType(calltype),
+                           make.Select(receiver, impl).setType(erasure(impl.type)),
                            translateArgs(make.Idents(md.params), ProtoType.from(origErasure.getParameterTypes(),
                                    types.decorateDescriptor(types.memberType(origin.type, impl), impl.type).getParameterTypes()), null))
                 .setType(calltype);
@@ -731,8 +731,6 @@
             tree.args, argtypes, tree.varargsElement != null ?
                 new ProtoType(tree.varargsElement, unerasedVarargs) : null);
         tree.def = translate(tree.def, null);
-        if (erasedConstructorType != null)
-            tree.constructorType = erasedConstructorType;
         tree.type = erasure(tree.type);
         result = tree;
     }
@@ -753,6 +751,7 @@
     public void visitParens(JCParens tree) {
         tree.expr = translate(tree.expr, pt);
         tree.type = erasure(tree.expr.type);
+        tree.unerasedType = tree.expr.unerasedType;
         result = tree;
     }
 
@@ -794,7 +793,9 @@
     }
 
     public void visitTypeCast(JCTypeCast tree) {
+        Type unerased = TreeInfo.unerasedTypeOrType(tree.clazz);
         tree.clazz = translate(tree.clazz, null);
+        ((JCExpression)tree.clazz).unerasedType = unerased;
         Type originalTarget = tree.type;
         tree.type = erasure(tree.type);
         JCExpression newExpression = translate(tree.expr, new ProtoType(tree.type, tree.unerasedType));
@@ -844,6 +845,7 @@
         // Map type variables to their bounds.
         if (tree.sym.kind == TYP && tree.sym.type.hasTag(TYPEVAR)) {
             result = make.at(tree.pos).Type(et);
+            ((JCExpression)result).unerasedType = tree.unerasedType;
         } else
         // Map constants expressions to themselves.
         if (tree.type.constValue() != null) {
@@ -943,6 +945,11 @@
         }
 
         @Override
+        public boolean isPrimitive() {
+            return qtype.isPrimitive();
+        }
+
+        @Override
         public Type cloneWithMetadata(TypeMetadata md) {
             throw new AssertionError("Not supported");
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Tue Dec 08 14:42:24 2015 +0000
@@ -49,7 +49,6 @@
 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.file.BaseFileObject;
 import com.sun.tools.javac.jvm.ClassFile.Version;
-import com.sun.tools.javac.jvm.Pool.NameAndType;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -93,11 +92,6 @@
      */
     boolean checkClassFile;
 
-    /** Switch: read constant pool and code sections. This switch is initially
-     *  set to false but can be turned on from outside.
-     */
-    public boolean readAllOfClassFile = false;
-
     /** Switch: allow simplified varargs.
      */
     boolean allowSimplifiedVarargs;
@@ -419,21 +413,21 @@
             break;
         case CONSTANT_Fieldref: {
             ClassSymbol owner = readClassSymbol(getChar(index + 1));
-            NameAndType nt = readNameAndType(getChar(index + 3));
-            poolObj[i] = new VarSymbol(0, nt.name, nt.uniqueType.type, owner);
+            Tuple2<Name, Type> nt = readNameAndType(getChar(index + 3));
+            poolObj[i] = new VarSymbol(0, nt.elem0, nt.elem1, owner);
             break;
         }
         case CONSTANT_Methodref:
         case CONSTANT_InterfaceMethodref: {
             ClassSymbol owner = readClassSymbol(getChar(index + 1));
-            NameAndType nt = readNameAndType(getChar(index + 3));
-            poolObj[i] = new ReaderMethodSymbol(0, nt.name, nt.uniqueType.type, owner);
+            Tuple2<Name, Type> nt = readNameAndType(getChar(index + 3));
+            poolObj[i] = new ReaderMethodSymbol(0, nt.elem0, nt.elem1, owner);
             break;
         }
         case CONSTANT_NameandType:
-            poolObj[i] = new NameAndType(
+            poolObj[i] = new Tuple2<>(
                 readName(getChar(index + 1)),
-                readType(getChar(index + 3)), types);
+                readType(getChar(index + 3)));
             break;
         case CONSTANT_Integer:
             poolObj[i] = getInt(index + 1);
@@ -516,13 +510,14 @@
 
     /** Read name and type.
      */
-    NameAndType readNameAndType(int i) {
+    @SuppressWarnings("unchecked")
+    Tuple2<Name, Type> readNameAndType(int i) {
         Object obj = readPool(i);
-        if (obj != null && !(obj instanceof NameAndType))
+        if (obj != null && !(obj instanceof Tuple2<?, ?>))
             throw badClassFile("bad.const.pool.entry",
                                currentClassFile.toString(),
                                "CONSTANT_NameAndType_info", i);
-        return (NameAndType)obj;
+        return (Tuple2<Name, Type>)obj;
     }
 
 /************************************************************************
@@ -910,7 +905,7 @@
 
             new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) {
                 protected void read(Symbol sym, int attrLen) {
-                    if (readAllOfClassFile || saveParameterNames)
+                    if (saveParameterNames)
                         ((MethodSymbol)sym).code = readCode(sym);
                     else
                         bp = bp + attrLen;
@@ -1256,7 +1251,7 @@
         sym.owner.members().remove(sym);
         ClassSymbol self = (ClassSymbol)sym;
         ClassSymbol c = readClassSymbol(nextChar());
-        NameAndType nt = readNameAndType(nextChar());
+        Tuple2<Name, Type> nt = readNameAndType(nextChar());
 
         if (c.members_field == null)
             throw badClassFile("bad.enclosing.class", self, c);
@@ -1303,32 +1298,32 @@
         return names.fromString(simpleBinaryName.substring(index));
     }
 
-    private MethodSymbol findMethod(NameAndType nt, Scope scope, long flags) {
+    private MethodSymbol findMethod(Tuple2<Name, Type> nt, Scope scope, long flags) {
         if (nt == null)
             return null;
 
-        MethodType type = nt.uniqueType.type.asMethodType();
+        MethodType type = nt.elem1.asMethodType();
 
-        for (Symbol sym : scope.getSymbolsByName(nt.name)) {
+        for (Symbol sym : scope.getSymbolsByName(nt.elem0)) {
             if (sym.kind == MTH && isSameBinaryType(asDescriptorType((MethodSymbol)sym).asMethodType(), type))
                 return (MethodSymbol)sym;
         }
 
-        if (nt.name != names.init)
+        if (nt.elem0 != names.init)
             // not a constructor
             return null;
         if ((flags & INTERFACE) != 0)
             // no enclosing instance
             return null;
-        if (nt.uniqueType.type.getParameterTypes().isEmpty())
+        if (nt.elem1.getParameterTypes().isEmpty())
             // no parameters
             return null;
 
         // A constructor of an inner class.
         // Remove the first argument (the enclosing instance)
-        nt.setType(new MethodType(nt.uniqueType.type.getParameterTypes().tail,
-                                 nt.uniqueType.type.getReturnType(),
-                                 nt.uniqueType.type.getThrownTypes(),
+        nt = new Tuple2<>(nt.elem0, new MethodType(nt.elem1.getParameterTypes().tail,
+                                 nt.elem1.getReturnType(),
+                                 nt.elem1.getThrownTypes(),
                                  syms.methodClass));
         // Try searching again
         return findMethod(nt, scope, flags);
@@ -2356,11 +2351,6 @@
         for (int i = 0; i < methodCount; i++) skipMember();
         readClassAttrs(c);
 
-        if (readAllOfClassFile) {
-            for (int i = 1; i < poolObj.length; i++) readPool(i);
-            c.pool = new Pool(poolObj.length, poolObj, types, names, false);
-        }
-
         // reset and read rest of classinfo
         bp = startbp;
         int n = nextChar();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Tue Dec 08 14:42:24 2015 +0000
@@ -27,10 +27,7 @@
 
 import java.io.*;
 import java.util.EnumSet;
-import java.util.LinkedHashMap;
 import java.util.Map;
-import java.util.Set;
-import java.util.HashSet;
 import java.util.Iterator;
 
 import javax.tools.JavaFileManager;
@@ -40,21 +37,11 @@
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
 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.SignatureGenerator.SigMode;
 import com.sun.tools.javac.code.Types.UnaryVisitor;
-import com.sun.tools.javac.code.Types.UniqueType;
 import com.sun.tools.javac.file.BaseFileObject;
+import com.sun.tools.javac.jvm.Gen.Descriptor;
 import com.sun.tools.javac.jvm.Gen.PoolMode;
-import com.sun.tools.javac.jvm.Pool.DynamicMethod;
-import com.sun.tools.javac.jvm.Pool.Method;
-import com.sun.tools.javac.jvm.Pool.MethodHandle;
-import com.sun.tools.javac.jvm.Pool.NameAndType;
-import com.sun.tools.javac.jvm.Pool.Signature;
-import com.sun.tools.javac.jvm.Pool.SignatureClass;
-import com.sun.tools.javac.jvm.Pool.SignatureMember;
-import com.sun.tools.javac.jvm.Pool.Variable;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.Tuple.Tuple2;
 
@@ -137,27 +124,13 @@
      */
     ByteBuffer databuf = new ByteBuffer(DATA_BUF_SIZE);
 
-    /** An output buffer for the constant pool.
+    /** An output buffer for the constant poolwriter.
      */
     ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
 
-    /** The constant pool.
+    /** The constant poolwriter.
      */
-    Pool pool;
-
-    /** The inner classes to be written, as a set.
-     */
-    Set<ClassSymbol> innerClasses;
-
-    /** The inner classes to be written, as a queue where
-     *  enclosing classes come first.
-     */
-    ListBuffer<ClassSymbol> innerClassesQueue;
-
-    /** The bootstrap methods to be written in the corresponding class attribute
-     *  (one for each invokedynamic)
-     */
-    Map<DynamicMethod.BootstrapMethodsKey, DynamicMethod.BootstrapMethodsValue> bootstrapMethods;
+    PoolWriter poolwriter;
 
     /** The log to use for verbose output.
      */
@@ -309,16 +282,16 @@
          * Check for uninitialized types before calling the general case.
          */
         @Override
-        public void assembleSig(Type type, SigMode mode) {
+        public void assembleSig(Type type) {
             switch (type.getTag()) {
                 case UNINITIALIZED_THIS:
                 case UNINITIALIZED_OBJECT:
                     // we don't yet have a spec for uninitialized types in the
                     // local variable table
-                    assembleSig(types.erasure(((UninitializedType)type).qtype), mode);
+                    assembleSig(types.erasure(((UninitializedType)type).qtype));
                     break;
                 default:
-                    super.assembleSig(type, mode);
+                    super.assembleSig(type);
             }
         }
 
@@ -339,7 +312,7 @@
 
         @Override
         protected void classReference(ClassSymbol c) {
-            enterInner(c);
+            poolwriter.enterInner(c);
         }
 
         private void reset() {
@@ -359,32 +332,15 @@
      * Return signature of given type
      */
     Name typeSig(Type type) {
-        return typeSig(type, SigMode.NORMAL);
-    }
-
-    Name typeSig(Type type, SigMode mode) {
         Assert.check(signatureGen.isEmpty());
         //- System.out.println(" ? " + type);
-        signatureGen.assembleSig(type, mode);
+        signatureGen.assembleSig(type);
         Name n = signatureGen.toName();
         signatureGen.reset();
         //- System.out.println("   " + n);
         return n;
     }
 
-    /** Given a type t, return the extended class name of its erasure in
-     *  external representation.
-     */
-    public Name xClassName(Type t) {
-        if (t.hasTag(CLASS)) {
-            return names.fromUtf(externalize(t.tsym.flatName()));
-        } else if (t.hasTag(ARRAY)) {
-            return typeSig(types.erasure(t));
-        } else {
-            throw new AssertionError("xClassName expects class or array type, got " + t);
-        }
-    }
-
 /******************************************************************
  * Writing the Constant Pool
  ******************************************************************/
@@ -403,130 +359,6 @@
         }
     }
 
-    /** Write constant pool to pool buffer.
-     *  Note: during writing, constant pool
-     *  might grow since some parts of constants still need to be entered.
-     */
-    boolean writePool(Pool pool) throws PoolOverflow, StringOverflow {
-        int poolCountIdx = poolbuf.length;
-        poolbuf.appendChar(0);
-        int i = 1;
-        boolean hasNewCPForms = false;
-        while (i < pool.pp) {
-            Object value = pool.pool[i];
-            Assert.checkNonNull(value);
-            if (value instanceof Method || value instanceof Variable)
-                value = ((DelegatedSymbol)value).getUnderlyingSymbol();
-
-            if (value instanceof MethodSymbol) {
-                MethodSymbol m = (MethodSymbol)value;
-                if (!m.isDynamic()) {
-                    poolbuf.appendByte((m.owner.flags() & INTERFACE) != 0
-                            ? CONSTANT_InterfaceMethodref
-                            : CONSTANT_Methodref);
-                    poolbuf.appendChar(pool.put(m.owner));
-                    poolbuf.appendChar(pool.put(nameType(m)));
-                } else {
-                    //invokedynamic
-                    DynamicMethodSymbol dynSym = (DynamicMethodSymbol)m;
-                    MethodHandle handle = new MethodHandle(dynSym.bsmKind, dynSym.bsm, types);
-                    DynamicMethod.BootstrapMethodsKey key = new DynamicMethod.BootstrapMethodsKey(dynSym, types);
-
-                    // Figure out the index for existing BSM; create a new BSM if no key
-                    DynamicMethod.BootstrapMethodsValue val = bootstrapMethods.get(key);
-                    if (val == null) {
-                        int index = bootstrapMethods.size();
-                        val = new DynamicMethod.BootstrapMethodsValue(handle, index);
-                        bootstrapMethods.put(key, val);
-                    }
-
-                    //init cp entries
-                    pool.put(names.BootstrapMethods);
-                    pool.put(handle);
-                    for (BootstrapArgument<?> staticArg : dynSym.staticArgs) {
-                        pool.put(staticArg.data);
-                    }
-                    poolbuf.appendByte(CONSTANT_InvokeDynamic);
-                    poolbuf.appendChar(val.index);
-                    poolbuf.appendChar(pool.put(nameType(dynSym)));
-                }
-            } else if (value instanceof SignatureMember) {
-                hasNewCPForms = true;
-                ((SignatureMember)value).writePool(poolbuf, pool);
-            } else if (value instanceof VarSymbol) {
-                VarSymbol v = (VarSymbol)value;
-                poolbuf.appendByte(CONSTANT_Fieldref);
-                poolbuf.appendChar(pool.put(v.owner));
-                poolbuf.appendChar(pool.put(nameType(v)));
-            } else if (value instanceof Name) {
-                poolbuf.appendByte(CONSTANT_Utf8);
-                byte[] bs = ((Name)value).toUtf();
-                poolbuf.appendChar(bs.length);
-                poolbuf.appendBytes(bs, 0, bs.length);
-                if (bs.length > Pool.MAX_STRING_LENGTH)
-                    throw new StringOverflow(value.toString());
-            } else if (value instanceof ClassSymbol) {
-                ClassSymbol c = (ClassSymbol)value;
-                if (c.owner.kind == TYP) pool.put(c.owner);
-                poolbuf.appendByte(CONSTANT_Class);
-                if (c.type.hasTag(ARRAY)) {
-                    poolbuf.appendChar(pool.put(typeSig(c.type)));
-                } else {
-                    poolbuf.appendChar(pool.put(names.fromUtf(externalize(c.flatname))));
-                    enterInner(c);
-                }
-            } else if (value instanceof Pool.SignatureClass) {
-                hasNewCPForms = true;
-                poolbuf.appendByte(CONSTANT_Class);
-                poolbuf.appendChar(pool.put(Signature.of(((SignatureClass)value).type, types)));
-            } else if (value instanceof NameAndType) {
-                ((NameAndType)value).writePool(poolbuf, pool, this::typeSig);
-            } else if (value instanceof Integer) {
-                poolbuf.appendByte(CONSTANT_Integer);
-                poolbuf.appendInt(((Integer)value).intValue());
-            } else if (value instanceof Long) {
-                poolbuf.appendByte(CONSTANT_Long);
-                poolbuf.appendLong(((Long)value).longValue());
-                i++;
-            } else if (value instanceof Float) {
-                poolbuf.appendByte(CONSTANT_Float);
-                poolbuf.appendFloat(((Float)value).floatValue());
-            } else if (value instanceof Double) {
-                poolbuf.appendByte(CONSTANT_Double);
-                poolbuf.appendDouble(((Double)value).doubleValue());
-                i++;
-            } else if (value instanceof String) {
-                poolbuf.appendByte(CONSTANT_String);
-                poolbuf.appendChar(pool.put(names.fromString((String)value)));
-            } else if (value instanceof Signature) {
-                hasNewCPForms = true;
-                ((Signature)value).writePool(poolbuf, pool);
-            } else if (value instanceof UniqueType) {
-                Type type = ((UniqueType)value).type;
-                if (type.hasTag(METHOD)) {
-                    poolbuf.appendByte(CONSTANT_MethodType);
-                    poolbuf.appendChar(pool.put(typeSig((MethodType)type)));
-                } else {
-                    Assert.check(type.hasTag(ARRAY));
-                    poolbuf.appendByte(CONSTANT_Class);
-                    poolbuf.appendChar(pool.put(xClassName(type)));
-                }
-            } else if (value instanceof MethodHandle) {
-                MethodHandle ref = (MethodHandle)value;
-                poolbuf.appendByte(CONSTANT_MethodHandle);
-                poolbuf.appendByte(ref.refKind);
-                poolbuf.appendChar(pool.put(ref.refSym));
-            } else {
-                Assert.error("writePool " + value);
-            }
-            i++;
-        }
-        if (pool.pp > Pool.MAX_ENTRIES)
-            throw new PoolOverflow();
-        putChar(poolbuf, poolCountIdx, pool.pp);
-        return hasNewCPForms;
-    }
-
     /** Given a field, return its name.
      */
     Name fieldName(Symbol sym) {
@@ -545,19 +377,6 @@
         }
     }
 
-    /** Given a symbol, return its name-and-type.
-     */
-    NameAndType nameType(Symbol sym) {
-        return new NameAndType(fieldName(sym),
-                               retrofit
-                               ? sym.erasure(types)
-                               : sym.externalType(types), types);
-        // if we retrofit, then the NameAndType has been read in as is
-        // and no change is necessary. If we compile normally, the
-        // NameAndType is generated from a symbol reference, and the
-        // adjustment of adding an additional this$n parameter needs to be made.
-    }
-
 /******************************************************************
  * Writing Attributes
  ******************************************************************/
@@ -566,7 +385,7 @@
      *  position past attribute length index.
      */
     int writeAttr(Name attrName) {
-        databuf.appendChar(pool.put(attrName));
+        databuf.appendChar(poolwriter.putConstant(attrName));
         databuf.appendInt(0);
         return databuf.length;
     }
@@ -613,8 +432,8 @@
              || c.owner.kind != MTH) // or member init
             ? null
             : (MethodSymbol)c.owner;
-        databuf.appendChar(pool.put(enclClass));
-        databuf.appendChar(enclMethod == null ? 0 : pool.put(nameType(c.owner)));
+        databuf.appendChar(poolwriter.putSymbol(enclClass));
+        databuf.appendChar(enclMethod == null ? 0 : poolwriter.putNameAndType(c.owner));
         endAttr(alenIdx);
         return 1;
     }
@@ -636,16 +455,14 @@
     int writeBridgeAttr(Symbol s) {
         int alenIdx = writeAttr(names.Bridge);
         Symbol impl = s.baseSymbol();
-        int kind = impl.enclClass().isInterface() ?
-                ClassFile.REF_invokeInterface : ClassFile.REF_invokeVirtual;
-        databuf.appendChar(pool.put(new MethodHandle(kind, impl, types)));
+        databuf.appendChar(poolwriter.putSymbol(new MethodHandleSymbol((MethodSymbol)impl)));
         endAttr(alenIdx);
         return 1;
     }
 
     boolean needsMemberSignature(Symbol sym) {
         return !types.isSameType(sym.type, sym.erasure(types)) ||
-             containsSpecialized(sym.type) ||
+             types.isSpecialized(sym.type) ||
              signatureGen.hasTypeVar(sym.type.getThrownTypes());
     }
 
@@ -669,7 +486,7 @@
                 // will get a signature attribute
                 int alenIdx = writeAttr(sigName);
 
-                databuf.appendChar(pool.put(typeSig(sym.type, regularSig ? SigMode.NORMAL : SigMode.SPECIALIZER)));
+                databuf.appendChar(poolwriter.putConstant(typeSig(sym.type)));
                 endAttr(alenIdx);
                 acount++;
             }
@@ -693,7 +510,7 @@
                 final int flags =
                     ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
                     ((int) m.flags() & SYNTHETIC);
-                databuf.appendChar(pool.put(s.name));
+                databuf.appendChar(poolwriter.putConstant(s.name));
                 databuf.appendChar(flags);
             }
             // Now write the real parameters
@@ -701,7 +518,7 @@
                 final int flags =
                     ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
                     ((int) m.flags() & SYNTHETIC);
-                databuf.appendChar(pool.put(s.name));
+                databuf.appendChar(poolwriter.putConstant(s.name));
                 databuf.appendChar(flags);
             }
             // Now write the captured locals
@@ -709,7 +526,7 @@
                 final int flags =
                     ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
                     ((int) m.flags() & SYNTHETIC);
-                databuf.appendChar(pool.put(s.name));
+                databuf.appendChar(poolwriter.putConstant(s.name));
                 databuf.appendChar(flags);
             }
             endAttr(attrIndex);
@@ -787,7 +604,7 @@
         databuf.appendByte(nvars);
 
         for (Map.Entry<Symbol, WhereClause.Kind> whereClause : m.whereClauses.entrySet()) {
-            databuf.appendChar(pool.put(typeSig(whereClause.getKey().type)));
+            databuf.appendChar(poolwriter.putConstant(typeSig(whereClause.getKey().type)));
             databuf.appendChar(whereClause.getValue().code());
         }
         endAttr(attrIndex);
@@ -929,16 +746,16 @@
             default:
                 throw new AssertionError(_value.type);
             }
-            databuf.appendChar(pool.put(value));
+            databuf.appendChar(poolwriter.putConstant(value));
         }
         public void visitEnum(Attribute.Enum e) {
             databuf.appendByte('e');
-            databuf.appendChar(pool.put(typeSig(e.value.type)));
-            databuf.appendChar(pool.put(e.value.name));
+            databuf.appendChar(poolwriter.putConstant(typeSig(e.value.type)));
+            databuf.appendChar(poolwriter.putConstant(e.value.name));
         }
         public void visitClass(Attribute.Class clazz) {
             databuf.appendByte('c');
-            databuf.appendChar(pool.put(typeSig(clazz.classType)));
+            databuf.appendChar(poolwriter.putConstant(typeSig(clazz.classType)));
         }
         public void visitCompound(Attribute.Compound compound) {
             databuf.appendByte('@');
@@ -959,10 +776,10 @@
 
     /** Write a compound attribute excluding the '@' marker. */
     void writeCompoundAttribute(Attribute.Compound c) {
-        databuf.appendChar(pool.put(typeSig(c.type)));
+        databuf.appendChar(poolwriter.putConstant(typeSig(c.type)));
         databuf.appendChar(c.values.length());
         for (Tuple2<MethodSymbol,Attribute> p : c.values) {
-            databuf.appendChar(pool.put(p.elem0.name));
+            databuf.appendChar(poolwriter.putConstant(p.elem0.name));
             p.elem1.accept(awriter);
         }
     }
@@ -1058,46 +875,12 @@
  * Writing Objects
  **********************************************************************/
 
-    /** Enter an inner class into the `innerClasses' set/queue.
-     */
-    void enterInner(ClassSymbol c) {
-        if (c.type.isCompound()) {
-            throw new AssertionError("Unexpected intersection type: " + c.type);
-        }
-        try {
-            c.complete();
-        } catch (CompletionFailure ex) {
-            System.err.println("error: " + c + ": " + ex.getMessage());
-            throw ex;
-        }
-        if (!c.type.hasTag(CLASS)) return; // arrays
-        if (pool != null && // pool might be null if called from xClassName
-            c.owner.enclClass() != null &&
-            (innerClasses == null || !innerClasses.contains(c))) {
-//          log.errWriter.println("enter inner " + c);//DEBUG
-            enterInner(c.owner.enclClass());
-            pool.put(c);
-            if (c.name != names.empty)
-                pool.put(c.name);
-            if (innerClasses == null) {
-                innerClasses = new HashSet<>();
-                innerClassesQueue = new ListBuffer<>();
-                pool.put(names.InnerClasses);
-            }
-            innerClasses.add(c);
-            innerClassesQueue.append(c);
-        }
-    }
-
     /** Write "inner classes" attribute.
      */
     void writeInnerClasses() {
         int alenIdx = writeAttr(names.InnerClasses);
-        databuf.appendChar(innerClassesQueue.length());
-        for (List<ClassSymbol> l = innerClassesQueue.toList();
-             l.nonEmpty();
-             l = l.tail) {
-            ClassSymbol inner = l.head;
+        databuf.appendChar(poolwriter.innerClasses.size());
+        for (ClassSymbol inner : poolwriter.innerClasses) {
             inner.markAbstractIfNeeded(types);
             int fl = (char) adjustFlags(inner.flags_field);
             if ((fl & VALUE) != 0) fl |= ACC_VALUE;
@@ -1110,11 +893,11 @@
                 pw.println("INNERCLASS  " + inner.name);
                 pw.println("---" + flagNames(flags));
             }
-            databuf.appendChar(pool.get(inner));
+            databuf.appendChar(poolwriter.putSymbol(inner));
             databuf.appendChar(
-                inner.owner.kind == TYP && !inner.name.isEmpty() ? pool.get(inner.owner) : 0);
+                inner.owner.kind == TYP && !inner.name.isEmpty() ? poolwriter.putSymbol(inner.owner) : 0);
             databuf.appendChar(
-                !inner.name.isEmpty() ? pool.get(inner.name) : 0);
+                !inner.name.isEmpty() ? poolwriter.putConstant(inner.name) : 0);
             databuf.appendChar(flags);
         }
         endAttr(alenIdx);
@@ -1124,17 +907,17 @@
      */
     void writeBootstrapMethods() {
         int alenIdx = writeAttr(names.BootstrapMethods);
-        databuf.appendChar(bootstrapMethods.size());
-        for (Map.Entry<DynamicMethod.BootstrapMethodsKey, DynamicMethod.BootstrapMethodsValue> entry : bootstrapMethods.entrySet()) {
-            DynamicMethod.BootstrapMethodsKey bsmKey = entry.getKey();
+        databuf.appendChar(poolwriter.bootstrapMethods.size());
+        for (Map.Entry<PoolWriter.BootstrapMethodsKey, Tuple2<Pool.MethodHandle, Integer>> entry : poolwriter.bootstrapMethods.entrySet()) {
+            PoolWriter.BootstrapMethodsKey bsmKey = entry.getKey();
             //write BSM handle
-            databuf.appendChar(pool.get(entry.getValue().mh));
-            Object[] uniqueArgs = bsmKey.getUniqueArgs();
+            databuf.appendChar(entry.getValue().elem0.index);
+            Pool.Entry[] uniqueArgs = bsmKey.staticArgs;
             //write static args length
             databuf.appendChar(uniqueArgs.length);
             //write static args array
-            for (Object o : uniqueArgs) {
-                databuf.appendChar(pool.get(o));
+            for (Pool.Entry e : uniqueArgs) {
+                databuf.appendChar(e.index);
             }
         }
         endAttr(alenIdx);
@@ -1162,15 +945,15 @@
 
         for (Tuple2<Symbol, List<Type>> _entries : varsByOwner) {
             List<Type> vars = _entries.elem1;
-            databuf.appendChar((short)pool.put(ownerToName(_entries.elem0)));
+            databuf.appendChar((short)poolwriter.putConstant(ownerToName(_entries.elem0)));
             databuf.appendByte((byte)vars.length());
 
             Assert.check((vars.size() & 0xFFFFFF00) == 0);
 
             for (Type t : vars) {
                 databuf.appendByte((byte)t.tsym.flags() & 0xFF);
-                databuf.appendChar((short)pool.put(t.tsym.name));
-                databuf.appendChar((short)pool.put(typeSig(types.getBounds((TypeVar)t).head)));
+                databuf.appendChar((short)poolwriter.putConstant(t.tsym.name));
+                databuf.appendChar((short)poolwriter.putConstant(typeSig(types.getBounds((TypeVar)t).head)));
             }
         }
         endAttr(alenIdx);
@@ -1208,14 +991,14 @@
             databuf.appendChar((short)opcodeMap.size());
             for (Map.Entry<Integer, Name> opcodeEntry : opcodeMap.entrySet()) {
                 databuf.appendChar(opcodeEntry.getKey().shortValue());
-                databuf.appendChar((short)pool.put(opcodeEntry.getValue()));
+                databuf.appendChar((short)poolwriter.putConstant(opcodeEntry.getValue()));
             }
             endAttr(alenIdx);
             return 1;
         }
     }
 
-    /** Write field symbol, entering all references into constant pool.
+    /** Write field symbol, entering all references into constant poolwriter.
      */
     void writeField(VarSymbol v) {
         int flags = adjustFlags(v.flags());
@@ -1225,13 +1008,13 @@
             pw.println("FIELD  " + fieldName(v));
             pw.println("---" + flagNames(v.flags()));
         }
-        databuf.appendChar(pool.put(fieldName(v)));
+        databuf.appendChar(poolwriter.putConstant(fieldName(v)));
         databuf.appendChar(writeMemberTypeRef(v));
         int acountIdx = beginAttrs();
         int acount = 0;
         if (v.getConstValue() != null) {
             int alenIdx = writeAttr(names.ConstantValue);
-            databuf.appendChar(pool.put(v.getConstValue()));
+            databuf.appendChar(poolwriter.putConstant(v.getConstValue()));
             endAttr(alenIdx);
             acount++;
         }
@@ -1239,7 +1022,7 @@
         endAttrs(acountIdx, acount);
     }
 
-    /** Write method symbol, entering all references into constant pool.
+    /** Write method symbol, entering all references into constant poolwriter.
      */
     void writeMethod(MethodSymbol m) {
         int flags = adjustFlags(m.flags());
@@ -1252,7 +1035,7 @@
             pw.println("METHOD  " + methodName(m));
             pw.println("---" + flagNames(m.flags()));
         }
-        databuf.appendChar(pool.put(methodName(m)));
+        databuf.appendChar(poolwriter.putConstant(methodName(m)));
         databuf.appendChar(writeMemberTypeRef(m));
         int acountIdx = beginAttrs();
         int acount = 0;
@@ -1275,7 +1058,7 @@
             int alenIdx = writeAttr(names.Exceptions);
             databuf.appendChar(thrown.length());
             for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
-                databuf.appendChar(pool.put(l.head.tsym));
+                databuf.appendChar(poolwriter.putSymbol(l.head.tsym));
             endAttr(alenIdx);
             acount++;
         }
@@ -1318,7 +1101,7 @@
         for (int i = l - 1; i >= 0; --i) {
             assert valueMembers.hasNext();
             databuf.appendChar(i);
-            databuf.appendChar(pool.put(valueMembers.next()));
+            databuf.appendChar(poolwriter.putSymbol(valueMembers.next()));
         }
     }
 
@@ -1378,9 +1161,9 @@
                             && (r.start_pc + r.length) <= code.cp);
                     databuf.appendChar(r.length);
                     VarSymbol sym = var.sym;
-                    databuf.appendChar(pool.put(sym.name));
+                    databuf.appendChar(poolwriter.putConstant(sym.name));
                     Type vartype = sym.erasure(types);
-                    databuf.appendChar(pool.put(typeSig(vartype)));
+                    databuf.appendChar(poolwriter.putConstant(typeSig(vartype)));
                     databuf.appendChar(var.reg);
                     if (needsLocalVariableTypeEntry(var.sym.type)) {
                         nGenericVars++;
@@ -1404,8 +1187,8 @@
                         // write variable info
                         databuf.appendChar(r.start_pc);
                         databuf.appendChar(r.length);
-                        databuf.appendChar(pool.put(sym.name));
-                        databuf.appendChar(pool.put(typeSig(sym.type)));
+                        databuf.appendChar(poolwriter.putConstant(sym.name));
+                        databuf.appendChar(poolwriter.putConstant(typeSig(sym.type)));
                         databuf.appendChar(var.reg);
                         count++;
                     }
@@ -1534,12 +1317,12 @@
             case ARRAY:
                 if (debugstackmap) System.out.print("object(" + t + ")");
                 databuf.appendByte(7);
-                databuf.appendChar(pool.put(t));
+                databuf.appendChar(poolwriter.putClass(types.normalize(t)));
                 break;
             case TYPEVAR:
                 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
                 databuf.appendByte(7);
-                databuf.appendChar(pool.put(types.erasure(t).tsym));
+                databuf.appendChar(poolwriter.putSymbol(types.erasure(t).tsym));
                 break;
             case UNINITIALIZED_THIS:
                 if (debugstackmap) System.out.print("uninit_this");
@@ -1829,14 +1612,10 @@
         databuf.reset();
         poolbuf.reset();
         signatureGen.reset();
-        pool = c.pool;
-        innerClasses = null;
-        innerClassesQueue = null;
-        bootstrapMethods = new LinkedHashMap<>();
+        poolwriter = c.poolWriter;
 
-        Type supertype = types.specialize(types.supertype(c.type));
-        List<Type> interfaces =
-                types.interfaces(c.type).stream().map(types::specialize).collect(List.collector());
+        Type supertype = types.supertype(c.type);
+        List<Type> interfaces = types.interfaces(c.type);
         List<Type> typarams = c.type.getTypeArguments();
 
         int flags = adjustFlags(c.flags() & ~DEFAULT);
@@ -1856,8 +1635,7 @@
         }
         databuf.appendChar(flags);
 
-        databuf.appendChar((poolModes.contains(PoolMode.SIGNATURES) && types.isAnyfied(c)) ?
-                pool.put(new Pool.SignatureClass(c.type, types)) : pool.put(c));
+        databuf.appendChar(poolwriter.putClass(c.type));
         databuf.appendChar(supertype.hasTag(CLASS) ? writeTypeRef(supertype) : 0);
         databuf.appendChar(interfaces.length());
         for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
@@ -1869,14 +1647,14 @@
             case VAR: fieldsCount++; break;
             case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
                       break;
-            case TYP: enterInner((ClassSymbol)sym); break;
+            case TYP: poolwriter.enterInner((ClassSymbol)sym); break;
             default : Assert.error();
             }
         }
 
         if (c.trans_local != null) {
             for (ClassSymbol local : c.trans_local) {
-                enterInner(local);
+                poolwriter.enterInner(local);
             }
         }
 
@@ -1891,16 +1669,16 @@
         boolean sigReq =
             typarams.length() != 0 ||
                     supertype.allparams().length() != 0 ||
-                    containsSpecialized(supertype);
+                    types.isSpecialized(supertype);
         for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
-            sigReq = l.head.allparams().length() != 0 || containsSpecialized(l.head);
+            sigReq = l.head.allparams().length() != 0 || types.isSpecialized(l.head);
         if (sigReq) {
             int alenIdx = writeAttr(names.Signature);
-            if (typarams.length() != 0) signatureGen.assembleParamsSig(typarams, SigMode.NORMAL);
-            signatureGen.assembleSig(types.unspecialize(supertype), SigMode.NORMAL);
+            if (typarams.length() != 0) signatureGen.assembleParamsSig(typarams);
+            signatureGen.assembleSig(supertype);
             for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
-                signatureGen.assembleSig(types.unspecialize(l.head), SigMode.NORMAL);
-            databuf.appendChar(pool.put(signatureGen.toName()));
+                signatureGen.assembleSig(l.head);
+            databuf.appendChar(poolwriter.putConstant(signatureGen.toName()));
             signatureGen.reset();
             endAttr(alenIdx);
             acount++;
@@ -1911,9 +1689,9 @@
             // WHM 6/29/1999: Strip file path prefix.  We do it here at
             // the last possible moment because the sourcefile may be used
             // elsewhere in error diagnostics. Fixes 4241573.
-            //databuf.appendChar(c.pool.put(c.sourcefile));
+            //databuf.appendChar(c.poolwriter.putSymbol(c.sourcefile));
             String simpleName = BaseFileObject.getSimpleName(c.sourcefile);
-            databuf.appendChar(c.pool.put(names.fromString(simpleName)));
+            databuf.appendChar(c.poolWriter.putConstant(names.fromString(simpleName)));
             endAttr(alenIdx);
             acount++;
         }
@@ -1921,12 +1699,12 @@
         if (genCrt) {
             // Append SourceID attribute
             int alenIdx = writeAttr(names.SourceID);
-            databuf.appendChar(c.pool.put(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
+            databuf.appendChar(c.poolWriter.putConstant(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
             endAttr(alenIdx);
             acount++;
             // Append CompilationID attribute
             alenIdx = writeAttr(names.CompilationID);
-            databuf.appendChar(c.pool.put(names.fromString(Long.toString(System.currentTimeMillis()))));
+            databuf.appendChar(c.poolWriter.putConstant(names.fromString(Long.toString(System.currentTimeMillis()))));
             endAttr(alenIdx);
             acount++;
         }
@@ -1942,76 +1720,37 @@
         poolbuf.appendChar(target.minorVersion);
         poolbuf.appendChar(target.majorVersion);
 
-        boolean useNewCPForms = writePool(c.pool);
-
-        if (useNewCPForms) {
-            //bump minor version by one
-            poolbuf.elems[5] = 0b1;
-        }
-
-        if (innerClasses != null) {
+        if (!poolwriter.innerClasses.isEmpty()) {
             writeInnerClasses();
             acount++;
         }
 
-        if (!bootstrapMethods.isEmpty()) {
+        if (!poolwriter.bootstrapMethods.isEmpty()) {
             writeBootstrapMethods();
             acount++;
         }
 
         endAttrs(acountIdx, acount);
 
+        poolwriter.writePool(poolbuf);
+
+        if (poolwriter.useNewCPForms) {
+            //bump minor version by one
+            poolbuf.elems[5] = 0b1;
+        }
+
         poolbuf.appendBytes(databuf.elems, 0, databuf.length);
         out.write(poolbuf.elems, 0, poolbuf.length);
 
-        pool = c.pool = null; // to conserve space
+        poolwriter = c.poolWriter = null; // to conserve space
      }
 
-    boolean containsSpecialized(Type type) {
-        return containsSpecialized.visit(type);
-    }
-
-    UnaryVisitor<Boolean> containsSpecialized = new UnaryVisitor<Boolean>() {
-
-        @Override
-        public Boolean visitType(Type t, Void aVoid) {
-            return false;
-        }
-
-        @Override
-        public Boolean visitClassType(ClassType t, Void aVoid) {
-            return (t.tsym.flags() & SPECIALIZED_CLASS) != 0 ||
-                    t.allparams().stream().anyMatch(this::visit);
-        }
-    };
-
     int writeTypeRef(Type t) {
-        return writePoolRef(t.tsym, t, t.allparams().length() != 0 || containsSpecialized(t));
+        return poolwriter.putClass(t);
     }
 
     int writeMemberTypeRef(Symbol s) {
-        return writePoolRef(s, s.type, needsMemberSignature(s));
-    }
-
-    int writePoolRef(Symbol sym, Type t, boolean sigReq) {
-        Object poolObj = null;
-        switch (sym.kind) {
-            case TYP:
-                poolObj = (sigReq && poolModes.contains(PoolMode.SIGNATURES)) ?
-                        Pool.Signature.of(t, types) : sym;
-                break;
-            case MTH:
-                poolObj = (sigReq && poolModes.contains(PoolMode.SIGNATURES)) ?
-                        Pool.Signature.of(t, types) : typeSig(sym.externalType(types));
-                break;
-            case VAR:
-                poolObj = (sigReq && poolModes.contains(PoolMode.SIGNATURES)) ?
-                        Pool.Signature.of(t, types) : typeSig(sym.erasure(types));
-                break;
-            default:
-                Assert.error();
-        }
-        return pool.put(poolObj);
+        return poolwriter.putType(Descriptor.of(s, s.enclClass().type, types).externalType(types));
     }
 
     /**Allows subclasses to write additional class attributes
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Tue Dec 08 14:42:24 2015 +0000
@@ -28,7 +28,6 @@
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Types.UniqueType;
-import com.sun.tools.javac.jvm.Pool.SignatureMember;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 
@@ -491,7 +490,7 @@
         emitop(invokespecial);
         if (!alive) return;
         emit2(meth);
-        Symbol sym = symbolForPool(pool.pool[meth]);
+        Symbol sym = symbolForPool(pool.get(meth).data.get());
         state.pop(argsize);
         if (sym.isConstructor())
             state.markInitialized((UninitializedType)state.peek());
@@ -549,7 +548,7 @@
             Type a = state.stack[state.stacksize-1];
             Assert.check(!a.hasTag(BOT)); // null type as is cannot be indexed.
             state.pop(1);
-            state.push(types.erasure(types.elemtype(a))); }
+            state.push(types.elemtype(a)); }
             break;
         case goto_:
             markDead();
@@ -953,7 +952,7 @@
             state.push(syms.intType);
             break;
         case ldc1:
-            state.push(typeForPool(pool.pool[od]));
+            state.push(typeForPool(pool.get(od).data.get()));
             break;
         default:
             throw new AssertionError(mnem(op));
@@ -969,12 +968,12 @@
         if (o instanceof Long) return syms.longType;
         if (o instanceof Double) return syms.doubleType;
         if (o instanceof ClassSymbol) return syms.classType;
-        if (o instanceof Pool.SignatureClass) return syms.classType;
-        if (o instanceof Pool.MethodHandle) return syms.methodHandleType;
+        if (o instanceof MethodHandleSymbol) return syms.methodHandleType;
         if (o instanceof UniqueType) return typeForPool(((UniqueType)o).type);
         if (o instanceof Type) {
             Type ty = (Type) o;
-
+            if (ty instanceof Type.TypeVar) return syms.classType;
+            if (ty instanceof Type.ClassType) return syms.classType;
             if (ty instanceof Type.ArrayType) return syms.classType;
             if (ty instanceof Type.MethodType) return syms.methodTypeType;
         }
@@ -984,7 +983,6 @@
     /** The symbol of a constant pool entry. */
     private Symbol symbolForPool(Object o) {
         if (o instanceof Symbol) return (Symbol)o;
-        if (o instanceof SignatureMember) return ((SignatureMember)o).sym;
         throw new AssertionError("Invalid symbol of constant pool entry: " + o.getClass());
     }
 
@@ -1078,23 +1076,22 @@
         emit2(od);
         switch (op) {
         case getstatic:
-            state.push(((Symbol)(pool.pool[od])).erasure(types));
+            state.push(symbolForPool(pool.get(od).data.get()).externalType(types));
             break;
         case putstatic:
-            state.pop(((Symbol)(pool.pool[od])).erasure(types));
+            state.pop(symbolForPool(pool.get(od).data.get()).externalType(types));
             break;
         case vnew:
         case new_:
-            Symbol sym;
-            if (pool.pool[od] instanceof UniqueType) {
+            Type t;
+            if (pool.get(od).data.get() instanceof Type) {
                 // Required by change in Gen.makeRef to allow
                 // annotated types.
-                // TODO: is this needed anywhere else?
-                sym = ((UniqueType)(pool.pool[od])).type.tsym;
+                t = (Type)pool.get(od).data.get();
             } else {
-                sym = (Symbol)(pool.pool[od]);
+                t = ((Symbol)(pool.get(od).data.get())).type;
             }
-            state.push(uninitializedObject(sym.erasure(types), cp-3));
+            state.push(uninitializedObject(t, cp-3));
             break;
         case sipush:
             state.push(syms.intType);
@@ -1123,31 +1120,31 @@
             markDead();
             break;
         case putfield:
-            state.pop(symbolForPool(pool.pool[od]).erasure(types));
+            state.pop(symbolForPool(pool.get(od).data.get()).externalType(types));
             state.pop(1); // object ref
             break;
         case getfield:
         case vgetfield:
             state.pop(1); // object ref
-            state.push(symbolForPool(pool.pool[od]).erasure(types));
+            state.push(symbolForPool(pool.get(od).data.get()).externalType(types));
             break;
         case checkcast: {
             state.pop(1); // object ref
-            Object o = pool.pool[od];
-            Type t = (o instanceof Symbol)
+            Object o = pool.get(od).data.get();
+            Type cat = (o instanceof Symbol)
                 ? ((Symbol)o).erasure(types)
-                : types.erasure((((UniqueType)o).type));
-            state.push(t);
+                : (Type)o;
+            state.push(cat);
             break; }
         case ldc2w:
-            state.push(typeForPool(pool.pool[od]));
+            state.push(typeForPool(pool.get(od).data.get()));
             break;
         case instanceof_:
             state.pop(1);
             state.push(syms.intType);
             break;
         case ldc2:
-            state.push(typeForPool(pool.pool[od]));
+            state.push(typeForPool(pool.get(od).data.get()));
             break;
         case jsr:
         case typed:
@@ -1395,7 +1392,7 @@
                 Symbol local = lvar[i].sym;
                 Type vtype = local.type;
                 if (!(vtype instanceof UninitializedType))
-                    vtype = local.erasure(types);
+                    vtype = local.type;
                 frame.locals[i] = vtype;
             }
         }
@@ -1425,7 +1422,7 @@
                 Symbol local = lvar[i].sym;
                 Type vtype = local.type;
                 if (!(local.type instanceof UninitializedType))
-                    vtype = local.erasure(types);
+                    vtype = local.type;
                 locals[i] = vtype;
                 if (width(vtype) > 1) i++;
             }
@@ -1447,7 +1444,7 @@
         stackCount = 0;
         for (int i=0; i<state.stacksize; i++) {
             if (state.stack[i] != null) {
-                frame.stack[stackCount++] = types.erasure(state.stack[i]);
+                frame.stack[stackCount++] = state.stack[i];
             }
         }
 
@@ -1476,13 +1473,13 @@
             if (meth.isConstructor() && thisType != syms.objectType) {
                 frame.locals[count++] = UninitializedType.uninitializedThis(thisType);
             } else {
-                frame.locals[count++] = types.erasure(thisType);
+                frame.locals[count++] = thisType;
             }
         } else {
             frame.locals = new Type[len];
         }
         for (Type arg_type : arg_types) {
-            frame.locals[count++] = types.erasure(arg_type);
+            frame.locals[count++] = arg_type;
         }
         frame.pc = -1;
         frame.stack = null;
@@ -1872,7 +1869,7 @@
                 int width = width(t);
                 Type old = stack[stacksize-width];
                 Assert.check(types.isSubtype(types.erasure(old),
-                                       types.erasure(t)));
+                                       types.erasure(t))); //TODO: this check could be tigher
                 stack[stacksize-width] = t;
                 break;
             default:
@@ -1903,10 +1900,10 @@
             for (int i=0; i<stacksize; ) {
                 Type t = stack[i];
                 Type tother = other.stack[i];
-                Type result =
+                Type result = //TODO: this check could be tighter
                     t==tother ? t :
-                    types.isSubtype(t, tother) ? tother :
-                    types.isSubtype(tother, t) ? t :
+                    types.isSubtype(types.erasure(t), types.erasure(tother)) ? tother :
+                    types.isSubtype(types.erasure(tother), types.erasure(t)) ? t :
                     error();
                 int w = width(result);
                 stack[i] = result;
@@ -2297,7 +2294,7 @@
     }
 
     public int newLocal(VarSymbol v) {
-        int reg = v.adr = newLocal(v.erasure(types));
+        int reg = v.adr = newLocal(v.type);
         addLocalVar(v);
         return reg;
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Tue Dec 08 14:42:24 2015 +0000
@@ -26,13 +26,11 @@
 package com.sun.tools.javac.jvm;
 
 import java.util.*;
-import java.util.function.BiConsumer;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.function.Predicate;
 
 import com.sun.tools.javac.code.Types.TypeVarContext;
-import com.sun.tools.javac.jvm.Pool.Signature;
-import com.sun.tools.javac.jvm.Pool.SignatureClass;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.List;
@@ -98,7 +96,7 @@
 
     /** Constant pool, reset by genClass.
      */
-    private Pool pool;
+    private PoolWriter pool;
 
     protected Gen(Context context) {
         context.put(genKey, this);
@@ -131,7 +129,6 @@
         allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
         allowBetterNullChecks = target.hasObjects();
         poolModes = PoolMode.getPoolMode(options);
-        pool = new Pool(types, names, poolModes.contains(PoolMode.SPECIALIZED));
 
         // ignore cldc because we cannot have both stackmap formats
         this.stackMap = StackMapFormat.JSR202;
@@ -151,7 +148,7 @@
         annotate = Annotate.instance(context);
     }
 
-    enum PoolMode {
+    public enum PoolMode {
         TYPE1("type1"),
         TYPE2("type2"),
         TYPE3("type3"),
@@ -280,67 +277,118 @@
         }
     }
 
-    /** Construct a symbol to reflect the qualifying type that should
-     *  appear in the byte code as per JLS 13.1.
-     *
-     *  For {@literal target >= 1.2}: Clone a method with the qualifier as owner (except
-     *  for those cases where we need to work around VM bugs).
-     *
-     *  For {@literal target <= 1.1}: If qualified variable or method is defined in a
-     *  non-accessible class, clone it with the qualifier class as owner.
-     *
-     *  @param sym    The accessed symbol
-     *  @param site   The qualifier's type.
+    /**
+     * Construct a symbol to reflect the qualifying type that should
+     * appear in the byte code as per JLS 13.1.
      */
-    Symbol binaryQualifier(Symbol sym, Type site) {
+    public static class Descriptor extends DelegatedSymbol<Symbol> {
 
-        if (site.hasTag(ARRAY)) {
-            if (sym == syms.lengthVar ||
-                sym.owner != syms.arrayClass)
-                return sym;
-            // array clone can be qualified by the array type in later targets
-            Symbol qualifier = new ClassSymbol(Flags.PUBLIC, site.tsym.name,
-                                               site, syms.noSymbol);
-            return sym.clone(qualifier);
-        }
+        /** The instantiated descriptor owner. */
+        public Type site;
 
-        if (sym.owner == site.tsym ||
-            (sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) {
-            return sym;
-        }
-
-        // leave alone methods inherited from Object
-        // JLS 13.1.
-        if (sym.owner == syms.objectType.tsym)
-            return sym;
-
-        //fixup static access to specializable classes
-        if (sym.isStatic()) {
-            site = site.tsym.baseSymbol().type;
-        }
-
-        return new BinarySymbol(sym, site.tsym);
-    }
-
-    /**
-     * This class is used to store the binary representation of a given variable/method symbol.
-     * As javac stores regular symbols in the constant pool, such symbols needs to be 'adjusted'
-     * to point at the right receiver (see {@link Gen#binaryQualifier(com.sun.tools.javac.code.Symbol, com.sun.tools.javac.code.Type)}.
-     * Since symbols are adjusted using cloning, it means the original symbol would no longer
-     * be available for inspection (at least not reliably). This class bridges that gap.
-     */
-    static class BinarySymbol extends Symbol.DelegatedSymbol<Symbol> {
-
-        Symbol orig;
-
-        BinarySymbol(Symbol sym, TypeSymbol owner) {
-            super(sym.clone(owner));
-            this.orig = sym;
+        private Descriptor(Symbol other, Type site) {
+            super(other);
+            this.site = site;
         }
 
         @Override
         public Symbol baseSymbol() {
-            return orig;
+            return other.baseSymbol();
+        }
+
+        @Override
+        public Type externalType(Types types) {
+            return erasure(types);
+        }
+
+        @Override
+        public Type erasure(Types types) {
+            switch (other.kind) {
+                case MTH:
+                    Type mt1 = asExternalType(instType(types), types);
+                    Type mt2 = asExternalType(other.type, types);
+                    return types.decorateDescriptor(mt1, mt2).asMethodType();
+                case VAR:
+                    return types.decorateDescriptor(types.memberType(types.capture(site), other), other.type);
+                default:
+                    throw new AssertionError("Cant get here!");
+            }
+        }
+
+        /**
+         * Return the instantiated view of this descriptor.
+         */
+        private Type instType(Types types) {
+            if (!other.isStatic()) {
+                return types.memberType(types.capture(site), other);
+            } else if (other.name.toString().startsWith("access$")) {
+                //patch up accessor symbol
+                List<Type> from = other.enclClass().type.allparams();
+                List<Type> to = site.allparams();
+                return types.subst(other.type, from, to);
+            } else {
+                return other.type;
+            }
+        }
+
+        /**
+         * Return external type associated with given method (this is similar to {@link Symbol#externalType(Types)}
+         * but it takes generic info into account).
+         */
+        private Type asExternalType(Type t, Types types) {
+            List<Type> params = t.getParameterTypes();
+            boolean addedParams = false;
+            if (name == name.table.names.init && other.owner.hasOuterInstance()) {
+                //add outer instance param
+                params = params.prepend(other.externalType(types).getParameterTypes().head);
+                addedParams = true;
+            } else if (name == name.table.names.init &&
+                    (other.owner.flags_field & ENUM) != 0 &&
+                    (other.flags() & SYNTHETIC) == 0) { //do not touch access constructor
+                params = params.prependList(other.externalType(types).getParameterTypes().take(2));
+                addedParams = true;
+            }
+            for (Symbol p : ((MethodSymbol)other).capturedLocals) {
+                //add proxy var
+                params = params.append(p.type);
+                addedParams = true;
+            }
+            return addedParams ?
+                    types.createMethodTypeWithParameters(t, params) :
+                    t;
+        }
+
+        /**
+         * Factory method for creating descriptors.
+         */
+        public static Descriptor of(Symbol sym, Type site, Types types) {
+            Type descSite;
+            if (sym.owner == types.syms.objectType.tsym) {
+                // leave alone methods inherited from Object
+                // JLS 13.1.
+                descSite = sym.enclClass().type;
+            } else if (site.hasTag(ARRAY) ||
+                    (types.isSpecialized(site) && (!sym.isStatic() || (sym.flags() & SPECIALIZABLE) != 0))) {
+                //keep specialized info
+                descSite = site;
+            } else if ((sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) {
+                //not sure what this is for...
+                descSite = sym.enclClass().type;
+            } else {
+                //use uninstantiated info
+                Type erasedSite = types.erasure(site);
+                if (!erasedSite.tsym.isSubClass(sym.enclClass(), types)) {
+                    //intersection type!
+                    erasedSite = sym.enclClass().type;
+                }
+                descSite = erasedSite.tsym.type;
+            }
+            return new Descriptor(sym, descSite);
+        }
+
+        @Override
+        public <R, P> R accept(Visitor<R, P> v, P p) {
+            return v.visitSymbol(this, p);
         }
     }
 
@@ -351,16 +399,7 @@
      */
     int makeRef(DiagnosticPosition pos, Type type) {
         checkDimension(pos, type);
-        if (type.isAnnotated()) {
-            return pool.put(type);
-        } else {
-            return pool.put(type.hasTag(CLASS) ? type.tsym : type);
-        }
-    }
-
-    int makeGenericRef(DiagnosticPosition pos, Type type) {
-        checkDimension(pos, type);
-        return pool.put(new SignatureClass(type, types));
+        return pool.putClass(type);
     }
 
     /**
@@ -375,7 +414,7 @@
         MethodType mtype = new MethodType(args, type, List.nil(), syms.methodClass);
         MethodSymbol sym = new MethodSymbol(Flags.VALUEFACTORY, names.vminit, mtype, type.tsym);
         env.enclClass.sym.members_field.enterIfAbsent(sym);
-        return pool.put(sym);
+        return pool.putSymbol(sym);
     }
 
     /** Check if the given type is an array with too many dimensions.
@@ -647,7 +686,7 @@
                         break;
                     case TYPE_1:
                         if (poolModes.contains(PoolMode.TYPE1)) {
-                            code.emitop2(typed, pool.put(Signature.of(type, types)));
+                            code.emitop2(typed, pool.putType(type));
                         } else {
                             code.markAny(pc, types.typeSig(type));
                         }
@@ -659,22 +698,21 @@
         });
     }
 
-    private void emitAndMarkIfNeeded2(DiagnosticPosition pos, Type unerased, Type erased, int opcode) {
-        emitAndMarkIfNeeded2(pos, unerased, erased, (ref) -> code.emitop2(opcode, ref));
+    private void emitAndMarkIfNeeded2(DiagnosticPosition pos, Type unerased, int opcode) {
+        emitAndMarkIfNeeded2(pos, unerased, (ref) -> code.emitop2(opcode, ref), null);
     }
 
-    private void emitAndMarkIfNeeded2(DiagnosticPosition pos, Type unerased, Type erased, Consumer<Integer> snippet) {
-        boolean needsMangling = validUnerasedType(unerased) && types.needsMangling(unerased);
-        int ref = needsMangling && poolModes.contains(PoolMode.TYPE2) ?
-                makeGenericRef(pos, unerased) :
-                makeRef(pos, erased);
+    private void emitAndMarkIfNeeded2(DiagnosticPosition pos, Type unerased, Consumer<Integer> snippet, Function<Type, Type> poolFuncOpt) {
+        boolean needsMangling = types.needsMangling(unerased);
+        Type poolType = poolFuncOpt != null ? poolFuncOpt.apply(unerased) : unerased;
+        int ref = makeRef(pos, poolType);
         code.withDecorator(() -> snippet.accept(ref), (opcode, pc) -> {
             OpcodeKind ok = OpcodeKind.of(opcode);
             if (needsMangling) {
                 switch (ok) {
                     case TYPE_2:
                         if (!poolModes.contains(PoolMode.TYPE2)) {
-                            code.markAny(pc, types.specializerSig(unerased));
+                            code.markAny(pc, types.bytecodeMappingSig(unerased));
                         }
                         break;
                     default:
@@ -933,7 +971,7 @@
         @Override
         public void visitIdent(JCIdent tree) {
             if (tree.sym.owner instanceof ClassSymbol) {
-                pool.put(tree.sym.owner);
+                pool.putSymbol(tree.sym.owner);
             }
         }
 
@@ -1136,7 +1174,7 @@
                                                : null,
                                         syms,
                                         types,
-                                        pool);
+                                        pool.pool);
             items = new Items(pool, code, syms, types, names, poolModes);
             if (code.debugCode) {
                 System.err.println(meth + " for body " + tree);
@@ -1832,7 +1870,7 @@
                 ((JCUnary) e).setTag(PREDEC);
                 break;
         }
-        genExpr(tree.expr, tree.expr.type).drop();
+        genExpr(tree.expr, TreeInfo.unerasedTypeOrType(tree.expr)).drop();
     }
 
     public void visitBreak(JCBreak tree) {
@@ -1904,7 +1942,7 @@
         // Generate code for all arguments, where the expected types are
         // 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);
+        Symbol msym = m.member();
         if (msym.name.toString().startsWith("access$") &&
                 m.isAny() && !msym.baseSymbol().isStatic() &&
                 tree.args.head.unerasedType != null) {
@@ -1917,13 +1955,25 @@
                     types.subst(anyItem.ownerType, from, to),
                     types.subst(anyItem.memberType, from, to));
         }
-        genArgs(tree.args,
-                msym.externalType(types).getParameterTypes());
-        if (!msym.isDynamic()) {
+
+        List<Type> params = msym.externalType(types).getParameterTypes();
+
+        genArgs(tree.args, params);
+        if (!isDynamic(msym)) {
             code.statBegin(tree.pos);
         }
         result = m.invoke();
     }
+    //where
+        boolean isDynamic(Symbol s) {
+            if (s instanceof DelegatedSymbol<?>) {
+                return isDynamic(((DelegatedSymbol)s).getUnderlyingSymbol());
+            } else if (s instanceof MethodSymbol) {
+                return ((MethodSymbol)s).isDynamic();
+            } else {
+                return false;
+            }
+        }
 
     public void visitConditional(JCConditional tree) {
         Chain thenExit = null;
@@ -1934,7 +1984,7 @@
             int startpc = genCrt ? code.curCP() : 0;
             code.statBegin(tree.truepart.pos);
             genExpr(tree.truepart, pt).load();
-            code.state.forceStackTop(tree.type);
+            code.state.forceStackTop(TreeInfo.unerasedTypeOrType(tree));
             if (genCrt) code.crt.put(tree.truepart, CRT_FLOW_TARGET,
                                      startpc, code.curCP());
             thenExit = code.branch(goto_);
@@ -1944,7 +1994,7 @@
             int startpc = genCrt ? code.curCP() : 0;
             code.statBegin(tree.falsepart.pos);
             genExpr(tree.falsepart, pt).load();
-            code.state.forceStackTop(tree.type);
+            code.state.forceStackTop(TreeInfo.unerasedTypeOrType(tree));
             if (genCrt) code.crt.put(tree.falsepart, CRT_FLOW_TARGET,
                                      startpc, code.curCP());
         }
@@ -1997,9 +2047,7 @@
         Assert.check(tree.encl == null && tree.def == null);
         setTypeAnnotationPositions(tree.pos);
 
-        Type newType = validUnerasedType(tree.unerasedType) ?
-                tree.unerasedType :
-                tree.type;
+        Type newType = TreeInfo.unerasedTypeOrType(tree);
 
         if (newType.isValue()) {
             // For values, the creation sequence is simpler: push all arguments, then emit vnew.
@@ -2008,15 +2056,16 @@
             genArgs(tree.args, parameterTypes);
             code.emitVnew(newType, makeRef(tree.pos(), tree.type, parameterTypes), Code.width(parameterTypes));
         } else {
-            emitAndMarkIfNeeded2(tree, newType, tree.type, new_);
+            emitAndMarkIfNeeded2(tree, newType, new_);
             code.emitop0(dup);
 
             // Generate code for all arguments, where the expected types are
             // the parameters of the constructor's external type (that is,
             // any implicit outer instance appears as first parameter).
-            genArgs(tree.args, tree.constructor.externalType(types).getParameterTypes());
+            Symbol s = Descriptor.of(tree.constructor, newType, types);
 
-            items.makeMethodItem(items.makeStackItem(newType), tree.constructor, true).invoke();
+            genArgs(tree.args, s.externalType(types).getParameterTypes());
+            items.makeMethodItem(items.makeStackItem(newType), s, true).invoke();
         }
         result = items.makeStackItem(newType);
     }
@@ -2051,8 +2100,7 @@
         Item makeNewArray(JCNewArray tree, int ndims) {
             Type erasedType = tree.type;
 
-            Type sigType = validUnerasedType(tree.unerasedType) ?
-                    tree.unerasedType : erasedType;
+            Type sigType = TreeInfo.unerasedTypeOrType(tree);
 
             Type erasedElementType = types.elemtype(erasedType);
             if (types.dimensions(sigType) > ClassFile.MAX_DIMENSIONS) {
@@ -2061,9 +2109,9 @@
             }
             int elemcode = Code.arraycode(erasedElementType);
             if (erasedElementType.isValue()) {
-                code.emitVnewarray(makeRef(tree, erasedElementType), erasedType);
+                code.emitVnewarray(makeRef(tree, erasedType), erasedType);
             } else if (elemcode == 0 || (elemcode == 1 && ndims == 1)) {
-                emitAndMarkIfNeeded2(tree, sigType, erasedElementType, (ref) -> code.emitAnewarray(ref, erasedType));
+                emitAndMarkIfNeeded2(tree, sigType, (ref) -> code.emitAnewarray(ref, erasedType), t -> types.elemtype(t));
             } else if (elemcode == 1) {
                 // if the ultimate elements are values, use multivnewarray
                 Type u = erasedElementType;
@@ -2071,9 +2119,9 @@
                     u = types.elemtype(u);
                 }
                 if (u.isValue()) {
-                    emitAndMarkIfNeeded2(tree, sigType, erasedType, (ref) -> code.emitMultivnewarray(ndims, ref, erasedType));
+                    emitAndMarkIfNeeded2(tree, sigType, (ref) -> code.emitMultivnewarray(ndims, ref, erasedType), null);
                 } else {
-                    emitAndMarkIfNeeded2(tree, sigType, erasedType, (ref) -> code.emitMultianewarray(ndims, ref, erasedType));
+                    emitAndMarkIfNeeded2(tree, sigType, (ref) -> code.emitMultianewarray(ndims, ref, erasedType), null);
                 }
             } else {
                 code.emitNewarray(elemcode, erasedType);
@@ -2086,14 +2134,14 @@
     }
 
     public void visitAssign(JCAssign tree) {
-        Item l = genExpr(tree.lhs, tree.lhs.type);
-        genExpr(tree.rhs, tree.lhs.type).load();
+        Item l = genExpr(tree.lhs, TreeInfo.unerasedTypeOrType(tree.lhs));
+        genExpr(tree.rhs, TreeInfo.unerasedTypeOrType(tree.lhs)).load();
         if (tree.rhs.type.hasTag(BOT)) {
             /* This is just a case of widening reference conversion that per 5.1.5 simply calls
                for "regarding a reference as having some other type in a manner that can be proved
                correct at compile time."
             */
-            code.state.forceStackTop(tree.lhs.type);
+            code.state.forceStackTop(TreeInfo.unerasedTypeOrType(tree.lhs));
         }
         result = items.makeAssignItem(l);
     }
@@ -2382,18 +2430,18 @@
 
     public void visitTypeCast(JCTypeCast tree) {
         setTypeAnnotationPositions(tree.pos);
-        Type unerasedType = tree.unerasedType;
+        Type unerasedType = TreeInfo.unerasedTypeOrType(tree.clazz);
         result = wrapIfNeeded(genExpr(tree.expr, tree.clazz.type).load(), unerasedType);
         // Additional code is only needed if we cast to a reference type
         // which is not statically a supertype of the expression's type.
         // For basic types, the coerce(...) in genExpr(...) will do
         // the conversion.
-        if ((tree.unerasedType != null && types.needsMangling(tree.unerasedType)) || //do not skip cast to types containing avars
+        if (types.needsMangling(unerasedType) || //do not skip cast to types containing avars
                 (tree.clazz.type.hasTag(CLASS) && types.isAnyfied(tree.clazz.type.tsym)) || //do not skip cast to raw anyfied
                 (!tree.clazz.type.isPrimitive() &&
                 !types.isSameType(tree.expr.type, tree.clazz.type) &&
                 types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null)) {
-            emitAndMarkIfNeeded2(tree, unerasedType, tree.clazz.type, checkcast);
+            emitAndMarkIfNeeded2(tree, unerasedType, checkcast);
         }
     }
 
@@ -2404,8 +2452,8 @@
     public void visitTypeTest(JCInstanceOf tree) {
         setTypeAnnotationPositions(tree.pos);
         genExpr(tree.expr, tree.expr.type).load();
-        Type unerasedType = tree.unerasedType;
-        emitAndMarkIfNeeded2(tree, unerasedType, tree.clazz.type, instanceof_);
+        Type unerasedType = TreeInfo.unerasedTypeOrType(tree.clazz);
+        emitAndMarkIfNeeded2(tree, unerasedType, instanceof_);
         result = items.makeStackItem(syms.booleanType);
     }
 
@@ -2432,6 +2480,7 @@
             }
             if (sym.kind == MTH) {
                 // Generate code to address the constructor.
+                sym = Descriptor.of(sym, res.originalType(), types);
                 res = items.makeMethodItem(res.load(), sym, true);
             }
             result = res;
@@ -2441,13 +2490,13 @@
             result = items.makeDynamicItem(sym);
         } else if ((sym.flags() & STATIC) != 0) {
             if (!isAccessSuper(env.enclMethod))
-                sym = binaryQualifier(sym, env.enclClass.type);
+                sym = Descriptor.of(sym, env.enclClass.type, types);
             result = sym.kind == MTH ?
                     items.makeStaticMethodItem(sym) :
                     items.makeStaticFieldItem(sym);
         } else {
             Item rcv = items.makeThisItem(env.enclClass.sym.type).load();
-            sym = binaryQualifier(sym, env.enclClass.type);
+            sym = Descriptor.of(sym, env.enclClass.type, types);
             result = sym.kind == MTH ?
                     items.makeMethodItem(rcv, sym, (sym.flags() & PRIVATE) != 0) :
                     items.makeFieldItem(rcv, sym);
@@ -2458,7 +2507,7 @@
         Symbol sym = tree.sym;
 
         if (tree.name == names._class) {
-            emitAndMarkIfNeeded2(tree, tree.selected.unerasedType, tree.selected.type, code::emitLdc);
+            emitAndMarkIfNeeded2(tree, TreeInfo.unerasedTypeOrType(tree.selected), code::emitLdc, null);
             result = items.makeStackItem(pt);
             return;
        }
@@ -2500,7 +2549,7 @@
                 result = items.makeDynamicItem(sym);
                 return;
             } else {
-                sym = binaryQualifier(sym, tree.selected.type);
+                sym = Descriptor.of(sym, TreeInfo.unerasedTypeOrType(tree.selected), types);
             }
             if ((sym.flags() & STATIC) != 0) {
                 if (!selectSuper && (ssym == null || ssym.kind != TYP))
@@ -2511,7 +2560,7 @@
                         items.makeStaticFieldItem(sym);
             } else {
                 Item rcv = base.load();
-                if (sym == syms.lengthVar) {
+                if (sym.baseSymbol() == syms.lengthVar) {
                     code.emitop0(arraylength);
                     result = items.makeStackItem(syms.intType);
                 } else {
@@ -2548,7 +2597,7 @@
         code.endScopes(limit);
     }
 
-    private void generateReferencesToPrunedTree(ClassSymbol classSymbol, Pool pool) {
+    private void generateReferencesToPrunedTree(ClassSymbol classSymbol) {
         List<JCTree> prunedInfo = lower.prunedTree.get(classSymbol);
         if (prunedInfo != null) {
             for (JCTree prunedTree: prunedInfo) {
@@ -2574,12 +2623,11 @@
             ClassSymbol c = cdef.sym;
             this.toplevel = env.toplevel;
             this.endPosTable = toplevel.endPositions;
-            c.pool = pool;
-            pool.reset();
+            pool = c.poolWriter = new PoolWriter(types, poolModes);
             /* method normalizeDefs() can add references to external classes into the constant pool
              */
             cdef.defs = normalizeDefs(cdef.defs, c);
-            generateReferencesToPrunedTree(c, pool);
+            generateReferencesToPrunedTree(c);
             Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
             localEnv.toplevel = env.toplevel;
             localEnv.enclClass = cdef;
@@ -2587,7 +2635,7 @@
             for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
                 genDef(l.head, localEnv);
             }
-            if (pool.numEntries() > Pool.MAX_ENTRIES) {
+            if (pool.pool.size() > Pool.MAX_ENTRIES) {
                 log.error(cdef.pos(), "limit.pool");
                 nerrs++;
             }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Tue Dec 08 14:42:24 2015 +0000
@@ -26,16 +26,13 @@
 package com.sun.tools.javac.jvm;
 
 import com.sun.tools.javac.code.*;
-import com.sun.tools.javac.code.Kinds.Kind;
 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.DescriptorAugmentor;
 import com.sun.tools.javac.jvm.Code.*;
-import com.sun.tools.javac.jvm.Gen.BinarySymbol;
+import com.sun.tools.javac.jvm.Gen.Descriptor;
 import com.sun.tools.javac.jvm.Gen.PoolMode;
-import com.sun.tools.javac.jvm.Pool.Signature;
-import com.sun.tools.javac.jvm.Pool.SignatureMember;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.util.Assert;
 import com.sun.tools.javac.util.ListBuffer;
@@ -71,7 +68,7 @@
 
     /** The current constant pool.
      */
-    Pool pool;
+    PoolWriter pool;
 
     /** The current code buffer.
      */
@@ -95,7 +92,7 @@
     private final Item voidItem;
     private final Item[] stackItem = new Item[TypeCodeCount];
 
-    public Items(Pool pool, Code code, Symtab syms, Types types, Names names, EnumSet<PoolMode> poolModes) {
+    public Items(PoolWriter pool, Code code, Symtab syms, Types types, Names names, EnumSet<PoolMode> poolModes) {
         this.code = code;
         this.pool = pool;
         this.types = types;
@@ -298,12 +295,13 @@
      */
     private Item wrapMemberIfNeeded(Item rcvItem, MemberItem memberItem, Function<Type, Type> typeFunc) {
         Symbol member = memberItem.member;
-        if (member instanceof BinarySymbol) {
-            member = member.baseSymbol();
-        }
         Item result = memberItem;
         if (rcvItem.isAny()) {
             Type rcvType = rcvItem.originalType();
+            if (member instanceof Descriptor && !types.isSpecializableTypeVar(rcvType)) {
+                //cloned/specialized types must be rolled back - but not Object members!
+                member = member.baseSymbol();
+            }
             if (rcvType.hasTag(TypeTag.ARRAY)) {
                 //member access on arrays never requires specialization!
                 return memberItem;
@@ -431,6 +429,10 @@
             throw new AssertionError("originalType unsupported: " + this);
         }
 
+        Symbol member() {
+            throw new AssertionError("member unsupported: " + this);
+        }
+
         public abstract String toString();
     }
 
@@ -583,6 +585,11 @@
         }
 
         @Override
+        Symbol member() {
+            return delegatedItem.member();
+        }
+
+        @Override
         public String toString() {
             return "Any[" + delegatedItem.toString() + ", " + originalType + "]";
         }
@@ -612,10 +619,10 @@
                     if (types.isSpecializableTypeVar(originalType)) {
                         if (poolModes.contains(PoolMode.TYPE1)) {
                             //typed
-                            code.emitop2(typed, pool.put(Signature.of(originalType, types)));
+                            code.emitop2(typed, pool.putType(originalType));
                         } else {
                             //emit legacy bytecode mapping
-                            code.markAny(pc, types.specializerSig(originalType));
+                            code.markAny(pc, types.bytecodeMappingSig(originalType));
                         }
                     }
                     break;
@@ -699,22 +706,10 @@
 
         AnyMemberItem(SymbolicItem delegatedItem, Type originalType, Type ownerType, Type memberType) {
             super(delegatedItem, originalType);
-            if (poolModes.contains(PoolMode.TYPE3)) {
-                delegatedItem.poolRef = this::typedPoolRef;
-            }
             this.ownerType = ownerType;
             this.memberType = memberType;
         }
 
-        int typedPoolRef() {
-            Symbol member = ((SymbolicItem)delegatedItem).member;
-            if (poolModes.contains(PoolMode.TYPE3) && types.needsMangling(ownerType)) {
-                return pool.put(new SignatureMember(member, ownerType, memberType, types));
-            } else {
-                return pool.put(member);
-            }
-        }
-
         @Override
         protected void decorateOpcode(int opcode, int pc) {
             OpcodeKind kind = OpcodeKind.of(opcode);
@@ -723,8 +718,8 @@
                     if (!poolModes.contains(PoolMode.TYPE3)) {
                         if (types.needsMangling(ownerType)) {
                             code.markAny(pc, names.fromString(String.join("::",
-                                    types.specializerSig(ownerType),
-                                    types.specializerSig(memberType.map(new BmaDescriptorAdapter(), ((SymbolicItem)delegatedItem).member.type)))));
+                                    types.bytecodeMappingSig(ownerType),
+                                    types.bytecodeMappingSig(memberType.map(new BmaDescriptorAdapter(), ((SymbolicItem)delegatedItem).member.type)))));
                         }
                     }
                     break;
@@ -786,17 +781,17 @@
                         final String argSig;
                         switch (staticArg.kind) {
                             case METHOD_TYPE:
-                                argSig = types.specializerSig(staticArg.asType().get().baseType()).toString();
+                                argSig = types.bytecodeMappingSig(staticArg.asType().get().baseType()).toString();
                                 break;
                             case CLASS:
-                                argSig = types.specializerSig(staticArg.asType().get()).toString();
+                                argSig = types.bytecodeMappingSig(staticArg.asType().get()).toString();
                                 break;
                             case METHOD_HANDLE:
                                 Symbol refSym = staticArg.asSymbol().get();
                                 //Todo: this code doesn't throw away the ForAll
                                 argSig = names.fromString(String.join("::",
-                                        types.specializerSig(refSym.owner.type),
-                                        types.specializerSig(refSym.type))).toString();
+                                        types.bytecodeMappingSig(refSym.owner.type),
+                                        types.bytecodeMappingSig(refSym.type))).toString();
                                 break;
                             case STRING:
                                 argSig = (String)staticArg.data;
@@ -808,7 +803,7 @@
                         buf.add(String.format("%d=%s", i, argSig));
                     }
                 }
-                Name dynDesc = types.specializerSig(indyType);
+                Name dynDesc = types.bytecodeMappingSig(indyType);
                 code.markAny(pc, buf.isEmpty() ?
                         dynDesc :
                         dynDesc.append(names.fromString(buf.stream().collect(Collectors.joining("&", "::{", "}")))));
@@ -896,42 +891,6 @@
         }
     }
 
-    class NewItem extends Item {
-
-        int cpIndex;
-        Type type;
-        int argsize; // vnew only
-
-        NewItem(Type type, int cpIndex) {
-            super(OBJECTcode);
-            this.cpIndex = cpIndex;
-            this.type = type;
-            this.argsize = 0;
-        }
-
-        NewItem(Type type, int cpIndex, int argsize) {
-            super(OBJECTcode);
-            this.cpIndex = cpIndex;
-            this.type = type;
-            this.argsize = argsize;
-        }
-
-        @Override
-        void store() {
-            if (type.isValue()) {
-                code.emitVnew(type, cpIndex, argsize);
-                // dup is not needed for values
-            } else {
-                code.emitop2(new_, cpIndex);
-                code.emitop0(dup);
-            }
-        }
-
-        public String toString() {
-            return (type.isValue() ? "makeValue(" : "newClass(") + pool.pool[cpIndex] + ")";
-        }
-    }
-
     /** An item representing `this' or `super'.
      */
     class SelfItem extends Item {
@@ -955,6 +914,11 @@
             return stackItem[typecode];
         }
 
+        @Override
+        Type originalType() {
+            return type;
+        }
+
         public String toString() {
             return isSuper ? "super" : "this";
         }
@@ -1046,12 +1010,12 @@
         }
 
         Item load() {
-            code.emitop2(getstatic, poolRef.get());
+            code.emitop2(getstatic, pool.putSymbol(member));
             return stackItem[typecode];
         }
 
         void store() {
-            code.emitop2(putstatic, poolRef.get());
+            code.emitop2(putstatic, pool.putSymbol(member));
         }
     }
 
@@ -1064,7 +1028,7 @@
         Item invoke() {
             MethodType mtype = (MethodType)member.erasure(types);
             int rescode = Code.typecode(mtype.restype);
-            code.emitInvokestatic(poolRef.get(), mtype);
+            code.emitInvokestatic(pool.putSymbol(member), mtype);
             return stackItem[rescode];
         }
     }
@@ -1087,12 +1051,17 @@
 
         Item invoke() {
             // assert target.hasNativeInvokeDynamic();
-            MethodType mtype = (MethodType)member.erasure(types);
+            MethodType mtype = member.type.asMethodType();
             int rescode = Code.typecode(mtype.restype);
-            code.emitInvokedynamic(pool.put(member), mtype);
+            code.emitInvokedynamic(pool.putSymbol(member), mtype);
             return stackItem[rescode];
         }
 
+        @Override
+        Symbol member() {
+            return member;
+        }
+
         public String toString() {
             return "dynamic(" + member + ")";
         }
@@ -1105,12 +1074,16 @@
         /** The represented symbol.
          */
         Symbol member;
-        Supplier<Integer> poolRef = () -> pool.put(member);
 
         SymbolicItem(Symbol member) {
             super(Code.typecode(member.erasure(types)));
             this.member = member;
         }
+
+        @Override
+        Symbol member() {
+            return member;
+        }
     }
 
     /** An item representing an instance variable or method.
@@ -1149,12 +1122,12 @@
         }
 
         Item load() {
-            code.emitop2(member.enclClass().type.isValue() ? vgetfield : getfield, poolRef.get());
+            code.emitop2(member.enclClass().type.isValue() ? vgetfield : getfield, pool.putSymbol(member));
             return stackItem[typecode];
         }
 
         void store() {
-            code.emitop2(putfield, poolRef.get());
+            code.emitop2(putfield, pool.putSymbol(member));
         }
     }
 
@@ -1169,15 +1142,23 @@
             this.nonvirtual = nonvirtual;
         }
 
+        boolean isInvokeInterface() {
+            if (member instanceof Descriptor) {
+                return ((Descriptor)member).site.isInterface();
+            } else {
+                return member.owner.isInterface();
+            }
+        }
+
         Item invoke() {
             MethodType mtype = (MethodType)member.externalType(types);
             int rescode = Code.typecode(mtype.restype);
-            if ((member.owner.flags() & Flags.INTERFACE) != 0 && !nonvirtual) {
-                code.emitInvokeinterface(poolRef.get(), mtype);
+            if (isInvokeInterface() && !nonvirtual) {
+                code.emitInvokeinterface(pool.putSymbol(member), mtype);
             } else if (nonvirtual) {
-                code.emitInvokespecial(poolRef.get(), mtype);
+                code.emitInvokespecial(pool.putSymbol(member), mtype);
             } else {
-                code.emitInvokevirtual(poolRef.get(), mtype);
+                code.emitInvokevirtual(pool.putSymbol(member), mtype);
             }
             return stackItem[rescode];
         }
@@ -1201,7 +1182,7 @@
         }
 
         private void ldc() {
-            int idx = pool.put(value);
+            int idx = pool.putConstant(value);
             if (typecode == LONGcode || typecode == DOUBLEcode) {
                 code.emitop2(ldc2w, idx);
             } else {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java	Tue Dec 08 14:42:24 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Oracle and/or its affiliates. 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
@@ -26,729 +26,483 @@
 package com.sun.tools.javac.jvm;
 
 import com.sun.tools.javac.code.Symbol;
-import com.sun.tools.javac.code.Symbol.*;
-import com.sun.tools.javac.code.Type.CapturedType;
+import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
+import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.code.Type.ClassType;
 import com.sun.tools.javac.code.Type.TypeVar;
-import com.sun.tools.javac.code.Type.WildcardType;
-import com.sun.tools.javac.code.TypeTag;
-import com.sun.tools.javac.code.Type;
-import com.sun.tools.javac.code.Types;
-import com.sun.tools.javac.code.Types.UniqueType;
-
-import com.sun.tools.javac.jvm.Gen.BinarySymbol;
-import com.sun.tools.javac.jvm.Gen.PoolMode;
-import com.sun.tools.javac.util.ArrayUtils;
-import com.sun.tools.javac.util.Assert;
-import com.sun.tools.javac.util.ByteBuffer;
-import com.sun.tools.javac.util.Filter;
-import com.sun.tools.javac.util.List;
-import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.jvm.Pool.Entry;
 import com.sun.tools.javac.util.Name;
 
 import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.Objects;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
+import java.util.Optional;
 
-import com.sun.tools.javac.util.DefinedBy;
-import com.sun.tools.javac.util.DefinedBy.Api;
-import com.sun.tools.javac.util.Names;
-
-import static com.sun.tools.javac.code.Flags.SPECIALIZED_CLASS;
-import static com.sun.tools.javac.code.Kinds.*;
-import static com.sun.tools.javac.code.Kinds.Kind.*;
-
-/** An internal structure that corresponds to the constant pool of a classfile.
+/**
+ * An internal structure that corresponds to the constant pool of a classfile. Various type of entries
+ * are defined to match JVMS 4.4.
  *
  *  <p><b>This is NOT part of any supported API.
  *  If you write code that depends on this, you do so at your own risk.
  *  This code and its internal interfaces are subject to change or
  *  deletion without notice.</b>
  */
-public class Pool {
+public class Pool implements Iterable<Entry> {
 
+    /** Max number of constant pool entries. */
     public static final int MAX_ENTRIES = 0xFFFF;
+
+    /** Max number of char in a string constant. */
     public static final int MAX_STRING_LENGTH = 0xFFFF;
 
-    /** Index of next constant to be entered.
+    /** Pool entries. */
+    private LinkedHashMap<Entry, Entry> entries = new LinkedHashMap<>();
+
+    /** Reverse map associating entries to indices. */
+    private LinkedHashMap<Integer, Entry> entryByPos = new LinkedHashMap<>();
+
+    /** Index available for next entry to be stored. */
+    private int currIndex = 1;
+
+    /**
+     * Put a new pool entry, or rerieve an existing one if a match is found.
      */
-    int pp;
-
-    /** The initial pool buffer.
-     */
-    Object[] pool;
-
-    /** A hashtable containing all constants in the pool.
-     */
-    Map<Object,Integer> indices;
-
-    Types types;
-    Names names;
-    boolean expandSpecializedSymbols;
-
-    /** Construct a pool with given number of elements and element array.
-     */
-    public Pool(int pp, Object[] pool, Types types, Names names, boolean expandSpecializedSymbols) {
-        this.pp = pp;
-        this.pool = pool;
-        this.types = types;
-        this.names = names;
-        this.indices = new HashMap<>(pool.length);
-        for (int i = 1; i < pp; i++) {
-            if (pool[i] != null) indices.put(pool[i], i);
-        }
-        this.expandSpecializedSymbols = expandSpecializedSymbols;
-    }
-
-    /** Construct an empty pool.
-     */
-    public Pool(Types types, Names names, boolean expandSpecializedSymbols) {
-        this(1, new Object[64], types, names, expandSpecializedSymbols);
-    }
-
-    /** Return the number of entries in the constant pool.
-     */
-    public int numEntries() {
-        return pp;
-    }
-
-    /** Remove everything from this pool.
-     */
-    public void reset() {
-        pp = 1;
-        indices.clear();
-    }
-
-    /** Place an object in the pool, unless it is already there.
-     *  If object is a symbol also enter its owner unless the owner is a
-     *  package.  Return the object's index in the pool.
-     */
-    public int put(Object value) {
-        if (value instanceof TypeSymbol) {
-            TypeSymbol v = (TypeSymbol)value;
-            Assert.check(v.kind != NIL);
-        }
-        value = makePoolValue(value);
-        Assert.check(!(value instanceof Type.TypeVar));
-        Assert.check(!(value instanceof Types.UniqueType &&
-                        !(value instanceof SignatureClass || value instanceof Signature) &&
-                       ((UniqueType) value).type instanceof Type.TypeVar));
-        Integer index = indices.get(value);
-        if (index == null) {
-            index = pp;
-            indices.put(value, index);
-            pool = ArrayUtils.ensureCapacity(pool, pp);
-            pool[pp++] = value;
-            if (value instanceof Long || value instanceof Double) {
-                pool = ArrayUtils.ensureCapacity(pool, pp);
-                pool[pp++] = null;
-            }
-        }
-        return index.intValue();
-    }
-
-    Object makePoolValue(Object o) {
-        if (o instanceof DynamicMethodSymbol) {
-            return new DynamicMethod((DynamicMethodSymbol)o, types);
-        } else if (o instanceof MethodSymbol) {
-            return new Method((MethodSymbol)((Symbol)o).specialized(), types);
-        } else if (o instanceof VarSymbol) {
-            return new Variable((VarSymbol)((Symbol)o).specialized(), types);
-        } else if (o instanceof BinarySymbol) {
-            //unwind binary symbols
-            return makePoolValue(((BinarySymbol)o).getUnderlyingSymbol());
-        } else if (expandSpecializedSymbols && (o instanceof ClassSymbol)) {
-            ClassSymbol csym = (ClassSymbol)o;
-            if ((csym.flags() & SPECIALIZED_CLASS) != 0) {
-                return new SignatureClass(csym.type.baseType(), types);
-            }
-            return csym;
-        } else if (o instanceof Type) {
-            Type t = (Type)o;
-            // ClassRefs can come from ClassSymbols or from Types.
-            // Return the symbol for these types to avoid duplicates
-            // in the constant pool
-            if (t.hasTag(TypeTag.CLASS))
-                return makePoolValue(t.tsym);
-            else
-                return new UniqueType(t, types);
+    Entry put(Entry e) {
+        Entry prev = entries.get(e);
+        if (prev != null) {
+            return prev;
         } else {
-            return o;
+            e.index = currIndex;
+            entryByPos.put(e.index, e);
+            entries.put(e, e);
+            currIndex += e.size();
+            return e;
         }
     }
 
-    /** Return the given object's index in the pool,
-     *  or -1 if object is not in there.
+    /**
+     * Rerieve an entry given an index.
      */
-    public int get(Object o) {
-        Integer n = indices.get(o);
-        return n == null ? -1 : n.intValue();
+    Entry get(int pos) {
+        return entryByPos.get(pos);
     }
 
-    static class Method extends DelegatedSymbol<MethodSymbol> {
-        UniqueType uniqueType;
-        Method(MethodSymbol m, Types types) {
-            super((MethodSymbol)m.specialized());
-            this.uniqueType = new UniqueType(m.specialized().type, types);
+    /**
+     * Pool size.
+     */
+    int size() {
+        return 1 + entries.keySet().stream()
+                .mapToInt(Entry::size)
+                .sum();
+    }
+
+    @Override
+    public Iterator<Entry> iterator() {
+        return entries.keySet().iterator();
+    }
+
+    /**
+     * This is the root class of all constant pool entries. Each entry must define a size
+     * (default is 1) an index and a tag (see JVMS 4.4). Entries might optionally define
+     * custom data that is associated with them (e.g. a {@code CONSTANT_MethodRef_info} entry might
+     * be associated with a {@code MethodSymbol}).
+     */
+    static abstract class Entry {
+
+        /** The entry tag. */
+        int tag;
+
+        /** The entry index. */
+        int index;
+
+        /** Compiler data associated with this entry (optional). */
+        Optional<Object> data;
+
+        /**
+         * The entry size.
+         */
+        int size() {
+            return 1;
         }
-        @DefinedBy(Api.LANGUAGE_MODEL)
-        public boolean equals(Object any) {
-            if (!(any instanceof Method)) return false;
-            MethodSymbol o = ((Method)any).other;
-            MethodSymbol m = this.other;
-            return
-                o.name == m.name &&
-                o.owner == m.owner &&
-                ((Method)any).uniqueType.equals(uniqueType);
+
+        Entry(int tag) {
+            this(tag, null);
         }
-        @DefinedBy(Api.LANGUAGE_MODEL)
-        public int hashCode() {
-            MethodSymbol m = this.other;
-            return
-                m.name.hashCode() * 33 +
-                m.owner.hashCode() * 9 +
-                uniqueType.hashCode();
+
+        Entry(int tag, Object data) {
+            this.tag = tag;
+            this.data = Optional.ofNullable(data);
         }
     }
 
-    static class DynamicMethod extends Method {
-        public Object[] uniqueStaticArgs;
+    /**
+     * Pool entry associated with {@code CONSTANT_NameAndType_info} entries.
+     */
+    static class NameAndType extends Entry {
 
-        DynamicMethod(DynamicMethodSymbol m, Types types) {
-            super(m, types);
-            uniqueStaticArgs = getUniqueTypeArray(Stream.of(m.staticArgs).<Object>map(a -> a.data).toArray(), types);
+        /** The entry name. */
+        Constant<Name> name;
+
+        /** The entry type. */
+        Entry type;
+
+        NameAndType(Constant<Name> name, Entry type) {
+            super(ClassFile.CONSTANT_NameandType);
+            this.name = name;
+            this.type = type;
         }
 
-        @Override @DefinedBy(Api.LANGUAGE_MODEL)
-        public boolean equals(Object any) {
-            return equalsImpl(any, true);
+        @Override
+        public int hashCode() {
+            return Objects.hash(name, type);
         }
 
-        protected boolean equalsImpl(Object any, boolean includeDynamicArgs) {
-            if (includeDynamicArgs && !super.equals(any)) return false;
-            if (!(any instanceof DynamicMethod)) return false;
-            DynamicMethodSymbol dm1 = (DynamicMethodSymbol)other;
-            DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)any).other;
-            return dm1.bsm == dm2.bsm &&
-                        dm1.bsmKind == dm2.bsmKind &&
-                        Arrays.equals(uniqueStaticArgs,
-                            ((DynamicMethod)any).uniqueStaticArgs);
-        }
-
-        @Override @DefinedBy(Api.LANGUAGE_MODEL)
-        public int hashCode() {
-            return hashCodeImpl(true);
-        }
-
-        protected int hashCodeImpl(boolean includeDynamicArgs) {
-            int hash = includeDynamicArgs ? super.hashCode() : 0;
-            DynamicMethodSymbol dm = (DynamicMethodSymbol)other;
-            hash += dm.bsmKind * 7 +
-                    dm.bsm.hashCode() * 11;
-            for (int i = 0; i < dm.staticArgs.length; i++) {
-                hash += (uniqueStaticArgs[i].hashCode() * 23);
-            }
-            return hash;
-        }
-
-        private Object[] getUniqueTypeArray(Object[] objects, Types types) {
-            Object[] result = new Object[objects.length];
-            for (int i = 0; i < objects.length; i++) {
-                if (objects[i] instanceof Type) {
-                    result[i] = new UniqueType((Type)objects[i], types);
-                } else {
-                    result[i] = objects[i];
-                }
-            }
-            return result;
-        }
-
-        static class BootstrapMethodsKey extends DynamicMethod {
-            BootstrapMethodsKey(DynamicMethodSymbol m, Types types) {
-                super(m, types);
-            }
-
-            @Override @DefinedBy(Api.LANGUAGE_MODEL)
-            public boolean equals(Object any) {
-                return equalsImpl(any, false);
-            }
-
-            @Override @DefinedBy(Api.LANGUAGE_MODEL)
-            public int hashCode() {
-                return hashCodeImpl(false);
-            }
-
-            Object[] getUniqueArgs() {
-                return uniqueStaticArgs;
-            }
-        }
-
-        static class BootstrapMethodsValue {
-            final MethodHandle mh;
-            final int index;
-
-            public BootstrapMethodsValue(MethodHandle mh, int index) {
-                this.mh = mh;
-                this.index = index;
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof NameAndType) {
+                NameAndType that = (NameAndType)obj;
+                return that.name.equals(name) && that.type.equals(type);
+            } else {
+                return false;
             }
         }
     }
 
-    static class Variable extends DelegatedSymbol<VarSymbol> {
-        UniqueType uniqueType;
-        Variable(VarSymbol v, Types types) {
-            super((VarSymbol)v.specialized());
-            this.uniqueType = new UniqueType(v.specialized().type, types);
-        }
-        @DefinedBy(Api.LANGUAGE_MODEL)
-        public boolean equals(Object any) {
-            if (!(any instanceof Variable)) return false;
-            VarSymbol o = ((Variable)any).other;
-            VarSymbol v = other;
-            return
-                o.name == v.name &&
-                o.owner == v.owner &&
-                ((Variable)any).uniqueType.equals(uniqueType);
-        }
-        @DefinedBy(Api.LANGUAGE_MODEL)
-        public int hashCode() {
-            VarSymbol v = other;
-            return
-                v.name.hashCode() * 33 +
-                v.owner.hashCode() * 9 +
-                uniqueType.hashCode();
-        }
-    }
+    /**
+     * Pool entry associated with member reference entries ({@code CONSTANT_FieldRef_info},
+     * {@code CONSTANT_MethodRef_info} and {@code CONSTANT_InterfaceMethodRef_info}).
+     */
+    static class MemberRef extends Entry {
 
-    static class SignatureClass extends UniqueType {
+        /** The symbolic entry owner */
+        ClassRef owner;
 
-        public SignatureClass(Type t, Types types) {
-            super(t, types);
-        }
+        /** The symbolic entry name and type */
+        NameAndType nt;
 
-        public boolean equals(Object any) {
-            if (!any.getClass().equals(SignatureClass.class)) return false;
-            return super.equals(any);
+        MemberRef(int tag, ClassRef owner, NameAndType nt, Symbol data) {
+            super(tag, data);
+            this.owner = owner;
+            this.nt = nt;
         }
 
         @Override
         public int hashCode() {
-            return super.hashCode();
+            return Objects.hash(tag, owner, nt);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof MemberRef) {
+                MemberRef that = (MemberRef)obj;
+                return that.tag == tag && that.owner.equals(owner) && that.nt.equals(nt);
+            } else {
+                return false;
+            }
         }
     }
 
     /**
-     * A method/field reference constant backed by a generic signature.
+     * Pool entry associated with classes.
      */
-    static class SignatureMember {
+    static class ClassRef extends Entry {
 
-        Symbol sym;
-        UniqueType ownerType;
-        UniqueType fieldType;
+        /** Class name */
+        Entry clazz;
 
-        public SignatureMember(Symbol sym, Type ownerType, Type fieldType, Types types) {
-            this.sym = sym;
-            this.ownerType = new UniqueType(ownerType, types);
-            this.fieldType = new UniqueType(fieldType, types);
-        }
-
-        public boolean equals(Object any) {
-            if (!(any instanceof SignatureMember)) {
-                return false;
-            } else {
-                SignatureMember that = (SignatureMember)any;
-                return sym == that.sym &&
-                        ownerType.equals(that.ownerType) &&
-                        fieldType.equals(that.fieldType);
-            }
+        ClassRef(Entry clazz, Object data) {
+            super(ClassFile.CONSTANT_Class, data);
+            this.clazz = clazz;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(sym, ownerType, fieldType);
-        }
-
-        int getKind() {
-            if (sym.kind == VAR) {
-                return ClassFile.CONSTANT_Fieldref;
-            } else if (sym.owner.isInterface()) {
-                return ClassFile.CONSTANT_InterfaceMethodref;
-            } else {
-                return ClassFile.CONSTANT_Methodref;
-            }
-        }
-
-        public void writePool(ByteBuffer buf, Pool pool) {
-            buf.appendByte(getKind());
-            buf.appendChar(pool.put(new SignatureClass(ownerType.type, pool.types)));
-            buf.appendChar(pool.put(new SignatureNameAndType(sym.name, fieldType.type, pool.types)));
-        }
-    }
-
-    public static class MethodHandle {
-
-        /** Reference kind - see ClassFile */
-        public int refKind;
-
-        /** Reference symbol */
-        public Symbol refSym;
-
-        UniqueType uniqueType;
-
-        public MethodHandle(int refKind, Symbol refSym, Types types) {
-            this.refKind = refKind;
-            this.refSym = refSym;
-            this.uniqueType = new UniqueType(this.refSym.type, types);
-            checkConsistent();
-        }
-        public boolean equals(Object other) {
-            if (!(other instanceof MethodHandle)) return false;
-            MethodHandle mr = (MethodHandle) other;
-            if (mr.refKind != refKind)  return false;
-            Symbol o = mr.refSym;
-            return
-                o.name == refSym.name &&
-                o.owner == refSym.owner &&
-                ((MethodHandle)other).uniqueType.equals(uniqueType);
-        }
-        public int hashCode() {
-            return
-                refKind * 65 +
-                refSym.name.hashCode() * 33 +
-                refSym.owner.hashCode() * 9 +
-                uniqueType.hashCode();
-        }
-
-        /**
-         * Check consistency of reference kind and symbol (see JVMS 4.4.8)
-         */
-        @SuppressWarnings("fallthrough")
-        private void checkConsistent() {
-            boolean staticOk = false;
-            Kind expectedKind = null;
-            Filter<Name> nameFilter = nonInitFilter;
-            boolean interfaceOwner = false;
-            switch (refKind) {
-                case ClassFile.REF_getStatic:
-                case ClassFile.REF_putStatic:
-                    staticOk = true;
-                case ClassFile.REF_getField:
-                case ClassFile.REF_putField:
-                    expectedKind = VAR;
-                    break;
-                case ClassFile.REF_newInvokeSpecial:
-                    nameFilter = initFilter;
-                    expectedKind = MTH;
-                    break;
-                case ClassFile.REF_invokeInterface:
-                    interfaceOwner = true;
-                    expectedKind = MTH;
-                    break;
-                case ClassFile.REF_invokeStatic:
-                    interfaceOwner = true;
-                    staticOk = true;
-                case ClassFile.REF_invokeVirtual:
-                    expectedKind = MTH;
-                    break;
-                case ClassFile.REF_invokeSpecial:
-                    interfaceOwner = true;
-                    expectedKind = MTH;
-                    break;
-            }
-            Assert.check(!refSym.isStatic() || staticOk);
-            Assert.check(refSym.kind == expectedKind);
-            Assert.check(nameFilter.accepts(refSym.name));
-            Assert.check(!refSym.owner.isInterface() || interfaceOwner);
-        }
-        //where
-                Filter<Name> nonInitFilter = new Filter<Name>() {
-                    public boolean accepts(Name n) {
-                        return n != n.table.names.init && n != n.table.names.clinit;
-                    }
-                };
-
-                Filter<Name> initFilter = new Filter<Name>() {
-                    public boolean accepts(Name n) {
-                        return n == n.table.names.init;
-                    }
-                };
-    }
-
-    /** A class for the name-and-type signature of a method or field.
-     */
-    public static class NameAndType {
-        Name name;
-        UniqueType uniqueType;
-        Types types;
-
-        NameAndType(Name name, Type type, Types types) {
-            this.name = name;
-            this.uniqueType = new UniqueType(type, types);
-            this.types = types;
-        }
-
-        void setType(Type type) {
-            this.uniqueType = new UniqueType(type, types);
+            return Objects.hash(clazz);
         }
 
         @Override
-        public boolean equals(Object other) {
-            return (other.getClass().equals(NameAndType.class) &&
-                    name == ((NameAndType) other).name &&
-                        uniqueType.equals(((NameAndType) other).uniqueType));
-        }
-
-        @Override
-        public int hashCode() {
-            return name.hashCode() * uniqueType.hashCode();
-        }
-
-        public void writePool(ByteBuffer buf, Pool pool, Function<Type, Name> sigFunc) {
-            buf.appendByte(ClassFile.CONSTANT_NameandType);
-            buf.appendChar(pool.put(name));
-            buf.appendChar(pool.put(sigFunc.apply(uniqueType.type)));
+        public boolean equals(Object obj) {
+            if (obj instanceof ClassRef) {
+                ClassRef that = (ClassRef)obj;
+                return that.clazz.equals(clazz);
+            } else {
+                return false;
+            }
         }
     }
 
     /**
-     * A name-and-type entry backed by a generic signature.
+     * Pool entry associated with constant values; supported constants types are int, long, float,
+     * double and Name.
      */
-    public static class SignatureNameAndType extends NameAndType {
+    static class Constant<V> extends Entry {
 
-        public SignatureNameAndType(Name name, Type type, Types types) {
-            super(name, type, types);
+        /** The constant value. */
+        V value;
+
+        Constant(int tag, V value, Object data) {
+            super(tag, data);
+            this.value = value;
         }
-
-        @Override
-        public boolean equals(Object other) {
-            return (other.getClass().equals(SignatureNameAndType.class) &&
-                    name == ((NameAndType) other).name &&
-                        uniqueType.equals(((NameAndType) other).uniqueType));
-        }
-
+        
         @Override
         public int hashCode() {
-            return name.hashCode() * uniqueType.hashCode();
-        }
-
-        public void writePool(ByteBuffer buf, Pool pool, Function<Type, Name> sigFunc) {
-            buf.appendByte(ClassFile.CONSTANT_NameandType);
-            buf.appendChar(pool.put(name));
-            buf.appendChar(pool.put(Signature.of(uniqueType.type, types)));
-        }
-    }
-
-    /**
-     * Root class for all generic type pool entries.
-     */
-    static abstract class Signature extends UniqueType {
-
-        Signature(Type type, Types types) {
-            super(type, types);
-        }
-
-        Name asSig(Types types) {
-            return types.typeSig(type);
-        }
-
-        abstract void writePool(ByteBuffer buf, Pool pool);
-
-        static Signature of(Type t, Types types) {
-            switch (t.getTag()) {
-                case TYPEVAR:
-                    TypeVar tv = (TypeVar)t;
-                    return tv.isCaptured() ?
-                            of(((CapturedType)tv).wildcard, types) :
-                            new TypeVariable((TypeVar)t, types);
-                case WILDCARD:
-                    return of(((WildcardType)t).type, types);
-                case ANY_BOUND:
-                    return of(types.syms.objectType, types);
-                case ARRAY:
-                    return new ArrayType((Type.ArrayType)t, types);
-                case CLASS:
-                    if (t.allparams().isEmpty()) {
-                        return new Utf8Signature(t, types);
-                    } else {
-                        return new ParameterizedType((ClassType)t, types);
-                    }
-                case METHOD:
-                    return new MethodType((Type.MethodType)t, types);
-                default:
-                    return new Utf8Signature(t, types);
-            }
+            return value.hashCode();
         }
 
         @Override
         public boolean equals(Object obj) {
-            if (obj instanceof Signature) {
-                return super.equals(obj);
+            if (obj instanceof Constant<?>) {
+                Constant<?> that = (Constant<?>)obj;
+                return that.value.equals(value);
             } else {
                 return false;
             }
         }
 
         @Override
-        public int hashCode() {
-            return super.hashCode();
-        }
-    }
-
-    static class Utf8Signature extends Signature {
-        public Utf8Signature(Type type, Types types) {
-            super(type, types);
-        }
-
-        @Override
-        void writePool(ByteBuffer poolbuf, Pool pool) {
-            poolbuf.appendByte(ClassFile.CONSTANT_Utf8);
-            byte[] bs = asSig(pool.types).toUtf();
-            poolbuf.appendChar(bs.length);
-            poolbuf.appendBytes(bs, 0, bs.length);
+        int size() {
+            switch (tag) {
+                case ClassFile.CONSTANT_Long:
+                case ClassFile.CONSTANT_Double:
+                    return 2;
+                default:
+                    return 1;
+            }
         }
     }
 
     /**
-     * A class for type-variable entries.
+     * Pool entry associated with string constant.
      */
-    static class TypeVariable extends Signature {
+    static class StringRef extends Entry {
 
-        TypeVariable(TypeVar type, Types types) {
-            super(type, types);
+        /** String value. */
+        Constant<Name> strValue;
+
+        public StringRef(Constant<Name> strValue, String s) {
+            super(ClassFile.CONSTANT_String, s);
+            this.strValue = strValue;
         }
 
-        void writePool(ByteBuffer poolbuf, Pool pool) {
-            poolbuf.appendByte(ClassFile.CONSTANT_TypeVar);
-            poolbuf.appendChar(pool.put(type.tsym.name));
-            poolbuf.appendChar(pool.put(type.tsym.owner));
-            List<Type> bounds = pool.types.getBounds((TypeVar)type);
-            poolbuf.appendByte((byte)bounds.size());
-            bounds.stream().map(b -> Signature.of(b, pool.types)).forEach(s -> poolbuf.appendChar(pool.put(s)));
+        @Override
+        public int hashCode() {
+            return strValue.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof StringRef) {
+                StringRef that = (StringRef)obj;
+                return that.strValue.equals(strValue);
+            } else {
+                return false;
+            }
         }
     }
 
     /**
-     * A class for parameterized-type entries.
+     * Pool entry associated with invokedynamic callsites.
      */
-    static class ParameterizedType extends Signature {
+    static class InvokeDynamic extends Entry {
 
-        ParameterizedType(ClassType type, Types types) {
-            super(type, types);
+        /** Index into BootstrapMethods attribute. */
+        int bsmIndex;
+
+        /** Name and type. */
+        NameAndType nt;
+
+        InvokeDynamic(int bsmIndex, NameAndType nt) {
+            super(ClassFile.CONSTANT_InvokeDynamic);
+            this.bsmIndex = bsmIndex;
+            this.nt = nt;
         }
 
-        void writePool(ByteBuffer poolbuf, Pool pool) {
-            poolbuf.appendByte(ClassFile.CONSTANT_ParameterizedType);
-            poolbuf.appendChar(pool.put(type.tsym));
-            List<Type> targs = type.getTypeArguments();
-            poolbuf.appendByte((byte)targs.size());
-            targs.stream().map(ta -> Signature.of(ta, pool.types)).forEach(s -> poolbuf.appendChar(pool.put(s)));
+        @Override
+        public int hashCode() {
+            return Objects.hash(bsmIndex, nt);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof InvokeDynamic) {
+                InvokeDynamic that = (InvokeDynamic)obj;
+                return that.bsmIndex == bsmIndex && that.nt.equals(nt);
+            } else {
+                return false;
+            }
         }
     }
 
     /**
-     * Root class for compound type entries (either array or methods). A compound descriptor is made up
+     * Pool entry associated with method handles.
+     */
+    static class MethodHandle extends Entry {
+
+        /** Method handle reference kind. */
+        int refKind;
+
+        /** Underlying symbolic entry. */
+        MemberRef ref;
+
+        MethodHandle(int refKind, MemberRef ref, MethodHandleSymbol mhs) {
+            super(ClassFile.CONSTANT_MethodHandle, mhs);
+            this.refKind = refKind;
+            this.ref = ref;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(refKind, ref);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof MethodHandle) {
+                MethodHandle that = (MethodHandle)obj;
+                return that.refKind == refKind && that.ref.equals(ref);
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Pool entry associated with method types.
+     */
+    static class MethodType extends Entry {
+
+        /** The method type. */
+        Entry methodType;
+
+        public MethodType(Entry methodType, Type.MethodType mt) {
+            super(ClassFile.CONSTANT_MethodType, mt);
+            this.methodType = methodType;
+        }
+
+        @Override
+        public int hashCode() {
+            return methodType.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof MethodType) {
+                MethodType that = (MethodType)obj;
+                return that.methodType.equals(methodType);
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /*** Valhalla CP entries ***/
+
+    /**
+     * Pool entry associated with type-variable entries.
+     */
+    static class TypeVariable extends Entry {
+
+        /** Type-variable name. */
+        Constant<Name> name;
+
+        /** Type-variable owner. */
+        Entry owner;
+
+        /** Type-variable bounds. */
+        Entry[] bounds;
+
+        TypeVariable(Constant<Name> name, Entry owner, Entry[] bounds, TypeVar tv) {
+            super(ClassFile.CONSTANT_TypeVar, tv);
+            this.name = name;
+            this.owner = owner;
+            this.bounds = bounds;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(name, owner, Arrays.hashCode(bounds));
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof TypeVariable) {
+                TypeVariable that = (TypeVariable)obj;
+                return that.name.equals(name) && that.owner.equals(owner) &&
+                        Objects.deepEquals(that.bounds, bounds);
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Pool entry associated with parameterized-type entries.
+     */
+    static class ParameterizedType extends Entry {
+
+        /** Base class. */
+        ClassRef clazz;
+
+        /** Type-arguments list. */
+        Entry[] typeargs;
+
+        ParameterizedType(ClassRef clazz, Entry[] typeargs, ClassType ct) {
+            super(ClassFile.CONSTANT_ParameterizedType, ct);
+            this.clazz = clazz;
+            this.typeargs = typeargs;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(clazz, Arrays.hashCode(typeargs));
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof ParameterizedType) {
+                ParameterizedType that = (ParameterizedType)obj;
+                return that.clazz.equals(clazz) && Objects.deepEquals(that.typeargs, typeargs);
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Pool entry associated with compound type entries (either array or methods). A compound descriptor is made up
      * of a string descriptor (containing on or more holes) and a set of replacements. For instance,
      * an array type is represented with the string descriptor "#]" where "#" denotes a hole to
      * be replaced by actual array element type.
      */
-    static abstract class CompoundType extends Signature {
+    static class CompoundType extends Entry {
 
-        CompoundType(Type type, Types types) {
-            super(type, types);
+        /** Descriptor. */
+        Constant<Name> template;
+
+        /** Holes list. */
+        Entry[] holes;
+
+        CompoundType(Constant<Name> template, Entry[] holes, Type t) {
+            super(ClassFile.CONSTANT_CompoundType, t);
+            this.template = template;
+            this.holes = holes;
         }
 
-        abstract String getDesc(Types types);
-
-        abstract List<Type> getHoles(Types types);
-
-        void writePool(ByteBuffer poolbuf, Pool pool) {
-            poolbuf.appendByte(ClassFile.CONSTANT_CompoundType);
-            poolbuf.appendChar(pool.put(pool.names.fromString(getDesc(pool.types))));
-            List<Type> params = getHoles(pool.types);
-            poolbuf.appendByte((byte)params.size());
-            params.stream().map(ta -> Signature.of(ta, pool.types)).forEach(s -> poolbuf.appendChar(pool.put(s)));
-        }
-    }
-
-    /**
-     * A class for array types.
-     */
-    static class ArrayType extends CompoundType {
-
-        static final String desc = "[[[[[[[[[[[[[[[[#";
-
-        ArrayType(Type.ArrayType type, Types types) {
-            super(type, types);
+        @Override
+        public int hashCode() {
+            return Objects.hash(template, Arrays.hashCode(holes));
         }
 
-        String getDesc(Types types) {
-            int dim = types.dimensions(type);
-            Assert.check(dim <= 16);
-            return desc.substring(desc.length() - 1 - dim, desc.length());
-        }
-
-        List<Type> getHoles(Types types) {
-            Type arr = type;
-            while (types.elemtype(arr) != null) {
-                arr = types.elemtype(arr);
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof CompoundType) {
+                CompoundType that = (CompoundType)obj;
+                return that.template.equals(template) && Objects.deepEquals(that.holes, holes);
+            } else {
+                return false;
             }
-            return List.of(arr);
-        }
-    }
-
-    /**
-     * A class for method types.
-     */
-    static class MethodType extends CompoundType {
-
-        final Object[] holes;
-
-        MethodType(Type.MethodType type, Types types) {
-            super(type, types);
-            int offset = type.getParameterTypes().isEmpty() ? 1 : 0;
-            int holesCount = type.getParameterTypes().length() + 1 + offset;
-            holes = new Object[holesCount];
-            int count = offset;
-            for (Type t : type.getParameterTypes().append(type.getReturnType())) {
-                holes[count] = typeToHole(t, types);
-                count++;
-            }
-            if (offset > 0) {
-                holes[0] = "";
-            }
-        }
-
-        Object typeToHole(Type t, Types types) {
-            if (t.isPrimitiveOrVoid() || (t.hasTag(TypeTag.CLASS) && t.allparams().isEmpty())) {
-                return types.typeSig(t).toString();
-            } else {
-                return t;
-            }
-        }
-
-        String getDesc(Types types) {
-            String[] desc = Stream.of(holes)
-                    .map(o -> (o instanceof Type) ? "#" : o.toString())
-                    .toArray(String[]::new);
-            String args = Stream.of(desc).limit(desc.length - 1)
-                    .collect(Collectors.joining("", "(", ")"));
-            String ret = desc[desc.length - 1];
-            return args + ret;
-        }
-
-        List<Type> getHoles(Types types) {
-            ListBuffer<Type> typeHoles = new ListBuffer<>();
-            for (Object o : holes) {
-                if (o instanceof Type) {
-                    typeHoles.add((Type)o);
-                }
-            }
-            return typeHoles.toList();
         }
     }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/sym/CreateSymbols.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/sym/CreateSymbols.java	Tue Dec 08 14:42:24 2015 +0000
@@ -34,7 +34,8 @@
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.code.Types;
 import com.sun.tools.javac.jvm.ClassWriter;
-import com.sun.tools.javac.jvm.Pool;
+import com.sun.tools.javac.jvm.Gen.PoolMode;
+import com.sun.tools.javac.jvm.PoolWriter;
 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
@@ -203,7 +204,7 @@
 
         Type.moreInfo = true;
         Types types = Types.instance(task.getContext());
-        Pool pool = new Pool(types, names, false);
+        PoolWriter poolWriter = new PoolWriter(types, EnumSet.noneOf(PoolMode.class));
         for (JavaFileObject file : fm.list(jarLocation, "", EnumSet.of(CLASS), true)) {
             String className = fm.inferBinaryName(jarLocation, file);
             int index = className.lastIndexOf('.');
@@ -241,7 +242,7 @@
             int p = profiles.getProfile(cs.fullname.toString().replace(".", "/"));
             if (0 < p && p < profileAnnos.length)
                 cs.prependAttributes(List.of(profileAnnos[p]));
-            writeClass(pool, cs, writer);
+            writeClass(poolWriter, cs, writer);
         }
 
         if (false) {
@@ -256,12 +257,11 @@
         }
     }
 
-    void writeClass(final Pool pool, final ClassSymbol cs, final ClassWriter writer)
+    void writeClass(final PoolWriter pool, final ClassSymbol cs, final ClassWriter writer)
         throws IOException
     {
         try {
-            pool.reset();
-            cs.pool = pool;
+            cs.poolWriter = pool;
             writer.writeClass(cs);
             for (Symbol sym : cs.members().getSymbols(NON_RECURSIVE)) {
                 if (sym.kind == TYP) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Tue Dec 08 14:42:24 2015 +0000
@@ -209,6 +209,16 @@
         }
     }
 
+    public static Type unerasedTypeOrType(JCTree tree) {
+        if (tree instanceof JCExpression) {
+            JCExpression exp = (JCExpression)tree;
+            return exp.unerasedType != null ? exp.unerasedType : exp.type;
+        } else {
+            //Assert.error("Can't access unerased types on non-expressions!");
+            return null;
+        }
+    }
+
     public static boolean isEnumInit(JCTree tree) {
         switch (tree.getTag()) {
             case VARDEF:
--- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Tue Dec 08 14:42:24 2015 +0000
@@ -732,6 +732,11 @@
                 }
             }
         };
+        //drop first round: see JDK-8144733
+        Util.stream(scopeIterable)
+                .flatMap(s -> Util.stream((Iterable<?>)s.getLocalElements()))
+                .collect(toCollection(ArrayList :: new));
+        //now do this for real
         @SuppressWarnings("unchecked")
         List<Element> result = Util.stream(scopeIterable)
                              .flatMap(s -> Util.stream((Iterable<Element>)s.getLocalElements()))
--- a/test/tools/javac/lambda/TestInvokeDynamic.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/test/tools/javac/lambda/TestInvokeDynamic.java	Tue Dec 08 14:42:24 2015 +0000
@@ -183,10 +183,9 @@
                 case CLASS:
                     return syms.stringType.tsym;
                 case METHOD_HANDLE:
-                    return new Pool.MethodHandle(REF_invokeVirtual,
-                            syms.arrayCloneMethod, types);
+                    return syms.arrayCloneMethod.asHandle();
                 case METHOD_TYPE:
-                    return syms.arrayCloneMethod.type;
+                    return syms.arrayCloneMethod.type.asMethodType().asConstant();
                 default:
                     throw new AssertionError();
             }
--- a/test/tools/javac/scope/7046348/EagerInterfaceCompletionTest.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/test/tools/javac/scope/7046348/EagerInterfaceCompletionTest.java	Tue Dec 08 14:42:24 2015 +0000
@@ -33,6 +33,7 @@
 import java.net.URI;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Locale;
 
 import javax.tools.Diagnostic;
 import javax.tools.DiagnosticListener;
@@ -67,12 +68,13 @@
         actionKind.doAction(this);
         DiagnosticChecker dc = new DiagnosticChecker();
         compile(dc, testKind.source);
-        if (testKind.completionFailure(versionKind, actionKind, hierarchyKind) != dc.errorFound) {
-            if (dc.errorFound) {
+        if (testKind.completionFailure(versionKind, actionKind, hierarchyKind) != (dc.errorFound != null)) {
+            if (dc.errorFound != null) {
                 error("Unexpected completion failure" +
                       "\nhierarhcyKind " + hierarchyKind +
                       "\ntestKind " + testKind +
-                      "\nactionKind " + actionKind);
+                      "\nactionKind " + actionKind +
+                      "\nerror: " + dc.errorFound);
             } else {
                 error("Missing completion failure " +
                           "\nhierarhcyKind " + hierarchyKind +
@@ -111,11 +113,11 @@
 
     class DiagnosticChecker implements DiagnosticListener<JavaFileObject> {
 
-        boolean errorFound = false;
+        String errorFound = null;
 
         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
-                errorFound = true;
+                errorFound = diagnostic.getMessage(Locale.getDefault());
             }
         }
     }
--- a/test/tools/javac/valhalla/typespec/ObjectMethods.out	Mon Dec 07 16:50:51 2015 +0000
+++ b/test/tools/javac/valhalla/typespec/ObjectMethods.out	Tue Dec 08 14:42:24 2015 +0000
@@ -1,4 +1,4 @@
-ObjectMethods.java:12:11: compiler.err.cant.apply.symbol: kindname.method, equals, Z, java.lang.Object, kindname.class, compiler.misc.anonymous.class: compiler.misc.type.none, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, Z))
+ObjectMethods.java:12:11: compiler.err.cant.apply.symbol: kindname.method, equals, Z, java.lang.Object, kindname.class, java.lang.Object, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, Z))
 ObjectMethods.java:13:11: compiler.err.cant.resolve.location.args: kindname.method, clone, , , (compiler.misc.location.1: kindname.variable, z1, Z)
 ObjectMethods.java:14:11: compiler.err.cant.resolve.location.args: kindname.method, getClass, , , (compiler.misc.location.1: kindname.variable, z1, Z)
 ObjectMethods.java:15:11: compiler.err.cant.resolve.location.args: kindname.method, notify, , , (compiler.misc.location.1: kindname.variable, z1, Z)
@@ -6,23 +6,23 @@
 ObjectMethods.java:17:11: compiler.err.cant.resolve.location.args: kindname.method, wait, , , (compiler.misc.location.1: kindname.variable, z1, Z)
 ObjectMethods.java:18:11: compiler.err.cant.resolve.location.args: kindname.method, wait, , long, (compiler.misc.location.1: kindname.variable, z1, Z)
 ObjectMethods.java:19:11: compiler.err.cant.resolve.location.args: kindname.method, wait, , long,int, (compiler.misc.location.1: kindname.variable, z1, Z)
-ObjectMethods.java:26:17: compiler.err.cant.apply.symbol: kindname.method, equals, Z, java.lang.Object, kindname.class, compiler.misc.anonymous.class: compiler.misc.type.none, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, Z))
-ObjectMethods.java:27:17: compiler.err.cant.resolve.args: kindname.method, clone, , 
-ObjectMethods.java:28:17: compiler.err.cant.resolve.args: kindname.method, getClass, , 
-ObjectMethods.java:29:17: compiler.err.cant.resolve.args: kindname.method, notify, , 
-ObjectMethods.java:30:17: compiler.err.cant.resolve.args: kindname.method, notifyAll, , 
-ObjectMethods.java:31:17: compiler.err.cant.resolve.args: kindname.method, wait, , 
-ObjectMethods.java:32:17: compiler.err.cant.resolve.args: kindname.method, wait, , long
-ObjectMethods.java:33:17: compiler.err.cant.resolve.args: kindname.method, wait, , long,int
-ObjectMethods.java:40:20: compiler.err.cant.apply.symbol: kindname.method, equals, Z, java.lang.Object, kindname.class, compiler.misc.anonymous.class: compiler.misc.type.none, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, Z))
-ObjectMethods.java:41:20: compiler.err.cant.resolve.args: kindname.method, clone, , 
-ObjectMethods.java:42:20: compiler.err.cant.resolve.args: kindname.method, getClass, , 
-ObjectMethods.java:43:20: compiler.err.cant.resolve.args: kindname.method, notify, , 
-ObjectMethods.java:44:20: compiler.err.cant.resolve.args: kindname.method, notifyAll, , 
-ObjectMethods.java:45:20: compiler.err.cant.resolve.args: kindname.method, wait, , 
-ObjectMethods.java:46:20: compiler.err.cant.resolve.args: kindname.method, wait, , long
-ObjectMethods.java:47:20: compiler.err.cant.resolve.args: kindname.method, wait, , long,int
-ObjectMethods.java:54:11: compiler.err.cant.apply.symbol: kindname.method, equals, Z, java.lang.Object, kindname.class, compiler.misc.anonymous.class: compiler.misc.type.none, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, Z))
+ObjectMethods.java:26:17: compiler.err.cant.apply.symbol: kindname.method, equals, Z, java.lang.Object, kindname.class, java.lang.Object, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, Z))
+ObjectMethods.java:27:17: compiler.err.cant.resolve.location.args: kindname.method, clone, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:28:17: compiler.err.cant.resolve.location.args: kindname.method, getClass, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:29:17: compiler.err.cant.resolve.location.args: kindname.method, notify, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:30:17: compiler.err.cant.resolve.location.args: kindname.method, notifyAll, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:31:17: compiler.err.cant.resolve.location.args: kindname.method, wait, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:32:17: compiler.err.cant.resolve.location.args: kindname.method, wait, , long, (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:33:17: compiler.err.cant.resolve.location.args: kindname.method, wait, , long,int, (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:40:20: compiler.err.cant.apply.symbol: kindname.method, equals, Z, java.lang.Object, kindname.class, java.lang.Object, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, Z))
+ObjectMethods.java:41:20: compiler.err.cant.resolve.location.args: kindname.method, clone, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:42:20: compiler.err.cant.resolve.location.args: kindname.method, getClass, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:43:20: compiler.err.cant.resolve.location.args: kindname.method, notify, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:44:20: compiler.err.cant.resolve.location.args: kindname.method, notifyAll, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:45:20: compiler.err.cant.resolve.location.args: kindname.method, wait, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:46:20: compiler.err.cant.resolve.location.args: kindname.method, wait, , long, (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:47:20: compiler.err.cant.resolve.location.args: kindname.method, wait, , long,int, (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:54:11: compiler.err.cant.apply.symbol: kindname.method, equals, Z, java.lang.Object, kindname.class, java.lang.Object, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, Z))
 ObjectMethods.java:55:11: compiler.err.cant.resolve.location.args: kindname.method, clone, , , (compiler.misc.location.1: kindname.variable, z1, Z)
 ObjectMethods.java:56:11: compiler.err.cant.resolve.location.args: kindname.method, getClass, , , (compiler.misc.location.1: kindname.variable, z1, Z)
 ObjectMethods.java:57:11: compiler.err.cant.resolve.location.args: kindname.method, notify, , , (compiler.misc.location.1: kindname.variable, z1, Z)
@@ -30,20 +30,20 @@
 ObjectMethods.java:59:11: compiler.err.cant.resolve.location.args: kindname.method, wait, , , (compiler.misc.location.1: kindname.variable, z1, Z)
 ObjectMethods.java:60:11: compiler.err.cant.resolve.location.args: kindname.method, wait, , long, (compiler.misc.location.1: kindname.variable, z1, Z)
 ObjectMethods.java:61:11: compiler.err.cant.resolve.location.args: kindname.method, wait, , long,int, (compiler.misc.location.1: kindname.variable, z1, Z)
-ObjectMethods.java:68:17: compiler.err.cant.apply.symbol: kindname.method, equals, Z, java.lang.Object, kindname.class, compiler.misc.anonymous.class: compiler.misc.type.none, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, Z))
-ObjectMethods.java:69:17: compiler.err.cant.resolve.args: kindname.method, clone, , 
-ObjectMethods.java:70:17: compiler.err.cant.resolve.args: kindname.method, getClass, , 
-ObjectMethods.java:71:17: compiler.err.cant.resolve.args: kindname.method, notify, , 
-ObjectMethods.java:72:17: compiler.err.cant.resolve.args: kindname.method, notifyAll, , 
-ObjectMethods.java:73:17: compiler.err.cant.resolve.args: kindname.method, wait, , 
-ObjectMethods.java:74:17: compiler.err.cant.resolve.args: kindname.method, wait, , long
-ObjectMethods.java:75:17: compiler.err.cant.resolve.args: kindname.method, wait, , long,int
-ObjectMethods.java:82:20: compiler.err.cant.apply.symbol: kindname.method, equals, Z, java.lang.Object, kindname.class, compiler.misc.anonymous.class: compiler.misc.type.none, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, Z))
-ObjectMethods.java:83:20: compiler.err.cant.resolve.args: kindname.method, clone, , 
-ObjectMethods.java:84:20: compiler.err.cant.resolve.args: kindname.method, getClass, , 
-ObjectMethods.java:85:20: compiler.err.cant.resolve.args: kindname.method, notify, , 
-ObjectMethods.java:86:20: compiler.err.cant.resolve.args: kindname.method, notifyAll, , 
-ObjectMethods.java:87:20: compiler.err.cant.resolve.args: kindname.method, wait, , 
-ObjectMethods.java:88:20: compiler.err.cant.resolve.args: kindname.method, wait, , long
-ObjectMethods.java:89:20: compiler.err.cant.resolve.args: kindname.method, wait, , long,int
+ObjectMethods.java:68:17: compiler.err.cant.apply.symbol: kindname.method, equals, Z, java.lang.Object, kindname.class, java.lang.Object, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, Z))
+ObjectMethods.java:69:17: compiler.err.cant.resolve.location.args: kindname.method, clone, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:70:17: compiler.err.cant.resolve.location.args: kindname.method, getClass, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:71:17: compiler.err.cant.resolve.location.args: kindname.method, notify, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:72:17: compiler.err.cant.resolve.location.args: kindname.method, notifyAll, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:73:17: compiler.err.cant.resolve.location.args: kindname.method, wait, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:74:17: compiler.err.cant.resolve.location.args: kindname.method, wait, , long, (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:75:17: compiler.err.cant.resolve.location.args: kindname.method, wait, , long,int, (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:82:20: compiler.err.cant.apply.symbol: kindname.method, equals, Z, java.lang.Object, kindname.class, java.lang.Object, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, Z))
+ObjectMethods.java:83:20: compiler.err.cant.resolve.location.args: kindname.method, clone, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:84:20: compiler.err.cant.resolve.location.args: kindname.method, getClass, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:85:20: compiler.err.cant.resolve.location.args: kindname.method, notify, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:86:20: compiler.err.cant.resolve.location.args: kindname.method, notifyAll, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:87:20: compiler.err.cant.resolve.location.args: kindname.method, wait, , , (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:88:20: compiler.err.cant.resolve.location.args: kindname.method, wait, , long, (compiler.misc.location: kindname.class, java.lang.Object, null)
+ObjectMethods.java:89:20: compiler.err.cant.resolve.location.args: kindname.method, wait, , long,int, (compiler.misc.location: kindname.class, java.lang.Object, null)
 48 errors
--- a/test/tools/javac/valhalla/typespec/items/tests/TestRespecialization.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/test/tools/javac/valhalla/typespec/items/tests/TestRespecialization.java	Tue Dec 08 14:42:24 2015 +0000
@@ -36,13 +36,13 @@
     @BytecodeMapping(opcode = Opcodes.INVOKEDYNAMIC,
                      sig = "(LTestRespecialization$MultiBox<TA;TB;TC;TD;TE;>;I)LTestRespecialization$MultiBox<ITB;TC;TD;TE;>;::{0=LTestRespecialization$MultiBox<TA;TB;TC;TD;TE;>;}")
     @BytecodeMapping(opcode = Opcodes.INVOKEDYNAMIC,
-                     sig = "(LTestRespecialization$MultiBox<ITB;TC;TD;TE;>;J)LTestRespecialization$MultiBox<IJTC;TD;TE;>;::{0=LTestRespecialization$MultiBox${0=I}<TB;TC;TD;TE;>;}")
+                     sig = "(LTestRespecialization$MultiBox<ITB;TC;TD;TE;>;J)LTestRespecialization$MultiBox<IJTC;TD;TE;>;::{0=LTestRespecialization$MultiBox<ITB;TC;TD;TE;>;}")
     @BytecodeMapping(opcode = Opcodes.INVOKEDYNAMIC,
-                     sig = "(LTestRespecialization$MultiBox<IJTC;TD;TE;>;F)LTestRespecialization$MultiBox<IJFTD;TE;>;::{0=LTestRespecialization$MultiBox${0=I,1=J}<TC;TD;TE;>;}")
+                     sig = "(LTestRespecialization$MultiBox<IJTC;TD;TE;>;F)LTestRespecialization$MultiBox<IJFTD;TE;>;::{0=LTestRespecialization$MultiBox<IJTC;TD;TE;>;}")
     @BytecodeMapping(opcode = Opcodes.INVOKEDYNAMIC,
-                     sig = "(LTestRespecialization$MultiBox<IJFTD;TE;>;D)LTestRespecialization$MultiBox<IJFDTE;>;::{0=LTestRespecialization$MultiBox${0=I,1=J,2=F}<TD;TE;>;}")
+                     sig = "(LTestRespecialization$MultiBox<IJFTD;TE;>;D)LTestRespecialization$MultiBox<IJFDTE;>;::{0=LTestRespecialization$MultiBox<IJFTD;TE;>;}")
     @BytecodeMapping(opcode = Opcodes.INVOKEDYNAMIC,
-                     sig = "(LTestRespecialization$MultiBox<IJFDTE;>;Z)LTestRespecialization$MultiBox<IJFDZ>;::{0=LTestRespecialization$MultiBox${0=I,1=J,2=F,3=D}<TE;>;}")
+                     sig = "(LTestRespecialization$MultiBox<IJFDTE;>;Z)LTestRespecialization$MultiBox<IJFDZ>;::{0=LTestRespecialization$MultiBox<IJFDTE;>;}")
     <any A, any B, any C, any D, any E> void testForward(MultiBox<A, B, C, D, E> mb_abcde) {
         MultiBox<int, long, float, double, boolean> mb_ilfdb =
                 mb_abcde.withA(0)
@@ -55,13 +55,13 @@
     @BytecodeMapping(opcode = Opcodes.INVOKEDYNAMIC,
                      sig = "(LTestRespecialization$MultiBox<TA;TB;TC;TD;TE;>;Z)LTestRespecialization$MultiBox<TA;TB;TC;TD;Z>;::{0=LTestRespecialization$MultiBox<TA;TB;TC;TD;TE;>;}")
     @BytecodeMapping(opcode = Opcodes.INVOKEDYNAMIC,
-                     sig = "(LTestRespecialization$MultiBox<TA;TB;TC;TD;Z>;D)LTestRespecialization$MultiBox<TA;TB;TC;DZ>;::{0=LTestRespecialization$MultiBox${4=Z}<TA;TB;TC;TD;>;}")
+                     sig = "(LTestRespecialization$MultiBox<TA;TB;TC;TD;Z>;D)LTestRespecialization$MultiBox<TA;TB;TC;DZ>;::{0=LTestRespecialization$MultiBox<TA;TB;TC;TD;Z>;}")
     @BytecodeMapping(opcode = Opcodes.INVOKEDYNAMIC,
-                     sig = "(LTestRespecialization$MultiBox<TA;TB;TC;DZ>;F)LTestRespecialization$MultiBox<TA;TB;FDZ>;::{0=LTestRespecialization$MultiBox${3=D,4=Z}<TA;TB;TC;>;}")
+                     sig = "(LTestRespecialization$MultiBox<TA;TB;TC;DZ>;F)LTestRespecialization$MultiBox<TA;TB;FDZ>;::{0=LTestRespecialization$MultiBox<TA;TB;TC;DZ>;}")
     @BytecodeMapping(opcode = Opcodes.INVOKEDYNAMIC,
-                     sig = "(LTestRespecialization$MultiBox<TA;TB;FDZ>;J)LTestRespecialization$MultiBox<TA;JFDZ>;::{0=LTestRespecialization$MultiBox${2=F,3=D,4=Z}<TA;TB;>;}")
+                     sig = "(LTestRespecialization$MultiBox<TA;TB;FDZ>;J)LTestRespecialization$MultiBox<TA;JFDZ>;::{0=LTestRespecialization$MultiBox<TA;TB;FDZ>;}")
     @BytecodeMapping(opcode = Opcodes.INVOKEDYNAMIC,
-                     sig = "(LTestRespecialization$MultiBox<TA;JFDZ>;I)LTestRespecialization$MultiBox<IJFDZ>;::{0=LTestRespecialization$MultiBox${1=J,2=F,3=D,4=Z}<TA;>;}")
+                     sig = "(LTestRespecialization$MultiBox<TA;JFDZ>;I)LTestRespecialization$MultiBox<IJFDZ>;::{0=LTestRespecialization$MultiBox<TA;JFDZ>;}")
     <any A, any B, any C, any D, any E> void testBackwards(MultiBox<A, B, C, D, E> mb_abcde) {
         MultiBox<int, long, float, double, boolean> mb_ilfdb =
                 mb_abcde.withE(false)
@@ -77,12 +77,12 @@
                      sig = "LTestRespecialization$MultiBox<ITB;TC;TD;TE;>;::"
                          + "(Ljava/lang/Object;)LTestRespecialization$MultiBox<ITZ;TC;TD;TE;>;")
     @BytecodeMapping(opcode = Opcodes.INVOKEDYNAMIC,
-                     sig = "(LTestRespecialization$MultiBox<ILjava/lang/Object;TC;TD;TE;>;F)LTestRespecialization$MultiBox<ILjava/lang/Object;FTD;TE;>;::{0=LTestRespecialization$MultiBox${0=I}<Ljava/lang/Object;TC;TD;TE;>;}")
+                     sig = "(LTestRespecialization$MultiBox<ILjava/lang/Object;TC;TD;TE;>;F)LTestRespecialization$MultiBox<ILjava/lang/Object;FTD;TE;>;::{0=LTestRespecialization$MultiBox<ILjava/lang/Object;TC;TD;TE;>;}")
     @BytecodeMapping(opcode = Opcodes.INVOKEVIRTUAL,
                      sig = "LTestRespecialization$MultiBox<ILjava/lang/Object;FTD;TE;>;::" +
                            "(Ljava/lang/Object;)LTestRespecialization$MultiBox<ILjava/lang/Object;FTZ;TE;>;")
     @BytecodeMapping(opcode = Opcodes.INVOKEDYNAMIC,
-                     sig = "(LTestRespecialization$MultiBox<ILjava/lang/Object;FLjava/lang/Object;TE;>;Z)LTestRespecialization$MultiBox<ILjava/lang/Object;FLjava/lang/Object;Z>;::{0=LTestRespecialization$MultiBox${0=I,2=F}<Ljava/lang/Object;Ljava/lang/Object;TE;>;}")
+                     sig = "(LTestRespecialization$MultiBox<ILjava/lang/Object;FLjava/lang/Object;TE;>;Z)LTestRespecialization$MultiBox<ILjava/lang/Object;FLjava/lang/Object;Z>;::{0=LTestRespecialization$MultiBox<ILjava/lang/Object;FLjava/lang/Object;TE;>;}")
     <any A, any B, any C, any D, any E> void testHoles(MultiBox<A, B, C, D, E> mb_abcde) {
         MultiBox<int, Long, float, Double, boolean> mb_iLfDb =
                 mb_abcde.withA(0)
--- a/test/tools/javap/MethodParameters.java	Mon Dec 07 16:50:51 2015 +0000
+++ b/test/tools/javap/MethodParameters.java	Tue Dec 08 14:42:24 2015 +0000
@@ -49,7 +49,7 @@
          "    Code:\n" +
          "      stack=1, locals=1, args_size=1\n" +
          "         0: aload_0\n" +
-         "         1: invokespecial #1                  // Method java/lang/Object.\"<init>\":()V\n" +
+         "         1: invokespecial #6                  // Method java/lang/Object.\"<init>\":()V\n" +
          "         4: return\n" +
          "      LineNumberTable:\n" +
          "        line 2: 0").replaceAll(" +", " ");
@@ -61,7 +61,7 @@
          "    Code:\n" +
          "      stack=1, locals=2, args_size=2\n" +
          "         0: aload_0\n" +
-         "         1: invokespecial #1                  // Method java/lang/Object.\"<init>\":()V\n" +
+         "         1: invokespecial #6                  // Method java/lang/Object.\"<init>\":()V\n" +
          "         4: return\n" +
          "      LineNumberTable:\n" +
          "        line 3: 0\n" +