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

Tue, 25 Sep 2012 11:53:18 +0100

author
mcimadamore
date
Tue, 25 Sep 2012 11:53:18 +0100
changeset 1336
26d93df3905a
parent 1313
873ddd9f4900
child 1343
f1e6b361a329
permissions
-rw-r--r--

7194586: Add back-end support for invokedynamic
Summary: Add support for invokedynamic bytecode instruction; includes suppot for generation of all related classfile attributes
Reviewed-by: jjg

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

mercurial