Home » openjdk-7 » com.sun.tools » javac » jvm » [javadoc | source]

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

Home » openjdk-7 » com.sun.tools » javac » jvm » [javadoc | source]