< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java

Print this page

        

@@ -27,11 +27,13 @@
 
 import java.io.*;
 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;
 import javax.tools.JavaFileManager.Location;
 import javax.tools.JavaFileObject;

@@ -40,14 +42,17 @@
 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
 import com.sun.tools.javac.code.Directive.*;
 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.PoolConstant.LoadableConstant;
-import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey;
+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.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.util.*;
 
 import static com.sun.tools.javac.code.Flags.*;

@@ -114,34 +119,56 @@
 
     /** The initial sizes of the data and constant pool buffers.
      *  Sizes are increased when buffers get full.
      */
     static final int DATA_BUF_SIZE = 0x0fff0;
-    static final int CLASS_BUF_SIZE = 0x1fff0;
+    static final int POOL_BUF_SIZE = 0x1fff0;
 
     /** An output buffer for member info.
      */
     ByteBuffer databuf = new ByteBuffer(DATA_BUF_SIZE);
 
     /** An output buffer for the constant pool.
      */
-    ByteBuffer poolbuf = new ByteBuffer(CLASS_BUF_SIZE);
+    ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
 
-    /** The constant pool writer.
+    /** The constant pool.
      */
-    final PoolWriter poolWriter;
+    Pool pool;
+
+    /** The inner classes to be written, as a set.
+     */
+    Set<ClassSymbol> innerClasses;
+
+    /** The inner classes to be written, as a queue where
+     *  enclosing classes come first.
+     */
+    ListBuffer<ClassSymbol> innerClassesQueue;
+
+    /** The bootstrap methods to be written in the corresponding class attribute
+     *  (one for each invokedynamic)
+     */
+    Map<DynamicMethod.BootstrapMethodsKey, DynamicMethod.BootstrapMethodsValue> bootstrapMethods;
 
     /** The log to use for verbose output.
      */
     private final Log log;
 
     /** The name table. */
     private final Names names;
 
+    /** The symbol table. */
+    private final Symtab syms;
+
     /** Access to files. */
     private final JavaFileManager fileManager;
 
+    /** Sole signature generator */
+    private final CWSignatureGenerator signatureGen;
+
+    private final Constables constables;
+
     /** 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;
     static final int SAME_FRAME_EXTENDED = 251;
     static final int FULL_FRAME = 255;

@@ -160,18 +187,20 @@
     protected ClassWriter(Context context) {
         context.put(classWriterKey, this);
 
         log = Log.instance(context);
         names = Names.instance(context);
+        syms = Symtab.instance(context);
         options = Options.instance(context);
         preview = Preview.instance(context);
         target = Target.instance(context);
         source = Source.instance(context);
         types = Types.instance(context);
         check = Check.instance(context);
         fileManager = context.get(JavaFileManager.class);
-        poolWriter = Gen.instance(context).poolWriter;
+        signatureGen = new CWSignatureGenerator(types);
+        constables = Constables.instance(context);
 
         verbose        = options.isSet(VERBOSE);
         genCrt         = options.isSet(XJCOV);
         debugstackmap = options.isSet("debug.stackmap");
 

@@ -248,38 +277,281 @@
         buf.elems[adr+1] = (byte)((x >> 16) & 0xFF);
         buf.elems[adr+2] = (byte)((x >>  8) & 0xFF);
         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 RuntimeException {
+    public static class PoolOverflow extends Exception {
         private static final long serialVersionUID = 0;
         public PoolOverflow() {}
     }
-    public static class StringOverflow extends RuntimeException {
+    public static class StringOverflow extends Exception {
         private static final long serialVersionUID = 0;
         public final String value;
         public StringOverflow(String s) {
             value = s;
         }
     }
 
+    /** 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.isOwnerAnInterface()
+                              ? 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.BootstrapMethodsValue val = writeDynSymbol(dynSym, handle);
+                    poolbuf.appendByte(CONSTANT_InvokeDynamic);
+                    poolbuf.appendChar(val.index);
+                    poolbuf.appendChar(pool.put(nameType(dynSym)));
+                }
+            } else if (value instanceof VarSymbol) {
+                VarSymbol v = (VarSymbol)value;
+                if (!v.isDynamic()) {
+                    poolbuf.appendByte(CONSTANT_Fieldref);
+                    poolbuf.appendChar(pool.put(v.owner));
+                    poolbuf.appendChar(pool.put(nameType(v)));
+                } else {
+                    DynamicVarSymbol dynVarSym = (DynamicVarSymbol)v;
+                    MethodHandle handle = new MethodHandle(dynVarSym.bsmKind, dynVarSym.bsm, types);
+                    DynamicMethodSymbol dynSym = new DynamicMethodSymbol(
+                            handle.refSym.name,
+                            syms.noSymbol,
+                            handle.refKind,
+                            (MethodSymbol)handle.refSym,
+                            handle.refSym.type,
+                            dynVarSym.staticArgs);
+                    DynamicMethod.BootstrapMethodsValue val = writeDynSymbol(dynSym, handle);
+                    poolbuf.appendByte(CONSTANT_Dynamic);
+                    poolbuf.appendChar(val.index);
+                    NameAndType nt = new NameAndType(dynVarSym.name, dynVarSym.type, types);
+                    poolbuf.appendChar(pool.put(nt));
+                }
+            } 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);
+    }
+
+    DynamicMethod.BootstrapMethodsValue writeDynSymbol(DynamicMethodSymbol dynSym, MethodHandle handle) {
+        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);
+        }
+        return val;
+    }
+
+    /** 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
  ******************************************************************/
 
     /** Write header for an attribute to data buffer and return
      *  position past attribute length index.
      */
     int writeAttr(Name attrName) {
-        int index = poolWriter.putName(attrName);
-        databuf.appendChar(index);
+        databuf.appendChar(pool.put(attrName));
         databuf.appendInt(0);
         return databuf.length;
     }
 
     /** Fill in attribute length.

@@ -322,12 +594,12 @@
         MethodSymbol enclMethod =
             (c.owner.type == null // local to init block
              || c.owner.kind != MTH) // or member init
             ? null
             : (MethodSymbol)c.owner;
-        databuf.appendChar(poolWriter.putClass(enclClass));
-        databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(c.owner));
+        databuf.appendChar(pool.put(enclClass));
+        databuf.appendChar(enclMethod == null ? 0 : pool.put(nameType(c.owner)));
         endAttr(alenIdx);
         return 1;
     }
 
     /** Write flag attributes; return number of attributes written.

@@ -349,15 +621,15 @@
         int acount = writeFlagAttrs(sym.flags());
         long flags = sym.flags();
         if ((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC &&
             (flags & ANONCONSTR) == 0 &&
             (!types.isSameType(sym.type, sym.erasure(types)) ||
-             poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()))) {
+             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(poolWriter.putSignature(sym));
+            databuf.appendChar(pool.put(typeSig(sym.type)));
             endAttr(alenIdx);
             acount++;
         }
         acount += writeJavaAnnotations(sym.getRawAttributes());
         acount += writeTypeAnnotations(sym.getRawTypeAttributes(), false);

@@ -376,27 +648,27 @@
             // Write extra parameters first
             for (VarSymbol s : m.extraParams) {
                 final int flags =
                     ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
                     ((int) m.flags() & SYNTHETIC);
-                databuf.appendChar(poolWriter.putName(s.name));
+                databuf.appendChar(pool.put(s.name));
                 databuf.appendChar(flags);
             }
             // Now write the real parameters
             for (VarSymbol s : m.params) {
                 final int flags =
                     ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
                     ((int) m.flags() & SYNTHETIC);
-                databuf.appendChar(poolWriter.putName(s.name));
+                databuf.appendChar(pool.put(s.name));
                 databuf.appendChar(flags);
             }
             // Now write the captured locals
             for (VarSymbol s : m.capturedLocals) {
                 final int flags =
                     ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
                     ((int) m.flags() & SYNTHETIC);
-                databuf.appendChar(poolWriter.putName(s.name));
+                databuf.appendChar(pool.put(s.name));
                 databuf.appendChar(flags);
             }
             endAttr(attrIndex);
             return 1;
         } else

@@ -524,14 +796,14 @@
             if (tc.position.type.isLocal() != inCode)
                 continue;
             if (!tc.position.emitToClassfile())
                 continue;
             switch (types.getRetention(tc)) {
-            case SOURCE: break;
-            case CLASS: invisibles.append(tc); break;
-            case RUNTIME: visibles.append(tc); break;
-            default: // /* fail soft */ throw new AssertionError(vis);
+                case SOURCE: break;
+                case CLASS: invisibles.append(tc); break;
+                case RUNTIME: visibles.append(tc); break;
+                default: // /* fail soft */ throw new AssertionError(vis);
             }
         }
 
         int attrCount = 0;
         if (visibles.length() != 0) {

@@ -558,55 +830,54 @@
     /** A visitor to write an attribute including its leading
      *  single-character marker.
      */
     class AttributeWriter implements Attribute.Visitor {
         public void visitConstant(Attribute.Constant _value) {
-            if (_value.type.getTag() == CLASS) {
-                Assert.check(_value.value instanceof String);
-                String s = (String)_value.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);
                 databuf.appendByte('s');
-                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));
+                value = names.fromString(value.toString()); // CONSTANT_Utf8
+                break;
+            default:
+                throw new AssertionError(_value.type);
             }
+            databuf.appendChar(pool.put(value));
         }
         public void visitEnum(Attribute.Enum e) {
             databuf.appendByte('e');
-            databuf.appendChar(poolWriter.putDescriptor(e.value.type));
-            databuf.appendChar(poolWriter.putName(e.value.name));
+            databuf.appendChar(pool.put(typeSig(e.value.type)));
+            databuf.appendChar(pool.put(e.value.name));
         }
         public void visitClass(Attribute.Class clazz) {
             databuf.appendByte('c');
-            databuf.appendChar(poolWriter.putDescriptor(clazz.classType));
+            databuf.appendChar(pool.put(typeSig(types.erasure(clazz.classType))));
         }
         public void visitCompound(Attribute.Compound compound) {
             databuf.appendByte('@');
             writeCompoundAttribute(compound);
         }

@@ -623,14 +894,14 @@
     }
     AttributeWriter awriter = new AttributeWriter();
 
     /** Write a compound attribute excluding the '@' marker. */
     void writeCompoundAttribute(Attribute.Compound c) {
-        databuf.appendChar(poolWriter.putDescriptor(c.type));
+        databuf.appendChar(pool.put(typeSig(c.type)));
         databuf.appendChar(c.values.length());
         for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) {
-            databuf.appendChar(poolWriter.putName(p.fst.name));
+            databuf.appendChar(pool.put(p.fst.name));
             p.snd.accept(awriter);
         }
     }
 
     void writeTypeAnnotation(Attribute.TypeCompound c) {

@@ -730,60 +1001,60 @@
     int writeModuleAttribute(ClassSymbol c) {
         ModuleSymbol m = (ModuleSymbol) c.owner;
 
         int alenIdx = writeAttr(names.Module);
 
-        databuf.appendChar(poolWriter.putModule(m));
+        databuf.appendChar(pool.put(m));
         databuf.appendChar(ModuleFlags.value(m.flags)); // module_flags
-        databuf.appendChar(m.version != null ? poolWriter.putName(m.version) : 0);
+        databuf.appendChar(m.version != null ? pool.put(m.version) : 0);
 
         ListBuffer<RequiresDirective> requires = new ListBuffer<>();
         for (RequiresDirective r: m.requires) {
             if (!r.flags.contains(RequiresFlag.EXTRA))
                 requires.add(r);
         }
         databuf.appendChar(requires.size());
         for (RequiresDirective r: requires) {
-            databuf.appendChar(poolWriter.putModule(r.module));
+            databuf.appendChar(pool.put(r.module));
             databuf.appendChar(RequiresFlag.value(r.flags));
-            databuf.appendChar(r.module.version != null ? poolWriter.putName(r.module.version) : 0);
+            databuf.appendChar(r.module.version != null ? pool.put(r.module.version) : 0);
         }
 
         List<ExportsDirective> exports = m.exports;
         databuf.appendChar(exports.size());
         for (ExportsDirective e: exports) {
-            databuf.appendChar(poolWriter.putPackage(e.packge));
+            databuf.appendChar(pool.put(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(poolWriter.putModule(msym));
+                    databuf.appendChar(pool.put(msym));
                 }
             }
         }
 
         List<OpensDirective> opens = m.opens;
         databuf.appendChar(opens.size());
         for (OpensDirective o: opens) {
-            databuf.appendChar(poolWriter.putPackage(o.packge));
+            databuf.appendChar(pool.put(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(poolWriter.putModule(msym));
+                    databuf.appendChar(pool.put(msym));
                 }
             }
         }
 
         List<UsesDirective> uses = m.uses;
         databuf.appendChar(uses.size());
         for (UsesDirective s: uses) {
-            databuf.appendChar(poolWriter.putClass(s.service));
+            databuf.appendChar(pool.put(s.service));
         }
 
         // temporary fix to merge repeated provides clause for same service;
         // eventually this should be disallowed when analyzing the module,
         // so that each service type only appears once.

@@ -791,60 +1062,93 @@
         for (ProvidesDirective p : m.provides) {
             mergedProvides.computeIfAbsent(p.service, s -> new LinkedHashSet<>()).addAll(p.impls);
         }
         databuf.appendChar(mergedProvides.size());
         mergedProvides.forEach((srvc, impls) -> {
-            databuf.appendChar(poolWriter.putClass(srvc));
+            databuf.appendChar(pool.put(srvc));
             databuf.appendChar(impls.size());
-            impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl)));
+            impls.forEach(impl -> databuf.appendChar(pool.put(impl)));
         });
 
         endAttr(alenIdx);
         return 1;
     }
 
 /**********************************************************************
  * 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("warning: " + c + ": " + ex.getMessage());
+        }
+        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(poolWriter.innerClasses.size());
-        for (ClassSymbol inner : poolWriter.innerClasses) {
+        databuf.appendChar(innerClassesQueue.length());
+        for (List<ClassSymbol> l = innerClassesQueue.toList();
+             l.nonEmpty();
+             l = l.tail) {
+            ClassSymbol inner = l.head;
             inner.markAbstractIfNeeded(types);
             char flags = (char) adjustFlags(inner.flags_field);
             if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT
             flags &= ~STRICTFP; //inner classes should not have the strictfp flag set.
             if (dumpInnerClassModifiers) {
                 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
                 pw.println("INNERCLASS  " + inner.name);
                 pw.println("---" + flagNames(flags));
             }
-            databuf.appendChar(poolWriter.putClass(inner));
+            databuf.appendChar(pool.get(inner));
             databuf.appendChar(
-                inner.owner.kind == TYP && !inner.name.isEmpty() ? poolWriter.putClass((ClassSymbol)inner.owner) : 0);
+                inner.owner.kind == TYP && !inner.name.isEmpty() ? pool.get(inner.owner) : 0);
             databuf.appendChar(
-                !inner.name.isEmpty() ? poolWriter.putName(inner.name) : 0);
+                !inner.name.isEmpty() ? pool.get(inner.name) : 0);
             databuf.appendChar(flags);
         }
         endAttr(alenIdx);
     }
 
     /**
      * Write NestMembers attribute (if needed)
      */
     int writeNestMembersIfNeeded(ClassSymbol csym) {
-        ListBuffer<ClassSymbol> nested = new ListBuffer<>();
+        ListBuffer<Symbol> nested = new ListBuffer<>();
         listNested(csym, nested);
-        Set<ClassSymbol> nestedUnique = new LinkedHashSet<>(nested);
+        Set<Symbol> nestedUnique = new LinkedHashSet<>(nested);
         if (csym.owner.kind == PCK && !nestedUnique.isEmpty()) {
             int alenIdx = writeAttr(names.NestMembers);
             databuf.appendChar(nestedUnique.size());
-            for (ClassSymbol s : nestedUnique) {
-                databuf.appendChar(poolWriter.putClass(s));
+            for (Symbol s : nestedUnique) {
+                databuf.appendChar(pool.put(s));
             }
             endAttr(alenIdx);
             return 1;
         }
         return 0;

@@ -854,18 +1158,18 @@
      * Write NestHost attribute (if needed)
      */
     int writeNestHostIfNeeded(ClassSymbol csym) {
         if (csym.owner.kind != PCK) {
             int alenIdx = writeAttr(names.NestHost);
-            databuf.appendChar(poolWriter.putClass(csym.outermostClass()));
+            databuf.appendChar(pool.put(csym.outermostClass()));
             endAttr(alenIdx);
             return 1;
         }
         return 0;
     }
 
-    private void listNested(Symbol sym, ListBuffer<ClassSymbol> seen) {
+    private void listNested(Symbol sym, ListBuffer<Symbol> seen) {
         if (sym.kind != TYP) return;
         ClassSymbol csym = (ClassSymbol)sym;
         if (csym.owner.kind != PCK) {
             seen.add(csym);
         }

@@ -883,20 +1187,21 @@
 
     /** Write "bootstrapMethods" attribute.
      */
     void writeBootstrapMethods() {
         int alenIdx = writeAttr(names.BootstrapMethods);
-        databuf.appendChar(poolWriter.bootstrapMethods.size());
-        for (BsmKey bsmKey : poolWriter.bootstrapMethods.keySet()) {
+        databuf.appendChar(bootstrapMethods.size());
+        for (Map.Entry<DynamicMethod.BootstrapMethodsKey, DynamicMethod.BootstrapMethodsValue> entry : bootstrapMethods.entrySet()) {
+            DynamicMethod.BootstrapMethodsKey bsmKey = entry.getKey();
             //write BSM handle
-            databuf.appendChar(poolWriter.putConstant(bsmKey.bsm));
-            LoadableConstant[] uniqueArgs = bsmKey.staticArgs;
+            databuf.appendChar(pool.get(entry.getValue().mh));
+            Object[] uniqueArgs = bsmKey.getUniqueArgs();
             //write static args length
             databuf.appendChar(uniqueArgs.length);
             //write static args array
-            for (LoadableConstant arg : uniqueArgs) {
-                databuf.appendChar(poolWriter.putConstant(arg));
+            for (Object o : uniqueArgs) {
+                databuf.appendChar(pool.get(o));
             }
         }
         endAttr(alenIdx);
     }
 

@@ -908,17 +1213,17 @@
         if (dumpFieldModifiers) {
             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
             pw.println("FIELD  " + v.name);
             pw.println("---" + flagNames(v.flags()));
         }
-        databuf.appendChar(poolWriter.putName(v.name));
-        databuf.appendChar(poolWriter.putDescriptor(v));
+        databuf.appendChar(pool.put(v.name));
+        databuf.appendChar(pool.put(typeSig(v.erasure(types))));
         int acountIdx = beginAttrs();
         int acount = 0;
-        if (v.getConstValue() != null) {
+        if (v.getConstValue() != null && constables.canMakeItToConstantValue(v.type)) {
             int alenIdx = writeAttr(names.ConstantValue);
-            databuf.appendChar(poolWriter.putConstant(v.getConstValue()));
+            databuf.appendChar(pool.put(v.getConstValue()));
             endAttr(alenIdx);
             acount++;
         }
         acount += writeMemberAttrs(v);
         endAttrs(acountIdx, acount);

@@ -932,12 +1237,12 @@
         if (dumpMethodModifiers) {
             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
             pw.println("METHOD  " + m.name);
             pw.println("---" + flagNames(m.flags()));
         }
-        databuf.appendChar(poolWriter.putName(m.name));
-        databuf.appendChar(poolWriter.putDescriptor(m));
+        databuf.appendChar(pool.put(m.name));
+        databuf.appendChar(pool.put(typeSig(m.externalType(types))));
         int acountIdx = beginAttrs();
         int acount = 0;
         if (m.code != null) {
             int alenIdx = writeAttr(names.Code);
             writeCode(m.code);

@@ -948,11 +1253,11 @@
         List<Type> thrown = m.erasure(types).getThrownTypes();
         if (thrown.nonEmpty()) {
             int alenIdx = writeAttr(names.Exceptions);
             databuf.appendChar(thrown.length());
             for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
-                databuf.appendChar(poolWriter.putClass(l.head));
+                databuf.appendChar(pool.put(l.head.tsym));
             endAttr(alenIdx);
             acount++;
         }
         if (m.defaultValue != null) {
             int alenIdx = writeAttr(names.AnnotationDefault);

@@ -1024,12 +1329,13 @@
                     databuf.appendChar(r.start_pc);
                     Assert.check(r.length > 0
                             && (r.start_pc + r.length) <= code.cp);
                     databuf.appendChar(r.length);
                     VarSymbol sym = var.sym;
-                    databuf.appendChar(poolWriter.putName(sym.name));
-                    databuf.appendChar(poolWriter.putDescriptor(sym));
+                    databuf.appendChar(pool.put(sym.name));
+                    Type vartype = sym.erasure(types);
+                    databuf.appendChar(pool.put(typeSig(vartype)));
                     databuf.appendChar(var.reg);
                     if (needsLocalVariableTypeEntry(var.sym.type)) {
                         nGenericVars++;
                     }
                 }

@@ -1049,12 +1355,12 @@
                         continue;
                     for (Code.LocalVar.Range r : var.aliveRanges) {
                         // write variable info
                         databuf.appendChar(r.start_pc);
                         databuf.appendChar(r.length);
-                        databuf.appendChar(poolWriter.putName(sym.name));
-                        databuf.appendChar(poolWriter.putSignature(sym));
+                        databuf.appendChar(pool.put(sym.name));
+                        databuf.appendChar(pool.put(typeSig(sym.type)));
                         databuf.appendChar(var.reg);
                         count++;
                     }
                 }
                 Assert.check(count == nGenericVars);

@@ -1177,14 +1483,18 @@
                 if (debugstackmap) System.out.print("null");
                 databuf.appendByte(5);
                 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(poolWriter.putClass(types.erasure(t)));
+                databuf.appendChar(pool.put(types.erasure(t).tsym));
                 break;
             case UNINITIALIZED_THIS:
                 if (debugstackmap) System.out.print("uninit_this");
                 databuf.appendByte(6);
                 break;

@@ -1479,10 +1789,15 @@
     public void writeClassFile(OutputStream out, ClassSymbol c)
         throws IOException, PoolOverflow, StringOverflow {
         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);
         List<Type> typarams = c.type.getTypeArguments();
 

@@ -1504,33 +1819,33 @@
         }
         databuf.appendChar(flags);
 
         if (c.owner.kind == MDL) {
             PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage;
-            databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed)));
+            databuf.appendChar(pool.put(new ClassSymbol(0, names.module_info, unnamed)));
         } else {
-            databuf.appendChar(poolWriter.putClass(c));
+            databuf.appendChar(pool.put(c));
         }
-        databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0);
+        databuf.appendChar(supertype.hasTag(CLASS) ? pool.put(supertype.tsym) : 0);
         databuf.appendChar(interfaces.length());
         for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
-            databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym));
+            databuf.appendChar(pool.put(l.head.tsym));
         int fieldsCount = 0;
         int methodsCount = 0;
         for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
             switch (sym.kind) {
             case VAR: fieldsCount++; break;
             case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
                       break;
-            case TYP: poolWriter.enterInner((ClassSymbol)sym); break;
+            case TYP: enterInner((ClassSymbol)sym); break;
             default : Assert.error();
             }
         }
 
         if (c.trans_local != null) {
             for (ClassSymbol local : c.trans_local) {
-                poolWriter.enterInner(local);
+                enterInner(local);
             }
         }
 
         databuf.appendChar(fieldsCount);
         writeFields(c.members());

@@ -1544,35 +1859,41 @@
             typarams.length() != 0 || supertype.allparams().length() != 0;
         for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
             sigReq = l.head.allparams().length() != 0;
         if (sigReq) {
             int alenIdx = writeAttr(names.Signature);
-            databuf.appendChar(poolWriter.putSignature(c));
+            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();
             endAttr(alenIdx);
             acount++;
         }
 
         if (c.sourcefile != null && emitSourceFile) {
             int alenIdx = writeAttr(names.SourceFile);
             // 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(poolWriter.putName(names.fromString(simpleName)));
+            databuf.appendChar(c.pool.put(names.fromString(simpleName)));
             endAttr(alenIdx);
             acount++;
         }
 
         if (genCrt) {
             // Append SourceID attribute
             int alenIdx = writeAttr(names.SourceID);
-            databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
+            databuf.appendChar(c.pool.put(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
             endAttr(alenIdx);
             acount++;
             // Append CompilationID attribute
             alenIdx = writeAttr(names.CompilationID);
-            databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(System.currentTimeMillis()))));
+            databuf.appendChar(c.pool.put(names.fromString(Long.toString(System.currentTimeMillis()))));
             endAttr(alenIdx);
             acount++;
         }
 
         acount += writeFlagAttrs(c.flags());

@@ -1598,28 +1919,28 @@
                 acount += writeNestMembersIfNeeded(c);
                 acount += writeNestHostIfNeeded(c);
             }
         }
 
-        if (!poolWriter.bootstrapMethods.isEmpty()) {
-            writeBootstrapMethods();
+        writePool(c.pool);
+
+        if (innerClasses != null) {
+            writeInnerClasses();
             acount++;
         }
 
-        if (!poolWriter.innerClasses.isEmpty()) {
-            writeInnerClasses();
+        if (!bootstrapMethods.isEmpty()) {
+            writeBootstrapMethods();
             acount++;
         }
 
         endAttrs(acountIdx, acount);
 
+        poolbuf.appendBytes(databuf.elems, 0, databuf.length);
         out.write(poolbuf.elems, 0, poolbuf.length);
 
-        poolWriter.writePool(out);
-        poolWriter.reset(); // to save space
-
-        out.write(databuf.elems, 0, databuf.length);
+        pool = c.pool = null; // to conserve space
      }
 
     /**Allows subclasses to write additional class attributes
      *
      * @return the number of attributes written
< prev index next >