< prev index next >

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

Print this page

  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.jvm;
  27 
  28 import java.io.*;
  29 import java.util.LinkedHashMap;
  30 import java.util.Map;
  31 import java.util.Set;
  32 import java.util.LinkedHashSet;
  33 import java.util.function.ToIntFunction;
  34 
  35 import javax.tools.JavaFileManager;
  36 import javax.tools.FileObject;
  37 import javax.tools.JavaFileManager.Location;
  38 import javax.tools.JavaFileObject;
  39 
  40 import com.sun.tools.javac.code.*;
  41 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
  42 import com.sun.tools.javac.code.Directive.*;

  43 import com.sun.tools.javac.code.Source.Feature;
  44 import com.sun.tools.javac.code.Symbol.*;
  45 import com.sun.tools.javac.code.Type.*;
  46 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
  47 import com.sun.tools.javac.comp.Check;
  48 import com.sun.tools.javac.file.PathFileObject;
  49 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
  50 import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey;
  51 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  52 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  53 import com.sun.tools.javac.util.*;
  54 import com.sun.tools.javac.util.List;
  55 
  56 import static com.sun.tools.javac.code.Flags.*;
  57 import static com.sun.tools.javac.code.Kinds.Kind.*;
  58 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
  59 import static com.sun.tools.javac.code.TypeTag.*;
  60 import static com.sun.tools.javac.main.Option.*;
  61 
  62 import static javax.tools.StandardLocation.CLASS_OUTPUT;

 125 
 126     /** An output buffer for member info.
 127      */
 128     public ByteBuffer databuf = new ByteBuffer(DATA_BUF_SIZE);
 129 
 130     /** An output buffer for the constant pool.
 131      */
 132     ByteBuffer poolbuf = new ByteBuffer(CLASS_BUF_SIZE);
 133 
 134     /** The constant pool writer.
 135      */
 136     final PoolWriter poolWriter;
 137 
 138     /** The log to use for verbose output.
 139      */
 140     private final Log log;
 141 
 142     /** The name table. */
 143     private final Names names;
 144 


 145     /** Access to files. */
 146     private final JavaFileManager fileManager;
 147 
 148     /** The tags and constants used in compressed stackmap. */
 149     static final int SAME_FRAME_SIZE = 64;
 150     static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
 151     static final int SAME_FRAME_EXTENDED = 251;
 152     static final int FULL_FRAME = 255;
 153     static final int MAX_LOCAL_LENGTH_DIFF = 4;
 154 
 155     /** Get the ClassWriter instance for this context. */
 156     public static ClassWriter instance(Context context) {
 157         ClassWriter instance = context.get(classWriterKey);
 158         if (instance == null)
 159             instance = new ClassWriter(context);
 160         return instance;
 161     }
 162 
 163     /** Construct a class writer, given an options table.
 164      */
 165     protected ClassWriter(Context context) {
 166         context.put(classWriterKey, this);
 167 
 168         log = Log.instance(context);
 169         names = Names.instance(context);
 170         options = Options.instance(context);
 171         preview = Preview.instance(context);
 172         target = Target.instance(context);
 173         source = Source.instance(context);
 174         types = Types.instance(context);
 175         check = Check.instance(context);
 176         fileManager = context.get(JavaFileManager.class);
 177         poolWriter = Gen.instance(context).poolWriter;

 178 
 179         verbose        = options.isSet(VERBOSE);
 180         genCrt         = options.isSet(XJCOV);
 181         debugstackmap = options.isSet("debug.stackmap");
 182 
 183         emitSourceFile = options.isUnset(G_CUSTOM) ||
 184                             options.isSet(G_CUSTOM, "source");
 185 
 186         String modifierFlags = options.get("debug.dumpmodifiers");
 187         if (modifierFlags != null) {
 188             dumpClassModifiers = modifierFlags.indexOf('c') != -1;
 189             dumpFieldModifiers = modifierFlags.indexOf('f') != -1;
 190             dumpInnerClassModifiers = modifierFlags.indexOf('i') != -1;
 191             dumpMethodModifiers = modifierFlags.indexOf('m') != -1;
 192         }
 193     }
 194 
 195     public void addExtraAttributes(ToIntFunction<Symbol> addExtraAttributes) {
 196         extraAttributeHooks = extraAttributeHooks.prepend(addExtraAttributes);
 197     }
 198 
 199 /******************************************************************
 200  * Diagnostics: dump generated class names and modifiers
 201  ******************************************************************/
 202 
 203     /** Value of option 'dumpmodifiers' is a string
 204      *  indicating which modifiers should be dumped for debugging:
 205      *    'c' -- classes
 206      *    'f' -- fields
 207      *    'i' -- innerclass attributes
 208      *    'm' -- methods
 209      *  For example, to dump everything:
 210      *    javac -XDdumpmodifiers=cifm MyProg.java
 211      */
 212     private boolean dumpClassModifiers; // -XDdumpmodifiers=c
 213     private boolean dumpFieldModifiers; // -XDdumpmodifiers=f
 214     private boolean dumpInnerClassModifiers; // -XDdumpmodifiers=i
 215     private boolean dumpMethodModifiers; // -XDdumpmodifiers=m
 216 
 217 
 218     /** Return flags as a string, separated by " ".
 219      */
 220     public static String flagNames(long flags) {
 221         StringBuilder sbuf = new StringBuilder();
 222         int i = 0;
 223         long f = flags & StandardFlags;
 224         while (f != 0) {
 225             if ((f & 1) != 0) {
 226                 sbuf.append(" ");
 227                 sbuf.append(flagName[i]);
 228             }
 229             f = f >> 1;
 230             i++;
 231         }
 232         return sbuf.toString();
 233     }
 234     //where
 235         private static final String[] flagName = {
 236             "PUBLIC", "PRIVATE", "PROTECTED", "STATIC", "FINAL",
 237             "SUPER", "VOLATILE", "TRANSIENT", "NATIVE", "INTERFACE",
 238             "ABSTRACT", "STRICTFP"};
 239 
 240 /******************************************************************
 241  * Output routines
 242  ******************************************************************/
 243 
 244     /** Write a character into given byte buffer;
 245      *  byte buffer will not be grown.
 246      */
 247     void putChar(ByteBuffer buf, int op, int x) {
 248         buf.elems[op  ] = (byte)((x >>  8) & 0xFF);
 249         buf.elems[op+1] = (byte)((x      ) & 0xFF);
 250     }
 251 
 252     /** Write an integer into given byte buffer;
 253      *  byte buffer will not be grown.
 254      */
 255     void putInt(ByteBuffer buf, int adr, int x) {
 256         buf.elems[adr  ] = (byte)((x >> 24) & 0xFF);
 257         buf.elems[adr+1] = (byte)((x >> 16) & 0xFF);

 808             databuf.appendChar(poolWriter.putClass(srvc));
 809             databuf.appendChar(impls.size());
 810             impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl)));
 811         });
 812 
 813         endAttr(alenIdx);
 814         return 1;
 815     }
 816 
 817 /**********************************************************************
 818  * Writing Objects
 819  **********************************************************************/
 820 
 821     /** Write "inner classes" attribute.
 822      */
 823     void writeInnerClasses() {
 824         int alenIdx = writeAttr(names.InnerClasses);
 825         databuf.appendChar(poolWriter.innerClasses.size());
 826         for (ClassSymbol inner : poolWriter.innerClasses) {
 827             inner.markAbstractIfNeeded(types);
 828             char flags = (char) adjustFlags(inner.flags_field);
 829             if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT
 830             flags &= ~STRICTFP; //inner classes should not have the strictfp flag set.
 831             if (dumpInnerClassModifiers) {
 832                 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 833                 pw.println("INNERCLASS  " + inner.name);
 834                 pw.println("---" + flagNames(flags));
 835             }
 836             databuf.appendChar(poolWriter.putClass(inner));
 837             databuf.appendChar(
 838                 inner.owner.kind == TYP && !inner.name.isEmpty() ? poolWriter.putClass((ClassSymbol)inner.owner) : 0);
 839             databuf.appendChar(
 840                 !inner.name.isEmpty() ? poolWriter.putName(inner.name) : 0);
 841             databuf.appendChar(flags);
 842         }
 843         endAttr(alenIdx);
 844     }
 845 











 846     int writeRecordAttribute(ClassSymbol csym) {
 847         int alenIdx = writeAttr(names.Record);
 848         Scope s = csym.members();
 849         databuf.appendChar(csym.getRecordComponents().size());
 850         for (VarSymbol v: csym.getRecordComponents()) {
 851             //databuf.appendChar(poolWriter.putMember(v.accessor.head.snd));
 852             databuf.appendChar(poolWriter.putName(v.name));
 853             databuf.appendChar(poolWriter.putDescriptor(v));
 854             int acountIdx = beginAttrs();
 855             int acount = 0;
 856             acount += writeMemberAttrs(v, true);
 857             endAttrs(acountIdx, acount);
 858         }
 859         endAttr(alenIdx);
 860         return 1;
 861     }
 862 
 863     /**
 864      * Write NestMembers attribute (if needed)
 865      */

 939             //write static args array
 940             for (LoadableConstant arg : uniqueArgs) {
 941                 databuf.appendChar(poolWriter.putConstant(arg));
 942             }
 943         }
 944         endAttr(alenIdx);
 945     }
 946 
 947     /** Write field symbol, entering all references into constant pool.
 948      */
 949     void writeField(VarSymbol v) {
 950         int flags = adjustFlags(v.flags());
 951         databuf.appendChar(flags);
 952         if (dumpFieldModifiers) {
 953             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 954             pw.println("FIELD  " + v.name);
 955             pw.println("---" + flagNames(v.flags()));
 956         }
 957         databuf.appendChar(poolWriter.putName(v.name));
 958         databuf.appendChar(poolWriter.putDescriptor(v));




 959         int acountIdx = beginAttrs();
 960         int acount = 0;
 961         if (v.getConstValue() != null) {
 962             int alenIdx = writeAttr(names.ConstantValue);
 963             databuf.appendChar(poolWriter.putConstant(v.getConstValue()));
 964             endAttr(alenIdx);
 965             acount++;
 966         }
 967         acount += writeMemberAttrs(v, false);
 968         acount += writeExtraAttributes(v);
 969         endAttrs(acountIdx, acount);
 970     }
 971 
 972     /** Write method symbol, entering all references into constant pool.
 973      */
 974     void writeMethod(MethodSymbol m) {
 975         int flags = adjustFlags(m.flags());
 976         databuf.appendChar(flags);
 977         if (dumpMethodModifiers) {
 978             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 979             pw.println("METHOD  " + m.name);
 980             pw.println("---" + flagNames(m.flags()));
 981         }
 982         databuf.appendChar(poolWriter.putName(m.name));
 983         databuf.appendChar(poolWriter.putDescriptor(m));










 984         int acountIdx = beginAttrs();
 985         int acount = 0;
 986         if (m.code != null) {
 987             int alenIdx = writeAttr(names.Code);
 988             writeCode(m.code);
 989             m.code = null; // to conserve space
 990             endAttr(alenIdx);
 991             acount++;
 992         }
 993         List<Type> thrown = m.erasure(types).getThrownTypes();
 994         if (thrown.nonEmpty()) {
 995             int alenIdx = writeAttr(names.Exceptions);
 996             databuf.appendChar(thrown.length());
 997             for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
 998                 databuf.appendChar(poolWriter.putClass(l.head));
 999             endAttr(alenIdx);
1000             acount++;
1001         }
1002         if (m.defaultValue != null) {
1003             int alenIdx = writeAttr(names.AnnotationDefault);
1004             m.defaultValue.accept(awriter);
1005             endAttr(alenIdx);
1006             acount++;
1007         }
1008         if (target.hasMethodParameters() && (options.isSet(PARAMETERS) || m.isConstructor() && (m.flags_field & RECORD) != 0)) {


1009             if (!m.isLambdaMethod()) // Per JDK-8138729, do not emit parameters table for lambda bodies.
1010                 acount += writeMethodParametersAttr(m);
1011         }
1012         acount += writeMemberAttrs(m, false);
1013         if (!m.isLambdaMethod())
1014             acount += writeParameterAttrs(m.params);
1015         acount += writeExtraAttributes(m);
1016         endAttrs(acountIdx, acount);
1017     }
1018 
1019     /** Write code attribute of method.
1020      */
1021     void writeCode(Code code) {
1022         databuf.appendChar(code.max_stack);
1023         databuf.appendChar(code.max_locals);
1024         databuf.appendInt(code.cp);
1025         databuf.appendBytes(code.code, 0, code.cp);
1026         databuf.appendChar(code.catchInfo.length());
1027         for (List<char[]> l = code.catchInfo.toList();
1028              l.nonEmpty();

1208                 databuf.appendByte(1);
1209                 break;
1210             case FLOAT:
1211                 if (debugstackmap) System.out.print("float");
1212                 databuf.appendByte(2);
1213                 break;
1214             case DOUBLE:
1215                 if (debugstackmap) System.out.print("double");
1216                 databuf.appendByte(3);
1217                 break;
1218             case LONG:
1219                 if (debugstackmap) System.out.print("long");
1220                 databuf.appendByte(4);
1221                 break;
1222             case BOT: // null
1223                 if (debugstackmap) System.out.print("null");
1224                 databuf.appendByte(5);
1225                 break;
1226             case CLASS:
1227             case ARRAY:




1228             case TYPEVAR:
1229                 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1230                 databuf.appendByte(7);
1231                 databuf.appendChar(poolWriter.putClass(types.erasure(t)));
1232                 break;
1233             case UNINITIALIZED_THIS:
1234                 if (debugstackmap) System.out.print("uninit_this");
1235                 databuf.appendByte(6);
1236                 break;
1237             case UNINITIALIZED_OBJECT:
1238                 { UninitializedType uninitType = (UninitializedType)t;
1239                 databuf.appendByte(8);
1240                 if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset);
1241                 databuf.appendChar(uninitType.offset);
1242                 }
1243                 break;
1244             default:
1245                 throw new AssertionError();
1246             }
1247         }

1519         }
1520         return outFile; // may be null if write failed
1521     }
1522 
1523     /** Write class `c' to outstream `out'.
1524      */
1525     public void writeClassFile(OutputStream out, ClassSymbol c)
1526         throws IOException, PoolOverflow, StringOverflow {
1527         Assert.check((c.flags() & COMPOUND) == 0);
1528         databuf.reset();
1529         poolbuf.reset();
1530 
1531         Type supertype = types.supertype(c.type);
1532         List<Type> interfaces = types.interfaces(c.type);
1533         List<Type> typarams = c.type.getTypeArguments();
1534 
1535         int flags;
1536         if (c.owner.kind == MDL) {
1537             flags = ACC_MODULE;
1538         } else {
1539             flags = adjustFlags(c.flags() & ~DEFAULT);
1540             if ((flags & PROTECTED) != 0) flags |= PUBLIC;
1541             flags = flags & ClassFlags & ~STRICTFP;
1542             if ((flags & INTERFACE) == 0) flags |= ACC_SUPER;
1543         }
1544 
1545         if (dumpClassModifiers) {
1546             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1547             pw.println();
1548             pw.println("CLASSFILE  " + c.getQualifiedName());
1549             pw.println("---" + flagNames(flags));
1550         }
1551         databuf.appendChar(flags);
1552 
1553         if (c.owner.kind == MDL) {
1554             PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage;
1555             databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed)));
1556         } else {
1557             databuf.appendChar(poolWriter.putClass(c));
1558         }
1559         databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0);
1560         databuf.appendChar(interfaces.length());
1561         for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1562             databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym));
1563         int fieldsCount = 0;
1564         int methodsCount = 0;
1565         for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
1566             switch (sym.kind) {
1567             case VAR: fieldsCount++; break;
1568             case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
1569                       break;
1570             case TYP: poolWriter.enterInner((ClassSymbol)sym); break;
1571             default : Assert.error();
1572             }
1573         }
1574 
1575         if (c.trans_local != null) {
1576             for (ClassSymbol local : c.trans_local) {
1577                 poolWriter.enterInner(local);
1578             }
1579         }
1580 
1581         databuf.appendChar(fieldsCount);
1582         writeFields(c.members());
1583         databuf.appendChar(methodsCount);
1584         writeMethods(c.members());
1585 
1586         int acountIdx = beginAttrs();
1587         int acount = 0;
1588 
1589         boolean sigReq =
1590             typarams.length() != 0 || supertype.allparams().length() != 0;
1591         for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
1592             sigReq = l.head.allparams().length() != 0;
1593         if (sigReq) {
1594             int alenIdx = writeAttr(names.Signature);
1595             databuf.appendChar(poolWriter.putSignature(c));
1596             endAttr(alenIdx);
1597             acount++;

1648         }
1649 
1650         if (c.isRecord()) {
1651             acount += writeRecordAttribute(c);
1652         }
1653 
1654         if (target.hasSealedClasses()) {
1655             acount += writePermittedSubclassesIfNeeded(c);
1656         }
1657 
1658         if (!poolWriter.bootstrapMethods.isEmpty()) {
1659             writeBootstrapMethods();
1660             acount++;
1661         }
1662 
1663         if (!poolWriter.innerClasses.isEmpty()) {
1664             writeInnerClasses();
1665             acount++;
1666         }
1667 





1668         endAttrs(acountIdx, acount);
1669 
1670         out.write(poolbuf.elems, 0, poolbuf.length);
1671 
1672         poolWriter.writePool(out);
1673         poolWriter.reset(); // to save space
1674 
1675         out.write(databuf.elems, 0, databuf.length);
1676     }
1677 
1678      /**Allows subclasses to write additional class attributes
1679       *
1680       * @return the number of attributes written
1681       */
1682     protected int writeExtraClassAttributes(ClassSymbol c) {
1683         return 0;
1684     }
1685 
1686     /**Allows friends to write additional attributes
1687      *

1691         int i = 0;
1692         for (ToIntFunction<Symbol> hook : extraAttributeHooks) {
1693             i += hook.applyAsInt(sym);
1694         }
1695         return i;
1696     }
1697 
1698     int adjustFlags(final long flags) {
1699         int result = (int)flags;
1700 
1701         // Elide strictfp bit in class files
1702         if (target.obsoleteAccStrict())
1703             result &= ~STRICTFP;
1704 
1705         if ((flags & BRIDGE) != 0)
1706             result |= ACC_BRIDGE;
1707         if ((flags & VARARGS) != 0)
1708             result |= ACC_VARARGS;
1709         if ((flags & DEFAULT) != 0)
1710             result &= ~ABSTRACT;






1711         return result;
1712     }
1713 
1714     long getLastModified(FileObject filename) {
1715         long mod = 0;
1716         try {
1717             mod = filename.getLastModified();
1718         } catch (SecurityException e) {
1719             throw new AssertionError("CRT: couldn't get source file modification date: " + e.getMessage());
1720         }
1721         return mod;
1722     }
1723 }

  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.jvm;
  27 
  28 import java.io.*;
  29 import java.util.LinkedHashMap;
  30 import java.util.Map;
  31 import java.util.Set;
  32 import java.util.LinkedHashSet;
  33 import java.util.function.ToIntFunction;
  34 
  35 import javax.tools.JavaFileManager;
  36 import javax.tools.FileObject;
  37 import javax.tools.JavaFileManager.Location;
  38 import javax.tools.JavaFileObject;
  39 
  40 import com.sun.tools.javac.code.*;
  41 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
  42 import com.sun.tools.javac.code.Directive.*;
  43 import com.sun.tools.javac.code.Scope.WriteableScope;
  44 import com.sun.tools.javac.code.Source.Feature;
  45 import com.sun.tools.javac.code.Symbol.*;
  46 import com.sun.tools.javac.code.Type.*;
  47 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
  48 import com.sun.tools.javac.comp.Check;
  49 import com.sun.tools.javac.file.PathFileObject;
  50 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
  51 import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey;
  52 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  53 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  54 import com.sun.tools.javac.util.*;
  55 import com.sun.tools.javac.util.List;
  56 
  57 import static com.sun.tools.javac.code.Flags.*;
  58 import static com.sun.tools.javac.code.Kinds.Kind.*;
  59 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
  60 import static com.sun.tools.javac.code.TypeTag.*;
  61 import static com.sun.tools.javac.main.Option.*;
  62 
  63 import static javax.tools.StandardLocation.CLASS_OUTPUT;

 126 
 127     /** An output buffer for member info.
 128      */
 129     public ByteBuffer databuf = new ByteBuffer(DATA_BUF_SIZE);
 130 
 131     /** An output buffer for the constant pool.
 132      */
 133     ByteBuffer poolbuf = new ByteBuffer(CLASS_BUF_SIZE);
 134 
 135     /** The constant pool writer.
 136      */
 137     final PoolWriter poolWriter;
 138 
 139     /** The log to use for verbose output.
 140      */
 141     private final Log log;
 142 
 143     /** The name table. */
 144     private final Names names;
 145 
 146     private final Symtab syms;
 147 
 148     /** Access to files. */
 149     private final JavaFileManager fileManager;
 150 
 151     /** The tags and constants used in compressed stackmap. */
 152     static final int SAME_FRAME_SIZE = 64;
 153     static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
 154     static final int SAME_FRAME_EXTENDED = 251;
 155     static final int FULL_FRAME = 255;
 156     static final int MAX_LOCAL_LENGTH_DIFF = 4;
 157 
 158     /** Get the ClassWriter instance for this context. */
 159     public static ClassWriter instance(Context context) {
 160         ClassWriter instance = context.get(classWriterKey);
 161         if (instance == null)
 162             instance = new ClassWriter(context);
 163         return instance;
 164     }
 165 
 166     /** Construct a class writer, given an options table.
 167      */
 168     protected ClassWriter(Context context) {
 169         context.put(classWriterKey, this);
 170 
 171         log = Log.instance(context);
 172         names = Names.instance(context);
 173         options = Options.instance(context);
 174         preview = Preview.instance(context);
 175         target = Target.instance(context);
 176         source = Source.instance(context);
 177         types = Types.instance(context);
 178         check = Check.instance(context);
 179         fileManager = context.get(JavaFileManager.class);
 180         poolWriter = Gen.instance(context).poolWriter;
 181         syms = Symtab.instance(context);
 182 
 183         verbose        = options.isSet(VERBOSE);
 184         genCrt         = options.isSet(XJCOV);
 185         debugstackmap = options.isSet("debug.stackmap");
 186 
 187         emitSourceFile = options.isUnset(G_CUSTOM) ||
 188                             options.isSet(G_CUSTOM, "source");
 189 
 190         String modifierFlags = options.get("debug.dumpmodifiers");
 191         if (modifierFlags != null) {
 192             dumpClassModifiers = modifierFlags.indexOf('c') != -1;
 193             dumpFieldModifiers = modifierFlags.indexOf('f') != -1;
 194             dumpInnerClassModifiers = modifierFlags.indexOf('i') != -1;
 195             dumpMethodModifiers = modifierFlags.indexOf('m') != -1;
 196         }
 197     }
 198 
 199     public void addExtraAttributes(ToIntFunction<Symbol> addExtraAttributes) {
 200         extraAttributeHooks = extraAttributeHooks.prepend(addExtraAttributes);
 201     }
 202 
 203 /******************************************************************
 204  * Diagnostics: dump generated class names and modifiers
 205  ******************************************************************/
 206 
 207     /** Value of option 'dumpmodifiers' is a string
 208      *  indicating which modifiers should be dumped for debugging:
 209      *    'c' -- classes
 210      *    'f' -- fields
 211      *    'i' -- innerclass attributes
 212      *    'm' -- methods
 213      *  For example, to dump everything:
 214      *    javac -XDdumpmodifiers=cifm MyProg.java
 215      */
 216     private boolean dumpClassModifiers; // -XDdumpmodifiers=c
 217     private boolean dumpFieldModifiers; // -XDdumpmodifiers=f
 218     private boolean dumpInnerClassModifiers; // -XDdumpmodifiers=i
 219     private boolean dumpMethodModifiers; // -XDdumpmodifiers=m
 220 

 221     /** Return flags as a string, separated by " ".
 222      */
 223     public static String flagNames(long flags) {
 224         StringBuilder sbuf = new StringBuilder();
 225         int i = 0;
 226         long f = flags & StandardFlags;
 227         while (f != 0) {
 228             if ((f & 1) != 0) {
 229                 sbuf.append(" ");
 230                 sbuf.append(flagName[i]);
 231             }
 232             f = f >> 1;
 233             i++;
 234         }
 235         return sbuf.toString();
 236     }
 237     //where
 238         private static final String[] flagName = {
 239             "PUBLIC", "PRIVATE", "PROTECTED", "STATIC", "FINAL",
 240             "IDENTITY", "VOLATILE", "TRANSIENT", "NATIVE", "INTERFACE",
 241             "ABSTRACT", "STRICTFP"};
 242 
 243 /******************************************************************
 244  * Output routines
 245  ******************************************************************/
 246 
 247     /** Write a character into given byte buffer;
 248      *  byte buffer will not be grown.
 249      */
 250     void putChar(ByteBuffer buf, int op, int x) {
 251         buf.elems[op  ] = (byte)((x >>  8) & 0xFF);
 252         buf.elems[op+1] = (byte)((x      ) & 0xFF);
 253     }
 254 
 255     /** Write an integer into given byte buffer;
 256      *  byte buffer will not be grown.
 257      */
 258     void putInt(ByteBuffer buf, int adr, int x) {
 259         buf.elems[adr  ] = (byte)((x >> 24) & 0xFF);
 260         buf.elems[adr+1] = (byte)((x >> 16) & 0xFF);

 811             databuf.appendChar(poolWriter.putClass(srvc));
 812             databuf.appendChar(impls.size());
 813             impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl)));
 814         });
 815 
 816         endAttr(alenIdx);
 817         return 1;
 818     }
 819 
 820 /**********************************************************************
 821  * Writing Objects
 822  **********************************************************************/
 823 
 824     /** Write "inner classes" attribute.
 825      */
 826     void writeInnerClasses() {
 827         int alenIdx = writeAttr(names.InnerClasses);
 828         databuf.appendChar(poolWriter.innerClasses.size());
 829         for (ClassSymbol inner : poolWriter.innerClasses) {
 830             inner.markAbstractIfNeeded(types);
 831             char flags = (char) adjustFlags(inner.flags_field & ~STRICTFP); // inner classes should not have the strictfp flag set.
 832             if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT

 833             if (dumpInnerClassModifiers) {
 834                 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 835                 pw.println("INNERCLASS  " + inner.name);
 836                 pw.println("---" + flagNames(flags));
 837             }
 838             databuf.appendChar(poolWriter.putClass(inner));
 839             databuf.appendChar(
 840                 inner.owner.kind == TYP && !inner.name.isEmpty() ? poolWriter.putClass((ClassSymbol)inner.owner) : 0);
 841             databuf.appendChar(
 842                 !inner.name.isEmpty() ? poolWriter.putName(inner.name) : 0);
 843             databuf.appendChar(flags);
 844         }
 845         endAttr(alenIdx);
 846     }
 847 
 848      /** Write out "Preload" attribute by enumerating the value classes encountered in field/method descriptors during this compilation.
 849       */
 850      void writePreloadAttribute() {
 851         int alenIdx = writeAttr(names.Preload);
 852         databuf.appendChar(poolWriter.preloadClasses.size());
 853         for (ClassSymbol c : poolWriter.preloadClasses) {
 854             databuf.appendChar(poolWriter.putClass(c));
 855         }
 856         endAttr(alenIdx);
 857      }
 858 
 859     int writeRecordAttribute(ClassSymbol csym) {
 860         int alenIdx = writeAttr(names.Record);
 861         Scope s = csym.members();
 862         databuf.appendChar(csym.getRecordComponents().size());
 863         for (VarSymbol v: csym.getRecordComponents()) {
 864             //databuf.appendChar(poolWriter.putMember(v.accessor.head.snd));
 865             databuf.appendChar(poolWriter.putName(v.name));
 866             databuf.appendChar(poolWriter.putDescriptor(v));
 867             int acountIdx = beginAttrs();
 868             int acount = 0;
 869             acount += writeMemberAttrs(v, true);
 870             endAttrs(acountIdx, acount);
 871         }
 872         endAttr(alenIdx);
 873         return 1;
 874     }
 875 
 876     /**
 877      * Write NestMembers attribute (if needed)
 878      */

 952             //write static args array
 953             for (LoadableConstant arg : uniqueArgs) {
 954                 databuf.appendChar(poolWriter.putConstant(arg));
 955             }
 956         }
 957         endAttr(alenIdx);
 958     }
 959 
 960     /** Write field symbol, entering all references into constant pool.
 961      */
 962     void writeField(VarSymbol v) {
 963         int flags = adjustFlags(v.flags());
 964         databuf.appendChar(flags);
 965         if (dumpFieldModifiers) {
 966             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 967             pw.println("FIELD  " + v.name);
 968             pw.println("---" + flagNames(v.flags()));
 969         }
 970         databuf.appendChar(poolWriter.putName(v.name));
 971         databuf.appendChar(poolWriter.putDescriptor(v));
 972         Type fldType = v.erasure(types);
 973         if (fldType.requiresPreload(v.owner)) {
 974             poolWriter.enterPreloadClass((ClassSymbol) fldType.tsym);
 975         }
 976         int acountIdx = beginAttrs();
 977         int acount = 0;
 978         if (v.getConstValue() != null) {
 979             int alenIdx = writeAttr(names.ConstantValue);
 980             databuf.appendChar(poolWriter.putConstant(v.getConstValue()));
 981             endAttr(alenIdx);
 982             acount++;
 983         }
 984         acount += writeMemberAttrs(v, false);
 985         acount += writeExtraAttributes(v);
 986         endAttrs(acountIdx, acount);
 987     }
 988 
 989     /** Write method symbol, entering all references into constant pool.
 990      */
 991     void writeMethod(MethodSymbol m) {
 992         int flags = adjustFlags(m.flags());
 993         databuf.appendChar(flags);
 994         if (dumpMethodModifiers) {
 995             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 996             pw.println("METHOD  " + m.name);
 997             pw.println("---" + flagNames(m.flags()));
 998         }
 999         databuf.appendChar(poolWriter.putName(m.name));
1000         databuf.appendChar(poolWriter.putDescriptor(m));
1001         MethodType mtype = (MethodType) m.externalType(types);
1002         for (Type t : mtype.getParameterTypes()) {
1003             if (t.requiresPreload(m.owner)) {
1004                 poolWriter.enterPreloadClass((ClassSymbol) t.tsym);
1005             }
1006         }
1007         Type returnType = mtype.getReturnType();
1008         if (returnType.requiresPreload(m.owner)) {
1009             poolWriter.enterPreloadClass((ClassSymbol) returnType.tsym);
1010         }
1011         int acountIdx = beginAttrs();
1012         int acount = 0;
1013         if (m.code != null) {
1014             int alenIdx = writeAttr(names.Code);
1015             writeCode(m.code);
1016             m.code = null; // to conserve space
1017             endAttr(alenIdx);
1018             acount++;
1019         }
1020         List<Type> thrown = m.erasure(types).getThrownTypes();
1021         if (thrown.nonEmpty()) {
1022             int alenIdx = writeAttr(names.Exceptions);
1023             databuf.appendChar(thrown.length());
1024             for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
1025                 databuf.appendChar(poolWriter.putClass(l.head));
1026             endAttr(alenIdx);
1027             acount++;
1028         }
1029         if (m.defaultValue != null) {
1030             int alenIdx = writeAttr(names.AnnotationDefault);
1031             m.defaultValue.accept(awriter);
1032             endAttr(alenIdx);
1033             acount++;
1034         }
1035         if (target.hasMethodParameters() && (
1036                 options.isSet(PARAMETERS)
1037                 || ((m.flags_field & RECORD) != 0 && (m.isConstructor() || m.isValueObjectFactory())))) {
1038             if (!m.isLambdaMethod()) // Per JDK-8138729, do not emit parameters table for lambda bodies.
1039                 acount += writeMethodParametersAttr(m);
1040         }
1041         acount += writeMemberAttrs(m, false);
1042         if (!m.isLambdaMethod())
1043             acount += writeParameterAttrs(m.params);
1044         acount += writeExtraAttributes(m);
1045         endAttrs(acountIdx, acount);
1046     }
1047 
1048     /** Write code attribute of method.
1049      */
1050     void writeCode(Code code) {
1051         databuf.appendChar(code.max_stack);
1052         databuf.appendChar(code.max_locals);
1053         databuf.appendInt(code.cp);
1054         databuf.appendBytes(code.code, 0, code.cp);
1055         databuf.appendChar(code.catchInfo.length());
1056         for (List<char[]> l = code.catchInfo.toList();
1057              l.nonEmpty();

1237                 databuf.appendByte(1);
1238                 break;
1239             case FLOAT:
1240                 if (debugstackmap) System.out.print("float");
1241                 databuf.appendByte(2);
1242                 break;
1243             case DOUBLE:
1244                 if (debugstackmap) System.out.print("double");
1245                 databuf.appendByte(3);
1246                 break;
1247             case LONG:
1248                 if (debugstackmap) System.out.print("long");
1249                 databuf.appendByte(4);
1250                 break;
1251             case BOT: // null
1252                 if (debugstackmap) System.out.print("null");
1253                 databuf.appendByte(5);
1254                 break;
1255             case CLASS:
1256             case ARRAY:
1257                 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1258                 databuf.appendByte(7);
1259                 databuf.appendChar(t.isPrimitiveClass() ? poolWriter.putClass(new ConstantPoolQType(types.erasure(t), types)) : poolWriter.putClass(types.erasure(t)));
1260                 break;
1261             case TYPEVAR:
1262                 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1263                 databuf.appendByte(7);
1264                 databuf.appendChar(poolWriter.putClass(types.erasure(t)));
1265                 break;
1266             case UNINITIALIZED_THIS:
1267                 if (debugstackmap) System.out.print("uninit_this");
1268                 databuf.appendByte(6);
1269                 break;
1270             case UNINITIALIZED_OBJECT:
1271                 { UninitializedType uninitType = (UninitializedType)t;
1272                 databuf.appendByte(8);
1273                 if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset);
1274                 databuf.appendChar(uninitType.offset);
1275                 }
1276                 break;
1277             default:
1278                 throw new AssertionError();
1279             }
1280         }

1552         }
1553         return outFile; // may be null if write failed
1554     }
1555 
1556     /** Write class `c' to outstream `out'.
1557      */
1558     public void writeClassFile(OutputStream out, ClassSymbol c)
1559         throws IOException, PoolOverflow, StringOverflow {
1560         Assert.check((c.flags() & COMPOUND) == 0);
1561         databuf.reset();
1562         poolbuf.reset();
1563 
1564         Type supertype = types.supertype(c.type);
1565         List<Type> interfaces = types.interfaces(c.type);
1566         List<Type> typarams = c.type.getTypeArguments();
1567 
1568         int flags;
1569         if (c.owner.kind == MDL) {
1570             flags = ACC_MODULE;
1571         } else {
1572             flags = adjustFlags(c.flags() & ~(DEFAULT | STRICTFP));
1573             if ((flags & PROTECTED) != 0) flags |= PUBLIC;
1574             flags = flags & AdjustedClassFlags;

1575         }
1576 
1577         if (dumpClassModifiers) {
1578             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1579             pw.println();
1580             pw.println("CLASSFILE  " + c.getQualifiedName());
1581             pw.println("---" + flagNames(flags));
1582         }
1583         databuf.appendChar(flags);
1584 
1585         if (c.owner.kind == MDL) {
1586             PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage;
1587             databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed)));
1588         } else {
1589             databuf.appendChar(poolWriter.putClass(c));
1590         }
1591         databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0);
1592         databuf.appendChar(interfaces.length());
1593         for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1594             databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym));
1595         int fieldsCount = 0;
1596         int methodsCount = 0;
1597         for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
1598             switch (sym.kind) {
1599             case VAR: fieldsCount++; break;
1600             case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
1601                       break;
1602             case TYP: poolWriter.enterInnerClass((ClassSymbol)sym); break;
1603             default : Assert.error();
1604             }
1605         }
1606 
1607         if (c.trans_local != null) {
1608             for (ClassSymbol local : c.trans_local) {
1609                 poolWriter.enterInnerClass(local);
1610             }
1611         }
1612 
1613         databuf.appendChar(fieldsCount);
1614         writeFields(c.members());
1615         databuf.appendChar(methodsCount);
1616         writeMethods(c.members());
1617 
1618         int acountIdx = beginAttrs();
1619         int acount = 0;
1620 
1621         boolean sigReq =
1622             typarams.length() != 0 || supertype.allparams().length() != 0;
1623         for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
1624             sigReq = l.head.allparams().length() != 0;
1625         if (sigReq) {
1626             int alenIdx = writeAttr(names.Signature);
1627             databuf.appendChar(poolWriter.putSignature(c));
1628             endAttr(alenIdx);
1629             acount++;

1680         }
1681 
1682         if (c.isRecord()) {
1683             acount += writeRecordAttribute(c);
1684         }
1685 
1686         if (target.hasSealedClasses()) {
1687             acount += writePermittedSubclassesIfNeeded(c);
1688         }
1689 
1690         if (!poolWriter.bootstrapMethods.isEmpty()) {
1691             writeBootstrapMethods();
1692             acount++;
1693         }
1694 
1695         if (!poolWriter.innerClasses.isEmpty()) {
1696             writeInnerClasses();
1697             acount++;
1698         }
1699 
1700         if (!poolWriter.preloadClasses.isEmpty()) {
1701             writePreloadAttribute();
1702             acount++;
1703         }
1704 
1705         endAttrs(acountIdx, acount);
1706 
1707         out.write(poolbuf.elems, 0, poolbuf.length);
1708 
1709         poolWriter.writePool(out);
1710         poolWriter.reset(); // to save space
1711 
1712         out.write(databuf.elems, 0, databuf.length);
1713     }
1714 
1715      /**Allows subclasses to write additional class attributes
1716       *
1717       * @return the number of attributes written
1718       */
1719     protected int writeExtraClassAttributes(ClassSymbol c) {
1720         return 0;
1721     }
1722 
1723     /**Allows friends to write additional attributes
1724      *

1728         int i = 0;
1729         for (ToIntFunction<Symbol> hook : extraAttributeHooks) {
1730             i += hook.applyAsInt(sym);
1731         }
1732         return i;
1733     }
1734 
1735     int adjustFlags(final long flags) {
1736         int result = (int)flags;
1737 
1738         // Elide strictfp bit in class files
1739         if (target.obsoleteAccStrict())
1740             result &= ~STRICTFP;
1741 
1742         if ((flags & BRIDGE) != 0)
1743             result |= ACC_BRIDGE;
1744         if ((flags & VARARGS) != 0)
1745             result |= ACC_VARARGS;
1746         if ((flags & DEFAULT) != 0)
1747             result &= ~ABSTRACT;
1748         if ((flags & PRIMITIVE_CLASS) != 0)
1749             result |= ACC_PRIMITIVE;
1750         if ((flags & VALUE_CLASS) != 0)
1751             result |= ACC_VALUE;
1752         if ((flags & IDENTITY_TYPE) != 0)
1753             result |= ACC_IDENTITY;
1754         return result;
1755     }
1756 
1757     long getLastModified(FileObject filename) {
1758         long mod = 0;
1759         try {
1760             mod = filename.getLastModified();
1761         } catch (SecurityException e) {
1762             throw new AssertionError("CRT: couldn't get source file modification date: " + e.getMessage());
1763         }
1764         return mod;
1765     }
1766 }
< prev index next >