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

Mon, 15 Nov 2010 14:41:21 +0000

author
mcimadamore
date
Mon, 15 Nov 2010 14:41:21 +0000
changeset 747
1dd813a529cf
parent 700
7b413ac1a720
child 781
e3df8d7a9752
permissions
-rw-r--r--

6999635: Multicatch: crash while compiling simple code with a multicatch parameter
Summary: missing erasure when computing stackmaps leads to assertion error
Reviewed-by: darcy

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

mercurial