001    /*
002     * Copyright 1999-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.javac.jvm;
027    
028    import java.io.*;
029    import java.util.Set;
030    import java.util.HashSet;
031    
032    import javax.tools.JavaFileManager;
033    import javax.tools.FileObject;
034    import javax.tools.JavaFileObject;
035    
036    import com.sun.tools.javac.code.*;
037    import com.sun.tools.javac.code.Symbol.*;
038    import com.sun.tools.javac.code.Type.*;
039    import com.sun.tools.javac.util.*;
040    import com.sun.tools.javac.util.List;
041    
042    import static com.sun.tools.javac.code.BoundKind.*;
043    import static com.sun.tools.javac.code.Flags.*;
044    import static com.sun.tools.javac.code.Kinds.*;
045    import static com.sun.tools.javac.code.TypeTags.*;
046    import static com.sun.tools.javac.jvm.UninitializedType.*;
047    import static javax.tools.StandardLocation.CLASS_OUTPUT;
048    
049    /** This class provides operations to map an internal symbol table graph
050     *  rooted in a ClassSymbol into a classfile.
051     *
052     *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
053     *  you write code that depends on this, you do so at your own risk.
054     *  This code and its internal interfaces are subject to change or
055     *  deletion without notice.</b>
056     */
057    public class ClassWriter extends ClassFile {
058        protected static final Context.Key<ClassWriter> classWriterKey =
059            new Context.Key<ClassWriter>();
060    
061        private final Symtab syms;
062    
063        private final Options options;
064    
065        /** Switch: verbose output.
066         */
067        private boolean verbose;
068    
069        /** Switch: scrable private names.
070         */
071        private boolean scramble;
072    
073        /** Switch: scrable private names.
074         */
075        private boolean scrambleAll;
076    
077        /** Switch: retrofit mode.
078         */
079        private boolean retrofit;
080    
081        /** Switch: emit source file attribute.
082         */
083        private boolean emitSourceFile;
084    
085        /** Switch: generate CharacterRangeTable attribute.
086         */
087        private boolean genCrt;
088    
089        /** Switch: describe the generated stackmap
090         */
091        boolean debugstackmap;
092    
093        /**
094         * Target class version.
095         */
096        private Target target;
097    
098        /**
099         * Source language version.
100         */
101        private Source source;
102    
103        /** Type utilities. */
104        private Types types;
105    
106        /** The initial sizes of the data and constant pool buffers.
107         *  sizes are increased when buffers get full.
108         */
109        static final int DATA_BUF_SIZE = 0x0fff0;
110        static final int POOL_BUF_SIZE = 0x1fff0;
111    
112        /** An output buffer for member info.
113         */
114        ByteBuffer databuf = new ByteBuffer(DATA_BUF_SIZE);
115    
116        /** An output buffer for the constant pool.
117         */
118        ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
119    
120        /** An output buffer for type signatures.
121         */
122        ByteBuffer sigbuf = new ByteBuffer();
123    
124        /** The constant pool.
125         */
126        Pool pool;
127    
128        /** The inner classes to be written, as a set.
129         */
130        Set<ClassSymbol> innerClasses;
131    
132        /** The inner classes to be written, as a queue where
133         *  enclosing classes come first.
134         */
135        ListBuffer<ClassSymbol> innerClassesQueue;
136    
137        /** The log to use for verbose output.
138         */
139        private final Log log;
140    
141        /** The name table. */
142        private final Names names;
143    
144        /** Access to files. */
145        private final JavaFileManager fileManager;
146    
147        /** The tags and constants used in compressed stackmap. */
148        static final int SAME_FRAME_SIZE = 64;
149        static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
150        static final int SAME_FRAME_EXTENDED = 251;
151        static final int FULL_FRAME = 255;
152        static final int MAX_LOCAL_LENGTH_DIFF = 4;
153    
154        /** Get the ClassWriter instance for this context. */
155        public static ClassWriter instance(Context context) {
156            ClassWriter instance = context.get(classWriterKey);
157            if (instance == null)
158                instance = new ClassWriter(context);
159            return instance;
160        }
161    
162        /** Construct a class writer, given an options table.
163         */
164        private ClassWriter(Context context) {
165            context.put(classWriterKey, this);
166    
167            log = Log.instance(context);
168            names = Names.instance(context);
169            syms = Symtab.instance(context);
170            options = Options.instance(context);
171            target = Target.instance(context);
172            source = Source.instance(context);
173            types = Types.instance(context);
174            fileManager = context.get(JavaFileManager.class);
175    
176            verbose        = options.get("-verbose")     != null;
177            scramble       = options.get("-scramble")    != null;
178            scrambleAll    = options.get("-scrambleAll") != null;
179            retrofit       = options.get("-retrofit") != null;
180            genCrt         = options.get("-Xjcov") != null;
181            debugstackmap  = options.get("debugstackmap") != null;
182    
183            emitSourceFile = options.get("-g:")==null || options.get("-g:source")!=null;
184    
185            String dumpModFlags = options.get("dumpmodifiers");
186            dumpClassModifiers =
187                (dumpModFlags != null && dumpModFlags.indexOf('c') != -1);
188            dumpFieldModifiers =
189                (dumpModFlags != null && dumpModFlags.indexOf('f') != -1);
190            dumpInnerClassModifiers =
191                (dumpModFlags != null && dumpModFlags.indexOf('i') != -1);
192            dumpMethodModifiers =
193                (dumpModFlags != null && dumpModFlags.indexOf('m') != -1);
194        }
195    
196    /******************************************************************
197     * Diagnostics: dump generated class names and modifiers
198     ******************************************************************/
199    
200        /** Value of option 'dumpmodifiers' is a string
201         *  indicating which modifiers should be dumped for debugging:
202         *    'c' -- classes
203         *    'f' -- fields
204         *    'i' -- innerclass attributes
205         *    'm' -- methods
206         *  For example, to dump everything:
207         *    javac -XDdumpmodifiers=cifm MyProg.java
208         */
209        private final boolean dumpClassModifiers; // -XDdumpmodifiers=c
210        private final boolean dumpFieldModifiers; // -XDdumpmodifiers=f
211        private final boolean dumpInnerClassModifiers; // -XDdumpmodifiers=i
212        private final boolean dumpMethodModifiers; // -XDdumpmodifiers=m
213    
214    
215        /** Return flags as a string, separated by " ".
216         */
217        public static String flagNames(long flags) {
218            StringBuffer sbuf = new StringBuffer();
219            int i = 0;
220            long f = flags & StandardFlags;
221            while (f != 0) {
222                if ((f & 1) != 0) sbuf.append(" " + flagName[i]);
223                f = f >> 1;
224                i++;
225            }
226            return sbuf.toString();
227        }
228        //where
229            private final static String[] flagName = {
230                "PUBLIC", "PRIVATE", "PROTECTED", "STATIC", "FINAL",
231                "SUPER", "VOLATILE", "TRANSIENT", "NATIVE", "INTERFACE",
232                "ABSTRACT", "STRICTFP"};
233    
234    /******************************************************************
235     * Output routines
236     ******************************************************************/
237    
238        /** Write a character into given byte buffer;
239         *  byte buffer will not be grown.
240         */
241        void putChar(ByteBuffer buf, int op, int x) {
242            buf.elems[op  ] = (byte)((x >>  8) & 0xFF);
243            buf.elems[op+1] = (byte)((x      ) & 0xFF);
244        }
245    
246        /** Write an integer into given byte buffer;
247         *  byte buffer will not be grown.
248         */
249        void putInt(ByteBuffer buf, int adr, int x) {
250            buf.elems[adr  ] = (byte)((x >> 24) & 0xFF);
251            buf.elems[adr+1] = (byte)((x >> 16) & 0xFF);
252            buf.elems[adr+2] = (byte)((x >>  8) & 0xFF);
253            buf.elems[adr+3] = (byte)((x      ) & 0xFF);
254        }
255    
256    /******************************************************************
257     * Signature Generation
258     ******************************************************************/
259    
260        /** Assemble signature of given type in string buffer.
261         */
262        void assembleSig(Type type) {
263            switch (type.tag) {
264            case BYTE:
265                sigbuf.appendByte('B');
266                break;
267            case SHORT:
268                sigbuf.appendByte('S');
269                break;
270            case CHAR:
271                sigbuf.appendByte('C');
272                break;
273            case INT:
274                sigbuf.appendByte('I');
275                break;
276            case LONG:
277                sigbuf.appendByte('J');
278                break;
279            case FLOAT:
280                sigbuf.appendByte('F');
281                break;
282            case DOUBLE:
283                sigbuf.appendByte('D');
284                break;
285            case BOOLEAN:
286                sigbuf.appendByte('Z');
287                break;
288            case VOID:
289                sigbuf.appendByte('V');
290                break;
291            case CLASS:
292                sigbuf.appendByte('L');
293                assembleClassSig(type);
294                sigbuf.appendByte(';');
295                break;
296            case ARRAY:
297                ArrayType at = (ArrayType)type;
298                sigbuf.appendByte('[');
299                assembleSig(at.elemtype);
300                break;
301            case METHOD:
302                MethodType mt = (MethodType)type;
303                sigbuf.appendByte('(');
304                assembleSig(mt.argtypes);
305                sigbuf.appendByte(')');
306                assembleSig(mt.restype);
307                if (hasTypeVar(mt.thrown)) {
308                    for (List<Type> l = mt.thrown; l.nonEmpty(); l = l.tail) {
309                        sigbuf.appendByte('^');
310                        assembleSig(l.head);
311                    }
312                }
313                break;
314            case WILDCARD: {
315                WildcardType ta = (WildcardType) type;
316                switch (ta.kind) {
317                case SUPER:
318                    sigbuf.appendByte('-');
319                    assembleSig(ta.type);
320                    break;
321                case EXTENDS:
322                    sigbuf.appendByte('+');
323                    assembleSig(ta.type);
324                    break;
325                case UNBOUND:
326                    sigbuf.appendByte('*');
327                    break;
328                default:
329                    throw new AssertionError(ta.kind);
330                }
331                break;
332            }
333            case TYPEVAR:
334                sigbuf.appendByte('T');
335                sigbuf.appendName(type.tsym.name);
336                sigbuf.appendByte(';');
337                break;
338            case FORALL:
339                ForAll ft = (ForAll)type;
340                assembleParamsSig(ft.tvars);
341                assembleSig(ft.qtype);
342                break;
343            case UNINITIALIZED_THIS:
344            case UNINITIALIZED_OBJECT:
345                // we don't yet have a spec for uninitialized types in the
346                // local variable table
347                assembleSig(types.erasure(((UninitializedType)type).qtype));
348                break;
349            default:
350                throw new AssertionError("typeSig " + type.tag);
351            }
352        }
353    
354        boolean hasTypeVar(List<Type> l) {
355            while (l.nonEmpty()) {
356                if (l.head.tag == TypeTags.TYPEVAR) return true;
357                l = l.tail;
358            }
359            return false;
360        }
361    
362        void assembleClassSig(Type type) {
363            ClassType ct = (ClassType)type;
364            ClassSymbol c = (ClassSymbol)ct.tsym;
365            enterInner(c);
366            Type outer = ct.getEnclosingType();
367            if (outer.allparams().nonEmpty()) {
368                boolean rawOuter =
369                    c.owner.kind == MTH || // either a local class
370                    c.name == names.empty; // or anonymous
371                assembleClassSig(rawOuter
372                                 ? types.erasure(outer)
373                                 : outer);
374                sigbuf.appendByte('.');
375                assert c.flatname.startsWith(c.owner.enclClass().flatname);
376                sigbuf.appendName(rawOuter
377                                  ? c.flatname.subName(c.owner.enclClass().flatname.getByteLength()+1,c.flatname.getByteLength())
378                                  : c.name);
379            } else {
380                sigbuf.appendBytes(externalize(c.flatname));
381            }
382            if (ct.getTypeArguments().nonEmpty()) {
383                sigbuf.appendByte('<');
384                assembleSig(ct.getTypeArguments());
385                sigbuf.appendByte('>');
386            }
387        }
388    
389    
390        void assembleSig(List<Type> types) {
391            for (List<Type> ts = types; ts.nonEmpty(); ts = ts.tail)
392                assembleSig(ts.head);
393        }
394    
395        void assembleParamsSig(List<Type> typarams) {
396            sigbuf.appendByte('<');
397            for (List<Type> ts = typarams; ts.nonEmpty(); ts = ts.tail) {
398                TypeVar tvar = (TypeVar)ts.head;
399                sigbuf.appendName(tvar.tsym.name);
400                List<Type> bounds = types.getBounds(tvar);
401                if ((bounds.head.tsym.flags() & INTERFACE) != 0) {
402                    sigbuf.appendByte(':');
403                }
404                for (List<Type> l = bounds; l.nonEmpty(); l = l.tail) {
405                    sigbuf.appendByte(':');
406                    assembleSig(l.head);
407                }
408            }
409            sigbuf.appendByte('>');
410        }
411    
412        /** Return signature of given type
413         */
414        Name typeSig(Type type) {
415            assert sigbuf.length == 0;
416            //- System.out.println(" ? " + type);
417            assembleSig(type);
418            Name n = sigbuf.toName(names);
419            sigbuf.reset();
420            //- System.out.println("   " + n);
421            return n;
422        }
423    
424        /** Given a type t, return the extended class name of its erasure in
425         *  external representation.
426         */
427        public Name xClassName(Type t) {
428            if (t.tag == CLASS) {
429                return names.fromUtf(externalize(t.tsym.flatName()));
430            } else if (t.tag == ARRAY) {
431                return typeSig(types.erasure(t));
432            } else {
433                throw new AssertionError("xClassName");
434            }
435        }
436    
437    /******************************************************************
438     * Writing the Constant Pool
439     ******************************************************************/
440    
441        /** Thrown when the constant pool is over full.
442         */
443        public static class PoolOverflow extends Exception {
444            private static final long serialVersionUID = 0;
445            public PoolOverflow() {}
446        }
447        public static class StringOverflow extends Exception {
448            private static final long serialVersionUID = 0;
449            public final String value;
450            public StringOverflow(String s) {
451                value = s;
452            }
453        }
454    
455        /** Write constant pool to pool buffer.
456         *  Note: during writing, constant pool
457         *  might grow since some parts of constants still need to be entered.
458         */
459        void writePool(Pool pool) throws PoolOverflow, StringOverflow {
460            int poolCountIdx = poolbuf.length;
461            poolbuf.appendChar(0);
462            int i = 1;
463            while (i < pool.pp) {
464                Object value = pool.pool[i];
465                assert value != null;
466                if (value instanceof Pool.Method)
467                    value = ((Pool.Method)value).m;
468                else if (value instanceof Pool.Variable)
469                    value = ((Pool.Variable)value).v;
470    
471                if (value instanceof MethodSymbol) {
472                    MethodSymbol m = (MethodSymbol)value;
473                    poolbuf.appendByte((m.owner.flags() & INTERFACE) != 0
474                              ? CONSTANT_InterfaceMethodref
475                              : CONSTANT_Methodref);
476                    poolbuf.appendChar(pool.put(m.owner));
477                    poolbuf.appendChar(pool.put(nameType(m)));
478                } else if (value instanceof VarSymbol) {
479                    VarSymbol v = (VarSymbol)value;
480                    poolbuf.appendByte(CONSTANT_Fieldref);
481                    poolbuf.appendChar(pool.put(v.owner));
482                    poolbuf.appendChar(pool.put(nameType(v)));
483                } else if (value instanceof Name) {
484                    poolbuf.appendByte(CONSTANT_Utf8);
485                    byte[] bs = ((Name)value).toUtf();
486                    poolbuf.appendChar(bs.length);
487                    poolbuf.appendBytes(bs, 0, bs.length);
488                    if (bs.length > Pool.MAX_STRING_LENGTH)
489                        throw new StringOverflow(value.toString());
490                } else if (value instanceof ClassSymbol) {
491                    ClassSymbol c = (ClassSymbol)value;
492                    if (c.owner.kind == TYP) pool.put(c.owner);
493                    poolbuf.appendByte(CONSTANT_Class);
494                    if (c.type.tag == ARRAY) {
495                        poolbuf.appendChar(pool.put(typeSig(c.type)));
496                    } else {
497                        poolbuf.appendChar(pool.put(names.fromUtf(externalize(c.flatname))));
498                        enterInner(c);
499                    }
500                } else if (value instanceof NameAndType) {
501                    NameAndType nt = (NameAndType)value;
502                    poolbuf.appendByte(CONSTANT_NameandType);
503                    poolbuf.appendChar(pool.put(nt.name));
504                    poolbuf.appendChar(pool.put(typeSig(nt.type)));
505                } else if (value instanceof Integer) {
506                    poolbuf.appendByte(CONSTANT_Integer);
507                    poolbuf.appendInt(((Integer)value).intValue());
508                } else if (value instanceof Long) {
509                    poolbuf.appendByte(CONSTANT_Long);
510                    poolbuf.appendLong(((Long)value).longValue());
511                    i++;
512                } else if (value instanceof Float) {
513                    poolbuf.appendByte(CONSTANT_Float);
514                    poolbuf.appendFloat(((Float)value).floatValue());
515                } else if (value instanceof Double) {
516                    poolbuf.appendByte(CONSTANT_Double);
517                    poolbuf.appendDouble(((Double)value).doubleValue());
518                    i++;
519                } else if (value instanceof String) {
520                    poolbuf.appendByte(CONSTANT_String);
521                    poolbuf.appendChar(pool.put(names.fromString((String)value)));
522                } else if (value instanceof Type) {
523                    Type type = (Type)value;
524                    if (type.tag == CLASS) enterInner((ClassSymbol)type.tsym);
525                    poolbuf.appendByte(CONSTANT_Class);
526                    poolbuf.appendChar(pool.put(xClassName(type)));
527                } else {
528                    assert false : "writePool " + value;
529                }
530                i++;
531            }
532            if (pool.pp > Pool.MAX_ENTRIES)
533                throw new PoolOverflow();
534            putChar(poolbuf, poolCountIdx, pool.pp);
535        }
536    
537        /** Given a field, return its name.
538         */
539        Name fieldName(Symbol sym) {
540            if (scramble && (sym.flags() & PRIVATE) != 0 ||
541                scrambleAll && (sym.flags() & (PROTECTED | PUBLIC)) == 0)
542                return names.fromString("_$" + sym.name.getIndex());
543            else
544                return sym.name;
545        }
546    
547        /** Given a symbol, return its name-and-type.
548         */
549        NameAndType nameType(Symbol sym) {
550            return new NameAndType(fieldName(sym),
551                                   retrofit
552                                   ? sym.erasure(types)
553                                   : sym.externalType(types));
554            // if we retrofit, then the NameAndType has been read in as is
555            // and no change is necessary. If we compile normally, the
556            // NameAndType is generated from a symbol reference, and the
557            // adjustment of adding an additional this$n parameter needs to be made.
558        }
559    
560    /******************************************************************
561     * Writing Attributes
562     ******************************************************************/
563    
564        /** Write header for an attribute to data buffer and return
565         *  position past attribute length index.
566         */
567        int writeAttr(Name attrName) {
568            databuf.appendChar(pool.put(attrName));
569            databuf.appendInt(0);
570            return databuf.length;
571        }
572    
573        /** Fill in attribute length.
574         */
575        void endAttr(int index) {
576            putInt(databuf, index - 4, databuf.length - index);
577        }
578    
579        /** Leave space for attribute count and return index for
580         *  number of attributes field.
581         */
582        int beginAttrs() {
583            databuf.appendChar(0);
584            return databuf.length;
585        }
586    
587        /** Fill in number of attributes.
588         */
589        void endAttrs(int index, int count) {
590            putChar(databuf, index - 2, count);
591        }
592    
593        /** Write the EnclosingMethod attribute if needed.
594         *  Returns the number of attributes written (0 or 1).
595         */
596        int writeEnclosingMethodAttribute(ClassSymbol c) {
597            if (!target.hasEnclosingMethodAttribute() ||
598                c.owner.kind != MTH && // neither a local class
599                c.name != names.empty) // nor anonymous
600                return 0;
601    
602            int alenIdx = writeAttr(names.EnclosingMethod);
603            ClassSymbol enclClass = c.owner.enclClass();
604            MethodSymbol enclMethod =
605                (c.owner.type == null // local to init block
606                 || c.owner.kind != MTH) // or member init
607                ? null
608                : (MethodSymbol)c.owner;
609            databuf.appendChar(pool.put(enclClass));
610            databuf.appendChar(enclMethod == null ? 0 : pool.put(nameType(c.owner)));
611            endAttr(alenIdx);
612            return 1;
613        }
614    
615        /** Write flag attributes; return number of attributes written.
616         */
617        int writeFlagAttrs(long flags) {
618            int acount = 0;
619            if ((flags & DEPRECATED) != 0) {
620                int alenIdx = writeAttr(names.Deprecated);
621                endAttr(alenIdx);
622                acount++;
623            }
624            if ((flags & ENUM) != 0 && !target.useEnumFlag()) {
625                int alenIdx = writeAttr(names.Enum);
626                endAttr(alenIdx);
627                acount++;
628            }
629            if ((flags & SYNTHETIC) != 0 && !target.useSyntheticFlag()) {
630                int alenIdx = writeAttr(names.Synthetic);
631                endAttr(alenIdx);
632                acount++;
633            }
634            if ((flags & BRIDGE) != 0 && !target.useBridgeFlag()) {
635                int alenIdx = writeAttr(names.Bridge);
636                endAttr(alenIdx);
637                acount++;
638            }
639            if ((flags & VARARGS) != 0 && !target.useVarargsFlag()) {
640                int alenIdx = writeAttr(names.Varargs);
641                endAttr(alenIdx);
642                acount++;
643            }
644            if ((flags & ANNOTATION) != 0 && !target.useAnnotationFlag()) {
645                int alenIdx = writeAttr(names.Annotation);
646                endAttr(alenIdx);
647                acount++;
648            }
649            return acount;
650        }
651    
652        /** Write member (field or method) attributes;
653         *  return number of attributes written.
654         */
655        int writeMemberAttrs(Symbol sym) {
656            int acount = writeFlagAttrs(sym.flags());
657            long flags = sym.flags();
658            if (source.allowGenerics() &&
659                (flags & (SYNTHETIC|BRIDGE)) != SYNTHETIC &&
660                (flags & ANONCONSTR) == 0 &&
661                (!types.isSameType(sym.type, sym.erasure(types)) ||
662                 hasTypeVar(sym.type.getThrownTypes()))) {
663                // note that a local class with captured variables
664                // will get a signature attribute
665                int alenIdx = writeAttr(names.Signature);
666                databuf.appendChar(pool.put(typeSig(sym.type)));
667                endAttr(alenIdx);
668                acount++;
669            }
670            acount += writeJavaAnnotations(sym.getAnnotationMirrors());
671            return acount;
672        }
673    
674        /** Write method parameter annotations;
675         *  return number of attributes written.
676         */
677        int writeParameterAttrs(MethodSymbol m) {
678            boolean hasVisible = false;
679            boolean hasInvisible = false;
680            if (m.params != null) for (VarSymbol s : m.params) {
681                for (Attribute.Compound a : s.getAnnotationMirrors()) {
682                    switch (getRetention(a.type.tsym)) {
683                    case SOURCE: break;
684                    case CLASS: hasInvisible = true; break;
685                    case RUNTIME: hasVisible = true; break;
686                    default: ;// /* fail soft */ throw new AssertionError(vis);
687                    }
688                }
689            }
690    
691            int attrCount = 0;
692            if (hasVisible) {
693                int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations);
694                databuf.appendByte(m.params.length());
695                for (VarSymbol s : m.params) {
696                    ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>();
697                    for (Attribute.Compound a : s.getAnnotationMirrors())
698                        if (getRetention(a.type.tsym) == RetentionPolicy.RUNTIME)
699                            buf.append(a);
700                    databuf.appendChar(buf.length());
701                    for (Attribute.Compound a : buf)
702                        writeCompoundAttribute(a);
703                }
704                endAttr(attrIndex);
705                attrCount++;
706            }
707            if (hasInvisible) {
708                int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations);
709                databuf.appendByte(m.params.length());
710                for (VarSymbol s : m.params) {
711                    ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>();
712                    for (Attribute.Compound a : s.getAnnotationMirrors())
713                        if (getRetention(a.type.tsym) == RetentionPolicy.CLASS)
714                            buf.append(a);
715                    databuf.appendChar(buf.length());
716                    for (Attribute.Compound a : buf)
717                        writeCompoundAttribute(a);
718                }
719                endAttr(attrIndex);
720                attrCount++;
721            }
722            return attrCount;
723        }
724    
725    /**********************************************************************
726     * Writing Java-language annotations (aka metadata, attributes)
727     **********************************************************************/
728    
729        /** Write Java-language annotations; return number of JVM
730         *  attributes written (zero or one).
731         */
732        int writeJavaAnnotations(List<Attribute.Compound> attrs) {
733            if (attrs.isEmpty()) return 0;
734            ListBuffer<Attribute.Compound> visibles = new ListBuffer<Attribute.Compound>();
735            ListBuffer<Attribute.Compound> invisibles = new ListBuffer<Attribute.Compound>();
736            for (Attribute.Compound a : attrs) {
737                switch (getRetention(a.type.tsym)) {
738                case SOURCE: break;
739                case CLASS: invisibles.append(a); break;
740                case RUNTIME: visibles.append(a); break;
741                default: ;// /* fail soft */ throw new AssertionError(vis);
742                }
743            }
744    
745            int attrCount = 0;
746            if (visibles.length() != 0) {
747                int attrIndex = writeAttr(names.RuntimeVisibleAnnotations);
748                databuf.appendChar(visibles.length());
749                for (Attribute.Compound a : visibles)
750                    writeCompoundAttribute(a);
751                endAttr(attrIndex);
752                attrCount++;
753            }
754            if (invisibles.length() != 0) {
755                int attrIndex = writeAttr(names.RuntimeInvisibleAnnotations);
756                databuf.appendChar(invisibles.length());
757                for (Attribute.Compound a : invisibles)
758                    writeCompoundAttribute(a);
759                endAttr(attrIndex);
760                attrCount++;
761            }
762            return attrCount;
763        }
764    
765        /** A mirror of java.lang.annotation.RetentionPolicy. */
766        enum RetentionPolicy {
767            SOURCE,
768            CLASS,
769            RUNTIME
770        }
771    
772        RetentionPolicy getRetention(TypeSymbol annotationType) {
773            RetentionPolicy vis = RetentionPolicy.CLASS; // the default
774            Attribute.Compound c = annotationType.attribute(syms.retentionType.tsym);
775            if (c != null) {
776                Attribute value = c.member(names.value);
777                if (value != null && value instanceof Attribute.Enum) {
778                    Name levelName = ((Attribute.Enum)value).value.name;
779                    if (levelName == names.SOURCE) vis = RetentionPolicy.SOURCE;
780                    else if (levelName == names.CLASS) vis = RetentionPolicy.CLASS;
781                    else if (levelName == names.RUNTIME) vis = RetentionPolicy.RUNTIME;
782                    else ;// /* fail soft */ throw new AssertionError(levelName);
783                }
784            }
785            return vis;
786        }
787    
788        /** A visitor to write an attribute including its leading
789         *  single-character marker.
790         */
791        class AttributeWriter implements Attribute.Visitor {
792            public void visitConstant(Attribute.Constant _value) {
793                Object value = _value.value;
794                switch (_value.type.tag) {
795                case BYTE:
796                    databuf.appendByte('B');
797                    break;
798                case CHAR:
799                    databuf.appendByte('C');
800                    break;
801                case SHORT:
802                    databuf.appendByte('S');
803                    break;
804                case INT:
805                    databuf.appendByte('I');
806                    break;
807                case LONG:
808                    databuf.appendByte('J');
809                    break;
810                case FLOAT:
811                    databuf.appendByte('F');
812                    break;
813                case DOUBLE:
814                    databuf.appendByte('D');
815                    break;
816                case BOOLEAN:
817                    databuf.appendByte('Z');
818                    break;
819                case CLASS:
820                    assert value instanceof String;
821                    databuf.appendByte('s');
822                    value = names.fromString(value.toString()); // CONSTANT_Utf8
823                    break;
824                default:
825                    throw new AssertionError(_value.type);
826                }
827                databuf.appendChar(pool.put(value));
828            }
829            public void visitEnum(Attribute.Enum e) {
830                databuf.appendByte('e');
831                databuf.appendChar(pool.put(typeSig(e.value.type)));
832                databuf.appendChar(pool.put(e.value.name));
833            }
834            public void visitClass(Attribute.Class clazz) {
835                databuf.appendByte('c');
836                databuf.appendChar(pool.put(typeSig(clazz.type)));
837            }
838            public void visitCompound(Attribute.Compound compound) {
839                databuf.appendByte('@');
840                writeCompoundAttribute(compound);
841            }
842            public void visitError(Attribute.Error x) {
843                throw new AssertionError(x);
844            }
845            public void visitArray(Attribute.Array array) {
846                databuf.appendByte('[');
847                databuf.appendChar(array.values.length);
848                for (Attribute a : array.values) {
849                    a.accept(this);
850                }
851            }
852        }
853        AttributeWriter awriter = new AttributeWriter();
854    
855        /** Write a compound attribute excluding the '@' marker. */
856        void writeCompoundAttribute(Attribute.Compound c) {
857            databuf.appendChar(pool.put(typeSig(c.type)));
858            databuf.appendChar(c.values.length());
859            for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) {
860                databuf.appendChar(pool.put(p.fst.name));
861                p.snd.accept(awriter);
862            }
863        }
864    
865    /**********************************************************************
866     * Writing Objects
867     **********************************************************************/
868    
869        /** Enter an inner class into the `innerClasses' set/queue.
870         */
871        void enterInner(ClassSymbol c) {
872            assert !c.type.isCompound();
873            try {
874                c.complete();
875            } catch (CompletionFailure ex) {
876                System.err.println("error: " + c + ": " + ex.getMessage());
877                throw ex;
878            }
879            if (c.type.tag != CLASS) return; // arrays
880            if (pool != null && // pool might be null if called from xClassName
881                c.owner.kind != PCK &&
882                (innerClasses == null || !innerClasses.contains(c))) {
883    //          log.errWriter.println("enter inner " + c);//DEBUG
884                if (c.owner.kind == TYP) enterInner((ClassSymbol)c.owner);
885                pool.put(c);
886                pool.put(c.name);
887                if (innerClasses == null) {
888                    innerClasses = new HashSet<ClassSymbol>();
889                    innerClassesQueue = new ListBuffer<ClassSymbol>();
890                    pool.put(names.InnerClasses);
891                }
892                innerClasses.add(c);
893                innerClassesQueue.append(c);
894            }
895        }
896    
897        /** Write "inner classes" attribute.
898         */
899        void writeInnerClasses() {
900            int alenIdx = writeAttr(names.InnerClasses);
901            databuf.appendChar(innerClassesQueue.length());
902            for (List<ClassSymbol> l = innerClassesQueue.toList();
903                 l.nonEmpty();
904                 l = l.tail) {
905                ClassSymbol inner = l.head;
906                char flags = (char) adjustFlags(inner.flags_field);
907                if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT
908                if (inner.name.isEmpty()) flags &= ~FINAL; // Anonymous class: unset FINAL flag
909                if (dumpInnerClassModifiers) {
910                    log.errWriter.println("INNERCLASS  " + inner.name);
911                    log.errWriter.println("---" + flagNames(flags));
912                }
913                databuf.appendChar(pool.get(inner));
914                databuf.appendChar(
915                    inner.owner.kind == TYP ? pool.get(inner.owner) : 0);
916                databuf.appendChar(
917                    !inner.name.isEmpty() ? pool.get(inner.name) : 0);
918                databuf.appendChar(flags);
919            }
920            endAttr(alenIdx);
921        }
922    
923        /** Write field symbol, entering all references into constant pool.
924         */
925        void writeField(VarSymbol v) {
926            int flags = adjustFlags(v.flags());
927            databuf.appendChar(flags);
928            if (dumpFieldModifiers) {
929                log.errWriter.println("FIELD  " + fieldName(v));
930                log.errWriter.println("---" + flagNames(v.flags()));
931            }
932            databuf.appendChar(pool.put(fieldName(v)));
933            databuf.appendChar(pool.put(typeSig(v.erasure(types))));
934            int acountIdx = beginAttrs();
935            int acount = 0;
936            if (v.getConstValue() != null) {
937                int alenIdx = writeAttr(names.ConstantValue);
938                databuf.appendChar(pool.put(v.getConstValue()));
939                endAttr(alenIdx);
940                acount++;
941            }
942            acount += writeMemberAttrs(v);
943            endAttrs(acountIdx, acount);
944        }
945    
946        /** Write method symbol, entering all references into constant pool.
947         */
948        void writeMethod(MethodSymbol m) {
949            int flags = adjustFlags(m.flags());
950            databuf.appendChar(flags);
951            if (dumpMethodModifiers) {
952                log.errWriter.println("METHOD  " + fieldName(m));
953                log.errWriter.println("---" + flagNames(m.flags()));
954            }
955            databuf.appendChar(pool.put(fieldName(m)));
956            databuf.appendChar(pool.put(typeSig(m.externalType(types))));
957            int acountIdx = beginAttrs();
958            int acount = 0;
959            if (m.code != null) {
960                int alenIdx = writeAttr(names.Code);
961                writeCode(m.code);
962                m.code = null; // to conserve space
963                endAttr(alenIdx);
964                acount++;
965            }
966            List<Type> thrown = m.erasure(types).getThrownTypes();
967            if (thrown.nonEmpty()) {
968                int alenIdx = writeAttr(names.Exceptions);
969                databuf.appendChar(thrown.length());
970                for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
971                    databuf.appendChar(pool.put(l.head.tsym));
972                endAttr(alenIdx);
973                acount++;
974            }
975            if (m.defaultValue != null) {
976                int alenIdx = writeAttr(names.AnnotationDefault);
977                m.defaultValue.accept(awriter);
978                endAttr(alenIdx);
979                acount++;
980            }
981            acount += writeMemberAttrs(m);
982            acount += writeParameterAttrs(m);
983            endAttrs(acountIdx, acount);
984        }
985    
986        /** Write code attribute of method.
987         */
988        void writeCode(Code code) {
989            databuf.appendChar(code.max_stack);
990            databuf.appendChar(code.max_locals);
991            databuf.appendInt(code.cp);
992            databuf.appendBytes(code.code, 0, code.cp);
993            databuf.appendChar(code.catchInfo.length());
994            for (List<char[]> l = code.catchInfo.toList();
995                 l.nonEmpty();
996                 l = l.tail) {
997                for (int i = 0; i < l.head.length; i++)
998                    databuf.appendChar(l.head[i]);
999            }
1000            int acountIdx = beginAttrs();
1001            int acount = 0;
1002    
1003            if (code.lineInfo.nonEmpty()) {
1004                int alenIdx = writeAttr(names.LineNumberTable);
1005                databuf.appendChar(code.lineInfo.length());
1006                for (List<char[]> l = code.lineInfo.reverse();
1007                     l.nonEmpty();
1008                     l = l.tail)
1009                    for (int i = 0; i < l.head.length; i++)
1010                        databuf.appendChar(l.head[i]);
1011                endAttr(alenIdx);
1012                acount++;
1013            }
1014    
1015            if (genCrt && (code.crt != null)) {
1016                CRTable crt = code.crt;
1017                int alenIdx = writeAttr(names.CharacterRangeTable);
1018                int crtIdx = beginAttrs();
1019                int crtEntries = crt.writeCRT(databuf, code.lineMap, log);
1020                endAttrs(crtIdx, crtEntries);
1021                endAttr(alenIdx);
1022                acount++;
1023            }
1024    
1025            // counter for number of generic local variables
1026            int nGenericVars = 0;
1027    
1028            if (code.varBufferSize > 0) {
1029                int alenIdx = writeAttr(names.LocalVariableTable);
1030                databuf.appendChar(code.varBufferSize);
1031    
1032                for (int i=0; i<code.varBufferSize; i++) {
1033                    Code.LocalVar var = code.varBuffer[i];
1034    
1035                    // write variable info
1036                    assert var.start_pc >= 0;
1037                    assert var.start_pc <= code.cp;
1038                    databuf.appendChar(var.start_pc);
1039                    assert var.length >= 0;
1040                    assert (var.start_pc + var.length) <= code.cp;
1041                    databuf.appendChar(var.length);
1042                    VarSymbol sym = var.sym;
1043                    databuf.appendChar(pool.put(sym.name));
1044                    Type vartype = sym.erasure(types);
1045                    if (!types.isSameType(sym.type, vartype))
1046                        nGenericVars++;
1047                    databuf.appendChar(pool.put(typeSig(vartype)));
1048                    databuf.appendChar(var.reg);
1049                }
1050                endAttr(alenIdx);
1051                acount++;
1052            }
1053    
1054            if (nGenericVars > 0) {
1055                int alenIdx = writeAttr(names.LocalVariableTypeTable);
1056                databuf.appendChar(nGenericVars);
1057                int count = 0;
1058    
1059                for (int i=0; i<code.varBufferSize; i++) {
1060                    Code.LocalVar var = code.varBuffer[i];
1061                    VarSymbol sym = var.sym;
1062                    if (types.isSameType(sym.type, sym.erasure(types)))
1063                        continue;
1064                    count++;
1065                    // write variable info
1066                    databuf.appendChar(var.start_pc);
1067                    databuf.appendChar(var.length);
1068                    databuf.appendChar(pool.put(sym.name));
1069                    databuf.appendChar(pool.put(typeSig(sym.type)));
1070                    databuf.appendChar(var.reg);
1071                }
1072                assert count == nGenericVars;
1073                endAttr(alenIdx);
1074                acount++;
1075            }
1076    
1077            if (code.stackMapBufferSize > 0) {
1078                if (debugstackmap) System.out.println("Stack map for " + code.meth);
1079                int alenIdx = writeAttr(code.stackMap.getAttributeName(names));
1080                writeStackMap(code);
1081                endAttr(alenIdx);
1082                acount++;
1083            }
1084            endAttrs(acountIdx, acount);
1085        }
1086    
1087        void writeStackMap(Code code) {
1088            int nframes = code.stackMapBufferSize;
1089            if (debugstackmap) System.out.println(" nframes = " + nframes);
1090            databuf.appendChar(nframes);
1091    
1092            switch (code.stackMap) {
1093            case CLDC:
1094                for (int i=0; i<nframes; i++) {
1095                    if (debugstackmap) System.out.print("  " + i + ":");
1096                    Code.StackMapFrame frame = code.stackMapBuffer[i];
1097    
1098                    // output PC
1099                    if (debugstackmap) System.out.print(" pc=" + frame.pc);
1100                    databuf.appendChar(frame.pc);
1101    
1102                    // output locals
1103                    int localCount = 0;
1104                    for (int j=0; j<frame.locals.length;
1105                         j += (target.generateEmptyAfterBig() ? 1 : Code.width(frame.locals[j]))) {
1106                        localCount++;
1107                    }
1108                    if (debugstackmap) System.out.print(" nlocals=" +
1109                                                        localCount);
1110                    databuf.appendChar(localCount);
1111                    for (int j=0; j<frame.locals.length;
1112                         j += (target.generateEmptyAfterBig() ? 1 : Code.width(frame.locals[j]))) {
1113                        if (debugstackmap) System.out.print(" local[" + j + "]=");
1114                        writeStackMapType(frame.locals[j]);
1115                    }
1116    
1117                    // output stack
1118                    int stackCount = 0;
1119                    for (int j=0; j<frame.stack.length;
1120                         j += (target.generateEmptyAfterBig() ? 1 : Code.width(frame.stack[j]))) {
1121                        stackCount++;
1122                    }
1123                    if (debugstackmap) System.out.print(" nstack=" +
1124                                                        stackCount);
1125                    databuf.appendChar(stackCount);
1126                    for (int j=0; j<frame.stack.length;
1127                         j += (target.generateEmptyAfterBig() ? 1 : Code.width(frame.stack[j]))) {
1128                        if (debugstackmap) System.out.print(" stack[" + j + "]=");
1129                        writeStackMapType(frame.stack[j]);
1130                    }
1131                    if (debugstackmap) System.out.println();
1132                }
1133                break;
1134            case JSR202: {
1135                assert code.stackMapBuffer == null;
1136                for (int i=0; i<nframes; i++) {
1137                    if (debugstackmap) System.out.print("  " + i + ":");
1138                    StackMapTableFrame frame = code.stackMapTableBuffer[i];
1139                    frame.write(this);
1140                    if (debugstackmap) System.out.println();
1141                }
1142                break;
1143            }
1144            default:
1145                throw new AssertionError("Unexpected stackmap format value");
1146            }
1147        }
1148    
1149            //where
1150            void writeStackMapType(Type t) {
1151                if (t == null) {
1152                    if (debugstackmap) System.out.print("empty");
1153                    databuf.appendByte(0);
1154                }
1155                else switch(t.tag) {
1156                case BYTE:
1157                case CHAR:
1158                case SHORT:
1159                case INT:
1160                case BOOLEAN:
1161                    if (debugstackmap) System.out.print("int");
1162                    databuf.appendByte(1);
1163                    break;
1164                case FLOAT:
1165                    if (debugstackmap) System.out.print("float");
1166                    databuf.appendByte(2);
1167                    break;
1168                case DOUBLE:
1169                    if (debugstackmap) System.out.print("double");
1170                    databuf.appendByte(3);
1171                    break;
1172                case LONG:
1173                    if (debugstackmap) System.out.print("long");
1174                    databuf.appendByte(4);
1175                    break;
1176                case BOT: // null
1177                    if (debugstackmap) System.out.print("null");
1178                    databuf.appendByte(5);
1179                    break;
1180                case CLASS:
1181                case ARRAY:
1182                    if (debugstackmap) System.out.print("object(" + t + ")");
1183                    databuf.appendByte(7);
1184                    databuf.appendChar(pool.put(t));
1185                    break;
1186                case TYPEVAR:
1187                    if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1188                    databuf.appendByte(7);
1189                    databuf.appendChar(pool.put(types.erasure(t).tsym));
1190                    break;
1191                case UNINITIALIZED_THIS:
1192                    if (debugstackmap) System.out.print("uninit_this");
1193                    databuf.appendByte(6);
1194                    break;
1195                case UNINITIALIZED_OBJECT:
1196                    { UninitializedType uninitType = (UninitializedType)t;
1197                    databuf.appendByte(8);
1198                    if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset);
1199                    databuf.appendChar(uninitType.offset);
1200                    }
1201                    break;
1202                default:
1203                    throw new AssertionError();
1204                }
1205            }
1206    
1207        /** An entry in the JSR202 StackMapTable */
1208        abstract static class StackMapTableFrame {
1209            abstract int getFrameType();
1210    
1211            void write(ClassWriter writer) {
1212                int frameType = getFrameType();
1213                writer.databuf.appendByte(frameType);
1214                if (writer.debugstackmap) System.out.print(" frame_type=" + frameType);
1215            }
1216    
1217            static class SameFrame extends StackMapTableFrame {
1218                final int offsetDelta;
1219                SameFrame(int offsetDelta) {
1220                    this.offsetDelta = offsetDelta;
1221                }
1222                int getFrameType() {
1223                    return (offsetDelta < SAME_FRAME_SIZE) ? offsetDelta : SAME_FRAME_EXTENDED;
1224                }
1225                @Override
1226                void write(ClassWriter writer) {
1227                    super.write(writer);
1228                    if (getFrameType() == SAME_FRAME_EXTENDED) {
1229                        writer.databuf.appendChar(offsetDelta);
1230                        if (writer.debugstackmap){
1231                            System.out.print(" offset_delta=" + offsetDelta);
1232                        }
1233                    }
1234                }
1235            }
1236    
1237            static class SameLocals1StackItemFrame extends StackMapTableFrame {
1238                final int offsetDelta;
1239                final Type stack;
1240                SameLocals1StackItemFrame(int offsetDelta, Type stack) {
1241                    this.offsetDelta = offsetDelta;
1242                    this.stack = stack;
1243                }
1244                int getFrameType() {
1245                    return (offsetDelta < SAME_FRAME_SIZE) ?
1246                           (SAME_FRAME_SIZE + offsetDelta) :
1247                           SAME_LOCALS_1_STACK_ITEM_EXTENDED;
1248                }
1249                @Override
1250                void write(ClassWriter writer) {
1251                    super.write(writer);
1252                    if (getFrameType() == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
1253                        writer.databuf.appendChar(offsetDelta);
1254                        if (writer.debugstackmap) {
1255                            System.out.print(" offset_delta=" + offsetDelta);
1256                        }
1257                    }
1258                    if (writer.debugstackmap) {
1259                        System.out.print(" stack[" + 0 + "]=");
1260                    }
1261                    writer.writeStackMapType(stack);
1262                }
1263            }
1264    
1265            static class ChopFrame extends StackMapTableFrame {
1266                final int frameType;
1267                final int offsetDelta;
1268                ChopFrame(int frameType, int offsetDelta) {
1269                    this.frameType = frameType;
1270                    this.offsetDelta = offsetDelta;
1271                }
1272                int getFrameType() { return frameType; }
1273                @Override
1274                void write(ClassWriter writer) {
1275                    super.write(writer);
1276                    writer.databuf.appendChar(offsetDelta);
1277                    if (writer.debugstackmap) {
1278                        System.out.print(" offset_delta=" + offsetDelta);
1279                    }
1280                }
1281            }
1282    
1283            static class AppendFrame extends StackMapTableFrame {
1284                final int frameType;
1285                final int offsetDelta;
1286                final Type[] locals;
1287                AppendFrame(int frameType, int offsetDelta, Type[] locals) {
1288                    this.frameType = frameType;
1289                    this.offsetDelta = offsetDelta;
1290                    this.locals = locals;
1291                }
1292                int getFrameType() { return frameType; }
1293                @Override
1294                void write(ClassWriter writer) {
1295                    super.write(writer);
1296                    writer.databuf.appendChar(offsetDelta);
1297                    if (writer.debugstackmap) {
1298                        System.out.print(" offset_delta=" + offsetDelta);
1299                    }
1300                    for (int i=0; i<locals.length; i++) {
1301                         if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1302                         writer.writeStackMapType(locals[i]);
1303                    }
1304                }
1305            }
1306    
1307            static class FullFrame extends StackMapTableFrame {
1308                final int offsetDelta;
1309                final Type[] locals;
1310                final Type[] stack;
1311                FullFrame(int offsetDelta, Type[] locals, Type[] stack) {
1312                    this.offsetDelta = offsetDelta;
1313                    this.locals = locals;
1314                    this.stack = stack;
1315                }
1316                int getFrameType() { return FULL_FRAME; }
1317                @Override
1318                void write(ClassWriter writer) {
1319                    super.write(writer);
1320                    writer.databuf.appendChar(offsetDelta);
1321                    writer.databuf.appendChar(locals.length);
1322                    if (writer.debugstackmap) {
1323                        System.out.print(" offset_delta=" + offsetDelta);
1324                        System.out.print(" nlocals=" + locals.length);
1325                    }
1326                    for (int i=0; i<locals.length; i++) {
1327                        if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1328                        writer.writeStackMapType(locals[i]);
1329                    }
1330    
1331                    writer.databuf.appendChar(stack.length);
1332                    if (writer.debugstackmap) { System.out.print(" nstack=" + stack.length); }
1333                    for (int i=0; i<stack.length; i++) {
1334                        if (writer.debugstackmap) System.out.print(" stack[" + i + "]=");
1335                        writer.writeStackMapType(stack[i]);
1336                    }
1337                }
1338            }
1339    
1340           /** Compare this frame with the previous frame and produce
1341            *  an entry of compressed stack map frame. */
1342            static StackMapTableFrame getInstance(Code.StackMapFrame this_frame,
1343                                                  int prev_pc,
1344                                                  Type[] prev_locals,
1345                                                  Types types) {
1346                Type[] locals = this_frame.locals;
1347                Type[] stack = this_frame.stack;
1348                int offset_delta = this_frame.pc - prev_pc - 1;
1349                if (stack.length == 1) {
1350                    if (locals.length == prev_locals.length
1351                        && compare(prev_locals, locals, types) == 0) {
1352                        return new SameLocals1StackItemFrame(offset_delta, stack[0]);
1353                    }
1354                } else if (stack.length == 0) {
1355                    int diff_length = compare(prev_locals, locals, types);
1356                    if (diff_length == 0) {
1357                        return new SameFrame(offset_delta);
1358                    } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) {
1359                        // APPEND
1360                        Type[] local_diff = new Type[-diff_length];
1361                        for (int i=prev_locals.length, j=0; i<locals.length; i++,j++) {
1362                            local_diff[j] = locals[i];
1363                        }
1364                        return new AppendFrame(SAME_FRAME_EXTENDED - diff_length,
1365                                               offset_delta,
1366                                               local_diff);
1367                    } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) {
1368                        // CHOP
1369                        return new ChopFrame(SAME_FRAME_EXTENDED - diff_length,
1370                                             offset_delta);
1371                    }
1372                }
1373                // FULL_FRAME
1374                return new FullFrame(offset_delta, locals, stack);
1375            }
1376    
1377            static boolean isInt(Type t) {
1378                return (t.tag < TypeTags.INT || t.tag == TypeTags.BOOLEAN);
1379            }
1380    
1381            static boolean isSameType(Type t1, Type t2, Types types) {
1382                if (t1 == null) { return t2 == null; }
1383                if (t2 == null) { return false; }
1384    
1385                if (isInt(t1) && isInt(t2)) { return true; }
1386    
1387                if (t1.tag == UNINITIALIZED_THIS) {
1388                    return t2.tag == UNINITIALIZED_THIS;
1389                } else if (t1.tag == UNINITIALIZED_OBJECT) {
1390                    if (t2.tag == UNINITIALIZED_OBJECT) {
1391                        return ((UninitializedType)t1).offset == ((UninitializedType)t2).offset;
1392                    } else {
1393                        return false;
1394                    }
1395                } else if (t2.tag == UNINITIALIZED_THIS || t2.tag == UNINITIALIZED_OBJECT) {
1396                    return false;
1397                }
1398    
1399                return types.isSameType(t1, t2);
1400            }
1401    
1402            static int compare(Type[] arr1, Type[] arr2, Types types) {
1403                int diff_length = arr1.length - arr2.length;
1404                if (diff_length > MAX_LOCAL_LENGTH_DIFF || diff_length < -MAX_LOCAL_LENGTH_DIFF) {
1405                    return Integer.MAX_VALUE;
1406                }
1407                int len = (diff_length > 0) ? arr2.length : arr1.length;
1408                for (int i=0; i<len; i++) {
1409                    if (!isSameType(arr1[i], arr2[i], types)) {
1410                        return Integer.MAX_VALUE;
1411                    }
1412                }
1413                return diff_length;
1414            }
1415        }
1416    
1417        void writeFields(Scope.Entry e) {
1418            // process them in reverse sibling order;
1419            // i.e., process them in declaration order.
1420            List<VarSymbol> vars = List.nil();
1421            for (Scope.Entry i = e; i != null; i = i.sibling) {
1422                if (i.sym.kind == VAR) vars = vars.prepend((VarSymbol)i.sym);
1423            }
1424            while (vars.nonEmpty()) {
1425                writeField(vars.head);
1426                vars = vars.tail;
1427            }
1428        }
1429    
1430        void writeMethods(Scope.Entry e) {
1431            List<MethodSymbol> methods = List.nil();
1432            for (Scope.Entry i = e; i != null; i = i.sibling) {
1433                if (i.sym.kind == MTH && (i.sym.flags() & HYPOTHETICAL) == 0)
1434                    methods = methods.prepend((MethodSymbol)i.sym);
1435            }
1436            while (methods.nonEmpty()) {
1437                writeMethod(methods.head);
1438                methods = methods.tail;
1439            }
1440        }
1441    
1442        /** Emit a class file for a given class.
1443         *  @param c      The class from which a class file is generated.
1444         */
1445        public JavaFileObject writeClass(ClassSymbol c)
1446            throws IOException, PoolOverflow, StringOverflow
1447        {
1448            JavaFileObject outFile
1449                = fileManager.getJavaFileForOutput(CLASS_OUTPUT,
1450                                                   c.flatname.toString(),
1451                                                   JavaFileObject.Kind.CLASS,
1452                                                   c.sourcefile);
1453            OutputStream out = outFile.openOutputStream();
1454            try {
1455                writeClassFile(out, c);
1456                if (verbose)
1457                    log.errWriter.println(Log.getLocalizedString("verbose.wrote.file", outFile));
1458                out.close();
1459                out = null;
1460            } finally {
1461                if (out != null) {
1462                    // if we are propogating an exception, delete the file
1463                    out.close();
1464                    outFile.delete();
1465                    outFile = null;
1466                }
1467            }
1468            return outFile; // may be null if write failed
1469        }
1470    
1471        /** Write class `c' to outstream `out'.
1472         */
1473        public void writeClassFile(OutputStream out, ClassSymbol c)
1474            throws IOException, PoolOverflow, StringOverflow {
1475            assert (c.flags() & COMPOUND) == 0;
1476            databuf.reset();
1477            poolbuf.reset();
1478            sigbuf.reset();
1479            pool = c.pool;
1480            innerClasses = null;
1481            innerClassesQueue = null;
1482    
1483            Type supertype = types.supertype(c.type);
1484            List<Type> interfaces = types.interfaces(c.type);
1485            List<Type> typarams = c.type.getTypeArguments();
1486    
1487            int flags = adjustFlags(c.flags());
1488            if ((flags & PROTECTED) != 0) flags |= PUBLIC;
1489            flags = flags & ClassFlags & ~STRICTFP;
1490            if ((flags & INTERFACE) == 0) flags |= ACC_SUPER;
1491            if (c.isInner() && c.name.isEmpty()) flags &= ~FINAL;
1492            if (dumpClassModifiers) {
1493                log.errWriter.println();
1494                log.errWriter.println("CLASSFILE  " + c.getQualifiedName());
1495                log.errWriter.println("---" + flagNames(flags));
1496            }
1497            databuf.appendChar(flags);
1498    
1499            databuf.appendChar(pool.put(c));
1500            databuf.appendChar(supertype.tag == CLASS ? pool.put(supertype.tsym) : 0);
1501            databuf.appendChar(interfaces.length());
1502            for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1503                databuf.appendChar(pool.put(l.head.tsym));
1504            int fieldsCount = 0;
1505            int methodsCount = 0;
1506            for (Scope.Entry e = c.members().elems; e != null; e = e.sibling) {
1507                switch (e.sym.kind) {
1508                case VAR: fieldsCount++; break;
1509                case MTH: if ((e.sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
1510                          break;
1511                case TYP: enterInner((ClassSymbol)e.sym); break;
1512                default : assert false;
1513                }
1514            }
1515            databuf.appendChar(fieldsCount);
1516            writeFields(c.members().elems);
1517            databuf.appendChar(methodsCount);
1518            writeMethods(c.members().elems);
1519    
1520            int acountIdx = beginAttrs();
1521            int acount = 0;
1522    
1523            boolean sigReq =
1524                typarams.length() != 0 || supertype.getTypeArguments().length() != 0;
1525            for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
1526                sigReq = l.head.getTypeArguments().length() != 0;
1527            if (sigReq) {
1528                assert source.allowGenerics();
1529                int alenIdx = writeAttr(names.Signature);
1530                if (typarams.length() != 0) assembleParamsSig(typarams);
1531                assembleSig(supertype);
1532                for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1533                    assembleSig(l.head);
1534                databuf.appendChar(pool.put(sigbuf.toName(names)));
1535                sigbuf.reset();
1536                endAttr(alenIdx);
1537                acount++;
1538            }
1539    
1540            if (c.sourcefile != null && emitSourceFile) {
1541                int alenIdx = writeAttr(names.SourceFile);
1542                // WHM 6/29/1999: Strip file path prefix.  We do it here at
1543                // the last possible moment because the sourcefile may be used
1544                // elsewhere in error diagnostics. Fixes 4241573.
1545                //databuf.appendChar(c.pool.put(c.sourcefile));
1546                String filename = c.sourcefile.toString();
1547                int sepIdx = filename.lastIndexOf(File.separatorChar);
1548                // Allow '/' as separator on all platforms, e.g., on Win32.
1549                int slashIdx = filename.lastIndexOf('/');
1550                if (slashIdx > sepIdx) sepIdx = slashIdx;
1551                if (sepIdx >= 0) filename = filename.substring(sepIdx + 1);
1552                databuf.appendChar(c.pool.put(names.fromString(filename)));
1553                endAttr(alenIdx);
1554                acount++;
1555            }
1556    
1557            if (genCrt) {
1558                // Append SourceID attribute
1559                int alenIdx = writeAttr(names.SourceID);
1560                databuf.appendChar(c.pool.put(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
1561                endAttr(alenIdx);
1562                acount++;
1563                // Append CompilationID attribute
1564                alenIdx = writeAttr(names.CompilationID);
1565                databuf.appendChar(c.pool.put(names.fromString(Long.toString(System.currentTimeMillis()))));
1566                endAttr(alenIdx);
1567                acount++;
1568            }
1569    
1570            acount += writeFlagAttrs(c.flags());
1571            acount += writeJavaAnnotations(c.getAnnotationMirrors());
1572            acount += writeEnclosingMethodAttribute(c);
1573    
1574            poolbuf.appendInt(JAVA_MAGIC);
1575            poolbuf.appendChar(target.minorVersion);
1576            poolbuf.appendChar(target.majorVersion);
1577    
1578            writePool(c.pool);
1579    
1580            if (innerClasses != null) {
1581                writeInnerClasses();
1582                acount++;
1583            }
1584            endAttrs(acountIdx, acount);
1585    
1586            poolbuf.appendBytes(databuf.elems, 0, databuf.length);
1587            out.write(poolbuf.elems, 0, poolbuf.length);
1588    
1589            pool = c.pool = null; // to conserve space
1590         }
1591    
1592        int adjustFlags(final long flags) {
1593            int result = (int)flags;
1594            if ((flags & SYNTHETIC) != 0  && !target.useSyntheticFlag())
1595                result &= ~SYNTHETIC;
1596            if ((flags & ENUM) != 0  && !target.useEnumFlag())
1597                result &= ~ENUM;
1598            if ((flags & ANNOTATION) != 0  && !target.useAnnotationFlag())
1599                result &= ~ANNOTATION;
1600    
1601            if ((flags & BRIDGE) != 0  && target.useBridgeFlag())
1602                result |= ACC_BRIDGE;
1603            if ((flags & VARARGS) != 0  && target.useVarargsFlag())
1604                result |= ACC_VARARGS;
1605            return result;
1606        }
1607    
1608        long getLastModified(FileObject filename) {
1609            long mod = 0;
1610            try {
1611                mod = filename.getLastModified();
1612            } catch (SecurityException e) {
1613                throw new AssertionError("CRT: couldn't get source file modification date: " + e.getMessage());
1614            }
1615            return mod;
1616        }
1617    }