ClassWriter.java revision 3528:5538ba41cb97
1/*
2 * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.javac.jvm;
27
28import java.io.*;
29import java.util.LinkedHashMap;
30import java.util.Map;
31import java.util.Set;
32import java.util.HashSet;
33
34import javax.tools.JavaFileManager;
35import javax.tools.FileObject;
36import javax.tools.JavaFileManager.Location;
37import javax.tools.JavaFileObject;
38
39import com.sun.tools.javac.code.*;
40import com.sun.tools.javac.code.Attribute.RetentionPolicy;
41import com.sun.tools.javac.code.Directive.*;
42import com.sun.tools.javac.code.Symbol.*;
43import com.sun.tools.javac.code.Type.*;
44import com.sun.tools.javac.code.Types.UniqueType;
45import com.sun.tools.javac.file.PathFileObject;
46import com.sun.tools.javac.jvm.Pool.DynamicMethod;
47import com.sun.tools.javac.jvm.Pool.Method;
48import com.sun.tools.javac.jvm.Pool.MethodHandle;
49import com.sun.tools.javac.jvm.Pool.Variable;
50import com.sun.tools.javac.main.Option;
51import com.sun.tools.javac.util.*;
52
53import static com.sun.tools.javac.code.Flags.*;
54import static com.sun.tools.javac.code.Kinds.Kind.*;
55import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
56import static com.sun.tools.javac.code.TypeTag.*;
57import static com.sun.tools.javac.main.Option.*;
58
59import static javax.tools.StandardLocation.CLASS_OUTPUT;
60
61/** This class provides operations to map an internal symbol table graph
62 *  rooted in a ClassSymbol into a classfile.
63 *
64 *  <p><b>This is NOT part of any supported API.
65 *  If you write code that depends on this, you do so at your own risk.
66 *  This code and its internal interfaces are subject to change or
67 *  deletion without notice.</b>
68 */
69public class ClassWriter extends ClassFile {
70    protected static final Context.Key<ClassWriter> classWriterKey = new Context.Key<>();
71
72    private final Options options;
73
74    /** Switch: verbose output.
75     */
76    private boolean verbose;
77
78    /** Switch: emit source file attribute.
79     */
80    private boolean emitSourceFile;
81
82    /** Switch: generate CharacterRangeTable attribute.
83     */
84    private boolean genCrt;
85
86    /** Switch: describe the generated stackmap.
87     */
88    private boolean debugstackmap;
89
90    /**
91     * Target class version.
92     */
93    private Target target;
94
95    /**
96     * Source language version.
97     */
98    private Source source;
99
100    /** Type utilities. */
101    private Types types;
102
103    /**
104     * If true, class files will be written in module-specific subdirectories
105     * of the CLASS_OUTPUT location.
106     */
107    public boolean multiModuleMode;
108
109    /** The initial sizes of the data and constant pool buffers.
110     *  Sizes are increased when buffers get full.
111     */
112    static final int DATA_BUF_SIZE = 0x0fff0;
113    static final int POOL_BUF_SIZE = 0x1fff0;
114
115    /** An output buffer for member info.
116     */
117    ByteBuffer databuf = new ByteBuffer(DATA_BUF_SIZE);
118
119    /** An output buffer for the constant pool.
120     */
121    ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
122
123    /** The constant pool.
124     */
125    Pool pool;
126
127    /** The inner classes to be written, as a set.
128     */
129    Set<ClassSymbol> innerClasses;
130
131    /** The inner classes to be written, as a queue where
132     *  enclosing classes come first.
133     */
134    ListBuffer<ClassSymbol> innerClassesQueue;
135
136    /** The bootstrap methods to be written in the corresponding class attribute
137     *  (one for each invokedynamic)
138     */
139    Map<DynamicMethod.BootstrapMethodsKey, DynamicMethod.BootstrapMethodsValue> bootstrapMethods;
140
141    /** The log to use for verbose output.
142     */
143    private final Log log;
144
145    /** The name table. */
146    private final Names names;
147
148    /** Access to files. */
149    private final JavaFileManager fileManager;
150
151    /** Sole signature generator */
152    private final CWSignatureGenerator signatureGen;
153
154    /** The tags and constants used in compressed stackmap. */
155    static final int SAME_FRAME_SIZE = 64;
156    static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
157    static final int SAME_FRAME_EXTENDED = 251;
158    static final int FULL_FRAME = 255;
159    static final int MAX_LOCAL_LENGTH_DIFF = 4;
160
161    /** Get the ClassWriter instance for this context. */
162    public static ClassWriter instance(Context context) {
163        ClassWriter instance = context.get(classWriterKey);
164        if (instance == null)
165            instance = new ClassWriter(context);
166        return instance;
167    }
168
169    /** Construct a class writer, given an options table.
170     */
171    protected ClassWriter(Context context) {
172        context.put(classWriterKey, this);
173
174        log = Log.instance(context);
175        names = Names.instance(context);
176        options = Options.instance(context);
177        target = Target.instance(context);
178        source = Source.instance(context);
179        types = Types.instance(context);
180        fileManager = context.get(JavaFileManager.class);
181        signatureGen = new CWSignatureGenerator(types);
182
183        verbose        = options.isSet(VERBOSE);
184        genCrt         = options.isSet(XJCOV);
185        debugstackmap = options.isSet("debug.stackmap");
186
187        emitSourceFile = options.isUnset(G_CUSTOM) ||
188                            options.isSet(G_CUSTOM, "source");
189
190        String modifierFlags = options.get("debug.dumpmodifiers");
191        if (modifierFlags != null) {
192            dumpClassModifiers = modifierFlags.indexOf('c') != -1;
193            dumpFieldModifiers = modifierFlags.indexOf('f') != -1;
194            dumpInnerClassModifiers = modifierFlags.indexOf('i') != -1;
195            dumpMethodModifiers = modifierFlags.indexOf('m') != -1;
196        }
197    }
198
199/******************************************************************
200 * Diagnostics: dump generated class names and modifiers
201 ******************************************************************/
202
203    /** Value of option 'dumpmodifiers' is a string
204     *  indicating which modifiers should be dumped for debugging:
205     *    'c' -- classes
206     *    'f' -- fields
207     *    'i' -- innerclass attributes
208     *    'm' -- methods
209     *  For example, to dump everything:
210     *    javac -XDdumpmodifiers=cifm MyProg.java
211     */
212    private boolean dumpClassModifiers; // -XDdumpmodifiers=c
213    private boolean dumpFieldModifiers; // -XDdumpmodifiers=f
214    private boolean dumpInnerClassModifiers; // -XDdumpmodifiers=i
215    private boolean dumpMethodModifiers; // -XDdumpmodifiers=m
216
217
218    /** Return flags as a string, separated by " ".
219     */
220    public static String flagNames(long flags) {
221        StringBuilder sbuf = new StringBuilder();
222        int i = 0;
223        long f = flags & StandardFlags;
224        while (f != 0) {
225            if ((f & 1) != 0) {
226                sbuf.append(" ");
227                sbuf.append(flagName[i]);
228            }
229            f = f >> 1;
230            i++;
231        }
232        return sbuf.toString();
233    }
234    //where
235        private final static String[] flagName = {
236            "PUBLIC", "PRIVATE", "PROTECTED", "STATIC", "FINAL",
237            "SUPER", "VOLATILE", "TRANSIENT", "NATIVE", "INTERFACE",
238            "ABSTRACT", "STRICTFP"};
239
240/******************************************************************
241 * Output routines
242 ******************************************************************/
243
244    /** Write a character into given byte buffer;
245     *  byte buffer will not be grown.
246     */
247    void putChar(ByteBuffer buf, int op, int x) {
248        buf.elems[op  ] = (byte)((x >>  8) & 0xFF);
249        buf.elems[op+1] = (byte)((x      ) & 0xFF);
250    }
251
252    /** Write an integer into given byte buffer;
253     *  byte buffer will not be grown.
254     */
255    void putInt(ByteBuffer buf, int adr, int x) {
256        buf.elems[adr  ] = (byte)((x >> 24) & 0xFF);
257        buf.elems[adr+1] = (byte)((x >> 16) & 0xFF);
258        buf.elems[adr+2] = (byte)((x >>  8) & 0xFF);
259        buf.elems[adr+3] = (byte)((x      ) & 0xFF);
260    }
261
262    /**
263     * Signature Generation
264     */
265    private class CWSignatureGenerator extends Types.SignatureGenerator {
266
267        /**
268         * An output buffer for type signatures.
269         */
270        ByteBuffer sigbuf = new ByteBuffer();
271
272        CWSignatureGenerator(Types types) {
273            super(types);
274        }
275
276        /**
277         * Assemble signature of given type in string buffer.
278         * Check for uninitialized types before calling the general case.
279         */
280        @Override
281        public void assembleSig(Type type) {
282            switch (type.getTag()) {
283                case UNINITIALIZED_THIS:
284                case UNINITIALIZED_OBJECT:
285                    // we don't yet have a spec for uninitialized types in the
286                    // local variable table
287                    assembleSig(types.erasure(((UninitializedType)type).qtype));
288                    break;
289                default:
290                    super.assembleSig(type);
291            }
292        }
293
294        @Override
295        protected void append(char ch) {
296            sigbuf.appendByte(ch);
297        }
298
299        @Override
300        protected void append(byte[] ba) {
301            sigbuf.appendBytes(ba);
302        }
303
304        @Override
305        protected void append(Name name) {
306            sigbuf.appendName(name);
307        }
308
309        @Override
310        protected void classReference(ClassSymbol c) {
311            enterInner(c);
312        }
313
314        private void reset() {
315            sigbuf.reset();
316        }
317
318        private Name toName() {
319            return sigbuf.toName(names);
320        }
321
322        private boolean isEmpty() {
323            return sigbuf.length == 0;
324        }
325    }
326
327    /**
328     * Return signature of given type
329     */
330    Name typeSig(Type type) {
331        Assert.check(signatureGen.isEmpty());
332        //- System.out.println(" ? " + type);
333        signatureGen.assembleSig(type);
334        Name n = signatureGen.toName();
335        signatureGen.reset();
336        //- System.out.println("   " + n);
337        return n;
338    }
339
340    /** Given a type t, return the extended class name of its erasure in
341     *  external representation.
342     */
343    public Name xClassName(Type t) {
344        if (t.hasTag(CLASS)) {
345            return names.fromUtf(externalize(t.tsym.flatName()));
346        } else if (t.hasTag(ARRAY)) {
347            return typeSig(types.erasure(t));
348        } else {
349            throw new AssertionError("xClassName expects class or array type, got " + t);
350        }
351    }
352
353/******************************************************************
354 * Writing the Constant Pool
355 ******************************************************************/
356
357    /** Thrown when the constant pool is over full.
358     */
359    public static class PoolOverflow extends Exception {
360        private static final long serialVersionUID = 0;
361        public PoolOverflow() {}
362    }
363    public static class StringOverflow extends Exception {
364        private static final long serialVersionUID = 0;
365        public final String value;
366        public StringOverflow(String s) {
367            value = s;
368        }
369    }
370
371    /** Write constant pool to pool buffer.
372     *  Note: during writing, constant pool
373     *  might grow since some parts of constants still need to be entered.
374     */
375    void writePool(Pool pool) throws PoolOverflow, StringOverflow {
376        int poolCountIdx = poolbuf.length;
377        poolbuf.appendChar(0);
378        int i = 1;
379        while (i < pool.pp) {
380            Object value = pool.pool[i];
381            Assert.checkNonNull(value);
382            if (value instanceof Method || value instanceof Variable)
383                value = ((DelegatedSymbol)value).getUnderlyingSymbol();
384
385            if (value instanceof MethodSymbol) {
386                MethodSymbol m = (MethodSymbol)value;
387                if (!m.isDynamic()) {
388                    poolbuf.appendByte((m.owner.flags() & INTERFACE) != 0
389                              ? CONSTANT_InterfaceMethodref
390                              : CONSTANT_Methodref);
391                    poolbuf.appendChar(pool.put(m.owner));
392                    poolbuf.appendChar(pool.put(nameType(m)));
393                } else {
394                    //invokedynamic
395                    DynamicMethodSymbol dynSym = (DynamicMethodSymbol)m;
396                    MethodHandle handle = new MethodHandle(dynSym.bsmKind, dynSym.bsm, types);
397                    DynamicMethod.BootstrapMethodsKey key = new DynamicMethod.BootstrapMethodsKey(dynSym, types);
398
399                    // Figure out the index for existing BSM; create a new BSM if no key
400                    DynamicMethod.BootstrapMethodsValue val = bootstrapMethods.get(key);
401                    if (val == null) {
402                        int index = bootstrapMethods.size();
403                        val = new DynamicMethod.BootstrapMethodsValue(handle, index);
404                        bootstrapMethods.put(key, val);
405                    }
406
407                    //init cp entries
408                    pool.put(names.BootstrapMethods);
409                    pool.put(handle);
410                    for (Object staticArg : dynSym.staticArgs) {
411                        pool.put(staticArg);
412                    }
413                    poolbuf.appendByte(CONSTANT_InvokeDynamic);
414                    poolbuf.appendChar(val.index);
415                    poolbuf.appendChar(pool.put(nameType(dynSym)));
416                }
417            } else if (value instanceof VarSymbol) {
418                VarSymbol v = (VarSymbol)value;
419                poolbuf.appendByte(CONSTANT_Fieldref);
420                poolbuf.appendChar(pool.put(v.owner));
421                poolbuf.appendChar(pool.put(nameType(v)));
422            } else if (value instanceof Name) {
423                poolbuf.appendByte(CONSTANT_Utf8);
424                byte[] bs = ((Name)value).toUtf();
425                poolbuf.appendChar(bs.length);
426                poolbuf.appendBytes(bs, 0, bs.length);
427                if (bs.length > Pool.MAX_STRING_LENGTH)
428                    throw new StringOverflow(value.toString());
429            } else if (value instanceof ClassSymbol) {
430                ClassSymbol c = (ClassSymbol)value;
431                if (c.owner.kind == TYP) pool.put(c.owner);
432                poolbuf.appendByte(CONSTANT_Class);
433                if (c.type.hasTag(ARRAY)) {
434                    poolbuf.appendChar(pool.put(typeSig(c.type)));
435                } else {
436                    poolbuf.appendChar(pool.put(names.fromUtf(externalize(c.flatname))));
437                    enterInner(c);
438                }
439            } else if (value instanceof NameAndType) {
440                NameAndType nt = (NameAndType)value;
441                poolbuf.appendByte(CONSTANT_NameandType);
442                poolbuf.appendChar(pool.put(nt.name));
443                poolbuf.appendChar(pool.put(typeSig(nt.uniqueType.type)));
444            } else if (value instanceof Integer) {
445                poolbuf.appendByte(CONSTANT_Integer);
446                poolbuf.appendInt(((Integer)value).intValue());
447            } else if (value instanceof Long) {
448                poolbuf.appendByte(CONSTANT_Long);
449                poolbuf.appendLong(((Long)value).longValue());
450                i++;
451            } else if (value instanceof Float) {
452                poolbuf.appendByte(CONSTANT_Float);
453                poolbuf.appendFloat(((Float)value).floatValue());
454            } else if (value instanceof Double) {
455                poolbuf.appendByte(CONSTANT_Double);
456                poolbuf.appendDouble(((Double)value).doubleValue());
457                i++;
458            } else if (value instanceof String) {
459                poolbuf.appendByte(CONSTANT_String);
460                poolbuf.appendChar(pool.put(names.fromString((String)value)));
461            } else if (value instanceof UniqueType) {
462                Type type = ((UniqueType)value).type;
463                if (type.hasTag(METHOD)) {
464                    poolbuf.appendByte(CONSTANT_MethodType);
465                    poolbuf.appendChar(pool.put(typeSig((MethodType)type)));
466                } else {
467                    Assert.check(type.hasTag(ARRAY));
468                    poolbuf.appendByte(CONSTANT_Class);
469                    poolbuf.appendChar(pool.put(xClassName(type)));
470                }
471            } else if (value instanceof MethodHandle) {
472                MethodHandle ref = (MethodHandle)value;
473                poolbuf.appendByte(CONSTANT_MethodHandle);
474                poolbuf.appendByte(ref.refKind);
475                poolbuf.appendChar(pool.put(ref.refSym));
476            } else {
477                Assert.error("writePool " + value);
478            }
479            i++;
480        }
481        if (pool.pp > Pool.MAX_ENTRIES)
482            throw new PoolOverflow();
483        putChar(poolbuf, poolCountIdx, pool.pp);
484    }
485
486    /** Given a symbol, return its name-and-type.
487     */
488    NameAndType nameType(Symbol sym) {
489        return new NameAndType(sym.name, sym.externalType(types), types);
490        // the NameAndType is generated from a symbol reference, and the
491        // adjustment of adding an additional this$n parameter needs to be made.
492    }
493
494/******************************************************************
495 * Writing Attributes
496 ******************************************************************/
497
498    /** Write header for an attribute to data buffer and return
499     *  position past attribute length index.
500     */
501    int writeAttr(Name attrName) {
502        databuf.appendChar(pool.put(attrName));
503        databuf.appendInt(0);
504        return databuf.length;
505    }
506
507    /** Fill in attribute length.
508     */
509    void endAttr(int index) {
510        putInt(databuf, index - 4, databuf.length - index);
511    }
512
513    /** Leave space for attribute count and return index for
514     *  number of attributes field.
515     */
516    int beginAttrs() {
517        databuf.appendChar(0);
518        return databuf.length;
519    }
520
521    /** Fill in number of attributes.
522     */
523    void endAttrs(int index, int count) {
524        putChar(databuf, index - 2, count);
525    }
526
527    /** Write the EnclosingMethod attribute if needed.
528     *  Returns the number of attributes written (0 or 1).
529     */
530    int writeEnclosingMethodAttribute(ClassSymbol c) {
531        return writeEnclosingMethodAttribute(names.EnclosingMethod, c);
532    }
533
534    /** Write the EnclosingMethod attribute with a specified name.
535     *  Returns the number of attributes written (0 or 1).
536     */
537    protected int writeEnclosingMethodAttribute(Name attributeName, ClassSymbol c) {
538        if (c.owner.kind != MTH && // neither a local class
539            c.name != names.empty) // nor anonymous
540            return 0;
541
542        int alenIdx = writeAttr(attributeName);
543        ClassSymbol enclClass = c.owner.enclClass();
544        MethodSymbol enclMethod =
545            (c.owner.type == null // local to init block
546             || c.owner.kind != MTH) // or member init
547            ? null
548            : (MethodSymbol)c.owner;
549        databuf.appendChar(pool.put(enclClass));
550        databuf.appendChar(enclMethod == null ? 0 : pool.put(nameType(c.owner)));
551        endAttr(alenIdx);
552        return 1;
553    }
554
555    /** Write flag attributes; return number of attributes written.
556     */
557    int writeFlagAttrs(long flags) {
558        int acount = 0;
559        if ((flags & DEPRECATED) != 0) {
560            int alenIdx = writeAttr(names.Deprecated);
561            endAttr(alenIdx);
562            acount++;
563        }
564        return acount;
565    }
566
567    /** Write member (field or method) attributes;
568     *  return number of attributes written.
569     */
570    int writeMemberAttrs(Symbol sym) {
571        int acount = writeFlagAttrs(sym.flags());
572        long flags = sym.flags();
573        if ((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC &&
574            (flags & ANONCONSTR) == 0 &&
575            (!types.isSameType(sym.type, sym.erasure(types)) ||
576             signatureGen.hasTypeVar(sym.type.getThrownTypes()))) {
577            // note that a local class with captured variables
578            // will get a signature attribute
579            int alenIdx = writeAttr(names.Signature);
580            databuf.appendChar(pool.put(typeSig(sym.type)));
581            endAttr(alenIdx);
582            acount++;
583        }
584        acount += writeJavaAnnotations(sym.getRawAttributes());
585        acount += writeTypeAnnotations(sym.getRawTypeAttributes(), false);
586        return acount;
587    }
588
589    /**
590     * Write method parameter names attribute.
591     */
592    int writeMethodParametersAttr(MethodSymbol m) {
593        MethodType ty = m.externalType(types).asMethodType();
594        final int allparams = ty.argtypes.size();
595        if (m.params != null && allparams != 0) {
596            final int attrIndex = writeAttr(names.MethodParameters);
597            databuf.appendByte(allparams);
598            // Write extra parameters first
599            for (VarSymbol s : m.extraParams) {
600                final int flags =
601                    ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
602                    ((int) m.flags() & SYNTHETIC);
603                databuf.appendChar(pool.put(s.name));
604                databuf.appendChar(flags);
605            }
606            // Now write the real parameters
607            for (VarSymbol s : m.params) {
608                final int flags =
609                    ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
610                    ((int) m.flags() & SYNTHETIC);
611                databuf.appendChar(pool.put(s.name));
612                databuf.appendChar(flags);
613            }
614            // Now write the captured locals
615            for (VarSymbol s : m.capturedLocals) {
616                final int flags =
617                    ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
618                    ((int) m.flags() & SYNTHETIC);
619                databuf.appendChar(pool.put(s.name));
620                databuf.appendChar(flags);
621            }
622            endAttr(attrIndex);
623            return 1;
624        } else
625            return 0;
626    }
627
628
629    private void writeParamAnnotations(List<VarSymbol> params,
630                                       RetentionPolicy retention) {
631        for (VarSymbol s : params) {
632            ListBuffer<Attribute.Compound> buf = new ListBuffer<>();
633            for (Attribute.Compound a : s.getRawAttributes())
634                if (types.getRetention(a) == retention)
635                    buf.append(a);
636            databuf.appendChar(buf.length());
637            for (Attribute.Compound a : buf)
638                writeCompoundAttribute(a);
639        }
640
641    }
642
643    private void writeParamAnnotations(MethodSymbol m,
644                                       RetentionPolicy retention) {
645        databuf.appendByte(m.params.length());
646        writeParamAnnotations(m.params, retention);
647    }
648
649    /** Write method parameter annotations;
650     *  return number of attributes written.
651     */
652    int writeParameterAttrs(MethodSymbol m) {
653        boolean hasVisible = false;
654        boolean hasInvisible = false;
655        if (m.params != null) {
656            for (VarSymbol s : m.params) {
657                for (Attribute.Compound a : s.getRawAttributes()) {
658                    switch (types.getRetention(a)) {
659                    case SOURCE: break;
660                    case CLASS: hasInvisible = true; break;
661                    case RUNTIME: hasVisible = true; break;
662                    default: // /* fail soft */ throw new AssertionError(vis);
663                    }
664                }
665            }
666        }
667
668        int attrCount = 0;
669        if (hasVisible) {
670            int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations);
671            writeParamAnnotations(m, RetentionPolicy.RUNTIME);
672            endAttr(attrIndex);
673            attrCount++;
674        }
675        if (hasInvisible) {
676            int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations);
677            writeParamAnnotations(m, RetentionPolicy.CLASS);
678            endAttr(attrIndex);
679            attrCount++;
680        }
681        return attrCount;
682    }
683
684/**********************************************************************
685 * Writing Java-language annotations (aka metadata, attributes)
686 **********************************************************************/
687
688    /** Write Java-language annotations; return number of JVM
689     *  attributes written (zero or one).
690     */
691    int writeJavaAnnotations(List<Attribute.Compound> attrs) {
692        if (attrs.isEmpty()) return 0;
693        ListBuffer<Attribute.Compound> visibles = new ListBuffer<>();
694        ListBuffer<Attribute.Compound> invisibles = new ListBuffer<>();
695        for (Attribute.Compound a : attrs) {
696            switch (types.getRetention(a)) {
697            case SOURCE: break;
698            case CLASS: invisibles.append(a); break;
699            case RUNTIME: visibles.append(a); break;
700            default: // /* fail soft */ throw new AssertionError(vis);
701            }
702        }
703
704        int attrCount = 0;
705        if (visibles.length() != 0) {
706            int attrIndex = writeAttr(names.RuntimeVisibleAnnotations);
707            databuf.appendChar(visibles.length());
708            for (Attribute.Compound a : visibles)
709                writeCompoundAttribute(a);
710            endAttr(attrIndex);
711            attrCount++;
712        }
713        if (invisibles.length() != 0) {
714            int attrIndex = writeAttr(names.RuntimeInvisibleAnnotations);
715            databuf.appendChar(invisibles.length());
716            for (Attribute.Compound a : invisibles)
717                writeCompoundAttribute(a);
718            endAttr(attrIndex);
719            attrCount++;
720        }
721        return attrCount;
722    }
723
724    int writeTypeAnnotations(List<Attribute.TypeCompound> typeAnnos, boolean inCode) {
725        if (typeAnnos.isEmpty()) return 0;
726
727        ListBuffer<Attribute.TypeCompound> visibles = new ListBuffer<>();
728        ListBuffer<Attribute.TypeCompound> invisibles = new ListBuffer<>();
729
730        for (Attribute.TypeCompound tc : typeAnnos) {
731            if (tc.hasUnknownPosition()) {
732                boolean fixed = tc.tryFixPosition();
733
734                // Could we fix it?
735                if (!fixed) {
736                    // This happens for nested types like @A Outer. @B Inner.
737                    // For method parameters we get the annotation twice! Once with
738                    // a valid position, once unknown.
739                    // TODO: find a cleaner solution.
740                    PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
741                    pw.println("ClassWriter: Position UNKNOWN in type annotation: " + tc);
742                    continue;
743                }
744            }
745
746            if (tc.position.type.isLocal() != inCode)
747                continue;
748            if (!tc.position.emitToClassfile())
749                continue;
750            switch (types.getRetention(tc)) {
751            case SOURCE: break;
752            case CLASS: invisibles.append(tc); break;
753            case RUNTIME: visibles.append(tc); break;
754            default: // /* fail soft */ throw new AssertionError(vis);
755            }
756        }
757
758        int attrCount = 0;
759        if (visibles.length() != 0) {
760            int attrIndex = writeAttr(names.RuntimeVisibleTypeAnnotations);
761            databuf.appendChar(visibles.length());
762            for (Attribute.TypeCompound p : visibles)
763                writeTypeAnnotation(p);
764            endAttr(attrIndex);
765            attrCount++;
766        }
767
768        if (invisibles.length() != 0) {
769            int attrIndex = writeAttr(names.RuntimeInvisibleTypeAnnotations);
770            databuf.appendChar(invisibles.length());
771            for (Attribute.TypeCompound p : invisibles)
772                writeTypeAnnotation(p);
773            endAttr(attrIndex);
774            attrCount++;
775        }
776
777        return attrCount;
778    }
779
780    /** A visitor to write an attribute including its leading
781     *  single-character marker.
782     */
783    class AttributeWriter implements Attribute.Visitor {
784        public void visitConstant(Attribute.Constant _value) {
785            Object value = _value.value;
786            switch (_value.type.getTag()) {
787            case BYTE:
788                databuf.appendByte('B');
789                break;
790            case CHAR:
791                databuf.appendByte('C');
792                break;
793            case SHORT:
794                databuf.appendByte('S');
795                break;
796            case INT:
797                databuf.appendByte('I');
798                break;
799            case LONG:
800                databuf.appendByte('J');
801                break;
802            case FLOAT:
803                databuf.appendByte('F');
804                break;
805            case DOUBLE:
806                databuf.appendByte('D');
807                break;
808            case BOOLEAN:
809                databuf.appendByte('Z');
810                break;
811            case CLASS:
812                Assert.check(value instanceof String);
813                databuf.appendByte('s');
814                value = names.fromString(value.toString()); // CONSTANT_Utf8
815                break;
816            default:
817                throw new AssertionError(_value.type);
818            }
819            databuf.appendChar(pool.put(value));
820        }
821        public void visitEnum(Attribute.Enum e) {
822            databuf.appendByte('e');
823            databuf.appendChar(pool.put(typeSig(e.value.type)));
824            databuf.appendChar(pool.put(e.value.name));
825        }
826        public void visitClass(Attribute.Class clazz) {
827            databuf.appendByte('c');
828            databuf.appendChar(pool.put(typeSig(types.erasure(clazz.classType))));
829        }
830        public void visitCompound(Attribute.Compound compound) {
831            databuf.appendByte('@');
832            writeCompoundAttribute(compound);
833        }
834        public void visitError(Attribute.Error x) {
835            throw new AssertionError(x);
836        }
837        public void visitArray(Attribute.Array array) {
838            databuf.appendByte('[');
839            databuf.appendChar(array.values.length);
840            for (Attribute a : array.values) {
841                a.accept(this);
842            }
843        }
844    }
845    AttributeWriter awriter = new AttributeWriter();
846
847    /** Write a compound attribute excluding the '@' marker. */
848    void writeCompoundAttribute(Attribute.Compound c) {
849        databuf.appendChar(pool.put(typeSig(c.type)));
850        databuf.appendChar(c.values.length());
851        for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) {
852            databuf.appendChar(pool.put(p.fst.name));
853            p.snd.accept(awriter);
854        }
855    }
856
857    void writeTypeAnnotation(Attribute.TypeCompound c) {
858        writePosition(c.position);
859        writeCompoundAttribute(c);
860    }
861
862    void writePosition(TypeAnnotationPosition p) {
863        databuf.appendByte(p.type.targetTypeValue()); // TargetType tag is a byte
864        switch (p.type) {
865        // instanceof
866        case INSTANCEOF:
867        // new expression
868        case NEW:
869        // constructor/method reference receiver
870        case CONSTRUCTOR_REFERENCE:
871        case METHOD_REFERENCE:
872            databuf.appendChar(p.offset);
873            break;
874        // local variable
875        case LOCAL_VARIABLE:
876        // resource variable
877        case RESOURCE_VARIABLE:
878            databuf.appendChar(p.lvarOffset.length);  // for table length
879            for (int i = 0; i < p.lvarOffset.length; ++i) {
880                databuf.appendChar(p.lvarOffset[i]);
881                databuf.appendChar(p.lvarLength[i]);
882                databuf.appendChar(p.lvarIndex[i]);
883            }
884            break;
885        // exception parameter
886        case EXCEPTION_PARAMETER:
887            databuf.appendChar(p.getExceptionIndex());
888            break;
889        // method receiver
890        case METHOD_RECEIVER:
891            // Do nothing
892            break;
893        // type parameter
894        case CLASS_TYPE_PARAMETER:
895        case METHOD_TYPE_PARAMETER:
896            databuf.appendByte(p.parameter_index);
897            break;
898        // type parameter bound
899        case CLASS_TYPE_PARAMETER_BOUND:
900        case METHOD_TYPE_PARAMETER_BOUND:
901            databuf.appendByte(p.parameter_index);
902            databuf.appendByte(p.bound_index);
903            break;
904        // class extends or implements clause
905        case CLASS_EXTENDS:
906            databuf.appendChar(p.type_index);
907            break;
908        // throws
909        case THROWS:
910            databuf.appendChar(p.type_index);
911            break;
912        // method parameter
913        case METHOD_FORMAL_PARAMETER:
914            databuf.appendByte(p.parameter_index);
915            break;
916        // type cast
917        case CAST:
918        // method/constructor/reference type argument
919        case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
920        case METHOD_INVOCATION_TYPE_ARGUMENT:
921        case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
922        case METHOD_REFERENCE_TYPE_ARGUMENT:
923            databuf.appendChar(p.offset);
924            databuf.appendByte(p.type_index);
925            break;
926        // We don't need to worry about these
927        case METHOD_RETURN:
928        case FIELD:
929            break;
930        case UNKNOWN:
931            throw new AssertionError("jvm.ClassWriter: UNKNOWN target type should never occur!");
932        default:
933            throw new AssertionError("jvm.ClassWriter: Unknown target type for position: " + p);
934        }
935
936        { // Append location data for generics/arrays.
937            databuf.appendByte(p.location.size());
938            java.util.List<Integer> loc = TypeAnnotationPosition.getBinaryFromTypePath(p.location);
939            for (int i : loc)
940                databuf.appendByte((byte)i);
941        }
942    }
943
944/**********************************************************************
945 * Writing module attributes
946 **********************************************************************/
947
948    /** Write the Module attribute if needed.
949     *  Returns the number of attributes written (0 or 1).
950     */
951    int writeModuleAttribute(ClassSymbol c) {
952        ModuleSymbol m = (ModuleSymbol) c.owner;
953
954        int alenIdx = writeAttr(names.Module);
955        ListBuffer<RequiresDirective> requires = new ListBuffer<>();
956        for (RequiresDirective r: m.requires) {
957            if (!r.flags.contains(RequiresFlag.EXTRA))
958                requires.add(r);
959        }
960        databuf.appendChar(requires.size());
961        for (RequiresDirective r: requires) {
962            databuf.appendChar(pool.put(r.module.name));
963            databuf.appendChar(RequiresFlag.value(r.flags));
964        }
965
966        List<ExportsDirective> exports = m.exports;
967        databuf.appendChar(exports.size());
968        for (ExportsDirective e: exports) {
969            databuf.appendChar(pool.put(names.fromUtf(externalize(e.packge.flatName()))));
970            if (e.modules == null) {
971                databuf.appendChar(0);
972            } else {
973                databuf.appendChar(e.modules.size());
974                for (ModuleSymbol msym: e.modules)
975                    databuf.appendChar(pool.put(msym.name));
976            }
977        }
978
979        List<UsesDirective> uses = m.uses;
980        databuf.appendChar(uses.size());
981        for (UsesDirective s: uses) {
982            databuf.appendChar(pool.put(s.service));
983        }
984
985        List<ProvidesDirective> services = m.provides;
986        databuf.appendChar(services.size());
987        for (ProvidesDirective s: services) {
988            databuf.appendChar(pool.put(s.service));
989            databuf.appendChar(pool.put(s.impl));
990        }
991
992        endAttr(alenIdx);
993        return 1;
994    }
995
996/**********************************************************************
997 * Writing Objects
998 **********************************************************************/
999
1000    /** Enter an inner class into the `innerClasses' set/queue.
1001     */
1002    void enterInner(ClassSymbol c) {
1003        if (c.type.isCompound()) {
1004            throw new AssertionError("Unexpected intersection type: " + c.type);
1005        }
1006        try {
1007            c.complete();
1008        } catch (CompletionFailure ex) {
1009            System.err.println("error: " + c + ": " + ex.getMessage());
1010            throw ex;
1011        }
1012        if (!c.type.hasTag(CLASS)) return; // arrays
1013        if (pool != null && // pool might be null if called from xClassName
1014            c.owner.enclClass() != null &&
1015            (innerClasses == null || !innerClasses.contains(c))) {
1016//          log.errWriter.println("enter inner " + c);//DEBUG
1017            enterInner(c.owner.enclClass());
1018            pool.put(c);
1019            if (c.name != names.empty)
1020                pool.put(c.name);
1021            if (innerClasses == null) {
1022                innerClasses = new HashSet<>();
1023                innerClassesQueue = new ListBuffer<>();
1024                pool.put(names.InnerClasses);
1025            }
1026            innerClasses.add(c);
1027            innerClassesQueue.append(c);
1028        }
1029    }
1030
1031    /** Write "inner classes" attribute.
1032     */
1033    void writeInnerClasses() {
1034        int alenIdx = writeAttr(names.InnerClasses);
1035        databuf.appendChar(innerClassesQueue.length());
1036        for (List<ClassSymbol> l = innerClassesQueue.toList();
1037             l.nonEmpty();
1038             l = l.tail) {
1039            ClassSymbol inner = l.head;
1040            inner.markAbstractIfNeeded(types);
1041            char flags = (char) adjustFlags(inner.flags_field);
1042            if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT
1043            if (inner.name.isEmpty()) flags &= ~FINAL; // Anonymous class: unset FINAL flag
1044            flags &= ~STRICTFP; //inner classes should not have the strictfp flag set.
1045            if (dumpInnerClassModifiers) {
1046                PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1047                pw.println("INNERCLASS  " + inner.name);
1048                pw.println("---" + flagNames(flags));
1049            }
1050            databuf.appendChar(pool.get(inner));
1051            databuf.appendChar(
1052                inner.owner.kind == TYP && !inner.name.isEmpty() ? pool.get(inner.owner) : 0);
1053            databuf.appendChar(
1054                !inner.name.isEmpty() ? pool.get(inner.name) : 0);
1055            databuf.appendChar(flags);
1056        }
1057        endAttr(alenIdx);
1058    }
1059
1060    /** Write "bootstrapMethods" attribute.
1061     */
1062    void writeBootstrapMethods() {
1063        int alenIdx = writeAttr(names.BootstrapMethods);
1064        databuf.appendChar(bootstrapMethods.size());
1065        for (Map.Entry<DynamicMethod.BootstrapMethodsKey, DynamicMethod.BootstrapMethodsValue> entry : bootstrapMethods.entrySet()) {
1066            DynamicMethod.BootstrapMethodsKey bsmKey = entry.getKey();
1067            //write BSM handle
1068            databuf.appendChar(pool.get(entry.getValue().mh));
1069            Object[] uniqueArgs = bsmKey.getUniqueArgs();
1070            //write static args length
1071            databuf.appendChar(uniqueArgs.length);
1072            //write static args array
1073            for (Object o : uniqueArgs) {
1074                databuf.appendChar(pool.get(o));
1075            }
1076        }
1077        endAttr(alenIdx);
1078    }
1079
1080    /** Write field symbol, entering all references into constant pool.
1081     */
1082    void writeField(VarSymbol v) {
1083        int flags = adjustFlags(v.flags());
1084        databuf.appendChar(flags);
1085        if (dumpFieldModifiers) {
1086            PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1087            pw.println("FIELD  " + v.name);
1088            pw.println("---" + flagNames(v.flags()));
1089        }
1090        databuf.appendChar(pool.put(v.name));
1091        databuf.appendChar(pool.put(typeSig(v.erasure(types))));
1092        int acountIdx = beginAttrs();
1093        int acount = 0;
1094        if (v.getConstValue() != null) {
1095            int alenIdx = writeAttr(names.ConstantValue);
1096            databuf.appendChar(pool.put(v.getConstValue()));
1097            endAttr(alenIdx);
1098            acount++;
1099        }
1100        acount += writeMemberAttrs(v);
1101        endAttrs(acountIdx, acount);
1102    }
1103
1104    /** Write method symbol, entering all references into constant pool.
1105     */
1106    void writeMethod(MethodSymbol m) {
1107        int flags = adjustFlags(m.flags());
1108        databuf.appendChar(flags);
1109        if (dumpMethodModifiers) {
1110            PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1111            pw.println("METHOD  " + m.name);
1112            pw.println("---" + flagNames(m.flags()));
1113        }
1114        databuf.appendChar(pool.put(m.name));
1115        databuf.appendChar(pool.put(typeSig(m.externalType(types))));
1116        int acountIdx = beginAttrs();
1117        int acount = 0;
1118        if (m.code != null) {
1119            int alenIdx = writeAttr(names.Code);
1120            writeCode(m.code);
1121            m.code = null; // to conserve space
1122            endAttr(alenIdx);
1123            acount++;
1124        }
1125        List<Type> thrown = m.erasure(types).getThrownTypes();
1126        if (thrown.nonEmpty()) {
1127            int alenIdx = writeAttr(names.Exceptions);
1128            databuf.appendChar(thrown.length());
1129            for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
1130                databuf.appendChar(pool.put(l.head.tsym));
1131            endAttr(alenIdx);
1132            acount++;
1133        }
1134        if (m.defaultValue != null) {
1135            int alenIdx = writeAttr(names.AnnotationDefault);
1136            m.defaultValue.accept(awriter);
1137            endAttr(alenIdx);
1138            acount++;
1139        }
1140        if (options.isSet(PARAMETERS)) {
1141            if (!m.isLambdaMethod()) // Per JDK-8138729, do not emit parameters table for lambda bodies.
1142                acount += writeMethodParametersAttr(m);
1143        }
1144        acount += writeMemberAttrs(m);
1145        if (!m.isLambdaMethod())
1146            acount += writeParameterAttrs(m);
1147        endAttrs(acountIdx, acount);
1148    }
1149
1150    /** Write code attribute of method.
1151     */
1152    void writeCode(Code code) {
1153        databuf.appendChar(code.max_stack);
1154        databuf.appendChar(code.max_locals);
1155        databuf.appendInt(code.cp);
1156        databuf.appendBytes(code.code, 0, code.cp);
1157        databuf.appendChar(code.catchInfo.length());
1158        for (List<char[]> l = code.catchInfo.toList();
1159             l.nonEmpty();
1160             l = l.tail) {
1161            for (int i = 0; i < l.head.length; i++)
1162                databuf.appendChar(l.head[i]);
1163        }
1164        int acountIdx = beginAttrs();
1165        int acount = 0;
1166
1167        if (code.lineInfo.nonEmpty()) {
1168            int alenIdx = writeAttr(names.LineNumberTable);
1169            databuf.appendChar(code.lineInfo.length());
1170            for (List<char[]> l = code.lineInfo.reverse();
1171                 l.nonEmpty();
1172                 l = l.tail)
1173                for (int i = 0; i < l.head.length; i++)
1174                    databuf.appendChar(l.head[i]);
1175            endAttr(alenIdx);
1176            acount++;
1177        }
1178
1179        if (genCrt && (code.crt != null)) {
1180            CRTable crt = code.crt;
1181            int alenIdx = writeAttr(names.CharacterRangeTable);
1182            int crtIdx = beginAttrs();
1183            int crtEntries = crt.writeCRT(databuf, code.lineMap, log);
1184            endAttrs(crtIdx, crtEntries);
1185            endAttr(alenIdx);
1186            acount++;
1187        }
1188
1189        // counter for number of generic local variables
1190        if (code.varDebugInfo && code.varBufferSize > 0) {
1191            int nGenericVars = 0;
1192            int alenIdx = writeAttr(names.LocalVariableTable);
1193            databuf.appendChar(code.getLVTSize());
1194            for (int i=0; i<code.varBufferSize; i++) {
1195                Code.LocalVar var = code.varBuffer[i];
1196
1197                for (Code.LocalVar.Range r: var.aliveRanges) {
1198                    // write variable info
1199                    Assert.check(r.start_pc >= 0
1200                            && r.start_pc <= code.cp);
1201                    databuf.appendChar(r.start_pc);
1202                    Assert.check(r.length > 0
1203                            && (r.start_pc + r.length) <= code.cp);
1204                    databuf.appendChar(r.length);
1205                    VarSymbol sym = var.sym;
1206                    databuf.appendChar(pool.put(sym.name));
1207                    Type vartype = sym.erasure(types);
1208                    databuf.appendChar(pool.put(typeSig(vartype)));
1209                    databuf.appendChar(var.reg);
1210                    if (needsLocalVariableTypeEntry(var.sym.type)) {
1211                        nGenericVars++;
1212                    }
1213                }
1214            }
1215            endAttr(alenIdx);
1216            acount++;
1217
1218            if (nGenericVars > 0) {
1219                alenIdx = writeAttr(names.LocalVariableTypeTable);
1220                databuf.appendChar(nGenericVars);
1221                int count = 0;
1222
1223                for (int i=0; i<code.varBufferSize; i++) {
1224                    Code.LocalVar var = code.varBuffer[i];
1225                    VarSymbol sym = var.sym;
1226                    if (!needsLocalVariableTypeEntry(sym.type))
1227                        continue;
1228                    for (Code.LocalVar.Range r : var.aliveRanges) {
1229                        // write variable info
1230                        databuf.appendChar(r.start_pc);
1231                        databuf.appendChar(r.length);
1232                        databuf.appendChar(pool.put(sym.name));
1233                        databuf.appendChar(pool.put(typeSig(sym.type)));
1234                        databuf.appendChar(var.reg);
1235                        count++;
1236                    }
1237                }
1238                Assert.check(count == nGenericVars);
1239                endAttr(alenIdx);
1240                acount++;
1241            }
1242        }
1243
1244        if (code.stackMapBufferSize > 0) {
1245            if (debugstackmap) System.out.println("Stack map for " + code.meth);
1246            int alenIdx = writeAttr(code.stackMap.getAttributeName(names));
1247            writeStackMap(code);
1248            endAttr(alenIdx);
1249            acount++;
1250        }
1251
1252        acount += writeTypeAnnotations(code.meth.getRawTypeAttributes(), true);
1253
1254        endAttrs(acountIdx, acount);
1255    }
1256    //where
1257    private boolean needsLocalVariableTypeEntry(Type t) {
1258        //a local variable needs a type-entry if its type T is generic
1259        //(i.e. |T| != T) and if it's not an intersection type (not supported
1260        //in signature attribute grammar)
1261        return (!types.isSameType(t, types.erasure(t)) &&
1262                !t.isCompound());
1263    }
1264
1265    void writeStackMap(Code code) {
1266        int nframes = code.stackMapBufferSize;
1267        if (debugstackmap) System.out.println(" nframes = " + nframes);
1268        databuf.appendChar(nframes);
1269
1270        switch (code.stackMap) {
1271        case CLDC:
1272            for (int i=0; i<nframes; i++) {
1273                if (debugstackmap) System.out.print("  " + i + ":");
1274                Code.StackMapFrame frame = code.stackMapBuffer[i];
1275
1276                // output PC
1277                if (debugstackmap) System.out.print(" pc=" + frame.pc);
1278                databuf.appendChar(frame.pc);
1279
1280                // output locals
1281                int localCount = 0;
1282                for (int j=0; j<frame.locals.length;
1283                     j += Code.width(frame.locals[j])) {
1284                    localCount++;
1285                }
1286                if (debugstackmap) System.out.print(" nlocals=" +
1287                                                    localCount);
1288                databuf.appendChar(localCount);
1289                for (int j=0; j<frame.locals.length;
1290                     j += Code.width(frame.locals[j])) {
1291                    if (debugstackmap) System.out.print(" local[" + j + "]=");
1292                    writeStackMapType(frame.locals[j]);
1293                }
1294
1295                // output stack
1296                int stackCount = 0;
1297                for (int j=0; j<frame.stack.length;
1298                     j += Code.width(frame.stack[j])) {
1299                    stackCount++;
1300                }
1301                if (debugstackmap) System.out.print(" nstack=" +
1302                                                    stackCount);
1303                databuf.appendChar(stackCount);
1304                for (int j=0; j<frame.stack.length;
1305                     j += Code.width(frame.stack[j])) {
1306                    if (debugstackmap) System.out.print(" stack[" + j + "]=");
1307                    writeStackMapType(frame.stack[j]);
1308                }
1309                if (debugstackmap) System.out.println();
1310            }
1311            break;
1312        case JSR202: {
1313            Assert.checkNull(code.stackMapBuffer);
1314            for (int i=0; i<nframes; i++) {
1315                if (debugstackmap) System.out.print("  " + i + ":");
1316                StackMapTableFrame frame = code.stackMapTableBuffer[i];
1317                frame.write(this);
1318                if (debugstackmap) System.out.println();
1319            }
1320            break;
1321        }
1322        default:
1323            throw new AssertionError("Unexpected stackmap format value");
1324        }
1325    }
1326
1327        //where
1328        void writeStackMapType(Type t) {
1329            if (t == null) {
1330                if (debugstackmap) System.out.print("empty");
1331                databuf.appendByte(0);
1332            }
1333            else switch(t.getTag()) {
1334            case BYTE:
1335            case CHAR:
1336            case SHORT:
1337            case INT:
1338            case BOOLEAN:
1339                if (debugstackmap) System.out.print("int");
1340                databuf.appendByte(1);
1341                break;
1342            case FLOAT:
1343                if (debugstackmap) System.out.print("float");
1344                databuf.appendByte(2);
1345                break;
1346            case DOUBLE:
1347                if (debugstackmap) System.out.print("double");
1348                databuf.appendByte(3);
1349                break;
1350            case LONG:
1351                if (debugstackmap) System.out.print("long");
1352                databuf.appendByte(4);
1353                break;
1354            case BOT: // null
1355                if (debugstackmap) System.out.print("null");
1356                databuf.appendByte(5);
1357                break;
1358            case CLASS:
1359            case ARRAY:
1360                if (debugstackmap) System.out.print("object(" + t + ")");
1361                databuf.appendByte(7);
1362                databuf.appendChar(pool.put(t));
1363                break;
1364            case TYPEVAR:
1365                if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1366                databuf.appendByte(7);
1367                databuf.appendChar(pool.put(types.erasure(t).tsym));
1368                break;
1369            case UNINITIALIZED_THIS:
1370                if (debugstackmap) System.out.print("uninit_this");
1371                databuf.appendByte(6);
1372                break;
1373            case UNINITIALIZED_OBJECT:
1374                { UninitializedType uninitType = (UninitializedType)t;
1375                databuf.appendByte(8);
1376                if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset);
1377                databuf.appendChar(uninitType.offset);
1378                }
1379                break;
1380            default:
1381                throw new AssertionError();
1382            }
1383        }
1384
1385    /** An entry in the JSR202 StackMapTable */
1386    abstract static class StackMapTableFrame {
1387        abstract int getFrameType();
1388
1389        void write(ClassWriter writer) {
1390            int frameType = getFrameType();
1391            writer.databuf.appendByte(frameType);
1392            if (writer.debugstackmap) System.out.print(" frame_type=" + frameType);
1393        }
1394
1395        static class SameFrame extends StackMapTableFrame {
1396            final int offsetDelta;
1397            SameFrame(int offsetDelta) {
1398                this.offsetDelta = offsetDelta;
1399            }
1400            int getFrameType() {
1401                return (offsetDelta < SAME_FRAME_SIZE) ? offsetDelta : SAME_FRAME_EXTENDED;
1402            }
1403            @Override
1404            void write(ClassWriter writer) {
1405                super.write(writer);
1406                if (getFrameType() == SAME_FRAME_EXTENDED) {
1407                    writer.databuf.appendChar(offsetDelta);
1408                    if (writer.debugstackmap){
1409                        System.out.print(" offset_delta=" + offsetDelta);
1410                    }
1411                }
1412            }
1413        }
1414
1415        static class SameLocals1StackItemFrame extends StackMapTableFrame {
1416            final int offsetDelta;
1417            final Type stack;
1418            SameLocals1StackItemFrame(int offsetDelta, Type stack) {
1419                this.offsetDelta = offsetDelta;
1420                this.stack = stack;
1421            }
1422            int getFrameType() {
1423                return (offsetDelta < SAME_FRAME_SIZE) ?
1424                       (SAME_FRAME_SIZE + offsetDelta) :
1425                       SAME_LOCALS_1_STACK_ITEM_EXTENDED;
1426            }
1427            @Override
1428            void write(ClassWriter writer) {
1429                super.write(writer);
1430                if (getFrameType() == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
1431                    writer.databuf.appendChar(offsetDelta);
1432                    if (writer.debugstackmap) {
1433                        System.out.print(" offset_delta=" + offsetDelta);
1434                    }
1435                }
1436                if (writer.debugstackmap) {
1437                    System.out.print(" stack[" + 0 + "]=");
1438                }
1439                writer.writeStackMapType(stack);
1440            }
1441        }
1442
1443        static class ChopFrame extends StackMapTableFrame {
1444            final int frameType;
1445            final int offsetDelta;
1446            ChopFrame(int frameType, int offsetDelta) {
1447                this.frameType = frameType;
1448                this.offsetDelta = offsetDelta;
1449            }
1450            int getFrameType() { return frameType; }
1451            @Override
1452            void write(ClassWriter writer) {
1453                super.write(writer);
1454                writer.databuf.appendChar(offsetDelta);
1455                if (writer.debugstackmap) {
1456                    System.out.print(" offset_delta=" + offsetDelta);
1457                }
1458            }
1459        }
1460
1461        static class AppendFrame extends StackMapTableFrame {
1462            final int frameType;
1463            final int offsetDelta;
1464            final Type[] locals;
1465            AppendFrame(int frameType, int offsetDelta, Type[] locals) {
1466                this.frameType = frameType;
1467                this.offsetDelta = offsetDelta;
1468                this.locals = locals;
1469            }
1470            int getFrameType() { return frameType; }
1471            @Override
1472            void write(ClassWriter writer) {
1473                super.write(writer);
1474                writer.databuf.appendChar(offsetDelta);
1475                if (writer.debugstackmap) {
1476                    System.out.print(" offset_delta=" + offsetDelta);
1477                }
1478                for (int i=0; i<locals.length; i++) {
1479                     if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1480                     writer.writeStackMapType(locals[i]);
1481                }
1482            }
1483        }
1484
1485        static class FullFrame extends StackMapTableFrame {
1486            final int offsetDelta;
1487            final Type[] locals;
1488            final Type[] stack;
1489            FullFrame(int offsetDelta, Type[] locals, Type[] stack) {
1490                this.offsetDelta = offsetDelta;
1491                this.locals = locals;
1492                this.stack = stack;
1493            }
1494            int getFrameType() { return FULL_FRAME; }
1495            @Override
1496            void write(ClassWriter writer) {
1497                super.write(writer);
1498                writer.databuf.appendChar(offsetDelta);
1499                writer.databuf.appendChar(locals.length);
1500                if (writer.debugstackmap) {
1501                    System.out.print(" offset_delta=" + offsetDelta);
1502                    System.out.print(" nlocals=" + locals.length);
1503                }
1504                for (int i=0; i<locals.length; i++) {
1505                    if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1506                    writer.writeStackMapType(locals[i]);
1507                }
1508
1509                writer.databuf.appendChar(stack.length);
1510                if (writer.debugstackmap) { System.out.print(" nstack=" + stack.length); }
1511                for (int i=0; i<stack.length; i++) {
1512                    if (writer.debugstackmap) System.out.print(" stack[" + i + "]=");
1513                    writer.writeStackMapType(stack[i]);
1514                }
1515            }
1516        }
1517
1518       /** Compare this frame with the previous frame and produce
1519        *  an entry of compressed stack map frame. */
1520        static StackMapTableFrame getInstance(Code.StackMapFrame this_frame,
1521                                              int prev_pc,
1522                                              Type[] prev_locals,
1523                                              Types types) {
1524            Type[] locals = this_frame.locals;
1525            Type[] stack = this_frame.stack;
1526            int offset_delta = this_frame.pc - prev_pc - 1;
1527            if (stack.length == 1) {
1528                if (locals.length == prev_locals.length
1529                    && compare(prev_locals, locals, types) == 0) {
1530                    return new SameLocals1StackItemFrame(offset_delta, stack[0]);
1531                }
1532            } else if (stack.length == 0) {
1533                int diff_length = compare(prev_locals, locals, types);
1534                if (diff_length == 0) {
1535                    return new SameFrame(offset_delta);
1536                } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) {
1537                    // APPEND
1538                    Type[] local_diff = new Type[-diff_length];
1539                    for (int i=prev_locals.length, j=0; i<locals.length; i++,j++) {
1540                        local_diff[j] = locals[i];
1541                    }
1542                    return new AppendFrame(SAME_FRAME_EXTENDED - diff_length,
1543                                           offset_delta,
1544                                           local_diff);
1545                } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) {
1546                    // CHOP
1547                    return new ChopFrame(SAME_FRAME_EXTENDED - diff_length,
1548                                         offset_delta);
1549                }
1550            }
1551            // FULL_FRAME
1552            return new FullFrame(offset_delta, locals, stack);
1553        }
1554
1555        static boolean isInt(Type t) {
1556            return (t.getTag().isStrictSubRangeOf(INT)  || t.hasTag(BOOLEAN));
1557        }
1558
1559        static boolean isSameType(Type t1, Type t2, Types types) {
1560            if (t1 == null) { return t2 == null; }
1561            if (t2 == null) { return false; }
1562
1563            if (isInt(t1) && isInt(t2)) { return true; }
1564
1565            if (t1.hasTag(UNINITIALIZED_THIS)) {
1566                return t2.hasTag(UNINITIALIZED_THIS);
1567            } else if (t1.hasTag(UNINITIALIZED_OBJECT)) {
1568                if (t2.hasTag(UNINITIALIZED_OBJECT)) {
1569                    return ((UninitializedType)t1).offset == ((UninitializedType)t2).offset;
1570                } else {
1571                    return false;
1572                }
1573            } else if (t2.hasTag(UNINITIALIZED_THIS) || t2.hasTag(UNINITIALIZED_OBJECT)) {
1574                return false;
1575            }
1576
1577            return types.isSameType(t1, t2);
1578        }
1579
1580        static int compare(Type[] arr1, Type[] arr2, Types types) {
1581            int diff_length = arr1.length - arr2.length;
1582            if (diff_length > MAX_LOCAL_LENGTH_DIFF || diff_length < -MAX_LOCAL_LENGTH_DIFF) {
1583                return Integer.MAX_VALUE;
1584            }
1585            int len = (diff_length > 0) ? arr2.length : arr1.length;
1586            for (int i=0; i<len; i++) {
1587                if (!isSameType(arr1[i], arr2[i], types)) {
1588                    return Integer.MAX_VALUE;
1589                }
1590            }
1591            return diff_length;
1592        }
1593    }
1594
1595    void writeFields(Scope s) {
1596        // process them in reverse sibling order;
1597        // i.e., process them in declaration order.
1598        List<VarSymbol> vars = List.nil();
1599        for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
1600            if (sym.kind == VAR) vars = vars.prepend((VarSymbol)sym);
1601        }
1602        while (vars.nonEmpty()) {
1603            writeField(vars.head);
1604            vars = vars.tail;
1605        }
1606    }
1607
1608    void writeMethods(Scope s) {
1609        List<MethodSymbol> methods = List.nil();
1610        for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
1611            if (sym.kind == MTH && (sym.flags() & HYPOTHETICAL) == 0)
1612                methods = methods.prepend((MethodSymbol)sym);
1613        }
1614        while (methods.nonEmpty()) {
1615            writeMethod(methods.head);
1616            methods = methods.tail;
1617        }
1618    }
1619
1620    /** Emit a class file for a given class.
1621     *  @param c      The class from which a class file is generated.
1622     */
1623    public JavaFileObject writeClass(ClassSymbol c)
1624        throws IOException, PoolOverflow, StringOverflow
1625    {
1626        String name = (c.owner.kind == MDL ? c.name : c.flatname).toString();
1627        Location outLocn;
1628        if (multiModuleMode) {
1629            ModuleSymbol msym = c.owner.kind == MDL ? (ModuleSymbol) c.owner : c.packge().modle;
1630            outLocn = fileManager.getModuleLocation(CLASS_OUTPUT, msym.name.toString());
1631        } else {
1632            outLocn = CLASS_OUTPUT;
1633        }
1634        JavaFileObject outFile
1635            = fileManager.getJavaFileForOutput(outLocn,
1636                                               name,
1637                                               JavaFileObject.Kind.CLASS,
1638                                               c.sourcefile);
1639        OutputStream out = outFile.openOutputStream();
1640        try {
1641            writeClassFile(out, c);
1642            if (verbose)
1643                log.printVerbose("wrote.file", outFile);
1644            out.close();
1645            out = null;
1646        } finally {
1647            if (out != null) {
1648                // if we are propagating an exception, delete the file
1649                out.close();
1650                outFile.delete();
1651                outFile = null;
1652            }
1653        }
1654        return outFile; // may be null if write failed
1655    }
1656
1657    /** Write class `c' to outstream `out'.
1658     */
1659    public void writeClassFile(OutputStream out, ClassSymbol c)
1660        throws IOException, PoolOverflow, StringOverflow {
1661        Assert.check((c.flags() & COMPOUND) == 0);
1662        databuf.reset();
1663        poolbuf.reset();
1664        signatureGen.reset();
1665        pool = c.pool;
1666        innerClasses = null;
1667        innerClassesQueue = null;
1668        bootstrapMethods = new LinkedHashMap<>();
1669
1670        Type supertype = types.supertype(c.type);
1671        List<Type> interfaces = types.interfaces(c.type);
1672        List<Type> typarams = c.type.getTypeArguments();
1673
1674        int flags;
1675        if (c.owner.kind == MDL) {
1676            flags = ACC_MODULE;
1677        } else {
1678            flags = adjustFlags(c.flags() & ~DEFAULT);
1679            if ((flags & PROTECTED) != 0) flags |= PUBLIC;
1680            flags = flags & ClassFlags & ~STRICTFP;
1681            if ((flags & INTERFACE) == 0) flags |= ACC_SUPER;
1682            if (c.isInner() && c.name.isEmpty()) flags &= ~FINAL;
1683        }
1684
1685        if (dumpClassModifiers) {
1686            PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1687            pw.println();
1688            pw.println("CLASSFILE  " + c.getQualifiedName());
1689            pw.println("---" + flagNames(flags));
1690        }
1691        databuf.appendChar(flags);
1692
1693        databuf.appendChar(pool.put(c));
1694        databuf.appendChar(supertype.hasTag(CLASS) ? pool.put(supertype.tsym) : 0);
1695        databuf.appendChar(interfaces.length());
1696        for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1697            databuf.appendChar(pool.put(l.head.tsym));
1698        int fieldsCount = 0;
1699        int methodsCount = 0;
1700        for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
1701            switch (sym.kind) {
1702            case VAR: fieldsCount++; break;
1703            case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
1704                      break;
1705            case TYP: enterInner((ClassSymbol)sym); break;
1706            default : Assert.error();
1707            }
1708        }
1709
1710        if (c.trans_local != null) {
1711            for (ClassSymbol local : c.trans_local) {
1712                enterInner(local);
1713            }
1714        }
1715
1716        databuf.appendChar(fieldsCount);
1717        writeFields(c.members());
1718        databuf.appendChar(methodsCount);
1719        writeMethods(c.members());
1720
1721        int acountIdx = beginAttrs();
1722        int acount = 0;
1723
1724        boolean sigReq =
1725            typarams.length() != 0 || supertype.allparams().length() != 0;
1726        for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
1727            sigReq = l.head.allparams().length() != 0;
1728        if (sigReq) {
1729            int alenIdx = writeAttr(names.Signature);
1730            if (typarams.length() != 0) signatureGen.assembleParamsSig(typarams);
1731            signatureGen.assembleSig(supertype);
1732            for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1733                signatureGen.assembleSig(l.head);
1734            databuf.appendChar(pool.put(signatureGen.toName()));
1735            signatureGen.reset();
1736            endAttr(alenIdx);
1737            acount++;
1738        }
1739
1740        if (c.sourcefile != null && emitSourceFile) {
1741            int alenIdx = writeAttr(names.SourceFile);
1742            // WHM 6/29/1999: Strip file path prefix.  We do it here at
1743            // the last possible moment because the sourcefile may be used
1744            // elsewhere in error diagnostics. Fixes 4241573.
1745            //databuf.appendChar(c.pool.put(c.sourcefile));
1746            String simpleName = PathFileObject.getSimpleName(c.sourcefile);
1747            databuf.appendChar(c.pool.put(names.fromString(simpleName)));
1748            endAttr(alenIdx);
1749            acount++;
1750        }
1751
1752        if (genCrt) {
1753            // Append SourceID attribute
1754            int alenIdx = writeAttr(names.SourceID);
1755            databuf.appendChar(c.pool.put(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
1756            endAttr(alenIdx);
1757            acount++;
1758            // Append CompilationID attribute
1759            alenIdx = writeAttr(names.CompilationID);
1760            databuf.appendChar(c.pool.put(names.fromString(Long.toString(System.currentTimeMillis()))));
1761            endAttr(alenIdx);
1762            acount++;
1763        }
1764
1765        acount += writeFlagAttrs(c.flags());
1766        acount += writeJavaAnnotations(c.getRawAttributes());
1767        acount += writeTypeAnnotations(c.getRawTypeAttributes(), false);
1768        acount += writeEnclosingMethodAttribute(c);
1769        if (c.owner.kind == MDL) {
1770            acount += writeModuleAttribute(c);
1771        }
1772        acount += writeExtraClassAttributes(c);
1773
1774        poolbuf.appendInt(JAVA_MAGIC);
1775        poolbuf.appendChar(target.minorVersion);
1776        poolbuf.appendChar(target.majorVersion);
1777
1778        writePool(c.pool);
1779
1780        if (innerClasses != null) {
1781            writeInnerClasses();
1782            acount++;
1783        }
1784
1785        if (!bootstrapMethods.isEmpty()) {
1786            writeBootstrapMethods();
1787            acount++;
1788        }
1789
1790        endAttrs(acountIdx, acount);
1791
1792        poolbuf.appendBytes(databuf.elems, 0, databuf.length);
1793        out.write(poolbuf.elems, 0, poolbuf.length);
1794
1795        pool = c.pool = null; // to conserve space
1796     }
1797
1798    /**Allows subclasses to write additional class attributes
1799     *
1800     * @return the number of attributes written
1801     */
1802    protected int writeExtraClassAttributes(ClassSymbol c) {
1803        return 0;
1804    }
1805
1806    int adjustFlags(final long flags) {
1807        int result = (int)flags;
1808
1809        if ((flags & BRIDGE) != 0)
1810            result |= ACC_BRIDGE;
1811        if ((flags & VARARGS) != 0)
1812            result |= ACC_VARARGS;
1813        if ((flags & DEFAULT) != 0)
1814            result &= ~ABSTRACT;
1815        return result;
1816    }
1817
1818    long getLastModified(FileObject filename) {
1819        long mod = 0;
1820        try {
1821            mod = filename.getLastModified();
1822        } catch (SecurityException e) {
1823            throw new AssertionError("CRT: couldn't get source file modification date: " + e.getMessage());
1824        }
1825        return mod;
1826    }
1827}
1828