8222289: Overhaul logic for reading/writing constant pool entries
authormcimadamore
Wed, 17 Apr 2019 15:37:20 +0100
changeset 54568 b2ed96c35687
parent 54567 224515275cf9
child 54569 7689e1cc56fe
8222289: Overhaul logic for reading/writing constant pool entries Summary: Rewrite of Pool,ClassReader,ClassWriter to use shared pool helper components Reviewed-by: vromero
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/LambdaToMethod.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.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/ModuleNameReader.java
src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java
src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolConstant.java
src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolReader.java
src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolWriter.java
src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java
src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
src/jdk.compiler/share/classes/com/sun/tools/javac/util/ByteBuffer.java
src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java
test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnnotatedExtendsTest.java
test/langtools/tools/javac/annotations/typeAnnotations/classfile/BridgeShouldHaveNoInteriorAnnotationsTest.java
test/langtools/tools/javac/annotations/typeAnnotations/classfile/NestedLambdasCastedTest.java
test/langtools/tools/javac/diags/examples.not-yet.txt
test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java
test/langtools/tools/javac/lambda/TestInvokeDynamic.java
test/langtools/tools/javac/modules/T8159439/NPEForModuleInfoWithNonZeroSuperClassTest.out
test/langtools/tools/javac/nestmates/CheckNestmateAttrs.java
test/langtools/tools/javap/AnnoTest.java
test/langtools/tools/javap/typeAnnotations/AnnotationDefaultNewlineTest.java
test/langtools/tools/javap/typeAnnotations/InvisibleParameterAnnotationsTest.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Wed Apr 17 15:37:20 2019 +0100
@@ -55,6 +55,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.PoolConstant;
 import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
 import com.sun.tools.javac.tree.JCTree.Tag;
@@ -91,7 +92,7 @@
  *  This code and its internal interfaces are subject to change or
  *  deletion without notice.</b>
  */
-public abstract class Symbol extends AnnoConstruct implements Element {
+public abstract class Symbol extends AnnoConstruct implements PoolConstant, Element {
 
     /** The kind of this symbol.
      *  @see Kinds
@@ -286,6 +287,11 @@
         this.name = name;
     }
 
+    @Override
+    public int poolTag() {
+        throw new AssertionError("Invalid pool entry");
+    }
+
     /** Clone this symbol with new owner.
      *  Legal only for fields and methods.
      */
@@ -971,6 +977,11 @@
             this.type = new ModuleType(this);
         }
 
+        @Override
+        public int poolTag() {
+            return ClassFile.CONSTANT_Module;
+        }
+
         @Override @DefinedBy(Api.LANGUAGE_MODEL)
         public Name getSimpleName() {
             return Convert.shortName(name);
@@ -1137,6 +1148,11 @@
             return members_field;
         }
 
+        @Override
+        public int poolTag() {
+            return ClassFile.CONSTANT_Package;
+        }
+
         public long flags() {
             complete();
             return flags_field;
@@ -1237,10 +1253,6 @@
          */
         public List<ClassSymbol> trans_local;
 
-        /** the constant pool of the class
-         */
-        public Pool pool;
-
         /** the annotation metadata attached to this class */
         private AnnotationTypeMetadata annotationTypeMetadata;
 
@@ -1251,7 +1263,6 @@
             this.flatname = formFlatName(name, owner);
             this.sourcefile = null;
             this.classfile = null;
-            this.pool = null;
             this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
         }
 
@@ -1543,6 +1554,11 @@
             super(VAR, flags, name, type, owner);
         }
 
+        @Override
+        public int poolTag() {
+            return ClassFile.CONSTANT_Fieldref;
+        }
+
         /** Clone this symbol with new owner.
          */
         public VarSymbol clone(Symbol newOwner) {
@@ -1551,6 +1567,11 @@
                 public Symbol baseSymbol() {
                     return VarSymbol.this;
                 }
+
+                @Override
+                public Object poolKey(Types types) {
+                    return new Pair<>(newOwner, baseSymbol());
+                }
             };
             v.pos = pos;
             v.adr = adr;
@@ -1711,6 +1732,11 @@
                 public Symbol baseSymbol() {
                     return MethodSymbol.this;
                 }
+
+                @Override
+                public Object poolKey(Types types) {
+                    return new Pair<>(newOwner, baseSymbol());
+                }
             };
             m.code = code;
             return m;
@@ -1740,10 +1766,25 @@
             }
         }
 
+        @Override
+        public int poolTag() {
+            return owner.isInterface() ?
+                    ClassFile.CONSTANT_InterfaceMethodref : ClassFile.CONSTANT_Methodref;
+        }
+
         public boolean isDynamic() {
             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
@@ -2027,16 +2068,14 @@
 
     /** A class for invokedynamic method calls.
      */
-    public static class DynamicMethodSymbol extends MethodSymbol {
+    public static class DynamicMethodSymbol extends MethodSymbol implements Dynamic {
 
-        public Object[] staticArgs;
-        public Symbol bsm;
-        public int bsmKind;
+        public LoadableConstant[] staticArgs;
+        public MethodHandleSymbol bsm;
 
-        public DynamicMethodSymbol(Name name, Symbol owner, int bsmKind, MethodSymbol bsm, Type type, Object[] staticArgs) {
+        public DynamicMethodSymbol(Name name, Symbol owner, MethodHandleSymbol bsm, Type type, LoadableConstant[] staticArgs) {
             super(0, name, type, owner);
             this.bsm = bsm;
-            this.bsmKind = bsmKind;
             this.staticArgs = staticArgs;
         }
 
@@ -2044,6 +2083,83 @@
         public boolean isDynamic() {
             return true;
         }
+
+        @Override
+        public LoadableConstant[] staticArgs() {
+            return staticArgs;
+        }
+
+        @Override
+        public MethodHandleSymbol bootstrapMethod() {
+            return bsm;
+        }
+
+        @Override
+        public int poolTag() {
+            return ClassFile.CONSTANT_InvokeDynamic;
+        }
+
+        @Override
+        public Type dynamicType() {
+            return type;
+        }
+    }
+
+    /** A class for method handles.
+     */
+    public static class MethodHandleSymbol extends MethodSymbol implements LoadableConstant {
+
+        private Symbol refSym;
+
+        public MethodHandleSymbol(Symbol 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 int poolTag() {
+            return ClassFile.CONSTANT_MethodHandle;
+        }
+
+        @Override
+        public Object poolKey(Types types) {
+            return new Pair<>(baseSymbol(), referenceKind());
+        }
+
+        @Override
+        public MethodHandleSymbol asHandle() {
+            return this;
+        }
+
+        @Override
+        public Symbol baseSymbol() {
+            return refSym;
+        }
+
+
+        @Override
+        public boolean isHandle() {
+            return true;
+        }
     }
 
     /** A class for predefined operators.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Wed Apr 17 15:37:20 2019 +0100
@@ -36,7 +36,10 @@
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.TypeMetadata.Entry;
 import com.sun.tools.javac.code.Types.TypeMapping;
+import com.sun.tools.javac.code.Types.UniqueType;
 import com.sun.tools.javac.comp.Infer.IncorporationAction;
+import com.sun.tools.javac.jvm.ClassFile;
+import com.sun.tools.javac.jvm.PoolConstant;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
 
@@ -73,7 +76,7 @@
  *
  *  @see TypeTag
  */
-public abstract class Type extends AnnoConstruct implements TypeMirror {
+public abstract class Type extends AnnoConstruct implements TypeMirror, PoolConstant {
 
     /**
      * Type metadata,  Should be {@code null} for the default value.
@@ -125,6 +128,16 @@
      */
     public TypeSymbol tsym;
 
+    @Override
+    public int poolTag() {
+        throw new AssertionError("Invalid pool entry");
+    }
+
+    @Override
+    public Object poolKey(Types types) {
+        return new UniqueType(this, types);
+    }
+
     /**
      * Checks if the current type tag is equal to the given tag.
      * @return true if tag is equal to the current type tag.
@@ -930,7 +943,7 @@
         }
     }
 
-    public static class ClassType extends Type implements DeclaredType,
+    public static class ClassType extends Type implements DeclaredType, LoadableConstant,
                                                           javax.lang.model.type.ErrorType {
 
         /** The enclosing type of this type. If this is the type of an inner
@@ -975,6 +988,10 @@
             this.interfaces_field = null;
         }
 
+        public int poolTag() {
+            return ClassFile.CONSTANT_Class;
+        }
+
         @Override
         public ClassType cloneWithMetadata(TypeMetadata md) {
             return new ClassType(outer_field, typarams_field, tsym, md) {
@@ -1277,7 +1294,7 @@
     }
 
     public static class ArrayType extends Type
-            implements javax.lang.model.type.ArrayType {
+            implements LoadableConstant, javax.lang.model.type.ArrayType {
 
         public Type elemtype;
 
@@ -1297,6 +1314,10 @@
             this(that.elemtype, that.tsym, that.getMetadata());
         }
 
+        public int poolTag() {
+            return ClassFile.CONSTANT_Class;
+        }
+
         @Override
         public ArrayType cloneWithMetadata(TypeMetadata md) {
             return new ArrayType(elemtype, tsym, md) {
@@ -1412,7 +1433,7 @@
         }
     }
 
-    public static class MethodType extends Type implements ExecutableType {
+    public static class MethodType extends Type implements ExecutableType, LoadableConstant {
 
         public List<Type> argtypes;
         public Type restype;
@@ -1479,6 +1500,11 @@
                 restype != null && restype.isErroneous();
         }
 
+        @Override
+        public int poolTag() {
+            return ClassFile.CONSTANT_MethodType;
+        }
+
         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	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Wed Apr 17 15:37:20 2019 +0100
@@ -48,6 +48,8 @@
 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.LambdaToMethod;
+import com.sun.tools.javac.jvm.ClassFile;
 import com.sun.tools.javac.util.*;
 
 import static com.sun.tools.javac.code.BoundKind.*;
@@ -5181,6 +5183,29 @@
             }
         }
     }
+
+    public Type constantType(LoadableConstant c) {
+        switch (c.poolTag()) {
+            case ClassFile.CONSTANT_Class:
+                return syms.classType;
+            case ClassFile.CONSTANT_String:
+                return syms.stringType;
+            case ClassFile.CONSTANT_Integer:
+                return syms.intType;
+            case ClassFile.CONSTANT_Float:
+                return syms.floatType;
+            case ClassFile.CONSTANT_Long:
+                return syms.longType;
+            case ClassFile.CONSTANT_Double:
+                return syms.doubleType;
+            case ClassFile.CONSTANT_MethodHandle:
+                return syms.methodHandleType;
+            case ClassFile.CONSTANT_MethodType:
+                return syms.methodTypeType;
+            default:
+                throw new AssertionError("Not a loadable constant: " + c.poolTag());
+        }
+    }
     // </editor-fold>
 
     public void newRound() {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed Apr 17 15:37:20 2019 +0100
@@ -25,7 +25,9 @@
 
 package com.sun.tools.javac.comp;
 
+import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
+import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.tree.*;
@@ -59,7 +61,6 @@
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Consumer;
@@ -70,13 +71,10 @@
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 import static com.sun.tools.javac.code.TypeTag.*;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
-import static com.sun.tools.javac.jvm.Pool.DynamicMethod;
 
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.type.TypeKind;
 
-import com.sun.tools.javac.code.Type.IntersectionClassType;
-import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
 import com.sun.tools.javac.main.Option;
 
 /**
@@ -214,7 +212,7 @@
 
         private Map<DedupedLambda, DedupedLambda> dedupedLambdas;
 
-        private Map<DynamicMethod, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
+        private Map<Object, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
 
         /**
          * list of deserialization cases
@@ -439,11 +437,8 @@
         //then, determine the arguments to the indy call
         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
 
-        //build a sam instance using an indy call to the meta-factory
-        int refKind = referenceKind(sym);
-
         //convert to an invokedynamic call
-        result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
+        result = makeMetafactoryIndyCall(context, sym.asHandle(), indy_args);
     }
 
     // where
@@ -488,7 +483,7 @@
 
         //first determine the method symbol to be used to generate the sam instance
         //this is either the method reference symbol, or the bridged reference symbol
-        Symbol refSym = tree.sym;
+        MethodSymbol refSym = (MethodSymbol)tree.sym;
 
         //the qualifying expression is treated as a special captured arg
         JCExpression init;
@@ -522,7 +517,7 @@
 
 
         //build a sam instance using an indy call to the meta-factory
-        result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
+        result = makeMetafactoryIndyCall(localContext, refSym.asHandle(), indy_args);
     }
 
     /**
@@ -765,8 +760,8 @@
                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil()));
      }
 
-    private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
-            DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
+    private void addDeserializationCase(MethodHandleSymbol refSym, Type targetType, MethodSymbol samSym,
+                                        DiagnosticPosition pos, List<LoadableConstant> staticArgs, MethodType indyType) {
         String functionalInterfaceClass = classSig(targetType);
         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
@@ -774,7 +769,8 @@
         String implMethodName = refSym.getQualifiedName().toString();
         String implMethodSignature = typeSig(types.erasure(refSym.type));
 
-        JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
+        JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType),
+                make.Literal(refSym.referenceKind()));
         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
         int i = 0;
         for (Type t : indyType.getParameterTypes()) {
@@ -1106,13 +1102,13 @@
      * Generate an indy method call to the meta factory
      */
     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
-            int refKind, Symbol refSym, List<JCExpression> indy_args) {
+            MethodHandleSymbol refSym, List<JCExpression> indy_args) {
         JCFunctionalExpression tree = context.tree;
         //determine the static bsm args
         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
-        List<Object> staticArgs = List.of(
+        List<LoadableConstant> staticArgs = List.of(
                 typeToMethodType(samSym.type),
-                new Pool.MethodHandle(refKind, refSym, types),
+                ((MethodSymbol)refSym).asHandle(),
                 typeToMethodType(tree.getDescriptorType(types)));
 
         //computed indy arg types
@@ -1131,7 +1127,7 @@
                 names.altMetafactory : names.metafactory;
 
         if (context.needsAltMetafactory()) {
-            ListBuffer<Object> markers = new ListBuffer<>();
+            ListBuffer<Type> markers = new ListBuffer<>();
             List<Type> targets = tree.target.isIntersection() ?
                     types.directSupertypes(tree.target) :
                     List.nil();
@@ -1140,7 +1136,7 @@
                 if (t.tsym != syms.serializableType.tsym &&
                     t.tsym != tree.type.tsym &&
                     t.tsym != syms.objectType.tsym) {
-                    markers.append(t.tsym);
+                    markers.append(t);
                 }
             }
             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
@@ -1152,17 +1148,17 @@
             if (hasBridges) {
                 flags |= FLAG_BRIDGES;
             }
-            staticArgs = staticArgs.append(flags);
+            staticArgs = staticArgs.append(LoadableConstant.Int(flags));
             if (hasMarkers) {
-                staticArgs = staticArgs.append(markers.length());
-                staticArgs = staticArgs.appendList(markers.toList());
+                staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
+                staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
             }
             if (hasBridges) {
-                staticArgs = staticArgs.append(context.bridges.length() - 1);
+                staticArgs = staticArgs.append(LoadableConstant.Int(context.bridges.length() - 1));
                 for (Symbol s : context.bridges) {
                     Type s_erasure = s.erasure(types);
                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
-                        staticArgs = staticArgs.append(s.erasure(types));
+                        staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
                     }
                 }
             }
@@ -1170,7 +1166,7 @@
                 int prevPos = make.pos;
                 try {
                     make.at(kInfo.clazz);
-                    addDeserializationCase(refKind, refSym, tree.type, samSym,
+                    addDeserializationCase(refSym, tree.type, samSym,
                             tree, staticArgs, indyType);
                 } finally {
                     make.at(prevPos);
@@ -1186,14 +1182,14 @@
      * arguments types
      */
     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
-            List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
-            Name methName) {
+                                      List<LoadableConstant> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
+                                      Name methName) {
         int prevPos = make.pos;
         try {
             make.at(pos);
             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
-                    syms.stringType,
-                    syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
+                syms.stringType,
+                syms.methodTypeType).appendList(staticArgs.map(types::constantType));
 
             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
                     bsmName, bsm_staticArgs, List.nil());
@@ -1201,15 +1197,12 @@
             DynamicMethodSymbol dynSym =
                     new DynamicMethodSymbol(methName,
                                             syms.noSymbol,
-                                            bsm.isStatic() ?
-                                                ClassFile.REF_invokeStatic :
-                                                ClassFile.REF_invokeVirtual,
-                                            (MethodSymbol)bsm,
+                                            ((MethodSymbol)bsm).asHandle(),
                                             indyType,
-                                            staticArgs.toArray());
+                                            staticArgs.toArray(new LoadableConstant[staticArgs.length()]));
             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
             DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent(
-                    new DynamicMethod(dynSym, types), dynSym);
+                    dynSym.poolKey(types), dynSym);
             qualifier.sym = existing != null ? existing : dynSym;
             qualifier.type = indyType.getReturnType();
 
@@ -1220,57 +1213,6 @@
             make.at(prevPos);
         }
     }
-    //where
-    private List<Type> bsmStaticArgToTypes(List<Object> args) {
-        ListBuffer<Type> argtypes = new ListBuffer<>();
-        for (Object arg : args) {
-            argtypes.append(bsmStaticArgToType(arg));
-        }
-        return argtypes.toList();
-    }
-
-    private Type bsmStaticArgToType(Object arg) {
-        Assert.checkNonNull(arg);
-        if (arg instanceof ClassSymbol) {
-            return syms.classType;
-        } else if (arg instanceof Integer) {
-            return syms.intType;
-        } else if (arg instanceof Long) {
-            return syms.longType;
-        } else if (arg instanceof Float) {
-            return syms.floatType;
-        } else if (arg instanceof Double) {
-            return syms.doubleType;
-        } else if (arg instanceof String) {
-            return syms.stringType;
-        } else if (arg instanceof Pool.MethodHandle) {
-            return syms.methodHandleType;
-        } else if (arg instanceof MethodType) {
-            return syms.methodTypeType;
-        } else {
-            Assert.error("bad static arg " + arg.getClass());
-            return null;
-        }
-    }
-
-    /**
-     * Get the opcode associated with this method reference
-     */
-    private int referenceKind(Symbol refSym) {
-        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;
-            }
-        }
-    }
 
     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
     /**
@@ -2312,13 +2254,6 @@
                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
             }
 
-            /**
-             * Get the opcode associated with this method reference
-             */
-            int referenceKind() {
-                return LambdaToMethod.this.referenceKind(tree.sym);
-            }
-
             boolean needsVarArgsConversion() {
                 return tree.varargsElement != null;
             }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Wed Apr 17 15:37:20 2019 +0100
@@ -93,7 +93,6 @@
     private final Attr attr;
     private TreeMaker make;
     private DiagnosticPosition make_pos;
-    private final ClassWriter writer;
     private final ConstFold cfolder;
     private final Target target;
     private final Source source;
@@ -116,7 +115,6 @@
         chk = Check.instance(context);
         attr = Attr.instance(context);
         make = TreeMaker.instance(context);
-        writer = ClassWriter.instance(context);
         cfolder = ConstFold.instance(context);
         target = Target.instance(context);
         source = Source.instance(context);
@@ -475,7 +473,7 @@
                 .fromString(target.syntheticNameChar() +
                             "SwitchMap" +
                             target.syntheticNameChar() +
-                            writer.xClassName(forEnum.type).toString()
+                            names.fromUtf(ClassWriter.externalize(forEnum.type.tsym.flatName())).toString()
                             .replace('/', '.')
                             .replace('.', target.syntheticNameChar()));
             ClassSymbol outerCacheClass = outerCacheClass();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java	Wed Apr 17 15:37:20 2019 +0100
@@ -25,9 +25,6 @@
 
 package com.sun.tools.javac.jvm;
 
-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.util.Name;
 
 
@@ -189,38 +186,4 @@
     public static byte[] externalize(Name name) {
         return externalize(name.getByteArray(), name.getByteOffset(), name.getByteLength());
     }
-
-/************************************************************************
- * Name-and-type
- ***********************************************************************/
-
-    /** 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);
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            return (other instanceof NameAndType &&
-                    name == ((NameAndType) other).name &&
-                        uniqueType.equals(((NameAndType) other).uniqueType));
-        }
-
-        @Override
-        public int hashCode() {
-            return name.hashCode() * uniqueType.hashCode();
-        }
-    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Wed Apr 17 15:37:20 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, 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
@@ -36,6 +36,7 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.IntFunction;
 
 import javax.lang.model.element.Modifier;
 import javax.lang.model.element.NestingKind;
@@ -55,8 +56,8 @@
 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.file.BaseFileManager;
 import com.sun.tools.javac.file.PathFileObject;
-import com.sun.tools.javac.jvm.ClassFile.NameAndType;
 import com.sun.tools.javac.jvm.ClassFile.Version;
+import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
 import com.sun.tools.javac.main.Option;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
@@ -100,11 +101,6 @@
      */
     boolean verbose;
 
-    /** 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 modules.
      */
     boolean allowModules;
@@ -170,20 +166,15 @@
 
     /** The buffer containing the currently read class file.
      */
-    byte[] buf = new byte[INITIAL_BUFFER_SIZE];
+    ByteBuffer buf = new ByteBuffer(INITIAL_BUFFER_SIZE);
 
     /** The current input pointer.
      */
     protected int bp;
 
-    /** The objects of the constant pool.
+    /** The pool reader.
      */
-    Object[] poolObj;
-
-    /** For every constant pool entry, an index into buf where the
-     *  defining section of the entry is found.
-     */
-    int[] poolIdx;
+    PoolReader poolReader;
 
     /** The major version number of the class file being read. */
     int majorVersion;
@@ -323,294 +314,29 @@
     /** Read a character.
      */
     char nextChar() {
-        return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF));
+        char res = buf.getChar(bp);
+        bp += 2;
+        return res;
     }
 
     /** Read a byte.
      */
     int nextByte() {
-        return buf[bp++] & 0xFF;
+        return buf.getByte(bp++) & 0xFF;
     }
 
     /** Read an integer.
      */
     int nextInt() {
-        return
-            ((buf[bp++] & 0xFF) << 24) +
-            ((buf[bp++] & 0xFF) << 16) +
-            ((buf[bp++] & 0xFF) << 8) +
-            (buf[bp++] & 0xFF);
-    }
-
-    /** Extract a character at position bp from buf.
-     */
-    char getChar(int bp) {
-        return
-            (char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF));
-    }
-
-    /** Extract an integer at position bp from buf.
-     */
-    int getInt(int bp) {
-        return
-            ((buf[bp] & 0xFF) << 24) +
-            ((buf[bp+1] & 0xFF) << 16) +
-            ((buf[bp+2] & 0xFF) << 8) +
-            (buf[bp+3] & 0xFF);
-    }
-
-
-    /** Extract a long integer at position bp from buf.
-     */
-    long getLong(int bp) {
-        DataInputStream bufin =
-            new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
-        try {
-            return bufin.readLong();
-        } catch (IOException e) {
-            throw new AssertionError(e);
-        }
-    }
-
-    /** Extract a float at position bp from buf.
-     */
-    float getFloat(int bp) {
-        DataInputStream bufin =
-            new DataInputStream(new ByteArrayInputStream(buf, bp, 4));
-        try {
-            return bufin.readFloat();
-        } catch (IOException e) {
-            throw new AssertionError(e);
-        }
-    }
-
-    /** Extract a double at position bp from buf.
-     */
-    double getDouble(int bp) {
-        DataInputStream bufin =
-            new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
-        try {
-            return bufin.readDouble();
-        } catch (IOException e) {
-            throw new AssertionError(e);
-        }
+        int res = buf.getInt(bp);
+        bp += 4;
+        return res;
     }
 
 /************************************************************************
  * Constant Pool Access
  ***********************************************************************/
 
-    /** Index all constant pool entries, writing their start addresses into
-     *  poolIdx.
-     */
-    void indexPool() {
-        poolIdx = new int[nextChar()];
-        poolObj = new Object[poolIdx.length];
-        int i = 1;
-        while (i < poolIdx.length) {
-            poolIdx[i++] = bp;
-            byte tag = buf[bp++];
-            switch (tag) {
-            case CONSTANT_Utf8: case CONSTANT_Unicode: {
-                int len = nextChar();
-                bp = bp + len;
-                break;
-            }
-            case CONSTANT_Class:
-            case CONSTANT_String:
-            case CONSTANT_MethodType:
-            case CONSTANT_Module:
-            case CONSTANT_Package:
-                bp = bp + 2;
-                break;
-            case CONSTANT_MethodHandle:
-                bp = bp + 3;
-                break;
-            case CONSTANT_Fieldref:
-            case CONSTANT_Methodref:
-            case CONSTANT_InterfaceMethodref:
-            case CONSTANT_NameandType:
-            case CONSTANT_Integer:
-            case CONSTANT_Float:
-            case CONSTANT_Dynamic:
-            case CONSTANT_InvokeDynamic:
-                bp = bp + 4;
-                break;
-            case CONSTANT_Long:
-            case CONSTANT_Double:
-                bp = bp + 8;
-                i++;
-                break;
-            default:
-                throw badClassFile("bad.const.pool.tag.at",
-                                   Byte.toString(tag),
-                                   Integer.toString(bp -1));
-            }
-        }
-    }
-
-    /** Read constant pool entry at start address i, use pool as a cache.
-     */
-    Object readPool(int i) {
-        Object result = poolObj[i];
-        if (result != null) return result;
-
-        int index = poolIdx[i];
-        if (index == 0) return null;
-
-        byte tag = buf[index];
-        switch (tag) {
-        case CONSTANT_Utf8:
-            poolObj[i] = names.fromUtf(buf, index + 3, getChar(index + 1));
-            break;
-        case CONSTANT_Unicode:
-            throw badClassFile("unicode.str.not.supported");
-        case CONSTANT_Class:
-            poolObj[i] = readClassOrType(getChar(index + 1));
-            break;
-        case CONSTANT_String:
-            // FIXME: (footprint) do not use toString here
-            poolObj[i] = readName(getChar(index + 1)).toString();
-            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);
-            break;
-        }
-        case CONSTANT_Methodref:
-        case CONSTANT_InterfaceMethodref: {
-            ClassSymbol owner = readClassSymbol(getChar(index + 1));
-            NameAndType nt = readNameAndType(getChar(index + 3));
-            poolObj[i] = new MethodSymbol(0, nt.name, nt.uniqueType.type, owner);
-            break;
-        }
-        case CONSTANT_NameandType:
-            poolObj[i] = new NameAndType(
-                readName(getChar(index + 1)),
-                readType(getChar(index + 3)), types);
-            break;
-        case CONSTANT_Integer:
-            poolObj[i] = getInt(index + 1);
-            break;
-        case CONSTANT_Float:
-            poolObj[i] = Float.valueOf(getFloat(index + 1));
-            break;
-        case CONSTANT_Long:
-            poolObj[i] = Long.valueOf(getLong(index + 1));
-            break;
-        case CONSTANT_Double:
-            poolObj[i] = Double.valueOf(getDouble(index + 1));
-            break;
-        case CONSTANT_MethodHandle:
-            skipBytes(4);
-            break;
-        case CONSTANT_MethodType:
-            skipBytes(3);
-            break;
-        case CONSTANT_Dynamic:
-        case CONSTANT_InvokeDynamic:
-            skipBytes(5);
-            break;
-        case CONSTANT_Module:
-        case CONSTANT_Package:
-            // this is temporary for now: treat as a simple reference to the underlying Utf8.
-            poolObj[i] = readName(getChar(index + 1));
-            break;
-        default:
-            throw badClassFile("bad.const.pool.tag", Byte.toString(tag));
-        }
-        return poolObj[i];
-    }
-
-    /** Read signature and convert to type.
-     */
-    Type readType(int i) {
-        int index = poolIdx[i];
-        return sigToType(buf, index + 3, getChar(index + 1));
-    }
-
-    /** If name is an array type or class signature, return the
-     *  corresponding type; otherwise return a ClassSymbol with given name.
-     */
-    Object readClassOrType(int i) {
-        int index =  poolIdx[i];
-        int len = getChar(index + 1);
-        int start = index + 3;
-        Assert.check(buf[start] == '[' || buf[start + len - 1] != ';');
-        // by the above assertion, the following test can be
-        // simplified to (buf[start] == '[')
-        return (buf[start] == '[' || buf[start + len - 1] == ';')
-            ? (Object)sigToType(buf, start, len)
-            : (Object)enterClass(names.fromUtf(internalize(buf, start,
-                                                           len)));
-    }
-
-    /** Read signature and convert to type parameters.
-     */
-    List<Type> readTypeParams(int i) {
-        int index = poolIdx[i];
-        return sigToTypeParams(buf, index + 3, getChar(index + 1));
-    }
-
-    /** Read class entry.
-     */
-    ClassSymbol readClassSymbol(int i) {
-        Object obj = readPool(i);
-        if (obj != null && !(obj instanceof ClassSymbol))
-            throw badClassFile("bad.const.pool.entry",
-                               currentClassFile.toString(),
-                               "CONSTANT_Class_info", i);
-        return (ClassSymbol)obj;
-    }
-
-    Name readClassName(int i) {
-        int index = poolIdx[i];
-        if (index == 0) return null;
-        byte tag = buf[index];
-        if (tag != CONSTANT_Class) {
-            throw badClassFile("bad.const.pool.entry",
-                               currentClassFile.toString(),
-                               "CONSTANT_Class_info", i);
-        }
-        int nameIndex =  poolIdx[getChar(index + 1)];
-        int len = getChar(nameIndex + 1);
-        int start = nameIndex + 3;
-        if (buf[start] == '[' || buf[start + len - 1] == ';')
-            throw badClassFile("wrong class name"); //TODO: proper diagnostics
-        return names.fromUtf(internalize(buf, start, len));
-    }
-
-    /** Read name.
-     */
-    Name readName(int i) {
-        Object obj = readPool(i);
-        if (obj != null && !(obj instanceof Name))
-            throw badClassFile("bad.const.pool.entry",
-                               currentClassFile.toString(),
-                               "CONSTANT_Utf8_info or CONSTANT_String_info", i);
-        return (Name)obj;
-    }
-
-    /** Read name and type.
-     */
-    NameAndType readNameAndType(int i) {
-        Object obj = readPool(i);
-        if (obj != null && !(obj instanceof NameAndType))
-            throw badClassFile("bad.const.pool.entry",
-                               currentClassFile.toString(),
-                               "CONSTANT_NameAndType_info", i);
-        return (NameAndType)obj;
-    }
-
-    /** Read the name of a module.
-     * The name is stored in a CONSTANT_Module entry, in
-     * JVMS 4.2 binary form (using ".", not "/")
-     */
-    Name readModuleName(int i) {
-        return readName(i);
-    }
-
     /** Read module_flags.
      */
     Set<ModuleFlags> readModuleFlags(int flags) {
@@ -762,7 +488,7 @@
             List<Type> argtypes = sigToTypes(')');
             Type restype = sigToType();
             List<Type> thrown = List.nil();
-            while (signature[sigp] == '^') {
+            while (sigp < siglimit && signature[sigp] == '^') {
                 sigp++;
                 thrown = thrown.prepend(sigToType());
             }
@@ -855,7 +581,7 @@
                     };
                 switch (signature[sigp++]) {
                 case ';':
-                    if (sigp < signature.length && signature[sigp] == '.') {
+                    if (sigp < siglimit && signature[sigp] == '.') {
                         // support old-style GJC signatures
                         // The signature produced was
                         // Lfoo/Outer<Lfoo/X;>;.Lfoo/Outer$Inner<Lfoo/Y;>;
@@ -1049,7 +775,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;
@@ -1058,7 +784,7 @@
 
             new AttributeReader(names.ConstantValue, V45_3, MEMBER_ATTRIBUTE) {
                 protected void read(Symbol sym, int attrLen) {
-                    Object v = readPool(nextChar());
+                    Object v = poolReader.getConstant(nextChar());
                     // Ignore ConstantValue attribute if field not final.
                     if ((sym.flags() & FINAL) == 0) {
                         return;
@@ -1115,7 +841,7 @@
                     int nexceptions = nextChar();
                     List<Type> thrown = List.nil();
                     for (int j = 0; j < nexceptions; j++)
-                        thrown = thrown.prepend(readClassSymbol(nextChar()).type);
+                        thrown = thrown.prepend(poolReader.getClass(nextChar()).type);
                     if (sym.type.getThrownTypes().isEmpty())
                         sym.type.asMethodType().thrown = thrown.reverse();
                 }
@@ -1173,7 +899,7 @@
             new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) {
                 protected void read(Symbol sym, int attrLen) {
                     ClassSymbol c = (ClassSymbol) sym;
-                    Name n = readName(nextChar());
+                    Name n = poolReader.getName(nextChar());
                     c.sourcefile = new SourceFileObject(n);
                     // If the class is a toplevel class, originating from a Java source file,
                     // but the class name does not match the file name, then it is
@@ -1211,7 +937,8 @@
                         try {
                             ClassType ct1 = (ClassType)c.type;
                             Assert.check(c == currentOwner);
-                            ct1.typarams_field = readTypeParams(nextChar());
+                            ct1.typarams_field = poolReader.getName(nextChar())
+                                    .map(ClassReader.this::sigToTypeParams);
                             ct1.supertype_field = sigToType();
                             ListBuffer<Type> is = new ListBuffer<>();
                             while (sigp != siglimit) is.append(sigToType());
@@ -1221,7 +948,7 @@
                         }
                     } else {
                         List<Type> thrown = sym.type.getThrownTypes();
-                        sym.type = readType(nextChar());
+                        sym.type = poolReader.getType(nextChar());
                         //- System.err.println(" # " + sym.type);
                         if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty())
                             sym.type.asMethodType().thrown = thrown;
@@ -1342,19 +1069,19 @@
                         ModuleSymbol msym = (ModuleSymbol) sym.owner;
                         ListBuffer<Directive> directives = new ListBuffer<>();
 
-                        Name moduleName = readModuleName(nextChar());
+                        Name moduleName = poolReader.peekModuleName(nextChar(), names::fromUtf);
                         if (currentModule.name != moduleName) {
                             throw badClassFile("module.name.mismatch", moduleName, currentModule.name);
                         }
 
                         Set<ModuleFlags> moduleFlags = readModuleFlags(nextChar());
                         msym.flags.addAll(moduleFlags);
-                        msym.version = readName(nextChar());
+                        msym.version = optPoolEntry(nextChar(), poolReader::getName, null);
 
                         ListBuffer<RequiresDirective> requires = new ListBuffer<>();
                         int nrequires = nextChar();
                         for (int i = 0; i < nrequires; i++) {
-                            ModuleSymbol rsym = syms.enterModule(readModuleName(nextChar()));
+                            ModuleSymbol rsym = poolReader.getModule(nextChar());
                             Set<RequiresFlag> flags = readRequiresFlags(nextChar());
                             if (rsym == syms.java_base && majorVersion >= V54.major) {
                                 if (flags.contains(RequiresFlag.TRANSITIVE)) {
@@ -1373,8 +1100,7 @@
                         ListBuffer<ExportsDirective> exports = new ListBuffer<>();
                         int nexports = nextChar();
                         for (int i = 0; i < nexports; i++) {
-                            Name n = readName(nextChar());
-                            PackageSymbol p = syms.enterPackage(currentModule, names.fromUtf(internalize(n)));
+                            PackageSymbol p = poolReader.getPackage(nextChar());
                             Set<ExportsFlag> flags = readExportsFlags(nextChar());
                             int nto = nextChar();
                             List<ModuleSymbol> to;
@@ -1383,7 +1109,7 @@
                             } else {
                                 ListBuffer<ModuleSymbol> lb = new ListBuffer<>();
                                 for (int t = 0; t < nto; t++)
-                                    lb.append(syms.enterModule(readModuleName(nextChar())));
+                                    lb.append(poolReader.getModule(nextChar()));
                                 to = lb.toList();
                             }
                             exports.add(new ExportsDirective(p, to, flags));
@@ -1396,8 +1122,7 @@
                             throw badClassFile("module.non.zero.opens", currentModule.name);
                         }
                         for (int i = 0; i < nopens; i++) {
-                            Name n = readName(nextChar());
-                            PackageSymbol p = syms.enterPackage(currentModule, names.fromUtf(internalize(n)));
+                            PackageSymbol p = poolReader.getPackage(nextChar());
                             Set<OpensFlag> flags = readOpensFlags(nextChar());
                             int nto = nextChar();
                             List<ModuleSymbol> to;
@@ -1406,7 +1131,7 @@
                             } else {
                                 ListBuffer<ModuleSymbol> lb = new ListBuffer<>();
                                 for (int t = 0; t < nto; t++)
-                                    lb.append(syms.enterModule(readModuleName(nextChar())));
+                                    lb.append(poolReader.getModule(nextChar()));
                                 to = lb.toList();
                             }
                             opens.add(new OpensDirective(p, to, flags));
@@ -1419,7 +1144,7 @@
                         ListBuffer<InterimUsesDirective> uses = new ListBuffer<>();
                         int nuses = nextChar();
                         for (int i = 0; i < nuses; i++) {
-                            Name srvc = readClassName(nextChar());
+                            Name srvc = poolReader.peekClassName(nextChar(), this::classNameMapper);
                             uses.add(new InterimUsesDirective(srvc));
                         }
                         interimUses = uses.toList();
@@ -1427,17 +1152,21 @@
                         ListBuffer<InterimProvidesDirective> provides = new ListBuffer<>();
                         int nprovides = nextChar();
                         for (int p = 0; p < nprovides; p++) {
-                            Name srvc = readClassName(nextChar());
+                            Name srvc = poolReader.peekClassName(nextChar(), this::classNameMapper);
                             int nimpls = nextChar();
                             ListBuffer<Name> impls = new ListBuffer<>();
                             for (int i = 0; i < nimpls; i++) {
-                                impls.append(readClassName(nextChar()));
+                                impls.append(poolReader.peekClassName(nextChar(), this::classNameMapper));
                             provides.add(new InterimProvidesDirective(srvc, impls.toList()));
                             }
                         }
                         interimProvides = provides.toList();
                     }
                 }
+
+                private Name classNameMapper(byte[] arr, int offset, int length) {
+                    return names.fromUtf(ClassFile.internalize(arr, offset, length));
+                }
             },
 
             new AttributeReader(names.ModuleResolution, V53, CLASS_ATTRIBUTE) {
@@ -1464,8 +1193,8 @@
         // the scope specified by the attribute
         sym.owner.members().remove(sym);
         ClassSymbol self = (ClassSymbol)sym;
-        ClassSymbol c = readClassSymbol(nextChar());
-        NameAndType nt = readNameAndType(nextChar());
+        ClassSymbol c = poolReader.getClass(nextChar());
+        NameAndType nt = optPoolEntry(nextChar(), poolReader::getNameAndType, null);
 
         if (c.members_field == null || c.kind != TYP)
             throw badClassFile("bad.enclosing.class", self, c);
@@ -1520,7 +1249,7 @@
         if (nt == null)
             return null;
 
-        MethodType type = nt.uniqueType.type.asMethodType();
+        MethodType type = nt.type.asMethodType();
 
         for (Symbol sym : scope.getSymbolsByName(nt.name)) {
             if (sym.kind == MTH && isSameBinaryType(sym.type.asMethodType(), type))
@@ -1533,15 +1262,15 @@
         if ((flags & INTERFACE) != 0)
             // no enclosing instance
             return null;
-        if (nt.uniqueType.type.getParameterTypes().isEmpty())
+        if (nt.type.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 NameAndType(nt.name, new MethodType(nt.type.getParameterTypes().tail,
+                                 nt.type.getReturnType(),
+                                 nt.type.getThrownTypes(),
                                  syms.methodClass));
         // Try searching again
         return findMethod(nt, scope, flags);
@@ -1578,7 +1307,7 @@
     void readAttrs(Symbol sym, AttributeKind kind) {
         char ac = nextChar();
         for (int i = 0; i < ac; i++) {
-            Name attrName = readName(nextChar());
+            Name attrName = poolReader.getName(nextChar());
             int attrLen = nextInt();
             AttributeReader r = attributeReaders.get(attrName);
             if (r != null && r.accepts(kind))
@@ -1681,7 +1410,7 @@
     /** Read parameter annotations.
      */
     void readParameterAnnotations(Symbol meth) {
-        int numParameters = buf[bp++] & 0xFF;
+        int numParameters = buf.getByte(bp++) & 0xFF;
         if (parameterAnnotations == null) {
             parameterAnnotations = new ParameterAnnotations[numParameters];
         } else if (parameterAnnotations.length != numParameters) {
@@ -1725,39 +1454,30 @@
 
     Type readTypeOrClassSymbol(int i) {
         // support preliminary jsr175-format class files
-        if (buf[poolIdx[i]] == CONSTANT_Class)
-            return readClassSymbol(i).type;
-        return readTypeToProxy(i);
-    }
-    Type readEnumType(int i) {
-        // support preliminary jsr175-format class files
-        int index = poolIdx[i];
-        int length = getChar(index + 1);
-        if (buf[index + length + 2] != ';')
-            return enterClass(readName(i)).type;
+        if (poolReader.hasTag(i, CONSTANT_Class))
+            return poolReader.getClass(i).type;
         return readTypeToProxy(i);
     }
     Type readTypeToProxy(int i) {
         if (currentModule.module_info == currentOwner) {
-            int index = poolIdx[i];
-            return new ProxyType(Arrays.copyOfRange(buf, index + 3, index + 3 + getChar(index + 1)));
+            return new ProxyType(i);
         } else {
-            return readType(i);
+            return poolReader.getType(i);
         }
     }
 
     CompoundAnnotationProxy readCompoundAnnotation() {
         Type t;
         if (currentModule.module_info == currentOwner) {
-            int index = poolIdx[nextChar()];
-            t = new ProxyType(Arrays.copyOfRange(buf, index + 3, index + 3 + getChar(index + 1)));
+            int cpIndex = nextChar();
+            t = new ProxyType(cpIndex);
         } else {
             t = readTypeOrClassSymbol(nextChar());
         }
         int numFields = nextChar();
         ListBuffer<Pair<Name,Attribute>> pairs = new ListBuffer<>();
         for (int i=0; i<numFields; i++) {
-            Name name = readName(nextChar());
+            Name name = poolReader.getName(nextChar());
             Attribute value = readAttributeValue();
             pairs.append(new Pair<>(name, value));
         }
@@ -1970,29 +1690,40 @@
 
     }
 
+    /**
+     * Helper function to read an optional pool entry (with given function); this is used while parsing
+     * InnerClasses and EnclosingMethod attributes, as well as when parsing supertype descriptor,
+     * as per JVMS.
+     */
+    <Z> Z optPoolEntry(int index, IntFunction<Z> poolFunc, Z defaultValue) {
+        return (index == 0) ?
+                defaultValue :
+                poolFunc.apply(index);
+    }
+
     Attribute readAttributeValue() {
-        char c = (char) buf[bp++];
+        char c = (char) buf.getByte(bp++);
         switch (c) {
         case 'B':
-            return new Attribute.Constant(syms.byteType, readPool(nextChar()));
+            return new Attribute.Constant(syms.byteType, poolReader.getConstant(nextChar()));
         case 'C':
-            return new Attribute.Constant(syms.charType, readPool(nextChar()));
+            return new Attribute.Constant(syms.charType, poolReader.getConstant(nextChar()));
         case 'D':
-            return new Attribute.Constant(syms.doubleType, readPool(nextChar()));
+            return new Attribute.Constant(syms.doubleType, poolReader.getConstant(nextChar()));
         case 'F':
-            return new Attribute.Constant(syms.floatType, readPool(nextChar()));
+            return new Attribute.Constant(syms.floatType, poolReader.getConstant(nextChar()));
         case 'I':
-            return new Attribute.Constant(syms.intType, readPool(nextChar()));
+            return new Attribute.Constant(syms.intType, poolReader.getConstant(nextChar()));
         case 'J':
-            return new Attribute.Constant(syms.longType, readPool(nextChar()));
+            return new Attribute.Constant(syms.longType, poolReader.getConstant(nextChar()));
         case 'S':
-            return new Attribute.Constant(syms.shortType, readPool(nextChar()));
+            return new Attribute.Constant(syms.shortType, poolReader.getConstant(nextChar()));
         case 'Z':
-            return new Attribute.Constant(syms.booleanType, readPool(nextChar()));
+            return new Attribute.Constant(syms.booleanType, poolReader.getConstant(nextChar()));
         case 's':
-            return new Attribute.Constant(syms.stringType, readPool(nextChar()).toString());
+            return new Attribute.Constant(syms.stringType, poolReader.getName(nextChar()).toString());
         case 'e':
-            return new EnumAttributeProxy(readEnumType(nextChar()), readName(nextChar()));
+            return new EnumAttributeProxy(readTypeToProxy(nextChar()), poolReader.getName(nextChar()));
         case 'c':
             return new ClassAttributeProxy(readTypeOrClassSymbol(nextChar()));
         case '[': {
@@ -2401,8 +2132,8 @@
      */
     VarSymbol readField() {
         long flags = adjustFieldFlags(nextChar());
-        Name name = readName(nextChar());
-        Type type = readType(nextChar());
+        Name name = poolReader.getName(nextChar());
+        Type type = poolReader.getType(nextChar());
         VarSymbol v = new VarSymbol(flags, name, type, currentOwner);
         readMemberAttrs(v);
         return v;
@@ -2412,8 +2143,8 @@
      */
     MethodSymbol readMethod() {
         long flags = adjustMethodFlags(nextChar());
-        Name name = readName(nextChar());
-        Type type = readType(nextChar());
+        Name name = poolReader.getName(nextChar());
+        Type type = poolReader.getType(nextChar());
         if (currentOwner.isInterface() &&
                 (flags & ABSTRACT) == 0 && !name.equals(names.clinit)) {
             if (majorVersion > Version.V52.major ||
@@ -2592,7 +2323,7 @@
         Name argName;
         if (parameterNameIndices != null && index < parameterNameIndices.length
                 && parameterNameIndices[index] != 0) {
-            argName = readName(parameterNameIndices[index]);
+            argName = optPoolEntry(parameterNameIndices[index], poolReader::getName, names.empty);
             flags |= NAME_FILLED;
         } else {
             String prefix = "arg";
@@ -2681,7 +2412,7 @@
             if (c.owner.kind == PCK || c.owner.kind == ERR) c.flags_field = flags;
             // read own class name and check that it matches
             currentModule = c.packge().modle;
-            ClassSymbol self = readClassSymbol(nextChar());
+            ClassSymbol self = poolReader.getClass(nextChar());
             if (c != self) {
                 throw badClassFile("class.file.wrong.class",
                                    self.flatname);
@@ -2710,11 +2441,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);
-        }
-
         // reset and read rest of classinfo
         bp = startbp;
         int n = nextChar();
@@ -2722,13 +2448,12 @@
             throw badClassFile("module.info.invalid.super.class");
         }
         if (ct.supertype_field == null)
-            ct.supertype_field = (n == 0)
-                ? Type.noType
-                : readClassSymbol(n).erasure(types);
+            ct.supertype_field =
+                    optPoolEntry(n, idx -> poolReader.getClass(idx).erasure(types), Type.noType);
         n = nextChar();
         List<Type> is = List.nil();
         for (int i = 0; i < n; i++) {
-            Type _inter = readClassSymbol(nextChar()).erasure(types);
+            Type _inter = poolReader.getClass(nextChar()).erasure(types);
             is = is.prepend(_inter);
         }
         if (ct.interfaces_field == null)
@@ -2749,8 +2474,10 @@
         int n = nextChar();
         for (int i = 0; i < n; i++) {
             nextChar(); // skip inner class symbol
-            ClassSymbol outer = readClassSymbol(nextChar());
-            Name name = readName(nextChar());
+            int outerIdx = nextChar();
+            int nameIdx = nextChar();
+            ClassSymbol outer = optPoolEntry(outerIdx, poolReader::getClass, null);
+            Name name = optPoolEntry(nameIdx, poolReader::getName, names.empty);
             if (name == null) name = names.empty;
             long flags = adjustClassFlags(nextChar());
             if (outer != null) { // we have a member class
@@ -2804,7 +2531,8 @@
             }
         }
 
-        indexPool();
+        poolReader = new PoolReader(this, names, syms);
+        bp = poolReader.readPool(buf, bp);
         if (signatureBuffer.length < bp) {
             int ns = Integer.highestOneBit(bp) << 1;
             signatureBuffer = new byte[ns];
@@ -2821,7 +2549,8 @@
         repeatable = null;
         try {
             bp = 0;
-            buf = readInputStream(buf, c.classfile.openInputStream());
+            buf.reset();
+            buf.appendStream(c.classfile.openInputStream());
             readClassBuffer(c);
             if (!missingTypeVariables.isEmpty() && !foundTypeVariables.isEmpty()) {
                 List<Type> missing = missingTypeVariables;
@@ -2875,43 +2604,6 @@
             filling = false;
         }
     }
-    // where
-        private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException {
-            try {
-                buf = ensureCapacity(buf, s.available());
-                int r = s.read(buf);
-                int bp = 0;
-                while (r != -1) {
-                    bp += r;
-                    buf = ensureCapacity(buf, bp);
-                    r = s.read(buf, bp, buf.length - bp);
-                }
-                return buf;
-            } finally {
-                try {
-                    s.close();
-                } catch (IOException e) {
-                    /* Ignore any errors, as this stream may have already
-                     * thrown a related exception which is the one that
-                     * should be reported.
-                     */
-                }
-            }
-        }
-        /*
-         * ensureCapacity will increase the buffer as needed, taking note that
-         * the new buffer will always be greater than the needed and never
-         * exactly equal to the needed size or bp. If equal then the read (above)
-         * will infinitely loop as buf.length - bp == 0.
-         */
-        private static byte[] ensureCapacity(byte[] buf, int needed) {
-            if (buf.length <= needed) {
-                byte[] old = buf;
-                buf = new byte[Integer.highestOneBit(needed) << 1];
-                System.arraycopy(old, 0, buf, 0, old.length);
-            }
-            return buf;
-        }
 
     /** We can only read a single class file at a time; this
      *  flag keeps track of when we are currently reading a class
@@ -3098,11 +2790,11 @@
 
     private class ProxyType extends Type {
 
-        private final byte[] content;
+        private final Name name;
 
-        public ProxyType(byte[] content) {
+        public ProxyType(int index) {
             super(syms.noSymbol, TypeMetadata.EMPTY);
-            this.content = content;
+            this.name = poolReader.getName(index);
         }
 
         @Override
@@ -3116,7 +2808,7 @@
         }
 
         public Type resolve() {
-            return sigToType(content, 0, content.length);
+            return name.map(ClassReader.this::sigToType);
         }
 
         @Override @DefinedBy(Api.LANGUAGE_MODEL)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Wed Apr 17 15:37:20 2019 +0100
@@ -29,9 +29,7 @@
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
-import java.util.HashSet;
 import java.util.LinkedHashSet;
-import java.util.stream.Collectors;
 
 import javax.tools.JavaFileManager;
 import javax.tools.FileObject;
@@ -44,13 +42,10 @@
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
-import com.sun.tools.javac.code.Types.UniqueType;
 import com.sun.tools.javac.comp.Check;
 import com.sun.tools.javac.file.PathFileObject;
-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.Variable;
+import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
+import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.util.*;
@@ -121,7 +116,7 @@
      *  Sizes are increased when buffers get full.
      */
     static final int DATA_BUF_SIZE = 0x0fff0;
-    static final int POOL_BUF_SIZE = 0x1fff0;
+    static final int CLASS_BUF_SIZE = 0x1fff0;
 
     /** An output buffer for member info.
      */
@@ -129,25 +124,11 @@
 
     /** An output buffer for the constant pool.
      */
-    ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
-
-    /** The constant pool.
-     */
-    Pool pool;
-
-    /** The inner classes to be written, as a set.
-     */
-    Set<ClassSymbol> innerClasses;
+    ByteBuffer poolbuf = new ByteBuffer(CLASS_BUF_SIZE);
 
-    /** The inner classes to be written, as a queue where
-     *  enclosing classes come first.
+    /** The constant pool writer.
      */
-    ListBuffer<ClassSymbol> innerClassesQueue;
-
-    /** The bootstrap methods to be written in the corresponding class attribute
-     *  (one for each invokedynamic)
-     */
-    Map<DynamicMethod.BootstrapMethodsKey, DynamicMethod.BootstrapMethodsValue> bootstrapMethods;
+    final PoolWriter poolWriter;
 
     /** The log to use for verbose output.
      */
@@ -159,9 +140,6 @@
     /** Access to files. */
     private final JavaFileManager fileManager;
 
-    /** Sole signature generator */
-    private final CWSignatureGenerator signatureGen;
-
     /** The tags and constants used in compressed stackmap. */
     static final int SAME_FRAME_SIZE = 64;
     static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
@@ -191,7 +169,7 @@
         types = Types.instance(context);
         check = Check.instance(context);
         fileManager = context.get(JavaFileManager.class);
-        signatureGen = new CWSignatureGenerator(types);
+        poolWriter = Gen.instance(context).poolWriter;
 
         verbose        = options.isSet(VERBOSE);
         genCrt         = options.isSet(XJCOV);
@@ -272,108 +250,17 @@
         buf.elems[adr+3] = (byte)((x      ) & 0xFF);
     }
 
-    /**
-     * Signature Generation
-     */
-    private class CWSignatureGenerator extends Types.SignatureGenerator {
-
-        /**
-         * An output buffer for type signatures.
-         */
-        ByteBuffer sigbuf = new ByteBuffer();
-
-        CWSignatureGenerator(Types types) {
-            super(types);
-        }
-
-        /**
-         * Assemble signature of given type in string buffer.
-         * Check for uninitialized types before calling the general case.
-         */
-        @Override
-        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));
-                    break;
-                default:
-                    super.assembleSig(type);
-            }
-        }
-
-        @Override
-        protected void append(char ch) {
-            sigbuf.appendByte(ch);
-        }
-
-        @Override
-        protected void append(byte[] ba) {
-            sigbuf.appendBytes(ba);
-        }
-
-        @Override
-        protected void append(Name name) {
-            sigbuf.appendName(name);
-        }
-
-        @Override
-        protected void classReference(ClassSymbol c) {
-            enterInner(c);
-        }
-
-        private void reset() {
-            sigbuf.reset();
-        }
-
-        private Name toName() {
-            return sigbuf.toName(names);
-        }
-
-        private boolean isEmpty() {
-            return sigbuf.length == 0;
-        }
-    }
-
-    /**
-     * Return signature of given type
-     */
-    Name typeSig(Type type) {
-        Assert.check(signatureGen.isEmpty());
-        //- System.out.println(" ? " + type);
-        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
  ******************************************************************/
 
     /** Thrown when the constant pool is over full.
      */
-    public static class PoolOverflow extends Exception {
+    public static class PoolOverflow extends RuntimeException {
         private static final long serialVersionUID = 0;
         public PoolOverflow() {}
     }
-    public static class StringOverflow extends Exception {
+    public static class StringOverflow extends RuntimeException {
         private static final long serialVersionUID = 0;
         public final String value;
         public StringOverflow(String s) {
@@ -381,137 +268,6 @@
         }
     }
 
-    /** Write constant pool to pool buffer.
-     *  Note: during writing, constant pool
-     *  might grow since some parts of constants still need to be entered.
-     */
-    void writePool(Pool pool) throws PoolOverflow, StringOverflow {
-        int poolCountIdx = poolbuf.length;
-        poolbuf.appendChar(0);
-        int i = 1;
-        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 (Object staticArg : dynSym.staticArgs) {
-                        pool.put(staticArg);
-                    }
-                    poolbuf.appendByte(CONSTANT_InvokeDynamic);
-                    poolbuf.appendChar(val.index);
-                    poolbuf.appendChar(pool.put(nameType(dynSym)));
-                }
-            } 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 NameAndType) {
-                NameAndType nt = (NameAndType)value;
-                poolbuf.appendByte(CONSTANT_NameandType);
-                poolbuf.appendChar(pool.put(nt.name));
-                poolbuf.appendChar(pool.put(typeSig(nt.uniqueType.type)));
-            } 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 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 if (value instanceof ModuleSymbol) {
-                ModuleSymbol m = (ModuleSymbol)value;
-                poolbuf.appendByte(CONSTANT_Module);
-                poolbuf.appendChar(pool.put(m.name));
-            } else if (value instanceof PackageSymbol) {
-                PackageSymbol m = (PackageSymbol)value;
-                poolbuf.appendByte(CONSTANT_Package);
-                poolbuf.appendChar(pool.put(names.fromUtf(externalize(m.fullname))));
-            } else {
-                Assert.error("writePool " + value);
-            }
-            i++;
-        }
-        if (pool.pp > Pool.MAX_ENTRIES)
-            throw new PoolOverflow();
-        putChar(poolbuf, poolCountIdx, pool.pp);
-    }
-
-    /** Given a symbol, return its name-and-type.
-     */
-    NameAndType nameType(Symbol sym) {
-        return new NameAndType(sym.name, sym.externalType(types), types);
-        // the NameAndType is generated from a symbol reference, and the
-        // adjustment of adding an additional this$n parameter needs to be made.
-    }
-
 /******************************************************************
  * Writing Attributes
  ******************************************************************/
@@ -520,7 +276,8 @@
      *  position past attribute length index.
      */
     int writeAttr(Name attrName) {
-        databuf.appendChar(pool.put(attrName));
+        int index = poolWriter.putName(attrName);
+        databuf.appendChar(index);
         databuf.appendInt(0);
         return databuf.length;
     }
@@ -567,8 +324,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.putClass(enclClass));
+        databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(c.owner));
         endAttr(alenIdx);
         return 1;
     }
@@ -594,11 +351,11 @@
         if ((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC &&
             (flags & ANONCONSTR) == 0 &&
             (!types.isSameType(sym.type, sym.erasure(types)) ||
-             signatureGen.hasTypeVar(sym.type.getThrownTypes()))) {
+             poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()))) {
             // note that a local class with captured variables
             // will get a signature attribute
             int alenIdx = writeAttr(names.Signature);
-            databuf.appendChar(pool.put(typeSig(sym.type)));
+            databuf.appendChar(poolWriter.putSignature(sym));
             endAttr(alenIdx);
             acount++;
         }
@@ -621,7 +378,7 @@
                 final int flags =
                     ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
                     ((int) m.flags() & SYNTHETIC);
-                databuf.appendChar(pool.put(s.name));
+                databuf.appendChar(poolWriter.putName(s.name));
                 databuf.appendChar(flags);
             }
             // Now write the real parameters
@@ -629,7 +386,7 @@
                 final int flags =
                     ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
                     ((int) m.flags() & SYNTHETIC);
-                databuf.appendChar(pool.put(s.name));
+                databuf.appendChar(poolWriter.putName(s.name));
                 databuf.appendChar(flags);
             }
             // Now write the captured locals
@@ -637,7 +394,7 @@
                 final int flags =
                     ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
                     ((int) m.flags() & SYNTHETIC);
-                databuf.appendChar(pool.put(s.name));
+                databuf.appendChar(poolWriter.putName(s.name));
                 databuf.appendChar(flags);
             }
             endAttr(attrIndex);
@@ -803,50 +560,51 @@
      */
     class AttributeWriter implements Attribute.Visitor {
         public void visitConstant(Attribute.Constant _value) {
-            Object value = _value.value;
-            switch (_value.type.getTag()) {
-            case BYTE:
-                databuf.appendByte('B');
-                break;
-            case CHAR:
-                databuf.appendByte('C');
-                break;
-            case SHORT:
-                databuf.appendByte('S');
-                break;
-            case INT:
-                databuf.appendByte('I');
-                break;
-            case LONG:
-                databuf.appendByte('J');
-                break;
-            case FLOAT:
-                databuf.appendByte('F');
-                break;
-            case DOUBLE:
-                databuf.appendByte('D');
-                break;
-            case BOOLEAN:
-                databuf.appendByte('Z');
-                break;
-            case CLASS:
-                Assert.check(value instanceof String);
+            if (_value.type.getTag() == CLASS) {
+                Assert.check(_value.value instanceof String);
+                String s = (String)_value.value;
                 databuf.appendByte('s');
-                value = names.fromString(value.toString()); // CONSTANT_Utf8
-                break;
-            default:
-                throw new AssertionError(_value.type);
+                databuf.appendChar(poolWriter.putName(names.fromString(s)));
+            } else {
+                switch (_value.type.getTag()) {
+                    case BYTE:
+                        databuf.appendByte('B');
+                        break;
+                    case CHAR:
+                        databuf.appendByte('C');
+                        break;
+                    case SHORT:
+                        databuf.appendByte('S');
+                        break;
+                    case INT:
+                        databuf.appendByte('I');
+                        break;
+                    case LONG:
+                        databuf.appendByte('J');
+                        break;
+                    case FLOAT:
+                        databuf.appendByte('F');
+                        break;
+                    case DOUBLE:
+                        databuf.appendByte('D');
+                        break;
+                    case BOOLEAN:
+                        databuf.appendByte('Z');
+                        break;
+                    default:
+                        throw new AssertionError(_value.type);
+                }
+                databuf.appendChar(poolWriter.putConstant(_value.value));
             }
-            databuf.appendChar(pool.put(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.putDescriptor(e.value.type));
+            databuf.appendChar(poolWriter.putName(e.value.name));
         }
         public void visitClass(Attribute.Class clazz) {
             databuf.appendByte('c');
-            databuf.appendChar(pool.put(typeSig(types.erasure(clazz.classType))));
+            databuf.appendChar(poolWriter.putDescriptor(clazz.classType));
         }
         public void visitCompound(Attribute.Compound compound) {
             databuf.appendByte('@');
@@ -867,10 +625,10 @@
 
     /** Write a compound attribute excluding the '@' marker. */
     void writeCompoundAttribute(Attribute.Compound c) {
-        databuf.appendChar(pool.put(typeSig(c.type)));
+        databuf.appendChar(poolWriter.putDescriptor(c.type));
         databuf.appendChar(c.values.length());
         for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) {
-            databuf.appendChar(pool.put(p.fst.name));
+            databuf.appendChar(poolWriter.putName(p.fst.name));
             p.snd.accept(awriter);
         }
     }
@@ -974,9 +732,9 @@
 
         int alenIdx = writeAttr(names.Module);
 
-        databuf.appendChar(pool.put(m));
+        databuf.appendChar(poolWriter.putModule(m));
         databuf.appendChar(ModuleFlags.value(m.flags)); // module_flags
-        databuf.appendChar(m.version != null ? pool.put(m.version) : 0);
+        databuf.appendChar(m.version != null ? poolWriter.putName(m.version) : 0);
 
         ListBuffer<RequiresDirective> requires = new ListBuffer<>();
         for (RequiresDirective r: m.requires) {
@@ -985,22 +743,22 @@
         }
         databuf.appendChar(requires.size());
         for (RequiresDirective r: requires) {
-            databuf.appendChar(pool.put(r.module));
+            databuf.appendChar(poolWriter.putModule(r.module));
             databuf.appendChar(RequiresFlag.value(r.flags));
-            databuf.appendChar(r.module.version != null ? pool.put(r.module.version) : 0);
+            databuf.appendChar(r.module.version != null ? poolWriter.putName(r.module.version) : 0);
         }
 
         List<ExportsDirective> exports = m.exports;
         databuf.appendChar(exports.size());
         for (ExportsDirective e: exports) {
-            databuf.appendChar(pool.put(e.packge));
+            databuf.appendChar(poolWriter.putPackage(e.packge));
             databuf.appendChar(ExportsFlag.value(e.flags));
             if (e.modules == null) {
                 databuf.appendChar(0);
             } else {
                 databuf.appendChar(e.modules.size());
                 for (ModuleSymbol msym: e.modules) {
-                    databuf.appendChar(pool.put(msym));
+                    databuf.appendChar(poolWriter.putModule(msym));
                 }
             }
         }
@@ -1008,14 +766,14 @@
         List<OpensDirective> opens = m.opens;
         databuf.appendChar(opens.size());
         for (OpensDirective o: opens) {
-            databuf.appendChar(pool.put(o.packge));
+            databuf.appendChar(poolWriter.putPackage(o.packge));
             databuf.appendChar(OpensFlag.value(o.flags));
             if (o.modules == null) {
                 databuf.appendChar(0);
             } else {
                 databuf.appendChar(o.modules.size());
                 for (ModuleSymbol msym: o.modules) {
-                    databuf.appendChar(pool.put(msym));
+                    databuf.appendChar(poolWriter.putModule(msym));
                 }
             }
         }
@@ -1023,7 +781,7 @@
         List<UsesDirective> uses = m.uses;
         databuf.appendChar(uses.size());
         for (UsesDirective s: uses) {
-            databuf.appendChar(pool.put(s.service));
+            databuf.appendChar(poolWriter.putClass(s.service));
         }
 
         // temporary fix to merge repeated provides clause for same service;
@@ -1035,9 +793,9 @@
         }
         databuf.appendChar(mergedProvides.size());
         mergedProvides.forEach((srvc, impls) -> {
-            databuf.appendChar(pool.put(srvc));
+            databuf.appendChar(poolWriter.putClass(srvc));
             databuf.appendChar(impls.size());
-            impls.forEach(impl -> databuf.appendChar(pool.put(impl)));
+            impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl)));
         });
 
         endAttr(alenIdx);
@@ -1048,46 +806,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);
             char flags = (char) adjustFlags(inner.flags_field);
             if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT
@@ -1097,11 +821,11 @@
                 pw.println("INNERCLASS  " + inner.name);
                 pw.println("---" + flagNames(flags));
             }
-            databuf.appendChar(pool.get(inner));
+            databuf.appendChar(poolWriter.putClass(inner));
             databuf.appendChar(
-                inner.owner.kind == TYP && !inner.name.isEmpty() ? pool.get(inner.owner) : 0);
+                inner.owner.kind == TYP && !inner.name.isEmpty() ? poolWriter.putClass((ClassSymbol)inner.owner) : 0);
             databuf.appendChar(
-                !inner.name.isEmpty() ? pool.get(inner.name) : 0);
+                !inner.name.isEmpty() ? poolWriter.putName(inner.name) : 0);
             databuf.appendChar(flags);
         }
         endAttr(alenIdx);
@@ -1111,14 +835,14 @@
      * Write NestMembers attribute (if needed)
      */
     int writeNestMembersIfNeeded(ClassSymbol csym) {
-        ListBuffer<Symbol> nested = new ListBuffer<>();
+        ListBuffer<ClassSymbol> nested = new ListBuffer<>();
         listNested(csym, nested);
-        Set<Symbol> nestedUnique = new LinkedHashSet<>(nested);
+        Set<ClassSymbol> nestedUnique = new LinkedHashSet<>(nested);
         if (csym.owner.kind == PCK && !nestedUnique.isEmpty()) {
             int alenIdx = writeAttr(names.NestMembers);
             databuf.appendChar(nestedUnique.size());
-            for (Symbol s : nestedUnique) {
-                databuf.appendChar(pool.put(s));
+            for (ClassSymbol s : nestedUnique) {
+                databuf.appendChar(poolWriter.putClass(s));
             }
             endAttr(alenIdx);
             return 1;
@@ -1132,14 +856,14 @@
     int writeNestHostIfNeeded(ClassSymbol csym) {
         if (csym.owner.kind != PCK) {
             int alenIdx = writeAttr(names.NestHost);
-            databuf.appendChar(pool.put(csym.outermostClass()));
+            databuf.appendChar(poolWriter.putClass(csym.outermostClass()));
             endAttr(alenIdx);
             return 1;
         }
         return 0;
     }
 
-    private void listNested(Symbol sym, ListBuffer<Symbol> seen) {
+    private void listNested(Symbol sym, ListBuffer<ClassSymbol> seen) {
         if (sym.kind != TYP) return;
         ClassSymbol csym = (ClassSymbol)sym;
         if (csym.owner.kind != PCK) {
@@ -1161,17 +885,16 @@
      */
     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 (BsmKey bsmKey : poolWriter.bootstrapMethods.keySet()) {
             //write BSM handle
-            databuf.appendChar(pool.get(entry.getValue().mh));
-            Object[] uniqueArgs = bsmKey.getUniqueArgs();
+            databuf.appendChar(poolWriter.putConstant(bsmKey.bsm));
+            LoadableConstant[] 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 (LoadableConstant arg : uniqueArgs) {
+                databuf.appendChar(poolWriter.putConstant(arg));
             }
         }
         endAttr(alenIdx);
@@ -1187,13 +910,13 @@
             pw.println("FIELD  " + v.name);
             pw.println("---" + flagNames(v.flags()));
         }
-        databuf.appendChar(pool.put(v.name));
-        databuf.appendChar(pool.put(typeSig(v.erasure(types))));
+        databuf.appendChar(poolWriter.putName(v.name));
+        databuf.appendChar(poolWriter.putDescriptor(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++;
         }
@@ -1211,8 +934,8 @@
             pw.println("METHOD  " + m.name);
             pw.println("---" + flagNames(m.flags()));
         }
-        databuf.appendChar(pool.put(m.name));
-        databuf.appendChar(pool.put(typeSig(m.externalType(types))));
+        databuf.appendChar(poolWriter.putName(m.name));
+        databuf.appendChar(poolWriter.putDescriptor(m));
         int acountIdx = beginAttrs();
         int acount = 0;
         if (m.code != null) {
@@ -1227,7 +950,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.putClass(l.head));
             endAttr(alenIdx);
             acount++;
         }
@@ -1303,9 +1026,8 @@
                             && (r.start_pc + r.length) <= code.cp);
                     databuf.appendChar(r.length);
                     VarSymbol sym = var.sym;
-                    databuf.appendChar(pool.put(sym.name));
-                    Type vartype = sym.erasure(types);
-                    databuf.appendChar(pool.put(typeSig(vartype)));
+                    databuf.appendChar(poolWriter.putName(sym.name));
+                    databuf.appendChar(poolWriter.putDescriptor(sym));
                     databuf.appendChar(var.reg);
                     if (needsLocalVariableTypeEntry(var.sym.type)) {
                         nGenericVars++;
@@ -1329,8 +1051,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.putName(sym.name));
+                        databuf.appendChar(poolWriter.putSignature(sym));
                         databuf.appendChar(var.reg);
                         count++;
                     }
@@ -1457,14 +1179,10 @@
                 break;
             case CLASS:
             case ARRAY:
-                if (debugstackmap) System.out.print("object(" + t + ")");
-                databuf.appendByte(7);
-                databuf.appendChar(pool.put(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.putClass(types.erasure(t)));
                 break;
             case UNINITIALIZED_THIS:
                 if (debugstackmap) System.out.print("uninit_this");
@@ -1763,11 +1481,6 @@
         Assert.check((c.flags() & COMPOUND) == 0);
         databuf.reset();
         poolbuf.reset();
-        signatureGen.reset();
-        pool = c.pool;
-        innerClasses = null;
-        innerClassesQueue = null;
-        bootstrapMethods = new LinkedHashMap<>();
 
         Type supertype = types.supertype(c.type);
         List<Type> interfaces = types.interfaces(c.type);
@@ -1793,14 +1506,14 @@
 
         if (c.owner.kind == MDL) {
             PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage;
-            databuf.appendChar(pool.put(new ClassSymbol(0, names.module_info, unnamed)));
+            databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed)));
         } else {
-            databuf.appendChar(pool.put(c));
+            databuf.appendChar(poolWriter.putClass(c));
         }
-        databuf.appendChar(supertype.hasTag(CLASS) ? pool.put(supertype.tsym) : 0);
+        databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0);
         databuf.appendChar(interfaces.length());
         for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
-            databuf.appendChar(pool.put(l.head.tsym));
+            databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym));
         int fieldsCount = 0;
         int methodsCount = 0;
         for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
@@ -1808,14 +1521,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);
             }
         }
 
@@ -1833,12 +1546,7 @@
             sigReq = l.head.allparams().length() != 0;
         if (sigReq) {
             int alenIdx = writeAttr(names.Signature);
-            if (typarams.length() != 0) signatureGen.assembleParamsSig(typarams);
-            signatureGen.assembleSig(supertype);
-            for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
-                signatureGen.assembleSig(l.head);
-            databuf.appendChar(pool.put(signatureGen.toName()));
-            signatureGen.reset();
+            databuf.appendChar(poolWriter.putSignature(c));
             endAttr(alenIdx);
             acount++;
         }
@@ -1848,9 +1556,8 @@
             // 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));
             String simpleName = PathFileObject.getSimpleName(c.sourcefile);
-            databuf.appendChar(c.pool.put(names.fromString(simpleName)));
+            databuf.appendChar(poolWriter.putName(names.fromString(simpleName)));
             endAttr(alenIdx);
             acount++;
         }
@@ -1858,12 +1565,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(poolWriter.putName(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(poolWriter.putName(names.fromString(Long.toString(System.currentTimeMillis()))));
             endAttr(alenIdx);
             acount++;
         }
@@ -1893,24 +1600,24 @@
             }
         }
 
-        writePool(c.pool);
-
-        if (innerClasses != null) {
-            writeInnerClasses();
+        if (!poolWriter.bootstrapMethods.isEmpty()) {
+            writeBootstrapMethods();
             acount++;
         }
 
-        if (!bootstrapMethods.isEmpty()) {
-            writeBootstrapMethods();
+        if (!poolWriter.innerClasses.isEmpty()) {
+            writeInnerClasses();
             acount++;
         }
 
         endAttrs(acountIdx, acount);
 
-        poolbuf.appendBytes(databuf.elems, 0, databuf.length);
         out.write(poolbuf.elems, 0, poolbuf.length);
 
-        pool = c.pool = null; // to conserve space
+        poolWriter.writePool(out);
+        poolWriter.reset(); // to save space
+
+        out.write(databuf.elems, 0, databuf.length);
      }
 
     /**Allows subclasses to write additional class attributes
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Wed Apr 17 15:37:20 2019 +0100
@@ -27,15 +27,27 @@
 
 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.resources.CompilerProperties.Errors;
-import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 
+import java.util.function.ToIntBiFunction;
+import java.util.function.ToIntFunction;
+
 import static com.sun.tools.javac.code.TypeTag.BOT;
 import static com.sun.tools.javac.code.TypeTag.INT;
 import static com.sun.tools.javac.jvm.ByteCodes.*;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
 import static com.sun.tools.javac.jvm.UninitializedType.*;
 import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
 
@@ -72,6 +84,7 @@
 
     final Types types;
     final Symtab syms;
+    final PoolWriter poolWriter;
 
 /*---------- classfile fields: --------------- */
 
@@ -177,10 +190,6 @@
      */
     Position.LineMap lineMap;
 
-    /** The constant pool of the current class.
-     */
-    final Pool pool;
-
     final MethodSymbol meth;
 
     private int letExprStackPos = 0;
@@ -197,7 +206,7 @@
                 CRTable crt,
                 Symtab syms,
                 Types types,
-                Pool pool) {
+                PoolWriter poolWriter) {
         this.meth = meth;
         this.fatcode = fatcode;
         this.lineMap = lineMap;
@@ -206,6 +215,7 @@
         this.crt = crt;
         this.syms = syms;
         this.types = types;
+        this.poolWriter = poolWriter;
         this.debugCode = debugCode;
         this.stackMap = stackMap;
         switch (stackMap) {
@@ -218,7 +228,6 @@
         }
         state = new State();
         lvar = new LocalVar[20];
-        this.pool = pool;
     }
 
 
@@ -389,12 +398,13 @@
 
     /** Emit a ldc (or ldc_w) instruction, taking into account operand size
     */
-    public void emitLdc(int od) {
+    public void emitLdc(LoadableConstant constant) {
+        int od = poolWriter.putConstant(constant);
         if (od <= 255) {
-            emitop1(ldc1, od);
+            emitop1(ldc1, od, constant);
         }
         else {
-            emitop2(ldc2, od);
+            emitop2(ldc2, od, constant);
         }
     }
 
@@ -431,11 +441,11 @@
 
     /** Emit an invokeinterface instruction.
      */
-    public void emitInvokeinterface(int meth, Type mtype) {
+    public void emitInvokeinterface(Symbol member, Type mtype) {
         int argsize = width(mtype.getParameterTypes());
         emitop(invokeinterface);
         if (!alive) return;
-        emit2(meth);
+        emit2(poolWriter.putMember(member));
         emit1(argsize + 1);
         emit1(0);
         state.pop(argsize + 1);
@@ -444,14 +454,13 @@
 
     /** Emit an invokespecial instruction.
      */
-    public void emitInvokespecial(int meth, Type mtype) {
+    public void emitInvokespecial(Symbol member, Type mtype) {
         int argsize = width(mtype.getParameterTypes());
         emitop(invokespecial);
         if (!alive) return;
-        emit2(meth);
-        Symbol sym = (Symbol)pool.pool[meth];
+        emit2(poolWriter.putMember(member));
         state.pop(argsize);
-        if (sym.isConstructor())
+        if (member.isConstructor())
             state.markInitialized((UninitializedType)state.peek());
         state.pop(1);
         state.push(mtype.getReturnType());
@@ -459,33 +468,33 @@
 
     /** Emit an invokestatic instruction.
      */
-    public void emitInvokestatic(int meth, Type mtype) {
+    public void emitInvokestatic(Symbol member, Type mtype) {
         int argsize = width(mtype.getParameterTypes());
         emitop(invokestatic);
         if (!alive) return;
-        emit2(meth);
+        emit2(poolWriter.putMember(member));
         state.pop(argsize);
         state.push(mtype.getReturnType());
     }
 
     /** Emit an invokevirtual instruction.
      */
-    public void emitInvokevirtual(int meth, Type mtype) {
+    public void emitInvokevirtual(Symbol member, Type mtype) {
         int argsize = width(mtype.getParameterTypes());
         emitop(invokevirtual);
         if (!alive) return;
-        emit2(meth);
+        emit2(poolWriter.putMember(member));
         state.pop(argsize + 1);
         state.push(mtype.getReturnType());
     }
 
     /** Emit an invokedynamic instruction.
      */
-    public void emitInvokedynamic(int desc, Type mtype) {
+    public void emitInvokedynamic(DynamicMethodSymbol dynMember, Type mtype) {
         int argsize = width(mtype.getParameterTypes());
         emitop(invokedynamic);
         if (!alive) return;
-        emit2(desc);
+        emit2(poolWriter.putDynamic(dynMember));
         emit2(0);
         state.pop(argsize);
         state.push(mtype.getReturnType());
@@ -896,6 +905,10 @@
     /** Emit an opcode with a one-byte operand field.
      */
     public void emitop1(int op, int od) {
+        emitop1(op, od, null);
+    }
+
+    public void emitop1(int op, int od, PoolConstant data) {
         emitop(op);
         if (!alive) return;
         emit1(od);
@@ -904,7 +917,7 @@
             state.push(syms.intType);
             break;
         case ldc1:
-            state.push(typeForPool(pool.pool[od]));
+            state.push(types.constantType((LoadableConstant)data));
             break;
         default:
             throw new AssertionError(mnem(op));
@@ -912,25 +925,6 @@
         postop();
     }
 
-    /** The type of a constant pool entry. */
-    private Type typeForPool(Object o) {
-        if (o instanceof Integer) return syms.intType;
-        if (o instanceof Float) return syms.floatType;
-        if (o instanceof String) return syms.stringType;
-        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.MethodHandle) return syms.methodHandleType;
-        if (o instanceof UniqueType) return typeForPool(((UniqueType)o).type);
-        if (o instanceof Type) {
-            Type ty = (Type) o;
-
-            if (ty instanceof Type.ArrayType) return syms.classType;
-            if (ty instanceof Type.MethodType) return syms.methodTypeType;
-        }
-        throw new AssertionError("Invalid type of constant pool entry: " + o.getClass());
-    }
-
     /** Emit an opcode with a one-byte operand field;
      *  widen if field does not fit in a byte.
      */
@@ -1003,29 +997,31 @@
 
     /** Emit an opcode with a two-byte operand field.
      */
+    public <P extends PoolConstant> void emitop2(int op, P constant, ToIntBiFunction<PoolWriter, P> poolFunc) {
+        int od = poolFunc.applyAsInt(poolWriter, constant);
+        emitop2(op, od, constant);
+    }
+
     public void emitop2(int op, int od) {
+        emitop2(op, od, null);
+    }
+
+    public void emitop2(int op, int od, PoolConstant data) {
         emitop(op);
         if (!alive) return;
         emit2(od);
         switch (op) {
         case getstatic:
-            state.push(((Symbol)(pool.pool[od])).erasure(types));
+            state.push(((Symbol)data).erasure(types));
             break;
         case putstatic:
-            state.pop(((Symbol)(pool.pool[od])).erasure(types));
+            state.pop(((Symbol)data).erasure(types));
             break;
-        case new_:
-            Symbol sym;
-            if (pool.pool[od] instanceof UniqueType) {
-                // Required by change in Gen.makeRef to allow
-                // annotated types.
-                // TODO: is this needed anywhere else?
-                sym = ((UniqueType)(pool.pool[od])).type.tsym;
-            } else {
-                sym = (Symbol)(pool.pool[od]);
-            }
-            state.push(uninitializedObject(sym.erasure(types), cp-3));
+        case new_: {
+            Type t = (Type)data;
+            state.push(uninitializedObject(t.tsym.erasure(types), cp-3));
             break;
+        }
         case sipush:
             state.push(syms.intType);
             break;
@@ -1053,30 +1049,27 @@
             markDead();
             break;
         case putfield:
-            state.pop(((Symbol)(pool.pool[od])).erasure(types));
+            state.pop(((Symbol)data).erasure(types));
             state.pop(1); // object ref
             break;
         case getfield:
             state.pop(1); // object ref
-            state.push(((Symbol)(pool.pool[od])).erasure(types));
+            state.push(((Symbol)data).erasure(types));
             break;
         case checkcast: {
             state.pop(1); // object ref
-            Object o = pool.pool[od];
-            Type t = (o instanceof Symbol)
-                ? ((Symbol)o).erasure(types)
-                : types.erasure((((UniqueType)o).type));
+            Type t = types.erasure((Type)data);
             state.push(t);
             break; }
         case ldc2w:
-            state.push(typeForPool(pool.pool[od]));
+            state.push(types.constantType((LoadableConstant)data));
             break;
         case instanceof_:
             state.pop(1);
             state.push(syms.intType);
             break;
         case ldc2:
-            state.push(typeForPool(pool.pool[od]));
+            state.push(types.constantType((LoadableConstant)data));
             break;
         case jsr:
             break;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Apr 17 15:37:20 2019 +0100
@@ -25,6 +25,7 @@
 
 package com.sun.tools.javac.jvm;
 
+import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
 import com.sun.tools.javac.tree.TreeInfo.PosKind;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -88,9 +89,9 @@
         return instance;
     }
 
-    /** Constant pool, reset by genClass.
+    /** Constant pool writer, set by genClass.
      */
-    private final Pool pool;
+    final PoolWriter poolWriter;
 
     protected Gen(Context context) {
         context.put(genKey, this);
@@ -121,7 +122,7 @@
         genCrt = options.isSet(XJCOV);
         debugCode = options.isSet("debug.code");
         disableVirtualizedPrivateInvoke = options.isSet("disableVirtualizedPrivateInvoke");
-        pool = new Pool(types);
+        poolWriter = new PoolWriter(types, names);
 
         // ignore cldc because we cannot have both stackmap formats
         this.stackMap = StackMapFormat.JSR202;
@@ -252,17 +253,17 @@
      *  @param type   The type for which a reference is inserted.
      */
     int makeRef(DiagnosticPosition pos, Type type) {
-        checkDimension(pos, type);
-        if (type.isAnnotated()) {
-            return pool.put((Object)type);
-        } else {
-            return pool.put(type.hasTag(CLASS) ? (Object)type.tsym : (Object)type);
-        }
+        return poolWriter.putClass(checkDimension(pos, type));
     }
 
     /** Check if the given type is an array with too many dimensions.
      */
-    private void checkDimension(DiagnosticPosition pos, Type t) {
+    private Type checkDimension(DiagnosticPosition pos, Type t) {
+        checkDimensionInternal(pos, t);
+        return t;
+    }
+
+    private void checkDimensionInternal(DiagnosticPosition pos, Type t) {
         switch (t.getTag()) {
         case METHOD:
             checkDimension(pos, t.getReturnType());
@@ -516,7 +517,7 @@
         if (nerrs != 0 || // only complain about a long string once
             constValue == null ||
             !(constValue instanceof String) ||
-            ((String)constValue).length() < Pool.MAX_STRING_LENGTH)
+            ((String)constValue).length() < PoolWriter.MAX_STRING_LENGTH)
             return;
         log.error(pos, Errors.LimitString);
         nerrs++;
@@ -806,7 +807,7 @@
         @Override
         public void visitIdent(JCIdent tree) {
             if (tree.sym.owner instanceof ClassSymbol) {
-                pool.put(tree.sym.owner);
+                poolWriter.putClass((ClassSymbol)tree.sym.owner);
             }
         }
 
@@ -1007,8 +1008,8 @@
                                                : null,
                                         syms,
                                         types,
-                                        pool);
-            items = new Items(pool, code, syms, types);
+                                        poolWriter);
+            items = new Items(poolWriter, code, syms, types);
             if (code.debugCode) {
                 System.err.println(meth + " for body " + tree);
             }
@@ -1886,7 +1887,7 @@
         Assert.check(tree.encl == null && tree.def == null);
         setTypeAnnotationPositions(tree.pos);
 
-        code.emitop2(new_, makeRef(tree.pos(), tree.type));
+        code.emitop2(new_, checkDimension(tree.pos(), tree.type), PoolWriter::putClass);
         code.emitop0(dup);
 
         // Generate code for all arguments, where the expected types are
@@ -2162,7 +2163,7 @@
         if (!tree.clazz.type.isPrimitive() &&
            !types.isSameType(tree.expr.type, tree.clazz.type) &&
            types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) {
-            code.emitop2(checkcast, makeRef(tree.pos(), tree.clazz.type));
+            code.emitop2(checkcast, checkDimension(tree.pos(), tree.clazz.type), PoolWriter::putClass);
         }
     }
 
@@ -2221,7 +2222,7 @@
         Symbol sym = tree.sym;
 
         if (tree.name == names._class) {
-            code.emitLdc(makeRef(tree.pos(), tree.selected.type));
+            code.emitLdc((LoadableConstant)checkDimension(tree.pos(), tree.selected.type));
             result = items.makeStackItem(pt);
             return;
        }
@@ -2305,7 +2306,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) {
@@ -2331,12 +2332,10 @@
             ClassSymbol c = cdef.sym;
             this.toplevel = env.toplevel;
             this.endPosTable = toplevel.endPositions;
-            c.pool = pool;
-            pool.reset();
             /* 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;
@@ -2344,7 +2343,7 @@
             for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
                 genDef(l.head, localEnv);
             }
-            if (pool.numEntries() > Pool.MAX_ENTRIES) {
+            if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
                 log.error(cdef.pos(), Errors.LimitPool);
                 nerrs++;
             }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Wed Apr 17 15:37:20 2019 +0100
@@ -29,6 +29,8 @@
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.jvm.Code.*;
+import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
+import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.util.Assert;
 
@@ -50,9 +52,9 @@
  */
 public class Items {
 
-    /** The current constant pool.
+    /** The current constant pool writer.
      */
-    Pool pool;
+    PoolWriter poolWriter;
 
     /** The current code buffer.
      */
@@ -72,9 +74,9 @@
     private final Item superItem;
     private final Item[] stackItem = new Item[TypeCodeCount];
 
-    public Items(Pool pool, Code code, Symtab syms, Types types) {
+    public Items(PoolWriter poolWriter, Code code, Symtab syms, Types types) {
         this.code = code;
-        this.pool = pool;
+        this.poolWriter = poolWriter;
         this.types = types;
         voidItem = new Item(VOIDcode) {
                 public String toString() { return "void"; }
@@ -444,18 +446,18 @@
         }
 
         Item load() {
-            code.emitop2(getstatic, pool.put(member));
+            code.emitop2(getstatic, member, PoolWriter::putMember);
             return stackItem[typecode];
         }
 
         void store() {
-            code.emitop2(putstatic, pool.put(member));
+            code.emitop2(putstatic, member, PoolWriter::putMember);
         }
 
         Item invoke() {
             MethodType mtype = (MethodType)member.erasure(types);
             int rescode = Code.typecode(mtype.restype);
-            code.emitInvokestatic(pool.put(member), mtype);
+            code.emitInvokestatic(member, mtype);
             return stackItem[rescode];
         }
 
@@ -484,7 +486,7 @@
             // assert target.hasNativeInvokeDynamic();
             MethodType mtype = (MethodType)member.erasure(types);
             int rescode = Code.typecode(mtype.restype);
-            code.emitInvokedynamic(pool.put(member), mtype);
+            code.emitInvokedynamic((DynamicMethodSymbol)member, mtype);
             return stackItem[rescode];
         }
 
@@ -512,23 +514,23 @@
         }
 
         Item load() {
-            code.emitop2(getfield, pool.put(member));
+            code.emitop2(getfield, member, PoolWriter::putMember);
             return stackItem[typecode];
         }
 
         void store() {
-            code.emitop2(putfield, pool.put(member));
+            code.emitop2(putfield, member, PoolWriter::putMember);
         }
 
         Item invoke() {
             MethodType mtype = (MethodType)member.externalType(types);
             int rescode = Code.typecode(mtype.restype);
             if ((member.owner.flags() & Flags.INTERFACE) != 0 && !nonvirtual) {
-                code.emitInvokeinterface(pool.put(member), mtype);
+                code.emitInvokeinterface(member, mtype);
             } else if (nonvirtual) {
-                code.emitInvokespecial(pool.put(member), mtype);
+                code.emitInvokespecial(member, mtype);
             } else {
-                code.emitInvokevirtual(pool.put(member), mtype);
+                code.emitInvokevirtual(member, mtype);
             }
             return stackItem[rescode];
         }
@@ -560,26 +562,50 @@
 
         /** The literal's value.
          */
-        Object value;
+        final LoadableConstant value;
 
         ImmediateItem(Type type, Object value) {
             super(Code.typecode(type));
-            this.value = value;
+            switch (typecode) {
+                case BYTEcode:
+                case SHORTcode:
+                case CHARcode:
+                case INTcode:
+                    this.value = LoadableConstant.Int((int)value);
+                    break;
+                case LONGcode:
+                    this.value = LoadableConstant.Long((long)value);
+                    break;
+                case FLOATcode:
+                    this.value = LoadableConstant.Float((float)value);
+                    break;
+                case DOUBLEcode:
+                    this.value = LoadableConstant.Double((double)value);
+                    break;
+                case OBJECTcode:
+                    this.value = LoadableConstant.String((String)value);
+                    break;
+                default:
+                    throw new UnsupportedOperationException("unsupported tag: " + typecode);
+            }
         }
 
         private void ldc() {
-            int idx = pool.put(value);
             if (typecode == LONGcode || typecode == DOUBLEcode) {
-                code.emitop2(ldc2w, idx);
+                code.emitop2(ldc2w, value, PoolWriter::putConstant);
             } else {
-                code.emitLdc(idx);
+                code.emitLdc(value);
             }
         }
 
+        private Number numericValue() {
+            return (Number)((BasicConstant)value).data;
+        }
+
         Item load() {
             switch (typecode) {
             case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
-                int ival = ((Number)value).intValue();
+                int ival = numericValue().intValue();
                 if (-1 <= ival && ival <= 5)
                     code.emitop0(iconst_0 + ival);
                 else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
@@ -590,14 +616,14 @@
                     ldc();
                 break;
             case LONGcode:
-                long lval = ((Number)value).longValue();
+                long lval = numericValue().longValue();
                 if (lval == 0 || lval == 1)
                     code.emitop0(lconst_0 + (int)lval);
                 else
                     ldc();
                 break;
             case FLOATcode:
-                float fval = ((Number)value).floatValue();
+                float fval = numericValue().floatValue();
                 if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
                     code.emitop0(fconst_0 + (int)fval);
                 else {
@@ -605,7 +631,7 @@
                 }
                 break;
             case DOUBLEcode:
-                double dval = ((Number)value).doubleValue();
+                double dval = numericValue().doubleValue();
                 if (isPosZero(dval) || dval == 1.0)
                     code.emitop0(dconst_0 + (int)dval);
                 else
@@ -632,7 +658,7 @@
             }
 
         CondItem mkCond() {
-            int ival = ((Number)value).intValue();
+            int ival = numericValue().intValue();
             return makeCondItem(ival != 0 ? goto_ : dontgoto);
         }
 
@@ -647,31 +673,31 @@
                     else
                         return new ImmediateItem(
                             syms.intType,
-                            ((Number)value).intValue());
+                            numericValue().intValue());
                 case LONGcode:
                     return new ImmediateItem(
                         syms.longType,
-                        ((Number)value).longValue());
+                            numericValue().longValue());
                 case FLOATcode:
                     return new ImmediateItem(
                         syms.floatType,
-                        ((Number)value).floatValue());
+                        numericValue().floatValue());
                 case DOUBLEcode:
                     return new ImmediateItem(
                         syms.doubleType,
-                        ((Number)value).doubleValue());
+                        numericValue().doubleValue());
                 case BYTEcode:
                     return new ImmediateItem(
                         syms.byteType,
-                        (int)(byte)((Number)value).intValue());
+                        (int)(byte)numericValue().intValue());
                 case CHARcode:
                     return new ImmediateItem(
                         syms.charType,
-                        (int)(char)((Number)value).intValue());
+                        (int)(char)numericValue().intValue());
                 case SHORTcode:
                     return new ImmediateItem(
                         syms.shortType,
-                        (int)(short)((Number)value).intValue());
+                        (int)(short)numericValue().intValue());
                 default:
                     return super.coerce(targetcode);
                 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ModuleNameReader.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ModuleNameReader.java	Wed Apr 17 15:37:20 2019 +0100
@@ -24,6 +24,9 @@
  */
 package com.sun.tools.javac.jvm;
 
+import com.sun.tools.javac.util.ByteBuffer;
+import com.sun.tools.javac.util.Name.NameMapper;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Files;
@@ -55,16 +58,15 @@
 
     /** The buffer containing the currently read class file.
      */
-    private byte[] buf = new byte[INITIAL_BUFFER_SIZE];
+    private ByteBuffer buf = new ByteBuffer(INITIAL_BUFFER_SIZE);
 
     /** The current input pointer.
      */
     private int bp;
 
-    /** For every constant pool entry, an index into buf where the
-     *  defining section of the entry is found.
+    /** The constant pool reader.
      */
-    private int[] poolIdx;
+    private PoolReader reader;
 
     public ModuleNameReader() {
     }
@@ -83,7 +85,8 @@
 
     public String readModuleName(InputStream in) throws IOException, BadClassFile {
         bp = 0;
-        buf = readInputStream(buf, in);
+        buf.reset();
+        buf.appendStream(in);
 
         int magic = nextInt();
         if (magic != JAVA_MAGIC)
@@ -94,7 +97,8 @@
         if (majorVersion < 53)
             throw new BadClassFile("bad major version number for module: " + majorVersion);
 
-        indexPool();
+        reader = new PoolReader(buf);
+        bp = reader.readPool(buf, bp);
 
         int access_flags = nextChar();
         if (access_flags != 0x8000)
@@ -110,8 +114,8 @@
         for (int i = 0; i < attributes_count; i++) {
             int attr_name = nextChar();
             int attr_length = nextInt();
-            if (getUtf8Value(attr_name, false).equals("Module") && attr_length > 2) {
-                return getModuleName(nextChar());
+            if (reader.peekName(attr_name, utf8Mapper(false)).equals("Module") && attr_length > 2) {
+                return reader.peekModuleName(nextChar(), utf8Mapper(true));
             } else {
                 // skip over unknown attributes
                 bp += attr_length;
@@ -125,132 +129,26 @@
             throw new BadClassFile("invalid " + name + " for module: " + count);
     }
 
-    /** Extract a character at position bp from buf.
-     */
-    char getChar(int bp) {
-        return
-            (char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF));
-    }
-
     /** Read a character.
      */
     char nextChar() {
-        return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF));
+        char res = buf.getChar(bp);
+        bp += 2;
+        return res;
     }
 
     /** Read an integer.
      */
     int nextInt() {
-        return
-            ((buf[bp++] & 0xFF) << 24) +
-            ((buf[bp++] & 0xFF) << 16) +
-            ((buf[bp++] & 0xFF) << 8) +
-            (buf[bp++] & 0xFF);
-    }
-
-    /** Index all constant pool entries, writing their start addresses into
-     *  poolIdx.
-     */
-    void indexPool() throws BadClassFile {
-        poolIdx = new int[nextChar()];
-        int i = 1;
-        while (i < poolIdx.length) {
-            poolIdx[i++] = bp;
-            byte tag = buf[bp++];
-            switch (tag) {
-            case CONSTANT_Utf8: case CONSTANT_Unicode: {
-                int len = nextChar();
-                bp = bp + len;
-                break;
-            }
-            case CONSTANT_Class:
-            case CONSTANT_String:
-            case CONSTANT_MethodType:
-            case CONSTANT_Module:
-            case CONSTANT_Package:
-                bp = bp + 2;
-                break;
-            case CONSTANT_MethodHandle:
-                bp = bp + 3;
-                break;
-            case CONSTANT_Fieldref:
-            case CONSTANT_Methodref:
-            case CONSTANT_InterfaceMethodref:
-            case CONSTANT_NameandType:
-            case CONSTANT_Integer:
-            case CONSTANT_Float:
-            case CONSTANT_InvokeDynamic:
-                bp = bp + 4;
-                break;
-            case CONSTANT_Long:
-            case CONSTANT_Double:
-                bp = bp + 8;
-                i++;
-                break;
-            default:
-                throw new BadClassFile("malformed constant pool");
-            }
-        }
+        int res = buf.getInt(bp);
+        bp += 4;
+        return res;
     }
 
-    String getUtf8Value(int index, boolean internalize) throws BadClassFile {
-        int utf8Index = poolIdx[index];
-        if (buf[utf8Index] == CONSTANT_Utf8) {
-            int len = getChar(utf8Index + 1);
-            int start = utf8Index + 3;
-            if (internalize) {
-                return new String(ClassFile.internalize(buf, start, len));
-            } else {
-                return new String(buf, start, len);
-            }
-        }
-        throw new BadClassFile("bad name at index " + index);
-    }
-
-    String getModuleName(int index) throws BadClassFile {
-        int infoIndex = poolIdx[index];
-        if (buf[infoIndex] == CONSTANT_Module) {
-            return getUtf8Value(getChar(infoIndex + 1), true);
-        } else {
-            throw new BadClassFile("bad module name at index " + index);
-        }
+    NameMapper<String> utf8Mapper(boolean internalize) {
+        return internalize ?
+                (buf, offset, len) -> new String(ClassFile.internalize(buf, offset, len)) :
+                String::new;
     }
 
-    private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException {
-        try {
-            buf = ensureCapacity(buf, s.available());
-            int r = s.read(buf);
-            int bp = 0;
-            while (r != -1) {
-                bp += r;
-                buf = ensureCapacity(buf, bp);
-                r = s.read(buf, bp, buf.length - bp);
-            }
-            return buf;
-        } finally {
-            try {
-                s.close();
-            } catch (IOException e) {
-                /* Ignore any errors, as this stream may have already
-                 * thrown a related exception which is the one that
-                 * should be reported.
-                 */
-            }
-        }
-    }
-
-    /*
-     * ensureCapacity will increase the buffer as needed, taking note that
-     * the new buffer will always be greater than the needed and never
-     * exactly equal to the needed size or bp. If equal then the read (above)
-     * will infinitely loop as buf.length - bp == 0.
-     */
-    private static byte[] ensureCapacity(byte[] buf, int needed) {
-        if (buf.length <= needed) {
-            byte[] old = buf;
-            buf = new byte[Integer.highestOneBit(needed) << 1];
-            System.arraycopy(old, 0, buf, 0, old.length);
-        }
-        return buf;
-    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java	Wed Apr 17 12:41:33 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,372 +0,0 @@
-/*
- * Copyright (c) 1999, 2018, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-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.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.util.ArrayUtils;
-import com.sun.tools.javac.util.Assert;
-import com.sun.tools.javac.util.Filter;
-import com.sun.tools.javac.util.Name;
-
-import java.util.*;
-
-import com.sun.tools.javac.util.DefinedBy;
-import com.sun.tools.javac.util.DefinedBy.Api;
-
-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.
- *
- *  <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 static final int MAX_ENTRIES = 0xFFFF;
-    public static final int MAX_STRING_LENGTH = 0xFFFF;
-
-    /** Index of next constant to be entered.
-     */
-    int pp;
-
-    /** The initial pool buffer.
-     */
-    Object[] pool;
-
-    /** A hashtable containing all constants in the pool.
-     */
-    Map<Object,Integer> indices;
-
-    Types types;
-
-    /** Construct a pool with given number of elements and element array.
-     */
-    public Pool(int pp, Object[] pool, Types types) {
-        this.pp = pp;
-        this.pool = pool;
-        this.types = types;
-        this.indices = new HashMap<>(pool.length);
-        for (int i = 1; i < pp; i++) {
-            if (pool[i] != null) indices.put(pool[i], i);
-        }
-    }
-
-    /** Construct an empty pool.
-     */
-    public Pool(Types types) {
-        this(1, new Object[64], types);
-    }
-
-    /** 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) {
-        value = makePoolValue(value);
-        Assert.check(!(value instanceof Type.TypeVar));
-        Assert.check(!(value instanceof Types.UniqueType &&
-                       ((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)o, types);
-        } else if (o instanceof VarSymbol) {
-            return new Variable((VarSymbol)o, types);
-        } 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 t.tsym;
-            else
-                return new UniqueType(t, types);
-        } else {
-            return o;
-        }
-    }
-
-    /** Return the given object's index in the pool,
-     *  or -1 if object is not in there.
-     */
-    public int get(Object o) {
-        Integer n = indices.get(o);
-        return n == null ? -1 : n.intValue();
-    }
-
-    static class Method extends DelegatedSymbol<MethodSymbol> {
-        UniqueType uniqueType;
-        Method(MethodSymbol m, Types types) {
-            super(m);
-            this.uniqueType = new UniqueType(m.type, types);
-        }
-        @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);
-        }
-        @DefinedBy(Api.LANGUAGE_MODEL)
-        public int hashCode() {
-            MethodSymbol m = this.other;
-            return
-                m.name.hashCode() * 33 +
-                m.owner.hashCode() * 9 +
-                uniqueType.hashCode();
-        }
-    }
-
-    public static class DynamicMethod extends Method {
-        public Object[] uniqueStaticArgs;
-
-        public DynamicMethod(DynamicMethodSymbol m, Types types) {
-            super(m, types);
-            uniqueStaticArgs = getUniqueTypeArray(m.staticArgs, types);
-        }
-
-        @Override @DefinedBy(Api.LANGUAGE_MODEL)
-        public boolean equals(Object any) {
-            return equalsImpl(any, true);
-        }
-
-        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;
-            }
-        }
-    }
-
-    static class Variable extends DelegatedSymbol<VarSymbol> {
-        UniqueType uniqueType;
-        Variable(VarSymbol v, Types types) {
-            super(v);
-            this.uniqueType = new UniqueType(v.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();
-        }
-    }
-
-    public static class MethodHandle {
-
-        /** Reference kind - see ClassFile */
-        int refKind;
-
-        /** Reference symbol */
-        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 = n -> (n != n.table.names.init && n != n.table.names.clinit);
-
-                Filter<Name> initFilter = n -> n == n.table.names.init;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolConstant.java	Wed Apr 17 15:37:20 2019 +0100
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.jvm;
+
+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.util.List;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Pair;
+
+import java.util.Objects;
+import java.util.stream.Stream;
+
+/**
+ * This interface models all javac entities that can be used to represent constant pool entries.
+ * A pool constant entity must (i) be associated with a constant pool entry tag and have a function
+ * which generates a key for the desired pool entry (so as to avoid duplicate entries when writing the
+ * constant pool).
+ */
+public interface PoolConstant {
+
+    /**
+     * The constant pool entry key.
+     */
+    default Object poolKey(Types types) { return this; }
+
+    /**
+     * The constant pool entry tag.
+     */
+    int poolTag();
+
+    /**
+     * The root of pool constants that can be loaded (e.g. with {@code ldc}, or appear as static
+     * arguments to a bootstrap method.
+     */
+    interface LoadableConstant extends PoolConstant {
+
+        /**
+         * Create a pool constant describing a given {@code int} value.
+         */
+        static LoadableConstant Int(int i) {
+            return new BasicConstant(ClassFile.CONSTANT_Integer, i);
+        }
+
+        /**
+         * Create a pool constant describing a given {@code float} value.
+         */
+        static LoadableConstant Float(float f) {
+            return new BasicConstant(ClassFile.CONSTANT_Float, f);
+        }
+
+        /**
+         * Create a pool constant describing a given {@code long} value.
+         */
+        static LoadableConstant Long(long l) {
+            return new BasicConstant(ClassFile.CONSTANT_Long, l);
+        }
+
+        /**
+         * Create a pool constant describing a given {@code double} value.
+         */
+        static LoadableConstant Double(double d) {
+            return new BasicConstant(ClassFile.CONSTANT_Double, d);
+        }
+
+        /**
+         * Create a pool constant describing a given {@code String} value.
+         */
+        static LoadableConstant String(String s) {
+            return new BasicConstant(ClassFile.CONSTANT_String, s);
+        }
+
+        /**
+         * This class models a pool constant of given basic type, one of {@code int}, {@code float},
+         * {@code long}, {@code double} or {@code String}.
+         */
+        class BasicConstant implements LoadableConstant {
+            int tag;
+            Object data;
+
+            private BasicConstant(int tag, Object data) {
+                this.tag = tag;
+                this.data = data;
+            }
+
+            @Override
+            public int poolTag() {
+                return tag;
+            }
+
+            @Override
+            public Object poolKey(Types types) {
+                return data;
+            }
+        }
+    }
+
+    /**
+     * This interface models a dynamic pool constant (either of kind {@code InvokeDynamic} or
+     * {@code ConstantDynamic}). In addition to the functionalities provided by the base interface,
+     * a dynamic pool constant must expose its dynamic type, bootstrap method and static argument list.
+     * Finally, a dynamic constant must have a way to compute a bootstrap method key - that is,
+     * a unique key for the bootstrap method entry it refers to, to avoid duplicates when writing
+     * the {@code BootstrapMethods} attribute.
+     */
+    interface Dynamic extends PoolConstant {
+
+        /**
+         * The dynamic constant's dynamic type.
+         */
+        PoolConstant dynamicType();
+
+        /**
+         * The dynamic constant's static argument list.
+         */
+        LoadableConstant[] staticArgs();
+
+        /**
+         * The dynamic constant's bootstrap method.
+         */
+        LoadableConstant bootstrapMethod();
+
+        default BsmKey bsmKey(Types types) {
+            return new BsmKey(types, bootstrapMethod(), staticArgs());
+        }
+
+        @Override
+        default Object poolKey(Types types) {
+            return new Pair<>(bsmKey(types), dynamicType().poolKey(types));
+        }
+
+        /**
+         * A class modelling a bootstrap method key.
+         */
+        class BsmKey {
+            /**
+             * The key's bootstrap method constant.
+             */
+            public final LoadableConstant bsm;
+
+            /**
+             * The key's static argument list.
+             */
+            public final LoadableConstant[] staticArgs;
+
+            private final Object bsmKey;
+            private final List<?> staticArgKeys;
+
+            private BsmKey(Types types, LoadableConstant bsm, LoadableConstant[] staticArgs) {
+                this.bsm = bsm;
+                this.bsmKey = bsm.poolKey(types);
+                this.staticArgs = staticArgs;
+                this.staticArgKeys = Stream.of(staticArgs)
+                        .map(p -> p.poolKey(types))
+                        .collect(List.collector());
+            }
+
+            @Override
+            public int hashCode() {
+                return bsmKey.hashCode() +
+                        staticArgKeys.hashCode();
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (obj instanceof BsmKey) {
+                    BsmKey other = (BsmKey)obj;
+                    return Objects.equals(bsmKey, other.bsmKey) &&
+                            Objects.equals(staticArgKeys, other.staticArgKeys);
+                } else {
+                    return false;
+                }
+            }
+        }
+    }
+
+    /**
+     * A pool constant implememntation describing a name and type pool entry.
+     */
+    final class NameAndType implements PoolConstant {
+
+        final Name name;
+        final Type type;
+
+        NameAndType(Name name, Type type) {
+            this.name = name;
+            this.type = type;
+        }
+
+        @Override
+        public int poolTag() {
+            return ClassFile.CONSTANT_NameandType;
+        }
+
+        @Override
+        public Object poolKey(Types types) {
+            return new Pair<>(name, new UniqueType(type, types));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolReader.java	Wed Apr 17 15:37:20 2019 +0100
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.jvm;
+
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.ModuleSymbol;
+import com.sun.tools.javac.code.Symbol.PackageSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
+import com.sun.tools.javac.util.ByteBuffer;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Name.NameMapper;
+import com.sun.tools.javac.util.Names;
+
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Dynamic;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InvokeDynamic;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Module;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_NameandType;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Package;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Utf8;
+import static com.sun.tools.javac.jvm.ClassFile.internalize;
+
+/**
+ * Pool interface towards {@code ClassReader}. Exposes methods to decode and read javac entities
+ * from the constant pool.
+ *
+ *  <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 PoolReader {
+
+    private final ClassReader reader;
+    private final ByteBuffer buf;
+    private final Names names;
+    private final Symtab syms;
+
+    private ImmutablePoolHelper pool;
+
+    PoolReader(ByteBuffer buf) {
+        this(null, buf, null, null);
+    }
+
+    PoolReader(ClassReader reader, Names names, Symtab syms) {
+        this(reader, reader.buf, names, syms);
+    }
+
+    PoolReader(ClassReader reader, ByteBuffer buf, Names names, Symtab syms) {
+        this.reader = reader;
+        this.buf = buf;
+        this.names = names;
+        this.syms = syms;
+    }
+
+    /**
+     * Get a class symbol from the pool at given index.
+     */
+    ClassSymbol getClass(int index) {
+        return pool.readIfNeeded(index);
+    }
+
+    /**
+     * Get class name without resolving
+     */
+    <Z> Z peekClassName(int index, NameMapper<Z> mapper) {
+        return peekName(buf.getChar(pool.offset(index)), mapper);
+    }
+
+    /**
+     * Get package name without resolving
+     */
+    <Z> Z peekPackageName(int index, NameMapper<Z> mapper) {
+        return peekName(buf.getChar(pool.offset(index)), mapper);
+    }
+
+    /**
+     * Get module name without resolving
+     */
+    <Z> Z peekModuleName(int index, NameMapper<Z> mapper) {
+        return peekName(buf.getChar(pool.offset(index)), mapper);
+    }
+
+    /**
+     * Get a module symbol from the pool at given index.
+     */
+    ModuleSymbol getModule(int index) {
+        return pool.readIfNeeded(index);
+    }
+
+    /**
+     * Get a module symbol from the pool at given index.
+     */
+    PackageSymbol getPackage(int index) {
+        return pool.readIfNeeded(index);
+    }
+
+    /**
+     * Peek a name from the pool at given index without resolving.
+     */
+    <Z> Z peekName(int index, Name.NameMapper<Z> mapper) {
+        return getUtf8(index, mapper);
+    }
+
+    /**
+     * Get a name from the pool at given index.
+     */
+    Name getName(int index) {
+        return pool.readIfNeeded(index);
+    }
+
+    /**
+     * Get a type from the pool at given index.
+     */
+    Type getType(int index) {
+        return getName(index).map(reader::sigToType);
+    }
+
+    /**
+     * Get a name and type pair from the pool at given index.
+     */
+    NameAndType getNameAndType(int index) {
+        return pool.readIfNeeded(index);
+    }
+
+    /**
+     * Get a class symbol from the pool at given index.
+     */
+    Object getConstant(int index) {
+        return pool.readIfNeeded(index);
+    }
+
+    boolean hasTag(int index, int tag) {
+        return pool.tag(index) == tag;
+    }
+
+    private <Z> Z getUtf8(int index, NameMapper<Z> mapper) {
+        int tag = pool.tag(index);
+        if (tag == CONSTANT_Utf8) {
+            int offset = pool.offset(index);
+            int len = pool.poolbuf.getChar(offset);
+            return mapper.map(pool.poolbuf.elems, offset + 2, len);
+        } else {
+            throw new AssertionError("Unexpected constant tag: " + tag);
+        }
+    }
+
+    private Object resolve(ByteBuffer poolbuf, int tag, int offset) {
+        switch (tag) {
+            case CONSTANT_Utf8: {
+                int len = poolbuf.getChar(offset);
+                return names.fromUtf(poolbuf.elems, offset + 2, len);
+            }
+            case CONSTANT_Class: {
+                int index = poolbuf.getChar(offset);
+                Name name = names.fromUtf(getName(index).map(ClassFile::internalize));
+                return syms.enterClass(reader.currentModule, name);
+            }
+            case CONSTANT_NameandType: {
+                Name name = getName(poolbuf.getChar(offset));
+                Type type = getType(poolbuf.getChar(offset + 2));
+                return new NameAndType(name, type);
+            }
+            case CONSTANT_Integer:
+                return poolbuf.getInt(offset);
+            case CONSTANT_Float:
+                return poolbuf.getFloat(offset);
+            case CONSTANT_Long:
+                return poolbuf.getLong(offset);
+            case CONSTANT_Double:
+                return poolbuf.getDouble(offset);
+            case CONSTANT_String:
+                return getName(poolbuf.getChar(offset)).toString();
+            case CONSTANT_Package: {
+                Name name = getName(poolbuf.getChar(offset));
+                return syms.enterPackage(reader.currentModule, names.fromUtf(internalize(name)));
+            }
+            case CONSTANT_Module: {
+                Name name = getName(poolbuf.getChar(offset));
+                return syms.enterModule(name);
+            }
+            default:
+                throw new AssertionError("Unexpected constant tag: " + tag);
+        }
+    }
+
+    /**
+     * Parse all constant pool entries, and keep track of their offsets. For performance and laziness
+     * reasons, it would be unwise to eagerly turn all pool entries into corresponding javac
+     * entities. First, not all entries are actually going to be read/used by javac; secondly,
+     * there are cases where creating a symbol too early might result in issues (hence methods like
+     * {@link PoolReader#peekClassName(int, NameMapper)}.
+     */
+    int readPool(ByteBuffer poolbuf, int offset) {
+        int poolSize = poolbuf.getChar(offset);
+        int index = 1;
+        offset += 2;
+        int[] offsets = new int[poolSize];
+        while (index < poolSize) {
+            byte tag = poolbuf.getByte(offset++);
+            offsets[index] = offset;
+            switch (tag) {
+                case CONSTANT_Utf8: {
+                    int len = poolbuf.getChar(offset);
+                    offset += 2 + len;
+                    break;
+                }
+                case CONSTANT_Class:
+                case CONSTANT_String:
+                case CONSTANT_Module:
+                case CONSTANT_Package:
+                case CONSTANT_MethodType:
+                    offset += 2;
+                    break;
+                case CONSTANT_MethodHandle:
+                    offset += 3;
+                    break;
+                case CONSTANT_Fieldref:
+                case CONSTANT_Methodref:
+                case CONSTANT_InterfaceMethodref:
+                case CONSTANT_NameandType:
+                case CONSTANT_Integer:
+                case CONSTANT_Float:
+                case CONSTANT_Dynamic:
+                case CONSTANT_InvokeDynamic:
+                    offset += 4;
+                    break;
+                case CONSTANT_Long:
+                case CONSTANT_Double:
+                    offset += 8;
+                    break;
+                default:
+                    throw reader.badClassFile("bad.const.pool.tag.at",
+                            Byte.toString(tag),
+                            Integer.toString(offset - 1));
+            }
+            index += sizeof(tag);
+        }
+        pool = new ImmutablePoolHelper(poolbuf, offsets);
+        return offset;
+    }
+
+    private int sizeof(int tag) {
+        switch (tag) {
+            case ClassFile.CONSTANT_Double: case ClassFile.CONSTANT_Long:
+                return 2;
+            default:
+                return 1;
+        }
+    }
+
+    class ImmutablePoolHelper {
+
+        final Object[] values;
+        final int[] offsets;
+        final ByteBuffer poolbuf;
+
+        public ImmutablePoolHelper(ByteBuffer poolbuf, int[] offsets) {
+            this.offsets = offsets;
+            this.values = new Object[offsets.length];
+            this.poolbuf = poolbuf;
+        }
+
+        private int checkIndex(int index) {
+            if (index <= 0 || index >= offsets.length) {
+                //pool index is outside valid range.
+                throw reader.badClassFile("bad.const.pool.index", reader.currentClassFile,
+                        index, offsets.length);
+            } else {
+                return index;
+            }
+        }
+
+        int offset(int index) {
+            return offsets[checkIndex(index)];
+        }
+
+        @SuppressWarnings("unchecked")
+        <P> P readIfNeeded(int index) {
+            Object v = values[checkIndex(index)];
+            if (v != null) {
+                return (P)v;
+            } else {
+                P p = (P)resolve(poolbuf, tag(index), offset(index));
+                values[index] = p;
+                return p;
+            }
+        }
+
+        int tag(int index) {
+            return poolbuf.elems[offset(index) - 1];
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolWriter.java	Wed Apr 17 15:37:20 2019 +0100
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2019, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.jvm;
+
+import com.sun.tools.javac.code.Kinds.Kind;
+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.MethodHandleSymbol;
+import com.sun.tools.javac.code.Symbol.ModuleSymbol;
+import com.sun.tools.javac.code.Symbol.PackageSymbol;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.jvm.ClassWriter.PoolOverflow;
+import com.sun.tools.javac.jvm.ClassWriter.StringOverflow;
+import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
+import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant;
+import com.sun.tools.javac.jvm.PoolConstant.Dynamic;
+import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey;
+import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
+import com.sun.tools.javac.util.ByteBuffer;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Names;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+
+import static com.sun.tools.javac.code.Kinds.Kind.TYP;
+import static com.sun.tools.javac.code.TypeTag.ARRAY;
+import static com.sun.tools.javac.code.TypeTag.CLASS;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
+import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
+import static com.sun.tools.javac.jvm.ClassFile.externalize;
+
+/**
+ * Pool interface towards {@code ClassWriter}. Exposes methods to encode and write javac entities
+ * into the constant pool.
+ *
+ *  <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 PoolWriter {
+
+    /** 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;
+
+    private static final int POOL_BUF_SIZE = 0x7fff;
+
+    private final Types types;
+
+    private final Names names;
+
+    /** Pool helper **/
+    final WriteablePoolHelper pool;
+
+    /** Sole signature generator */
+    final SharedSignatureGenerator signatureGen;
+
+    /** The inner classes to be written, as an ordered set (enclosing first). */
+    LinkedHashSet<ClassSymbol> innerClasses = new LinkedHashSet<>();
+
+    /** The list of entries in the BootstrapMethods attribute. */
+    Map<BsmKey, Integer> bootstrapMethods = new LinkedHashMap<>();
+
+    public PoolWriter(Types types, Names names) {
+        this.types = types;
+        this.names = names;
+        this.signatureGen = new SharedSignatureGenerator(types);
+        this.pool = new WriteablePoolHelper();
+    }
+
+    /**
+     * Puts a class symbol into the pool and return its index.
+     */
+    int putClass(ClassSymbol csym) {
+        return putClass(csym.type);
+    }
+
+    /**
+     * Puts a type into the pool and return its index. The type could be either a class, a type variable
+     * or an array type.
+     */
+    int putClass(Type t) {
+        return pool.writeIfNeeded(types.erasure(t));
+    }
+
+    /**
+     * Puts a member reference into the constant pool. Valid members are either field or method symbols.
+     */
+    int putMember(Symbol s) {
+        return pool.writeIfNeeded(s);
+    }
+
+    /**
+     * Puts a dynamic reference into the constant pool and return its index.
+     */
+    int putDynamic(DynamicMethodSymbol d) {
+        return pool.writeIfNeeded(d);
+    }
+
+    /**
+     * Puts a field or method descriptor into the constant pool and return its index.
+     */
+    int putDescriptor(Type t) {
+        return putName(typeSig(types.erasure(t)));
+    }
+
+    /**
+     * Puts a field or method descriptor into the constant pool and return its index.
+     */
+    int putDescriptor(Symbol s) {
+        return putDescriptor(descriptorType(s));
+    }
+
+    /**
+     * Puts a signature (see {@code Signature} attribute in JVMS 4.4) into the constant pool and
+     * return its index.
+     */
+    int putSignature(Symbol s) {
+        if (s.kind == TYP) {
+            return putName(classSig(s.type));
+        } else {
+            return putName(typeSig(s.type));
+        }
+    }
+
+    /**
+     * Puts a constant value into the pool and return its index. Supported values are int, float, long,
+     * double and String.
+     */
+    int putConstant(Object o) {
+        if (o instanceof Integer) {
+            return putConstant(LoadableConstant.Int((int)o));
+        } else if (o instanceof Float) {
+            return putConstant(LoadableConstant.Float((float)o));
+        } else if (o instanceof Long) {
+            return putConstant(LoadableConstant.Long((long)o));
+        } else if (o instanceof Double) {
+            return putConstant(LoadableConstant.Double((double)o));
+        } else if (o instanceof String) {
+            return putConstant(LoadableConstant.String((String)o));
+        } else {
+            throw new AssertionError("unexpected constant: " + o);
+        }
+    }
+
+    /**
+     * Puts a constant into the pool and return its index.
+     */
+    int putConstant(LoadableConstant c) {
+        switch (c.poolTag()) {
+            case CONSTANT_Class:
+                return putClass((Type)c);
+            case CONSTANT_MethodType:
+                return pool.writeIfNeeded(types.erasure((Type)c));
+            default:
+                return pool.writeIfNeeded(c);
+        }
+    }
+
+    int putName(Name name) {
+        return pool.writeIfNeeded(name);
+    }
+
+    /**
+     * Puts a name and type pair into the pool and returns its index.
+     */
+    int putNameAndType(Symbol s) {
+        return pool.writeIfNeeded(new NameAndType(s.name, descriptorType(s)));
+    }
+
+    /**
+     * Puts a package entry into the pool and returns its index.
+     */
+    int putPackage(PackageSymbol pkg) {
+        return pool.writeIfNeeded(pkg);
+    }
+
+    /**
+     * Puts a module entry into the pool and returns its index.
+     */
+    int putModule(ModuleSymbol mod) {
+        return pool.writeIfNeeded(mod);
+    }
+
+    /**
+     * Enter an inner class into the `innerClasses' set.
+     */
+    void enterInner(ClassSymbol c) {
+        if (c.type.isCompound()) {
+            throw new AssertionError("Unexpected intersection type: " + c.type);
+        }
+        c.complete();
+        if (c.owner.enclClass() != null && !innerClasses.contains(c)) {
+            enterInner(c.owner.enclClass());
+            innerClasses.add(c);
+        }
+    }
+
+    /**
+     * Create a new Utf8 entry representing a descriptor for given (member) symbol.
+     */
+    private Type descriptorType(Symbol s) {
+        return s.kind == Kind.MTH ? s.externalType(types) : s.erasure(types);
+    }
+
+    private int makeBoostrapEntry(Dynamic dynamic) {
+        BsmKey bsmKey = dynamic.bsmKey(types);
+
+        // Figure out the index for existing BSM; create a new BSM if no key
+        Integer index = bootstrapMethods.get(bsmKey);
+        if (index == null) {
+            index = bootstrapMethods.size();
+            bootstrapMethods.put(bsmKey, index);
+        }
+
+        return index;
+    }
+
+    /**
+     * Write pool contents into given byte buffer.
+     */
+    void writePool(OutputStream out) throws IOException, PoolOverflow {
+        if (pool.overflowString != null) {
+            throw new StringOverflow(pool.overflowString);
+        }
+        int size = size();
+        if (size > MAX_ENTRIES) {
+            throw new PoolOverflow();
+        }
+        out.write(size >> 8);
+        out.write(size);
+        out.write(pool.poolbuf.elems, 0, pool.poolbuf.length);
+    }
+
+    /**
+     * Signature Generation
+     */
+    class SharedSignatureGenerator extends Types.SignatureGenerator {
+
+        /**
+         * An output buffer for type signatures.
+         */
+        ByteBuffer sigbuf = new ByteBuffer();
+
+        SharedSignatureGenerator(Types types) {
+            super(types);
+        }
+
+        /**
+         * Assemble signature of given type in string buffer.
+         * Check for uninitialized types before calling the general case.
+         */
+        @Override
+        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));
+                    break;
+                default:
+                    super.assembleSig(type);
+            }
+        }
+
+        @Override
+        protected void append(char ch) {
+            sigbuf.appendByte(ch);
+        }
+
+        @Override
+        protected void append(byte[] ba) {
+            sigbuf.appendBytes(ba);
+        }
+
+        @Override
+        protected void append(Name name) {
+            sigbuf.appendName(name);
+        }
+
+        @Override
+        protected void classReference(ClassSymbol c) {
+            enterInner(c);
+        }
+
+        protected void reset() {
+            sigbuf.reset();
+        }
+
+        protected Name toName() {
+            return sigbuf.toName(names);
+        }
+    }
+
+    class WriteablePoolHelper {
+
+        /** Pool entries. */
+        private final Map<Object, Integer> keysToPos = new HashMap<>(64);
+
+        final ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
+
+        int currentIndex = 1;
+
+        ArrayDeque<PoolConstant> todo = new ArrayDeque<>();
+
+        String overflowString = null;
+
+        private <P extends PoolConstant> int writeIfNeeded(P p) {
+            Object key = p.poolKey(types);
+            Integer index = keysToPos.get(key);
+            if (index == null) {
+                keysToPos.put(key, index = currentIndex++);
+                boolean first = todo.isEmpty();
+                todo.addLast(p);
+                if (first) {
+                    while (!todo.isEmpty()) {
+                        writeConstant(todo.peekFirst());
+                        todo.removeFirst();
+                    }
+                }
+            }
+            return index;
+        }
+
+        void writeConstant(PoolConstant c) {
+            int tag = c.poolTag();
+            switch (tag) {
+                case ClassFile.CONSTANT_Class: {
+                    Type ct = (Type)c;
+                    Name name = ct.hasTag(ARRAY) ?
+                            typeSig(ct) :
+                            names.fromUtf(externalize(ct.tsym.flatName()));
+                    poolbuf.appendByte(tag);
+                    poolbuf.appendChar(putName(name));
+                    if (ct.hasTag(CLASS)) {
+                        enterInner((ClassSymbol)ct.tsym);
+                    }
+                    break;
+                }
+                case ClassFile.CONSTANT_Utf8: {
+                    Name name = (Name)c;
+                    poolbuf.appendByte(tag);
+                    byte[] bs = name.toUtf();
+                    poolbuf.appendChar(bs.length);
+                    poolbuf.appendBytes(bs, 0, bs.length);
+                    if (overflowString == null && bs.length > MAX_STRING_LENGTH) {
+                        //report error only once
+                        overflowString = new String(bs);
+                    }
+                    break;
+                }
+                case ClassFile.CONSTANT_InterfaceMethodref:
+                case ClassFile.CONSTANT_Methodref:
+                case ClassFile.CONSTANT_Fieldref: {
+                    Symbol sym = (Symbol)c;
+                    poolbuf.appendByte(tag);
+                    poolbuf.appendChar(putClass((ClassSymbol)sym.owner));
+                    poolbuf.appendChar(putNameAndType(sym));
+                    break;
+                }
+                case ClassFile.CONSTANT_Package: {
+                    PackageSymbol pkg = (PackageSymbol)c;
+                    Name pkgName = names.fromUtf(externalize(pkg.flatName()));
+                    poolbuf.appendByte(tag);
+                    poolbuf.appendChar(putName(pkgName));
+                    break;
+                }
+                case ClassFile.CONSTANT_Module: {
+                    ModuleSymbol mod = (ModuleSymbol)c;
+                    int modName = putName(mod.name);
+                    poolbuf.appendByte(mod.poolTag());
+                    poolbuf.appendChar(modName);
+                    break;
+                }
+                case ClassFile.CONSTANT_Integer:
+                    poolbuf.appendByte(tag);
+                    poolbuf.appendInt((int)((BasicConstant)c).data);
+                    break;
+                case ClassFile.CONSTANT_Float:
+                    poolbuf.appendByte(tag);
+                    poolbuf.appendFloat((float)((BasicConstant)c).data);
+                    break;
+                case ClassFile.CONSTANT_Long:
+                    currentIndex++;
+                    poolbuf.appendByte(tag);
+                    poolbuf.appendLong((long)((BasicConstant)c).data);
+                    break;
+                case ClassFile.CONSTANT_Double:
+                    currentIndex++;
+                    poolbuf.appendByte(tag);
+                    poolbuf.appendDouble((double)((BasicConstant)c).data);
+                    break;
+                case ClassFile.CONSTANT_MethodHandle: {
+                    MethodHandleSymbol h = (MethodHandleSymbol)c;
+                    poolbuf.appendByte(tag);
+                    poolbuf.appendByte(h.referenceKind());
+                    poolbuf.appendChar(putMember(h.baseSymbol()));
+                    break;
+                }
+                case ClassFile.CONSTANT_MethodType: {
+                    Type.MethodType mt = (Type.MethodType)c;
+                    poolbuf.appendByte(tag);
+                    poolbuf.appendChar(putDescriptor(mt.baseType()));
+                    break;
+                }
+                case ClassFile.CONSTANT_String: {
+                    Name utf = names.fromString((String)((BasicConstant)c).data);
+                    poolbuf.appendByte(tag);
+                    poolbuf.appendChar(putName(utf));
+                    break;
+                }
+                case ClassFile.CONSTANT_NameandType: {
+                    NameAndType nt = (NameAndType)c;
+                    poolbuf.appendByte(tag);
+                    poolbuf.appendChar(putName(nt.name));
+                    poolbuf.appendChar(putDescriptor(nt.type));
+                    break;
+                }
+                case ClassFile.CONSTANT_InvokeDynamic: {
+                    DynamicMethodSymbol d = (DynamicMethodSymbol)c;
+                    poolbuf.appendByte(tag);
+                    poolbuf.appendChar(makeBoostrapEntry(d));
+                    poolbuf.appendChar(putNameAndType(d));
+                    break;
+                }
+                default:
+                    throw new AssertionError("Unexpected constant tag: " + tag);
+            }
+        }
+
+        void reset() {
+            keysToPos.clear();
+            currentIndex = 1;
+            todo.clear();
+            overflowString = null;
+            poolbuf.reset();
+        }
+    }
+
+    int size() {
+        return pool.currentIndex;
+    }
+
+    /**
+     * Return signature of given type
+     */
+    private Name typeSig(Type type) {
+        signatureGen.reset();
+        signatureGen.assembleSig(type);
+        return signatureGen.toName();
+    }
+
+    private Name classSig(Type t) {
+        signatureGen.reset();
+        List<Type> typarams = t.getTypeArguments();
+        if (typarams.nonEmpty()) {
+            signatureGen.assembleParamsSig(typarams);
+        }
+        signatureGen.assembleSig(types.supertype(t));
+        for (Type i : types.interfaces(t))
+            signatureGen.assembleSig(i);
+        return signatureGen.toName();
+    }
+
+    void reset() {
+        innerClasses.clear();
+        bootstrapMethods.clear();
+        pool.reset();
+    }
+}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java	Wed Apr 17 15:37:20 2019 +0100
@@ -26,7 +26,9 @@
 package com.sun.tools.javac.jvm;
 
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
 import com.sun.tools.javac.comp.Resolve;
+import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.TreeInfo;
 import com.sun.tools.javac.tree.TreeMaker;
@@ -222,7 +224,7 @@
 
         private JCDiagnostic.DiagnosticPosition newStringBuilder(JCTree tree) {
             JCDiagnostic.DiagnosticPosition pos = tree.pos();
-            gen.getCode().emitop2(new_, gen.makeRef(pos, syms.stringBuilderType));
+            gen.getCode().emitop2(new_, gen.makeRef(pos, syms.stringBuilderType), syms.stringBuilderType);
             gen.getCode().emitop0(dup);
             gen.callMethod(pos, syms.stringBuilderType, names.init, List.nil(), false);
             return pos;
@@ -378,10 +380,9 @@
 
                 Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.makeConcat,
                         syms.noSymbol,
-                        ClassFile.REF_invokeStatic,
-                        (Symbol.MethodSymbol)bsm,
+                        ((MethodSymbol)bsm).asHandle(),
                         indyType,
-                        List.nil().toArray());
+                        List.nil().toArray(new LoadableConstant[0]));
 
                 Items.Item item = gen.getItems().makeDynamicItem(dynSym);
                 item.invoke();
@@ -416,7 +417,7 @@
 
                 StringBuilder recipe = new StringBuilder(t.size());
                 ListBuffer<Type> dynamicArgs = new ListBuffer<>();
-                ListBuffer<Object> staticArgs = new ListBuffer<>();
+                ListBuffer<LoadableConstant> staticArgs = new ListBuffer<>();
 
                 for (JCTree arg : t) {
                     Object constVal = arg.type.constValue();
@@ -431,7 +432,7 @@
                         String a = arg.type.stringValue();
                         if (a.indexOf(TAG_CONST) != -1 || a.indexOf(TAG_ARG) != -1) {
                             recipe.append(TAG_CONST);
-                            staticArgs.add(a);
+                            staticArgs.add(LoadableConstant.String(a));
                         } else {
                             recipe.append(a);
                         }
@@ -463,7 +464,7 @@
         }
 
         /** Produce the actual invokedynamic call to StringConcatFactory */
-        private void doCall(Type type, JCDiagnostic.DiagnosticPosition pos, String recipe, List<Object> staticArgs, List<Type> dynamicArgTypes) {
+        private void doCall(Type type, JCDiagnostic.DiagnosticPosition pos, String recipe, List<LoadableConstant> staticArgs, List<Type> dynamicArgTypes) {
             Type.MethodType indyType = new Type.MethodType(dynamicArgTypes,
                     type,
                     List.nil(),
@@ -474,8 +475,8 @@
                 make.at(pos);
 
                 ListBuffer<Type> constTypes = new ListBuffer<>();
-                ListBuffer<Object> constants = new ListBuffer<>();
-                for (Object t : staticArgs) {
+                ListBuffer<LoadableConstant> constants = new ListBuffer<>();
+                for (LoadableConstant t : staticArgs) {
                     constants.add(t);
                     constTypes.add(syms.stringType);
                 }
@@ -495,10 +496,10 @@
 
                 Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.makeConcatWithConstants,
                         syms.noSymbol,
-                        ClassFile.REF_invokeStatic,
-                        (Symbol.MethodSymbol)bsm,
+                        ((MethodSymbol)bsm).asHandle(),
                         indyType,
-                        List.<Object>of(recipe).appendList(constants).toArray());
+                        List.of(LoadableConstant.String(recipe))
+                                .appendList(constants).toArray(new LoadableConstant[constants.size()]));
 
                 Items.Item item = gen.getItems().makeDynamicItem(dynSym);
                 item.invoke();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Apr 17 15:37:20 2019 +0100
@@ -2164,6 +2164,11 @@
     bad constant pool entry in {0}\n\
     expected {1} at index {2}
 
+# 0: file name, 1: number (constant pool index), 2: number (constant pool size)
+compiler.misc.bad.const.pool.index=\
+    bad constant pool index in {0}\n\
+    index {1} is not within pool size {2}.
+
 # 0: file name, 1: message segment
 compiler.misc.bad.class.file.header=\
     bad class file: {0}\n\
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ByteBuffer.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ByteBuffer.java	Wed Apr 17 15:37:20 2019 +0100
@@ -147,6 +147,90 @@
         appendBytes(name.getByteArray(), name.getByteOffset(), name.getByteLength());
     }
 
+     /** Append the content of a given input stream.
+     */
+    public void appendStream(InputStream is) throws IOException {
+        try {
+            int start = length;
+            int initialSize = is.available();
+            elems = ArrayUtils.ensureCapacity(elems, length + initialSize);
+            int r = is.read(elems, start, initialSize);
+            int bp = start;
+            while (r != -1) {
+                bp += r;
+                elems = ArrayUtils.ensureCapacity(elems, bp);
+                r = is.read(elems, bp, elems.length - bp);
+            }
+        } finally {
+            try {
+                is.close();
+            } catch (IOException e) {
+                /* Ignore any errors, as this stream may have already
+                 * thrown a related exception which is the one that
+                 * should be reported.
+                 */
+            }
+        }
+    }
+
+    /** Extract an integer at position bp from elems.
+     */
+    public int getInt(int bp) {
+        return
+            ((elems[bp] & 0xFF) << 24) +
+            ((elems[bp+1] & 0xFF) << 16) +
+            ((elems[bp+2] & 0xFF) << 8) +
+            (elems[bp+3] & 0xFF);
+    }
+
+
+    /** Extract a long integer at position bp from elems.
+     */
+    public long getLong(int bp) {
+        DataInputStream elemsin =
+            new DataInputStream(new ByteArrayInputStream(elems, bp, 8));
+        try {
+            return elemsin.readLong();
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /** Extract a float at position bp from elems.
+     */
+    public float getFloat(int bp) {
+        DataInputStream elemsin =
+            new DataInputStream(new ByteArrayInputStream(elems, bp, 4));
+        try {
+            return elemsin.readFloat();
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /** Extract a double at position bp from elems.
+     */
+    public double getDouble(int bp) {
+        DataInputStream elemsin =
+            new DataInputStream(new ByteArrayInputStream(elems, bp, 8));
+        try {
+            return elemsin.readDouble();
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /** Extract a character at position bp from elems.
+     */
+    public char getChar(int bp) {
+        return
+            (char)(((elems[bp] & 0xFF) << 8) + (elems[bp+1] & 0xFF));
+    }
+
+    public byte getByte(int bp) {
+        return elems[bp];
+    }
+
     /** Reset to zero length.
      */
     public void reset() {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java	Wed Apr 17 15:37:20 2019 +0100
@@ -25,6 +25,8 @@
 
 package com.sun.tools.javac.util;
 
+import com.sun.tools.javac.jvm.ClassFile;
+import com.sun.tools.javac.jvm.PoolConstant;
 import com.sun.tools.javac.util.DefinedBy.Api;
 
 /** An abstraction for internal compiler strings. They are stored in
@@ -36,7 +38,7 @@
  *  This code and its internal interfaces are subject to change or
  *  deletion without notice.</b>
  */
-public abstract class Name implements javax.lang.model.element.Name {
+public abstract class Name implements javax.lang.model.element.Name, PoolConstant {
 
     public final Table table;
 
@@ -52,6 +54,11 @@
         return toString().equals(cs.toString());
     }
 
+    @Override
+    public int poolTag() {
+        return ClassFile.CONSTANT_Utf8;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -188,6 +195,14 @@
      */
     public abstract int getByteOffset();
 
+    public interface NameMapper<X> {
+        X map(byte[] bytes, int offset, int len);
+    }
+
+    public <X> X map(NameMapper<X> mapper) {
+        return mapper.map(getByteArray(), getByteOffset(), getByteLength());
+    }
+
     /** An abstraction for the hash table used to create unique Name instances.
      */
     public static abstract class Table {
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnnotatedExtendsTest.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnnotatedExtendsTest.java	Wed Apr 17 15:37:20 2019 +0100
@@ -59,7 +59,7 @@
                 .classes(classPath.toString())
                 .run()
                 .getOutput(Task.OutputKind.DIRECT);
-        if (!javapOut.contains("0: #21(): CLASS_EXTENDS, type_index=65535"))
+        if (!javapOut.contains("0: #22(): CLASS_EXTENDS, type_index=65535"))
             throw new AssertionError("Expected output missing: " + javapOut);
     }
 }
\ No newline at end of file
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/BridgeShouldHaveNoInteriorAnnotationsTest.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/BridgeShouldHaveNoInteriorAnnotationsTest.java	Wed Apr 17 15:37:20 2019 +0100
@@ -74,14 +74,14 @@
     // Expected output can't be directly encoded into NestedLambdasCastedTest !!!
     static class OutputExpectedOnceHolder {
         public String[] outputs = {
-            "0: #61(): CAST, offset=1, type_index=0, location=[TYPE_ARGUMENT(0)]",
-            "1: #61(): LOCAL_VARIABLE, {start_pc=5, length=2, index=1}, location=[TYPE_ARGUMENT(0)]",
+            "0: #120(): CAST, offset=1, type_index=0, location=[TYPE_ARGUMENT(0)]",
+            "1: #120(): LOCAL_VARIABLE, {start_pc=5, length=2, index=1}, location=[TYPE_ARGUMENT(0)]",
         };
     }
 
     static class OutputExpectedTwiceHolder {
         public String[] outputs = {
-            "0: #61(): METHOD_RETURN, location=[TYPE_ARGUMENT(0)]",
+            "0: #120(): METHOD_RETURN, location=[TYPE_ARGUMENT(0)]",
         };
     }
 
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NestedLambdasCastedTest.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NestedLambdasCastedTest.java	Wed Apr 17 15:37:20 2019 +0100
@@ -53,10 +53,10 @@
                       "private static strictfp void lambda$main$2();",
                       "private static strictfp void lambda$main$1();",
                       "private static strictfp void lambda$main$0();",
-                      "0: #62(#63=s#64): CAST, offset=5, type_index=0",
-                      "0: #62(#63=s#69): CAST, offset=5, type_index=0",
-                      "0: #62(#63=s#72): CAST, offset=5, type_index=0",
-                      "0: #62(#63=s#75): CAST, offset=5, type_index=0"
+                      "0: #111(#112=s#113): CAST, offset=5, type_index=0",
+                      "0: #111(#112=s#119): CAST, offset=5, type_index=0",
+                      "0: #111(#112=s#122): CAST, offset=5, type_index=0",
+                      "0: #111(#112=s#125): CAST, offset=5, type_index=0"
         };
     }
 
--- a/test/langtools/tools/javac/diags/examples.not-yet.txt	Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/diags/examples.not-yet.txt	Wed Apr 17 15:37:20 2019 +0100
@@ -46,6 +46,7 @@
 compiler.misc.bad.class.signature                       # bad class file
 compiler.misc.bad.const.pool.tag                        # bad class file
 compiler.misc.bad.const.pool.tag.at                     # bad class file
+compiler.misc.bad.const.pool.index                      # bad class file
 compiler.misc.bad.constant.range                        # bad class file
 compiler.misc.bad.constant.value                        # bad class file
 compiler.misc.bad.enclosing.class                       # bad class file
--- a/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java	Wed Apr 17 15:37:20 2019 +0100
@@ -61,6 +61,7 @@
 import com.sun.tools.javac.code.Symbol.MethodSymbol;
 import com.sun.tools.javac.code.Symtab;
 import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
 import com.sun.tools.javac.tree.JCTree.JCIdent;
@@ -190,7 +191,7 @@
             Symbol oldSym = ident.sym;
             if (!oldSym.isConstructor()) {
                 ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name,
-                        oldSym.owner, REF_invokeStatic, bsm, oldSym.type, new Object[0]);
+                        oldSym.owner, bsm.asHandle(), oldSym.type, new LoadableConstant[0]);
             }
             return null;
         }
--- a/test/langtools/tools/javac/lambda/TestInvokeDynamic.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/lambda/TestInvokeDynamic.java	Wed Apr 17 15:37:20 2019 +0100
@@ -60,26 +60,23 @@
 import com.sun.tools.classfile.LineNumberTable_attribute;
 import com.sun.tools.classfile.Method;
 
-import com.sun.tools.javac.api.JavacTaskImpl;
 import com.sun.tools.javac.code.Symbol;
-import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
 import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type.ClassType;
+import com.sun.tools.javac.code.Type.MethodType;
 import com.sun.tools.javac.code.Types;
-import com.sun.tools.javac.jvm.Pool;
+import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
 import com.sun.tools.javac.tree.JCTree.JCIdent;
-import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.Names;
 
 import combo.ComboParameter;
-import combo.ComboTask;
 import combo.ComboTestHelper;
 import combo.ComboInstance;
 import combo.ComboTask.Result;
 
-import static com.sun.tools.javac.jvm.ClassFile.*;
-
 public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
 
     enum StaticArgumentKind implements ComboParameter {
@@ -168,21 +165,24 @@
 
         abstract boolean check(CPInfo cpInfo) throws Exception;
 
-        Object getValue(Symtab syms, Names names, Types types) {
+        LoadableConstant getValue(Symtab syms) {
             switch (this) {
                 case STRING:
+                    return LoadableConstant.String((String)value);
                 case INTEGER:
+                    return LoadableConstant.Int((Integer)value);
                 case LONG:
+                    return LoadableConstant.Long((Long)value);
                 case FLOAT:
+                    return LoadableConstant.Float((Float)value);
                 case DOUBLE:
-                    return value;
+                    return LoadableConstant.Double((Double)value);
                 case CLASS:
-                    return syms.stringType.tsym;
+                    return (ClassType)syms.stringType;
                 case METHOD_HANDLE:
-                    return new Pool.MethodHandle(REF_invokeVirtual,
-                            syms.arrayCloneMethod, types);
+                    return syms.arrayCloneMethod.asHandle();
                 case METHOD_TYPE:
-                    return syms.arrayCloneMethod.type;
+                    return ((MethodType)syms.arrayCloneMethod.type);
                 default:
                     throw new AssertionError();
             }
@@ -394,7 +394,7 @@
 
     class Indifier extends TreeScanner<Void, Void> implements TaskListener {
 
-        MethodSymbol bsm;
+        MethodHandleSymbol bsm;
         Symtab syms;
         Names names;
         Types types;
@@ -424,12 +424,12 @@
             JCIdent ident = (JCIdent)apply.meth;
             Symbol oldSym = ident.sym;
             if (!oldSym.isConstructor()) {
-                Object[] staticArgs = new Object[arity.arity];
+                LoadableConstant[] staticArgs = new LoadableConstant[arity.arity];
                 for (int i = 0; i < arity.arity ; i++) {
-                    staticArgs[i] = saks[i].getValue(syms, names, types);
+                    staticArgs[i] = saks[i].getValue(syms);
                 }
                 ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name,
-                        oldSym.owner, REF_invokeStatic, bsm, oldSym.type, staticArgs);
+                        oldSym.owner, bsm, oldSym.type, staticArgs);
             }
             return null;
         }
@@ -438,7 +438,7 @@
         public Void visitMethod(MethodTree node, Void p) {
             super.visitMethod(node, p);
             if (node.getName().toString().equals("bsm")) {
-                bsm = ((JCMethodDecl)node).sym;
+                bsm = ((JCMethodDecl)node).sym.asHandle();
             }
             return null;
         }
--- a/test/langtools/tools/javac/modules/T8159439/NPEForModuleInfoWithNonZeroSuperClassTest.out	Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/modules/T8159439/NPEForModuleInfoWithNonZeroSuperClassTest.out	Wed Apr 17 15:37:20 2019 +0100
@@ -1,2 +1,2 @@
-- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.module.name.mismatch: mod/module-info, <error>))
+- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.bad.const.pool.index: module-info.class, 15, 10))
 1 error
--- a/test/langtools/tools/javac/nestmates/CheckNestmateAttrs.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/nestmates/CheckNestmateAttrs.java	Wed Apr 17 15:37:20 2019 +0100
@@ -90,8 +90,8 @@
                         "NestHost: class CheckNestmateAttrs",
                         "0: aload_0",
                         "1: getfield      #1                  // Field this$1:LCheckNestmateAttrs$Inner;",
-                        "4: getfield      #3                  // Field CheckNestmateAttrs$Inner.this$0:LCheckNestmateAttrs;",
-                        "7: invokevirtual #4                  // Method CheckNestmateAttrs.test:()V",
+                        "4: getfield      #13                 // Field CheckNestmateAttrs$Inner.this$0:LCheckNestmateAttrs;",
+                        "7: invokevirtual #19                 // Method CheckNestmateAttrs.test:()V",
                         "10: return"
         });
 
--- a/test/langtools/tools/javap/AnnoTest.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javap/AnnoTest.java	Wed Apr 17 15:37:20 2019 +0100
@@ -49,50 +49,50 @@
 
         expect(out,
                 "RuntimeVisibleAnnotations:\n" +
-                "  0: #18(#19=B#20)\n" +
+                "  0: #21(#22=B#23)\n" +
                 "    AnnoTest$ByteAnno(\n" +
                 "      value=(byte) 42\n" +
                 "    )\n" +
-                "  1: #23(#19=S#24)\n" +
+                "  1: #24(#22=S#25)\n" +
                 "    AnnoTest$ShortAnno(\n" +
                 "      value=(short) 3\n" +
                 "    )");
         expect(out,
                 "RuntimeInvisibleAnnotations:\n" +
-                "  0: #28(#19=[J#29,J#31,J#33,J#35,J#37])\n" +
+                "  0: #27(#22=[J#28,J#30,J#32,J#34,J#36])\n" +
                 "    AnnoTest$ArrayAnno(\n" +
                 "      value=[1l,2l,3l,4l,5l]\n" +
                 "    )\n" +
-                "  1: #41(#19=Z#42)\n" +
+                "  1: #38(#22=Z#39)\n" +
                 "    AnnoTest$BooleanAnno(\n" +
                 "      value=false\n" +
                 "    )\n" +
-                "  2: #45(#46=c#47)\n" +
+                "  2: #40(#41=c#42)\n" +
                 "    AnnoTest$ClassAnno(\n" +
                 "      type=class Ljava/lang/Object;\n" +
                 "    )\n" +
-                "  3: #50(#51=e#52.#53)\n" +
+                "  3: #43(#44=e#45.#46)\n" +
                 "    AnnoTest$EnumAnno(\n" +
                 "      kind=Ljavax/lang/model/element/ElementKind;.PACKAGE\n" +
                 "    )\n" +
-                "  4: #56(#19=I#57)\n" +
+                "  4: #47(#22=I#48)\n" +
                 "    AnnoTest$IntAnno(\n" +
                 "      value=2\n" +
                 "    )\n" +
-                "  5: #60()\n" +
+                "  5: #49()\n" +
                 "    AnnoTest$IntDefaultAnno\n" +
-                "  6: #63(#64=s#65)\n" +
+                "  6: #50(#51=s#52)\n" +
                 "    AnnoTest$NameAnno(\n" +
                 "      name=\"NAME\"\n" +
                 "    )\n" +
-                "  7: #68(#69=D#70,#72=F#73)\n" +
+                "  7: #53(#54=D#55,#57=F#58)\n" +
                 "    AnnoTest$MultiAnno(\n" +
                 "      d=3.14159d\n" +
                 "      f=2.71828f\n" +
                 "    )\n" +
-                "  8: #76()\n" +
+                "  8: #59()\n" +
                 "    AnnoTest$SimpleAnno\n" +
-                "  9: #79(#19=@#56(#19=I#80))\n" +
+                "  9: #60(#22=@#47(#22=I#61))\n" +
                 "    AnnoTest$AnnoAnno(\n" +
                 "      value=@AnnoTest$IntAnno(\n" +
                 "        value=5\n" +
@@ -100,7 +100,7 @@
                 "    )");
         expect(out,
                 "RuntimeInvisibleTypeAnnotations:\n" +
-                "  0: #84(): CLASS_EXTENDS, type_index=0\n" +
+                "  0: #63(): CLASS_EXTENDS, type_index=0\n" +
                 "    AnnoTest$TypeAnno");
 
         if (errors > 0)
--- a/test/langtools/tools/javap/typeAnnotations/AnnotationDefaultNewlineTest.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javap/typeAnnotations/AnnotationDefaultNewlineTest.java	Wed Apr 17 15:37:20 2019 +0100
@@ -51,7 +51,7 @@
 
     private static final String ExpectedSubstring =
             "    AnnotationDefault:\n" +
-            "      default_value: I#7\n";
+            "      default_value: I#9\n";
 
     public static void main(String[] args) throws Exception {
         ToolBox tb = new ToolBox();
--- a/test/langtools/tools/javap/typeAnnotations/InvisibleParameterAnnotationsTest.java	Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javap/typeAnnotations/InvisibleParameterAnnotationsTest.java	Wed Apr 17 15:37:20 2019 +0100
@@ -62,11 +62,11 @@
             "    RuntimeVisibleParameterAnnotations:\n" +
             "      parameter 0:\n" +
             "      parameter 1:\n" +
-            "        0: #16()\n" +
+            "        0: #14()\n" +
             "          Sample$VisAnno\n" +
             "    RuntimeInvisibleParameterAnnotations:\n" +
             "      parameter 0:\n" +
-            "        0: #18()\n" +
+            "        0: #16()\n" +
             "          Sample$InvisAnno\n" +
             "      parameter 1:";