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