EMMA Coverage Report (generated Thu Dec 06 15:24:05 GMT 2007)
[all classes][com.sun.tools.javac.jvm]

COVERAGE SUMMARY FOR SOURCE FILE [ClassWriter.java]

nameclass, %method, %block, %line, %
ClassWriter.java17%  (2/12)43%  (33/77)31%  (1525/4981)33%  (293/895)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ClassWriter$10%   (0/1)0%   (0/1)0%   (0/69)0%   (0/3)
<static initializer> 0%   (0/1)0%   (0/69)0%   (0/3)
     
class ClassWriter$PoolOverflow0%   (0/1)0%   (0/1)0%   (0/3)0%   (0/1)
ClassWriter$PoolOverflow (): void 0%   (0/1)0%   (0/3)0%   (0/1)
     
class ClassWriter$RetentionPolicy0%   (0/1)0%   (0/4)0%   (0/48)0%   (0/4)
<static initializer> 0%   (0/1)0%   (0/34)0%   (0/4)
ClassWriter$RetentionPolicy (String, int): void 0%   (0/1)0%   (0/5)0%   (0/1)
valueOf (String): ClassWriter$RetentionPolicy 0%   (0/1)0%   (0/5)0%   (0/1)
values (): ClassWriter$RetentionPolicy [] 0%   (0/1)0%   (0/4)0%   (0/1)
     
class ClassWriter$StackMapTableFrame0%   (0/1)0%   (0/6)0%   (0/253)0%   (0/45)
ClassWriter$StackMapTableFrame (): void 0%   (0/1)0%   (0/3)0%   (0/2)
compare (Type [], Type [], Types): int 0%   (0/1)0%   (0/42)0%   (0/8)
getInstance (Code$StackMapFrame, int, Type [], Types): ClassWriter$StackMapTa... 0%   (0/1)0%   (0/107)0%   (0/18)
isInt (Type): boolean 0%   (0/1)0%   (0/12)0%   (0/1)
isSameType (Type, Type, Types): boolean 0%   (0/1)0%   (0/68)0%   (0/12)
write (ClassWriter): void 0%   (0/1)0%   (0/21)0%   (0/4)
     
class ClassWriter$StackMapTableFrame$AppendFrame0%   (0/1)0%   (0/3)0%   (0/68)0%   (0/14)
ClassWriter$StackMapTableFrame$AppendFrame (int, int, Type []): void 0%   (0/1)0%   (0/12)0%   (0/5)
getFrameType (): int 0%   (0/1)0%   (0/3)0%   (0/1)
write (ClassWriter): void 0%   (0/1)0%   (0/53)0%   (0/8)
     
class ClassWriter$StackMapTableFrame$ChopFrame0%   (0/1)0%   (0/3)0%   (0/35)0%   (0/10)
ClassWriter$StackMapTableFrame$ChopFrame (int, int): void 0%   (0/1)0%   (0/9)0%   (0/4)
getFrameType (): int 0%   (0/1)0%   (0/3)0%   (0/1)
write (ClassWriter): void 0%   (0/1)0%   (0/23)0%   (0/5)
     
class ClassWriter$StackMapTableFrame$FullFrame0%   (0/1)0%   (0/3)0%   (0/136)0%   (0/21)
ClassWriter$StackMapTableFrame$FullFrame (int, Type [], Type []): void 0%   (0/1)0%   (0/12)0%   (0/5)
getFrameType (): int 0%   (0/1)0%   (0/2)0%   (0/1)
write (ClassWriter): void 0%   (0/1)0%   (0/122)0%   (0/15)
     
class ClassWriter$StackMapTableFrame$SameFrame0%   (0/1)0%   (0/3)0%   (0/42)0%   (0/10)
ClassWriter$StackMapTableFrame$SameFrame (int): void 0%   (0/1)0%   (0/6)0%   (0/3)
getFrameType (): int 0%   (0/1)0%   (0/9)0%   (0/1)
write (ClassWriter): void 0%   (0/1)0%   (0/27)0%   (0/6)
     
class ClassWriter$StackMapTableFrame$SameLocals1StackItemFrame0%   (0/1)0%   (0/3)0%   (0/57)0%   (0/14)
ClassWriter$StackMapTableFrame$SameLocals1StackItemFrame (int, Type): void 0%   (0/1)0%   (0/9)0%   (0/4)
getFrameType (): int 0%   (0/1)0%   (0/11)0%   (0/1)
write (ClassWriter): void 0%   (0/1)0%   (0/37)0%   (0/9)
     
class ClassWriter$StringOverflow0%   (0/1)0%   (0/1)0%   (0/6)0%   (0/3)
ClassWriter$StringOverflow (String): void 0%   (0/1)0%   (0/6)0%   (0/3)
     
class ClassWriter$AttributeWriter100% (1/1)25%  (2/8)6%   (13/205)2%   (0.9/42)
visitArray (Attribute$Array): void 0%   (0/1)0%   (0/33)0%   (0/5)
visitClass (Attribute$Class): void 0%   (0/1)0%   (0/19)0%   (0/3)
visitCompound (Attribute$Compound): void 0%   (0/1)0%   (0/10)0%   (0/3)
visitConstant (Attribute$Constant): void 0%   (0/1)0%   (0/93)0%   (0/25)
visitEnum (Attribute$Enum): void 0%   (0/1)0%   (0/31)0%   (0/4)
visitError (Attribute$Error): void 0%   (0/1)0%   (0/5)0%   (0/1)
<static initializer> 100% (1/1)88%  (7/8)87%  (0.9/1)
ClassWriter$AttributeWriter (ClassWriter): void 100% (1/1)100% (6/6)100% (1/1)
     
class ClassWriter100% (1/1)76%  (31/41)37%  (1512/4059)40%  (292.1/731)
access$000 (ClassWriter): Name$Table 0%   (0/1)0%   (0/3)0%   (0/1)
assembleParamsSig (List): void 0%   (0/1)0%   (0/65)0%   (0/12)
flagNames (long): String 0%   (0/1)0%   (0/42)0%   (0/8)
getLastModified (FileObject): long 0%   (0/1)0%   (0/22)0%   (0/6)
getRetention (Symbol$TypeSymbol): ClassWriter$RetentionPolicy 0%   (0/1)0%   (0/52)0%   (0/10)
writeCompoundAttribute (Attribute$Compound): void 0%   (0/1)0%   (0/45)0%   (0/6)
writeInnerClasses (): void 0%   (0/1)0%   (0/125)0%   (0/18)
writeStackMap (Code): void 0%   (0/1)0%   (0/299)0%   (0/40)
writeStackMapType (Type): void 0%   (0/1)0%   (0/176)0%   (0/37)
xClassName (Type): Name 0%   (0/1)0%   (0/28)0%   (0/5)
writeJavaAnnotations (List): int 100% (1/1)4%   (5/112)4%   (1/24)
writeParameterAttrs (Symbol$MethodSymbol): int 100% (1/1)17%  (34/203)20%  (7.6/38)
enterInner (Symbol$ClassSymbol): void 100% (1/1)18%  (19/105)25%  (4.5/18)
assembleSig (Type): void 100% (1/1)22%  (45/204)24%  (14/59)
fieldName (Symbol): Name 100% (1/1)24%  (9/37)43%  (1.3/3)
writeEnclosingMethodAttribute (Symbol$ClassSymbol): int 100% (1/1)25%  (17/68)22%  (2/9)
assembleClassSig (Type): void 100% (1/1)27%  (28/105)47%  (8/17)
writeCode (Code): void 100% (1/1)27%  (108/396)33%  (25.5/77)
hasTypeVar (List): boolean 100% (1/1)29%  (5/17)50%  (2/4)
writeFlagAttrs (long): int 100% (1/1)33%  (40/120)23%  (6/26)
writeClass (Symbol$ClassSymbol): JavaFileObject 100% (1/1)45%  (29/64)64%  (7.7/12)
adjustFlags (long): int 100% (1/1)47%  (35/75)42%  (5.1/12)
writeMethod (Symbol$MethodSymbol): void 100% (1/1)53%  (87/164)62%  (20/32)
writeField (Symbol$VarSymbol): void 100% (1/1)53%  (52/98)65%  (11/17)
writePool (Pool): void 100% (1/1)57%  (200/351)61%  (43/70)
writeClassFile (OutputStream, Symbol$ClassSymbol): void 100% (1/1)59%  (296/500)66%  (57.2/87)
typeSig (Type): Name 100% (1/1)67%  (16/24)84%  (4.2/5)
writeMemberAttrs (Symbol): int 100% (1/1)71%  (49/69)56%  (5/9)
nameType (Symbol): ClassFile$NameAndType 100% (1/1)74%  (14/19)73%  (0.7/1)
ClassWriter (Context): void 100% (1/1)76%  (146/192)90%  (24.4/27)
<static initializer> 100% (1/1)98%  (62/63)99%  (3/3)
assembleSig (List): void 100% (1/1)100% (15/15)100% (3/3)
beginAttrs (): int 100% (1/1)100% (8/8)100% (2/2)
endAttr (int): void 100% (1/1)100% (13/13)100% (2/2)
endAttrs (int, int): void 100% (1/1)100% (9/9)100% (2/2)
instance (Context): ClassWriter 100% (1/1)100% (14/14)100% (4/4)
putChar (ByteBuffer, int, int): void 100% (1/1)100% (21/21)100% (3/3)
putInt (ByteBuffer, int, int): void 100% (1/1)100% (45/45)100% (5/5)
writeAttr (Name): int 100% (1/1)100% (15/15)100% (3/3)
writeFields (Scope$Entry): void 100% (1/1)100% (34/34)100% (7/7)
writeMethods (Scope$Entry): void 100% (1/1)100% (42/42)100% (8/8)

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

[all classes][com.sun.tools.javac.jvm]
EMMA 2.0.5312 (C) Vladimir Roubtsov