ClassWriter.java revision 3770:d813bfb238a9
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            flags &= ~STRICTFP; //inner classes should not have the strictfp flag set.
1044            if (dumpInnerClassModifiers) {
1045                PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1046                pw.println("INNERCLASS  " + inner.name);
1047                pw.println("---" + flagNames(flags));
1048            }
1049            databuf.appendChar(pool.get(inner));
1050            databuf.appendChar(
1051                inner.owner.kind == TYP && !inner.name.isEmpty() ? pool.get(inner.owner) : 0);
1052            databuf.appendChar(
1053                !inner.name.isEmpty() ? pool.get(inner.name) : 0);
1054            databuf.appendChar(flags);
1055        }
1056        endAttr(alenIdx);
1057    }
1058
1059    /** Write "bootstrapMethods" attribute.
1060     */
1061    void writeBootstrapMethods() {
1062        int alenIdx = writeAttr(names.BootstrapMethods);
1063        databuf.appendChar(bootstrapMethods.size());
1064        for (Map.Entry<DynamicMethod.BootstrapMethodsKey, DynamicMethod.BootstrapMethodsValue> entry : bootstrapMethods.entrySet()) {
1065            DynamicMethod.BootstrapMethodsKey bsmKey = entry.getKey();
1066            //write BSM handle
1067            databuf.appendChar(pool.get(entry.getValue().mh));
1068            Object[] uniqueArgs = bsmKey.getUniqueArgs();
1069            //write static args length
1070            databuf.appendChar(uniqueArgs.length);
1071            //write static args array
1072            for (Object o : uniqueArgs) {
1073                databuf.appendChar(pool.get(o));
1074            }
1075        }
1076        endAttr(alenIdx);
1077    }
1078
1079    /** Write field symbol, entering all references into constant pool.
1080     */
1081    void writeField(VarSymbol v) {
1082        int flags = adjustFlags(v.flags());
1083        databuf.appendChar(flags);
1084        if (dumpFieldModifiers) {
1085            PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1086            pw.println("FIELD  " + v.name);
1087            pw.println("---" + flagNames(v.flags()));
1088        }
1089        databuf.appendChar(pool.put(v.name));
1090        databuf.appendChar(pool.put(typeSig(v.erasure(types))));
1091        int acountIdx = beginAttrs();
1092        int acount = 0;
1093        if (v.getConstValue() != null) {
1094            int alenIdx = writeAttr(names.ConstantValue);
1095            databuf.appendChar(pool.put(v.getConstValue()));
1096            endAttr(alenIdx);
1097            acount++;
1098        }
1099        acount += writeMemberAttrs(v);
1100        endAttrs(acountIdx, acount);
1101    }
1102
1103    /** Write method symbol, entering all references into constant pool.
1104     */
1105    void writeMethod(MethodSymbol m) {
1106        int flags = adjustFlags(m.flags());
1107        databuf.appendChar(flags);
1108        if (dumpMethodModifiers) {
1109            PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1110            pw.println("METHOD  " + m.name);
1111            pw.println("---" + flagNames(m.flags()));
1112        }
1113        databuf.appendChar(pool.put(m.name));
1114        databuf.appendChar(pool.put(typeSig(m.externalType(types))));
1115        int acountIdx = beginAttrs();
1116        int acount = 0;
1117        if (m.code != null) {
1118            int alenIdx = writeAttr(names.Code);
1119            writeCode(m.code);
1120            m.code = null; // to conserve space
1121            endAttr(alenIdx);
1122            acount++;
1123        }
1124        List<Type> thrown = m.erasure(types).getThrownTypes();
1125        if (thrown.nonEmpty()) {
1126            int alenIdx = writeAttr(names.Exceptions);
1127            databuf.appendChar(thrown.length());
1128            for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
1129                databuf.appendChar(pool.put(l.head.tsym));
1130            endAttr(alenIdx);
1131            acount++;
1132        }
1133        if (m.defaultValue != null) {
1134            int alenIdx = writeAttr(names.AnnotationDefault);
1135            m.defaultValue.accept(awriter);
1136            endAttr(alenIdx);
1137            acount++;
1138        }
1139        if (options.isSet(PARAMETERS)) {
1140            if (!m.isLambdaMethod()) // Per JDK-8138729, do not emit parameters table for lambda bodies.
1141                acount += writeMethodParametersAttr(m);
1142        }
1143        acount += writeMemberAttrs(m);
1144        if (!m.isLambdaMethod())
1145            acount += writeParameterAttrs(m);
1146        endAttrs(acountIdx, acount);
1147    }
1148
1149    /** Write code attribute of method.
1150     */
1151    void writeCode(Code code) {
1152        databuf.appendChar(code.max_stack);
1153        databuf.appendChar(code.max_locals);
1154        databuf.appendInt(code.cp);
1155        databuf.appendBytes(code.code, 0, code.cp);
1156        databuf.appendChar(code.catchInfo.length());
1157        for (List<char[]> l = code.catchInfo.toList();
1158             l.nonEmpty();
1159             l = l.tail) {
1160            for (int i = 0; i < l.head.length; i++)
1161                databuf.appendChar(l.head[i]);
1162        }
1163        int acountIdx = beginAttrs();
1164        int acount = 0;
1165
1166        if (code.lineInfo.nonEmpty()) {
1167            int alenIdx = writeAttr(names.LineNumberTable);
1168            databuf.appendChar(code.lineInfo.length());
1169            for (List<char[]> l = code.lineInfo.reverse();
1170                 l.nonEmpty();
1171                 l = l.tail)
1172                for (int i = 0; i < l.head.length; i++)
1173                    databuf.appendChar(l.head[i]);
1174            endAttr(alenIdx);
1175            acount++;
1176        }
1177
1178        if (genCrt && (code.crt != null)) {
1179            CRTable crt = code.crt;
1180            int alenIdx = writeAttr(names.CharacterRangeTable);
1181            int crtIdx = beginAttrs();
1182            int crtEntries = crt.writeCRT(databuf, code.lineMap, log);
1183            endAttrs(crtIdx, crtEntries);
1184            endAttr(alenIdx);
1185            acount++;
1186        }
1187
1188        // counter for number of generic local variables
1189        if (code.varDebugInfo && code.varBufferSize > 0) {
1190            int nGenericVars = 0;
1191            int alenIdx = writeAttr(names.LocalVariableTable);
1192            databuf.appendChar(code.getLVTSize());
1193            for (int i=0; i<code.varBufferSize; i++) {
1194                Code.LocalVar var = code.varBuffer[i];
1195
1196                for (Code.LocalVar.Range r: var.aliveRanges) {
1197                    // write variable info
1198                    Assert.check(r.start_pc >= 0
1199                            && r.start_pc <= code.cp);
1200                    databuf.appendChar(r.start_pc);
1201                    Assert.check(r.length > 0
1202                            && (r.start_pc + r.length) <= code.cp);
1203                    databuf.appendChar(r.length);
1204                    VarSymbol sym = var.sym;
1205                    databuf.appendChar(pool.put(sym.name));
1206                    Type vartype = sym.erasure(types);
1207                    databuf.appendChar(pool.put(typeSig(vartype)));
1208                    databuf.appendChar(var.reg);
1209                    if (needsLocalVariableTypeEntry(var.sym.type)) {
1210                        nGenericVars++;
1211                    }
1212                }
1213            }
1214            endAttr(alenIdx);
1215            acount++;
1216
1217            if (nGenericVars > 0) {
1218                alenIdx = writeAttr(names.LocalVariableTypeTable);
1219                databuf.appendChar(nGenericVars);
1220                int count = 0;
1221
1222                for (int i=0; i<code.varBufferSize; i++) {
1223                    Code.LocalVar var = code.varBuffer[i];
1224                    VarSymbol sym = var.sym;
1225                    if (!needsLocalVariableTypeEntry(sym.type))
1226                        continue;
1227                    for (Code.LocalVar.Range r : var.aliveRanges) {
1228                        // write variable info
1229                        databuf.appendChar(r.start_pc);
1230                        databuf.appendChar(r.length);
1231                        databuf.appendChar(pool.put(sym.name));
1232                        databuf.appendChar(pool.put(typeSig(sym.type)));
1233                        databuf.appendChar(var.reg);
1234                        count++;
1235                    }
1236                }
1237                Assert.check(count == nGenericVars);
1238                endAttr(alenIdx);
1239                acount++;
1240            }
1241        }
1242
1243        if (code.stackMapBufferSize > 0) {
1244            if (debugstackmap) System.out.println("Stack map for " + code.meth);
1245            int alenIdx = writeAttr(code.stackMap.getAttributeName(names));
1246            writeStackMap(code);
1247            endAttr(alenIdx);
1248            acount++;
1249        }
1250
1251        acount += writeTypeAnnotations(code.meth.getRawTypeAttributes(), true);
1252
1253        endAttrs(acountIdx, acount);
1254    }
1255    //where
1256    private boolean needsLocalVariableTypeEntry(Type t) {
1257        //a local variable needs a type-entry if its type T is generic
1258        //(i.e. |T| != T) and if it's not an intersection type (not supported
1259        //in signature attribute grammar)
1260        return (!types.isSameType(t, types.erasure(t)) &&
1261                !t.isCompound());
1262    }
1263
1264    void writeStackMap(Code code) {
1265        int nframes = code.stackMapBufferSize;
1266        if (debugstackmap) System.out.println(" nframes = " + nframes);
1267        databuf.appendChar(nframes);
1268
1269        switch (code.stackMap) {
1270        case CLDC:
1271            for (int i=0; i<nframes; i++) {
1272                if (debugstackmap) System.out.print("  " + i + ":");
1273                Code.StackMapFrame frame = code.stackMapBuffer[i];
1274
1275                // output PC
1276                if (debugstackmap) System.out.print(" pc=" + frame.pc);
1277                databuf.appendChar(frame.pc);
1278
1279                // output locals
1280                int localCount = 0;
1281                for (int j=0; j<frame.locals.length;
1282                     j += Code.width(frame.locals[j])) {
1283                    localCount++;
1284                }
1285                if (debugstackmap) System.out.print(" nlocals=" +
1286                                                    localCount);
1287                databuf.appendChar(localCount);
1288                for (int j=0; j<frame.locals.length;
1289                     j += Code.width(frame.locals[j])) {
1290                    if (debugstackmap) System.out.print(" local[" + j + "]=");
1291                    writeStackMapType(frame.locals[j]);
1292                }
1293
1294                // output stack
1295                int stackCount = 0;
1296                for (int j=0; j<frame.stack.length;
1297                     j += Code.width(frame.stack[j])) {
1298                    stackCount++;
1299                }
1300                if (debugstackmap) System.out.print(" nstack=" +
1301                                                    stackCount);
1302                databuf.appendChar(stackCount);
1303                for (int j=0; j<frame.stack.length;
1304                     j += Code.width(frame.stack[j])) {
1305                    if (debugstackmap) System.out.print(" stack[" + j + "]=");
1306                    writeStackMapType(frame.stack[j]);
1307                }
1308                if (debugstackmap) System.out.println();
1309            }
1310            break;
1311        case JSR202: {
1312            Assert.checkNull(code.stackMapBuffer);
1313            for (int i=0; i<nframes; i++) {
1314                if (debugstackmap) System.out.print("  " + i + ":");
1315                StackMapTableFrame frame = code.stackMapTableBuffer[i];
1316                frame.write(this);
1317                if (debugstackmap) System.out.println();
1318            }
1319            break;
1320        }
1321        default:
1322            throw new AssertionError("Unexpected stackmap format value");
1323        }
1324    }
1325
1326        //where
1327        void writeStackMapType(Type t) {
1328            if (t == null) {
1329                if (debugstackmap) System.out.print("empty");
1330                databuf.appendByte(0);
1331            }
1332            else switch(t.getTag()) {
1333            case BYTE:
1334            case CHAR:
1335            case SHORT:
1336            case INT:
1337            case BOOLEAN:
1338                if (debugstackmap) System.out.print("int");
1339                databuf.appendByte(1);
1340                break;
1341            case FLOAT:
1342                if (debugstackmap) System.out.print("float");
1343                databuf.appendByte(2);
1344                break;
1345            case DOUBLE:
1346                if (debugstackmap) System.out.print("double");
1347                databuf.appendByte(3);
1348                break;
1349            case LONG:
1350                if (debugstackmap) System.out.print("long");
1351                databuf.appendByte(4);
1352                break;
1353            case BOT: // null
1354                if (debugstackmap) System.out.print("null");
1355                databuf.appendByte(5);
1356                break;
1357            case CLASS:
1358            case ARRAY:
1359                if (debugstackmap) System.out.print("object(" + t + ")");
1360                databuf.appendByte(7);
1361                databuf.appendChar(pool.put(t));
1362                break;
1363            case TYPEVAR:
1364                if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1365                databuf.appendByte(7);
1366                databuf.appendChar(pool.put(types.erasure(t).tsym));
1367                break;
1368            case UNINITIALIZED_THIS:
1369                if (debugstackmap) System.out.print("uninit_this");
1370                databuf.appendByte(6);
1371                break;
1372            case UNINITIALIZED_OBJECT:
1373                { UninitializedType uninitType = (UninitializedType)t;
1374                databuf.appendByte(8);
1375                if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset);
1376                databuf.appendChar(uninitType.offset);
1377                }
1378                break;
1379            default:
1380                throw new AssertionError();
1381            }
1382        }
1383
1384    /** An entry in the JSR202 StackMapTable */
1385    abstract static class StackMapTableFrame {
1386        abstract int getFrameType();
1387
1388        void write(ClassWriter writer) {
1389            int frameType = getFrameType();
1390            writer.databuf.appendByte(frameType);
1391            if (writer.debugstackmap) System.out.print(" frame_type=" + frameType);
1392        }
1393
1394        static class SameFrame extends StackMapTableFrame {
1395            final int offsetDelta;
1396            SameFrame(int offsetDelta) {
1397                this.offsetDelta = offsetDelta;
1398            }
1399            int getFrameType() {
1400                return (offsetDelta < SAME_FRAME_SIZE) ? offsetDelta : SAME_FRAME_EXTENDED;
1401            }
1402            @Override
1403            void write(ClassWriter writer) {
1404                super.write(writer);
1405                if (getFrameType() == SAME_FRAME_EXTENDED) {
1406                    writer.databuf.appendChar(offsetDelta);
1407                    if (writer.debugstackmap){
1408                        System.out.print(" offset_delta=" + offsetDelta);
1409                    }
1410                }
1411            }
1412        }
1413
1414        static class SameLocals1StackItemFrame extends StackMapTableFrame {
1415            final int offsetDelta;
1416            final Type stack;
1417            SameLocals1StackItemFrame(int offsetDelta, Type stack) {
1418                this.offsetDelta = offsetDelta;
1419                this.stack = stack;
1420            }
1421            int getFrameType() {
1422                return (offsetDelta < SAME_FRAME_SIZE) ?
1423                       (SAME_FRAME_SIZE + offsetDelta) :
1424                       SAME_LOCALS_1_STACK_ITEM_EXTENDED;
1425            }
1426            @Override
1427            void write(ClassWriter writer) {
1428                super.write(writer);
1429                if (getFrameType() == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
1430                    writer.databuf.appendChar(offsetDelta);
1431                    if (writer.debugstackmap) {
1432                        System.out.print(" offset_delta=" + offsetDelta);
1433                    }
1434                }
1435                if (writer.debugstackmap) {
1436                    System.out.print(" stack[" + 0 + "]=");
1437                }
1438                writer.writeStackMapType(stack);
1439            }
1440        }
1441
1442        static class ChopFrame extends StackMapTableFrame {
1443            final int frameType;
1444            final int offsetDelta;
1445            ChopFrame(int frameType, int offsetDelta) {
1446                this.frameType = frameType;
1447                this.offsetDelta = offsetDelta;
1448            }
1449            int getFrameType() { return frameType; }
1450            @Override
1451            void write(ClassWriter writer) {
1452                super.write(writer);
1453                writer.databuf.appendChar(offsetDelta);
1454                if (writer.debugstackmap) {
1455                    System.out.print(" offset_delta=" + offsetDelta);
1456                }
1457            }
1458        }
1459
1460        static class AppendFrame extends StackMapTableFrame {
1461            final int frameType;
1462            final int offsetDelta;
1463            final Type[] locals;
1464            AppendFrame(int frameType, int offsetDelta, Type[] locals) {
1465                this.frameType = frameType;
1466                this.offsetDelta = offsetDelta;
1467                this.locals = locals;
1468            }
1469            int getFrameType() { return frameType; }
1470            @Override
1471            void write(ClassWriter writer) {
1472                super.write(writer);
1473                writer.databuf.appendChar(offsetDelta);
1474                if (writer.debugstackmap) {
1475                    System.out.print(" offset_delta=" + offsetDelta);
1476                }
1477                for (int i=0; i<locals.length; i++) {
1478                     if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1479                     writer.writeStackMapType(locals[i]);
1480                }
1481            }
1482        }
1483
1484        static class FullFrame extends StackMapTableFrame {
1485            final int offsetDelta;
1486            final Type[] locals;
1487            final Type[] stack;
1488            FullFrame(int offsetDelta, Type[] locals, Type[] stack) {
1489                this.offsetDelta = offsetDelta;
1490                this.locals = locals;
1491                this.stack = stack;
1492            }
1493            int getFrameType() { return FULL_FRAME; }
1494            @Override
1495            void write(ClassWriter writer) {
1496                super.write(writer);
1497                writer.databuf.appendChar(offsetDelta);
1498                writer.databuf.appendChar(locals.length);
1499                if (writer.debugstackmap) {
1500                    System.out.print(" offset_delta=" + offsetDelta);
1501                    System.out.print(" nlocals=" + locals.length);
1502                }
1503                for (int i=0; i<locals.length; i++) {
1504                    if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1505                    writer.writeStackMapType(locals[i]);
1506                }
1507
1508                writer.databuf.appendChar(stack.length);
1509                if (writer.debugstackmap) { System.out.print(" nstack=" + stack.length); }
1510                for (int i=0; i<stack.length; i++) {
1511                    if (writer.debugstackmap) System.out.print(" stack[" + i + "]=");
1512                    writer.writeStackMapType(stack[i]);
1513                }
1514            }
1515        }
1516
1517       /** Compare this frame with the previous frame and produce
1518        *  an entry of compressed stack map frame. */
1519        static StackMapTableFrame getInstance(Code.StackMapFrame this_frame,
1520                                              int prev_pc,
1521                                              Type[] prev_locals,
1522                                              Types types) {
1523            Type[] locals = this_frame.locals;
1524            Type[] stack = this_frame.stack;
1525            int offset_delta = this_frame.pc - prev_pc - 1;
1526            if (stack.length == 1) {
1527                if (locals.length == prev_locals.length
1528                    && compare(prev_locals, locals, types) == 0) {
1529                    return new SameLocals1StackItemFrame(offset_delta, stack[0]);
1530                }
1531            } else if (stack.length == 0) {
1532                int diff_length = compare(prev_locals, locals, types);
1533                if (diff_length == 0) {
1534                    return new SameFrame(offset_delta);
1535                } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) {
1536                    // APPEND
1537                    Type[] local_diff = new Type[-diff_length];
1538                    for (int i=prev_locals.length, j=0; i<locals.length; i++,j++) {
1539                        local_diff[j] = locals[i];
1540                    }
1541                    return new AppendFrame(SAME_FRAME_EXTENDED - diff_length,
1542                                           offset_delta,
1543                                           local_diff);
1544                } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) {
1545                    // CHOP
1546                    return new ChopFrame(SAME_FRAME_EXTENDED - diff_length,
1547                                         offset_delta);
1548                }
1549            }
1550            // FULL_FRAME
1551            return new FullFrame(offset_delta, locals, stack);
1552        }
1553
1554        static boolean isInt(Type t) {
1555            return (t.getTag().isStrictSubRangeOf(INT)  || t.hasTag(BOOLEAN));
1556        }
1557
1558        static boolean isSameType(Type t1, Type t2, Types types) {
1559            if (t1 == null) { return t2 == null; }
1560            if (t2 == null) { return false; }
1561
1562            if (isInt(t1) && isInt(t2)) { return true; }
1563
1564            if (t1.hasTag(UNINITIALIZED_THIS)) {
1565                return t2.hasTag(UNINITIALIZED_THIS);
1566            } else if (t1.hasTag(UNINITIALIZED_OBJECT)) {
1567                if (t2.hasTag(UNINITIALIZED_OBJECT)) {
1568                    return ((UninitializedType)t1).offset == ((UninitializedType)t2).offset;
1569                } else {
1570                    return false;
1571                }
1572            } else if (t2.hasTag(UNINITIALIZED_THIS) || t2.hasTag(UNINITIALIZED_OBJECT)) {
1573                return false;
1574            }
1575
1576            return types.isSameType(t1, t2);
1577        }
1578
1579        static int compare(Type[] arr1, Type[] arr2, Types types) {
1580            int diff_length = arr1.length - arr2.length;
1581            if (diff_length > MAX_LOCAL_LENGTH_DIFF || diff_length < -MAX_LOCAL_LENGTH_DIFF) {
1582                return Integer.MAX_VALUE;
1583            }
1584            int len = (diff_length > 0) ? arr2.length : arr1.length;
1585            for (int i=0; i<len; i++) {
1586                if (!isSameType(arr1[i], arr2[i], types)) {
1587                    return Integer.MAX_VALUE;
1588                }
1589            }
1590            return diff_length;
1591        }
1592    }
1593
1594    void writeFields(Scope s) {
1595        // process them in reverse sibling order;
1596        // i.e., process them in declaration order.
1597        List<VarSymbol> vars = List.nil();
1598        for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
1599            if (sym.kind == VAR) vars = vars.prepend((VarSymbol)sym);
1600        }
1601        while (vars.nonEmpty()) {
1602            writeField(vars.head);
1603            vars = vars.tail;
1604        }
1605    }
1606
1607    void writeMethods(Scope s) {
1608        List<MethodSymbol> methods = List.nil();
1609        for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
1610            if (sym.kind == MTH && (sym.flags() & HYPOTHETICAL) == 0)
1611                methods = methods.prepend((MethodSymbol)sym);
1612        }
1613        while (methods.nonEmpty()) {
1614            writeMethod(methods.head);
1615            methods = methods.tail;
1616        }
1617    }
1618
1619    /** Emit a class file for a given class.
1620     *  @param c      The class from which a class file is generated.
1621     */
1622    public JavaFileObject writeClass(ClassSymbol c)
1623        throws IOException, PoolOverflow, StringOverflow
1624    {
1625        String name = (c.owner.kind == MDL ? c.name : c.flatname).toString();
1626        Location outLocn;
1627        if (multiModuleMode) {
1628            ModuleSymbol msym = c.owner.kind == MDL ? (ModuleSymbol) c.owner : c.packge().modle;
1629            outLocn = fileManager.getLocationForModule(CLASS_OUTPUT, msym.name.toString());
1630        } else {
1631            outLocn = CLASS_OUTPUT;
1632        }
1633        JavaFileObject outFile
1634            = fileManager.getJavaFileForOutput(outLocn,
1635                                               name,
1636                                               JavaFileObject.Kind.CLASS,
1637                                               c.sourcefile);
1638        OutputStream out = outFile.openOutputStream();
1639        try {
1640            writeClassFile(out, c);
1641            if (verbose)
1642                log.printVerbose("wrote.file", outFile);
1643            out.close();
1644            out = null;
1645        } finally {
1646            if (out != null) {
1647                // if we are propagating an exception, delete the file
1648                out.close();
1649                outFile.delete();
1650                outFile = null;
1651            }
1652        }
1653        return outFile; // may be null if write failed
1654    }
1655
1656    /** Write class `c' to outstream `out'.
1657     */
1658    public void writeClassFile(OutputStream out, ClassSymbol c)
1659        throws IOException, PoolOverflow, StringOverflow {
1660        Assert.check((c.flags() & COMPOUND) == 0);
1661        databuf.reset();
1662        poolbuf.reset();
1663        signatureGen.reset();
1664        pool = c.pool;
1665        innerClasses = null;
1666        innerClassesQueue = null;
1667        bootstrapMethods = new LinkedHashMap<>();
1668
1669        Type supertype = types.supertype(c.type);
1670        List<Type> interfaces = types.interfaces(c.type);
1671        List<Type> typarams = c.type.getTypeArguments();
1672
1673        int flags;
1674        if (c.owner.kind == MDL) {
1675            flags = ACC_MODULE;
1676        } else {
1677            flags = adjustFlags(c.flags() & ~DEFAULT);
1678            if ((flags & PROTECTED) != 0) flags |= PUBLIC;
1679            flags = flags & ClassFlags & ~STRICTFP;
1680            if ((flags & INTERFACE) == 0) flags |= ACC_SUPER;
1681        }
1682
1683        if (dumpClassModifiers) {
1684            PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1685            pw.println();
1686            pw.println("CLASSFILE  " + c.getQualifiedName());
1687            pw.println("---" + flagNames(flags));
1688        }
1689        databuf.appendChar(flags);
1690
1691        databuf.appendChar(pool.put(c));
1692        databuf.appendChar(supertype.hasTag(CLASS) ? pool.put(supertype.tsym) : 0);
1693        databuf.appendChar(interfaces.length());
1694        for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1695            databuf.appendChar(pool.put(l.head.tsym));
1696        int fieldsCount = 0;
1697        int methodsCount = 0;
1698        for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
1699            switch (sym.kind) {
1700            case VAR: fieldsCount++; break;
1701            case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
1702                      break;
1703            case TYP: enterInner((ClassSymbol)sym); break;
1704            default : Assert.error();
1705            }
1706        }
1707
1708        if (c.trans_local != null) {
1709            for (ClassSymbol local : c.trans_local) {
1710                enterInner(local);
1711            }
1712        }
1713
1714        databuf.appendChar(fieldsCount);
1715        writeFields(c.members());
1716        databuf.appendChar(methodsCount);
1717        writeMethods(c.members());
1718
1719        int acountIdx = beginAttrs();
1720        int acount = 0;
1721
1722        boolean sigReq =
1723            typarams.length() != 0 || supertype.allparams().length() != 0;
1724        for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
1725            sigReq = l.head.allparams().length() != 0;
1726        if (sigReq) {
1727            int alenIdx = writeAttr(names.Signature);
1728            if (typarams.length() != 0) signatureGen.assembleParamsSig(typarams);
1729            signatureGen.assembleSig(supertype);
1730            for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1731                signatureGen.assembleSig(l.head);
1732            databuf.appendChar(pool.put(signatureGen.toName()));
1733            signatureGen.reset();
1734            endAttr(alenIdx);
1735            acount++;
1736        }
1737
1738        if (c.sourcefile != null && emitSourceFile) {
1739            int alenIdx = writeAttr(names.SourceFile);
1740            // WHM 6/29/1999: Strip file path prefix.  We do it here at
1741            // the last possible moment because the sourcefile may be used
1742            // elsewhere in error diagnostics. Fixes 4241573.
1743            //databuf.appendChar(c.pool.put(c.sourcefile));
1744            String simpleName = PathFileObject.getSimpleName(c.sourcefile);
1745            databuf.appendChar(c.pool.put(names.fromString(simpleName)));
1746            endAttr(alenIdx);
1747            acount++;
1748        }
1749
1750        if (genCrt) {
1751            // Append SourceID attribute
1752            int alenIdx = writeAttr(names.SourceID);
1753            databuf.appendChar(c.pool.put(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
1754            endAttr(alenIdx);
1755            acount++;
1756            // Append CompilationID attribute
1757            alenIdx = writeAttr(names.CompilationID);
1758            databuf.appendChar(c.pool.put(names.fromString(Long.toString(System.currentTimeMillis()))));
1759            endAttr(alenIdx);
1760            acount++;
1761        }
1762
1763        acount += writeFlagAttrs(c.flags());
1764        acount += writeJavaAnnotations(c.getRawAttributes());
1765        acount += writeTypeAnnotations(c.getRawTypeAttributes(), false);
1766        acount += writeEnclosingMethodAttribute(c);
1767        if (c.owner.kind == MDL) {
1768            acount += writeModuleAttribute(c);
1769        }
1770        acount += writeExtraClassAttributes(c);
1771
1772        poolbuf.appendInt(JAVA_MAGIC);
1773        poolbuf.appendChar(target.minorVersion);
1774        poolbuf.appendChar(target.majorVersion);
1775
1776        writePool(c.pool);
1777
1778        if (innerClasses != null) {
1779            writeInnerClasses();
1780            acount++;
1781        }
1782
1783        if (!bootstrapMethods.isEmpty()) {
1784            writeBootstrapMethods();
1785            acount++;
1786        }
1787
1788        endAttrs(acountIdx, acount);
1789
1790        poolbuf.appendBytes(databuf.elems, 0, databuf.length);
1791        out.write(poolbuf.elems, 0, poolbuf.length);
1792
1793        pool = c.pool = null; // to conserve space
1794     }
1795
1796    /**Allows subclasses to write additional class attributes
1797     *
1798     * @return the number of attributes written
1799     */
1800    protected int writeExtraClassAttributes(ClassSymbol c) {
1801        return 0;
1802    }
1803
1804    int adjustFlags(final long flags) {
1805        int result = (int)flags;
1806
1807        if ((flags & BRIDGE) != 0)
1808            result |= ACC_BRIDGE;
1809        if ((flags & VARARGS) != 0)
1810            result |= ACC_VARARGS;
1811        if ((flags & DEFAULT) != 0)
1812            result &= ~ABSTRACT;
1813        return result;
1814    }
1815
1816    long getLastModified(FileObject filename) {
1817        long mod = 0;
1818        try {
1819            mod = filename.getLastModified();
1820        } catch (SecurityException e) {
1821            throw new AssertionError("CRT: couldn't get source file modification date: " + e.getMessage());
1822        }
1823        return mod;
1824    }
1825}
1826