src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java

Tue, 04 Mar 2008 15:45:20 +0000

author
mcimadamore
date
Tue, 04 Mar 2008 15:45:20 +0000
changeset 8
38bd6375f37d
parent 1
9a66ca7c79fa
child 113
eff38cc97183
permissions
-rw-r--r--

6663588: Compiler goes into infinite loop for Cyclic Inheritance test case
Summary: interplay between cyclic inheritance and tvar bounds hangs javac
Reviewed-by: jjg

     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  */
    26 package com.sun.tools.javac.jvm;
    28 import java.io.*;
    29 import java.util.*;
    30 import java.util.Set;
    31 import java.util.HashSet;
    33 import javax.tools.JavaFileManager;
    34 import javax.tools.FileObject;
    35 import javax.tools.JavaFileObject;
    37 import com.sun.tools.javac.code.*;
    38 import com.sun.tools.javac.code.Symbol.*;
    39 import com.sun.tools.javac.code.Type.*;
    40 import com.sun.tools.javac.util.*;
    41 import com.sun.tools.javac.util.List;
    43 import static com.sun.tools.javac.code.BoundKind.*;
    44 import static com.sun.tools.javac.code.Flags.*;
    45 import static com.sun.tools.javac.code.Kinds.*;
    46 import static com.sun.tools.javac.code.TypeTags.*;
    47 import static com.sun.tools.javac.jvm.UninitializedType.*;
    48 import static javax.tools.StandardLocation.CLASS_OUTPUT;
    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  */
    58 public class ClassWriter extends ClassFile {
    59     protected static final Context.Key<ClassWriter> classWriterKey =
    60         new Context.Key<ClassWriter>();
    62     private final Symtab syms;
    64     private final Options options;
    66     /** Switch: verbose output.
    67      */
    68     private boolean verbose;
    70     /** Switch: scrable private names.
    71      */
    72     private boolean scramble;
    74     /** Switch: scrable private names.
    75      */
    76     private boolean scrambleAll;
    78     /** Switch: retrofit mode.
    79      */
    80     private boolean retrofit;
    82     /** Switch: emit source file attribute.
    83      */
    84     private boolean emitSourceFile;
    86     /** Switch: generate CharacterRangeTable attribute.
    87      */
    88     private boolean genCrt;
    90     /** Switch: describe the generated stackmap
    91      */
    92     boolean debugstackmap;
    94     /**
    95      * Target class version.
    96      */
    97     private Target target;
    99     /**
   100      * Source language version.
   101      */
   102     private Source source;
   104     /** Type utilities. */
   105     private Types types;
   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;
   113     /** An output buffer for member info.
   114      */
   115     ByteBuffer databuf = new ByteBuffer(DATA_BUF_SIZE);
   117     /** An output buffer for the constant pool.
   118      */
   119     ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
   121     /** An output buffer for type signatures.
   122      */
   123     ByteBuffer sigbuf = new ByteBuffer();
   125     /** The constant pool.
   126      */
   127     Pool pool;
   129     /** The inner classes to be written, as a set.
   130      */
   131     Set<ClassSymbol> innerClasses;
   133     /** The inner classes to be written, as a queue where
   134      *  enclosing classes come first.
   135      */
   136     ListBuffer<ClassSymbol> innerClassesQueue;
   138     /** The log to use for verbose output.
   139      */
   140     private final Log log;
   142     /** The name table. */
   143     private final Name.Table names;
   145     /** Access to files. */
   146     private final JavaFileManager fileManager;
   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;
   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     }
   163     /** Construct a class writer, given an options table.
   164      */
   165     private ClassWriter(Context context) {
   166         context.put(classWriterKey, this);
   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);
   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;
   184         emitSourceFile = options.get("-g:")==null || options.get("-g:source")!=null;
   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     }
   197 /******************************************************************
   198  * Diagnostics: dump generated class names and modifiers
   199  ******************************************************************/
   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
   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"};
   235 /******************************************************************
   236  * Output routines
   237  ******************************************************************/
   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     }
   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     }
   257 /******************************************************************
   258  * Signature Generation
   259  ******************************************************************/
   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     }
   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     }
   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     }
   393     void assembleSig(List<Type> types) {
   394         for (List<Type> ts = types; ts.nonEmpty(); ts = ts.tail)
   395             assembleSig(ts.head);
   396     }
   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     }
   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     }
   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     }
   440 /******************************************************************
   441  * Writing the Constant Pool
   442  ******************************************************************/
   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     }
   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;
   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     }
   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     }
   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     }
   563 /******************************************************************
   564  * Writing Attributes
   565  ******************************************************************/
   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     }
   576     /** Fill in attribute length.
   577      */
   578     void endAttr(int index) {
   579         putInt(databuf, index - 4, databuf.length - index);
   580     }
   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     }
   590     /** Fill in number of attributes.
   591      */
   592     void endAttrs(int index, int count) {
   593         putChar(databuf, index - 2, count);
   594     }
   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;
   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     }
   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     }
   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     }
   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         }
   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     }
   728 /**********************************************************************
   729  * Writing Java-language annotations (aka metadata, attributes)
   730  **********************************************************************/
   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         }
   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     }
   768     /** A mirror of java.lang.annotation.RetentionPolicy. */
   769     enum RetentionPolicy {
   770         SOURCE,
   771         CLASS,
   772         RUNTIME
   773     }
   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     }
   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();
   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     }
   868 /**********************************************************************
   869  * Writing Objects
   870  **********************************************************************/
   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     }
   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     }
   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     }
   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     }
   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]);
  1003         int acountIdx = beginAttrs();
  1004         int acount = 0;
  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++;
  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++;
  1028         // counter for number of generic local variables
  1029         int nGenericVars = 0;
  1031         if (code.varBufferSize > 0) {
  1032             int alenIdx = writeAttr(names.LocalVariableTable);
  1033             databuf.appendChar(code.varBufferSize);
  1035             for (int i=0; i<code.varBufferSize; i++) {
  1036                 Code.LocalVar var = code.varBuffer[i];
  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);
  1053             endAttr(alenIdx);
  1054             acount++;
  1057         if (nGenericVars > 0) {
  1058             int alenIdx = writeAttr(names.LocalVariableTypeTable);
  1059             databuf.appendChar(nGenericVars);
  1060             int count = 0;
  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);
  1075             assert count == nGenericVars;
  1076             endAttr(alenIdx);
  1077             acount++;
  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++;
  1087         endAttrs(acountIdx, acount);
  1090     void writeStackMap(Code code) {
  1091         int nframes = code.stackMapBufferSize;
  1092         if (debugstackmap) System.out.println(" nframes = " + nframes);
  1093         databuf.appendChar(nframes);
  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];
  1101                 // output PC
  1102                 if (debugstackmap) System.out.print(" pc=" + frame.pc);
  1103                 databuf.appendChar(frame.pc);
  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++;
  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]);
  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++;
  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]);
  1134                 if (debugstackmap) System.out.println();
  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();
  1145             break;
  1147         default:
  1148             throw new AssertionError("Unexpected stackmap format value");
  1152         //where
  1153         void writeStackMapType(Type t) {
  1154             if (t == null) {
  1155                 if (debugstackmap) System.out.print("empty");
  1156                 databuf.appendByte(0);
  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);
  1204                 break;
  1205             default:
  1206                 throw new AssertionError();
  1210     /** An entry in the JSR202 StackMapTable */
  1211     abstract static class StackMapTableFrame {
  1212         abstract int getFrameType();
  1214         void write(ClassWriter writer) {
  1215             int frameType = getFrameType();
  1216             writer.databuf.appendByte(frameType);
  1217             if (writer.debugstackmap) System.out.print(" frame_type=" + frameType);
  1220         static class SameFrame extends StackMapTableFrame {
  1221             final int offsetDelta;
  1222             SameFrame(int offsetDelta) {
  1223                 this.offsetDelta = offsetDelta;
  1225             int getFrameType() {
  1226                 return (offsetDelta < SAME_FRAME_SIZE) ? offsetDelta : SAME_FRAME_EXTENDED;
  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);
  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;
  1247             int getFrameType() {
  1248                 return (offsetDelta < SAME_FRAME_SIZE) ?
  1249                        (SAME_FRAME_SIZE + offsetDelta) :
  1250                        SAME_LOCALS_1_STACK_ITEM_EXTENDED;
  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);
  1261                 if (writer.debugstackmap) {
  1262                     System.out.print(" stack[" + 0 + "]=");
  1264                 writer.writeStackMapType(stack);
  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;
  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);
  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;
  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);
  1303                 for (int i=0; i<locals.length; i++) {
  1304                      if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
  1305                      writer.writeStackMapType(locals[i]);
  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;
  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);
  1329                 for (int i=0; i<locals.length; i++) {
  1330                     if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
  1331                     writer.writeStackMapType(locals[i]);
  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]);
  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]);
  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];
  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);
  1376             // FULL_FRAME
  1377             return new FullFrame(offset_delta, locals, stack);
  1380         static boolean isInt(Type t) {
  1381             return (t.tag < TypeTags.INT || t.tag == TypeTags.BOOLEAN);
  1384         static boolean isSameType(Type t1, Type t2, Types types) {
  1385             if (t1 == null) { return t2 == null; }
  1386             if (t2 == null) { return false; }
  1388             if (isInt(t1) && isInt(t2)) { return true; }
  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;
  1398             } else if (t2.tag == UNINITIALIZED_THIS || t2.tag == UNINITIALIZED_OBJECT) {
  1399                 return false;
  1402             return types.isSameType(t1, t2);
  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;
  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;
  1416             return diff_length;
  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);
  1427         while (vars.nonEmpty()) {
  1428             writeField(vars.head);
  1429             vars = vars.tail;
  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);
  1439         while (methods.nonEmpty()) {
  1440             writeMethod(methods.head);
  1441             methods = methods.tail;
  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
  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;
  1471         return outFile; // may be null if write failed
  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;
  1486         Type supertype = types.supertype(c.type);
  1487         List<Type> interfaces = types.interfaces(c.type);
  1488         List<Type> typarams = c.type.getTypeArguments();
  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));
  1500         databuf.appendChar(flags);
  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;
  1518         databuf.appendChar(fieldsCount);
  1519         writeFields(c.members().elems);
  1520         databuf.appendChar(methodsCount);
  1521         writeMethods(c.members().elems);
  1523         int acountIdx = beginAttrs();
  1524         int acount = 0;
  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++;
  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++;
  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++;
  1573         acount += writeFlagAttrs(c.flags());
  1574         acount += writeJavaAnnotations(c.getAnnotationMirrors());
  1575         acount += writeEnclosingMethodAttribute(c);
  1577         poolbuf.appendInt(JAVA_MAGIC);
  1578         poolbuf.appendChar(target.minorVersion);
  1579         poolbuf.appendChar(target.majorVersion);
  1581         writePool(c.pool);
  1583         if (innerClasses != null) {
  1584             writeInnerClasses();
  1585             acount++;
  1587         endAttrs(acountIdx, acount);
  1589         poolbuf.appendBytes(databuf.elems, 0, databuf.length);
  1590         out.write(poolbuf.elems, 0, poolbuf.length);
  1592         pool = c.pool = null; // to conserve space
  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;
  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;
  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());
  1618         return mod;

mercurial