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

  91 
  92     /** Preview language level.
  93      */
  94     private Preview preview;
  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     private Check check;
 110 


 111     /**
 112      * If true, class files will be written in module-specific subdirectories
 113      * of the CLASS_OUTPUT location.
 114      */
 115     public boolean multiModuleMode;
 116 
 117     private List<ToIntFunction<Symbol>> extraAttributeHooks = List.nil();
 118 
 119     /** The initial sizes of the data and constant pool buffers.
 120      *  Sizes are increased when buffers get full.
 121      */
 122     static final int DATA_BUF_SIZE = 0x0fff0;
 123     static final int CLASS_BUF_SIZE = 0x1fff0;
 124 
 125     /** An output buffer for member info.
 126      */
 127     public ByteBuffer databuf = new ByteBuffer(DATA_BUF_SIZE);
 128 
 129     /** An output buffer for the constant pool.
 130      */
 131     ByteBuffer poolbuf = new ByteBuffer(CLASS_BUF_SIZE);
 132 
 133     /** The constant pool writer.
 134      */
 135     final PoolWriter poolWriter;
 136 
 137     /** The log to use for verbose output.
 138      */
 139     private final Log log;
 140 
 141     /** The name table. */
 142     private final Names names;
 143 


 144     /** Access to files. */
 145     private final JavaFileManager fileManager;
 146 
 147     /** The tags and constants used in compressed stackmap. */
 148     static final int SAME_FRAME_SIZE = 64;
 149     static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
 150     static final int SAME_FRAME_EXTENDED = 251;
 151     static final int FULL_FRAME = 255;
 152     static final int MAX_LOCAL_LENGTH_DIFF = 4;
 153 
 154     /** Get the ClassWriter instance for this context. */
 155     public static ClassWriter instance(Context context) {
 156         ClassWriter instance = context.get(classWriterKey);
 157         if (instance == null)
 158             instance = new ClassWriter(context);
 159         return instance;
 160     }
 161 
 162     /** Construct a class writer, given an options table.
 163      */
 164     @SuppressWarnings("this-escape")
 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

 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);

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











 855     int writeRecordAttribute(ClassSymbol csym) {
 856         int alenIdx = writeAttr(names.Record);
 857         Scope s = csym.members();
 858         databuf.appendChar(csym.getRecordComponents().size());
 859         for (VarSymbol v: csym.getRecordComponents()) {
 860             //databuf.appendChar(poolWriter.putMember(v.accessor.head.snd));
 861             databuf.appendChar(poolWriter.putName(v.name));
 862             databuf.appendChar(poolWriter.putDescriptor(v));
 863             int acountIdx = beginAttrs();
 864             int acount = 0;
 865             acount += writeMemberAttrs(v, true);
 866             endAttrs(acountIdx, acount);
 867         }
 868         endAttr(alenIdx);
 869         return 1;
 870     }
 871 
 872     /**
 873      * Write NestMembers attribute (if needed)
 874      */

 957             //write static args array
 958             for (LoadableConstant arg : uniqueArgs) {
 959                 databuf.appendChar(poolWriter.putConstant(arg));
 960             }
 961         }
 962         endAttr(alenIdx);
 963     }
 964 
 965     /** Write field symbol, entering all references into constant pool.
 966      */
 967     void writeField(VarSymbol v) {
 968         int flags = adjustFlags(v.flags());
 969         databuf.appendChar(flags);
 970         if (dumpFieldModifiers) {
 971             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 972             pw.println("FIELD  " + v.name);
 973             pw.println("---" + flagNames(v.flags()));
 974         }
 975         databuf.appendChar(poolWriter.putName(v.name));
 976         databuf.appendChar(poolWriter.putDescriptor(v));




 977         int acountIdx = beginAttrs();
 978         int acount = 0;
 979         if (v.getConstValue() != null) {
 980             int alenIdx = writeAttr(names.ConstantValue);
 981             databuf.appendChar(poolWriter.putConstant(v.getConstValue()));
 982             endAttr(alenIdx);
 983             acount++;
 984         }
 985         acount += writeMemberAttrs(v, false);
 986         acount += writeExtraAttributes(v);
 987         endAttrs(acountIdx, acount);
 988     }
 989 
 990     /** Write method symbol, entering all references into constant pool.
 991      */
 992     void writeMethod(MethodSymbol m) {
 993         int flags = adjustFlags(m.flags());
 994         databuf.appendChar(flags);
 995         if (dumpMethodModifiers) {
 996             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 997             pw.println("METHOD  " + m.name);
 998             pw.println("---" + flagNames(m.flags()));
 999         }
1000         databuf.appendChar(poolWriter.putName(m.name));
1001         databuf.appendChar(poolWriter.putDescriptor(m));










1002         int acountIdx = beginAttrs();
1003         int acount = 0;
1004         if (m.code != null) {
1005             int alenIdx = writeAttr(names.Code);
1006             writeCode(m.code);
1007             m.code = null; // to conserve space
1008             endAttr(alenIdx);
1009             acount++;
1010         }
1011         List<Type> thrown = m.erasure(types).getThrownTypes();
1012         if (thrown.nonEmpty()) {
1013             int alenIdx = writeAttr(names.Exceptions);
1014             databuf.appendChar(thrown.length());
1015             for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
1016                 databuf.appendChar(poolWriter.putClass(l.head));
1017             endAttr(alenIdx);
1018             acount++;
1019         }
1020         if (m.defaultValue != null) {
1021             int alenIdx = writeAttr(names.AnnotationDefault);

1023             endAttr(alenIdx);
1024             acount++;
1025         }
1026         if (target.hasMethodParameters()) {
1027             if (!m.isLambdaMethod()) { // Per JDK-8138729, do not emit parameters table for lambda bodies.
1028                 boolean requiresParamNames = requiresParamNames(m);
1029                 if (requiresParamNames || requiresParamFlags(m))
1030                     acount += writeMethodParametersAttr(m, requiresParamNames);
1031             }
1032         }
1033         acount += writeMemberAttrs(m, false);
1034         if (!m.isLambdaMethod())
1035             acount += writeParameterAttrs(m.params);
1036         acount += writeExtraAttributes(m);
1037         endAttrs(acountIdx, acount);
1038     }
1039 
1040     private boolean requiresParamNames(MethodSymbol m) {
1041         if (options.isSet(PARAMETERS))
1042             return true;
1043         if (m.isConstructor() && (m.flags_field & RECORD) != 0)
1044             return true;
1045         return false;
1046     }
1047 
1048     private boolean requiresParamFlags(MethodSymbol m) {
1049         if (!m.extraParams.isEmpty()) {
1050             return m.extraParams.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0);
1051         }
1052         if (m.params != null) {
1053             // parameter is stored in params for Enum#valueOf(name)
1054             return m.params.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0);
1055         }
1056         return false;
1057     }
1058 
1059     /** Write code attribute of method.
1060      */
1061     void writeCode(Code code) {
1062         databuf.appendChar(code.max_stack);
1063         databuf.appendChar(code.max_locals);

1248                 databuf.appendByte(1);
1249                 break;
1250             case FLOAT:
1251                 if (debugstackmap) System.out.print("float");
1252                 databuf.appendByte(2);
1253                 break;
1254             case DOUBLE:
1255                 if (debugstackmap) System.out.print("double");
1256                 databuf.appendByte(3);
1257                 break;
1258             case LONG:
1259                 if (debugstackmap) System.out.print("long");
1260                 databuf.appendByte(4);
1261                 break;
1262             case BOT: // null
1263                 if (debugstackmap) System.out.print("null");
1264                 databuf.appendByte(5);
1265                 break;
1266             case CLASS:
1267             case ARRAY:




1268             case TYPEVAR:
1269                 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1270                 databuf.appendByte(7);
1271                 databuf.appendChar(poolWriter.putClass(types.erasure(t)));
1272                 break;
1273             case UNINITIALIZED_THIS:
1274                 if (debugstackmap) System.out.print("uninit_this");
1275                 databuf.appendByte(6);
1276                 break;
1277             case UNINITIALIZED_OBJECT:
1278                 { UninitializedType uninitType = (UninitializedType)t;
1279                 databuf.appendByte(8);
1280                 if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset);
1281                 databuf.appendChar(uninitType.offset);
1282                 }
1283                 break;
1284             default:
1285                 throw new AssertionError();
1286             }
1287         }

1559         }
1560         return outFile; // may be null if write failed
1561     }
1562 
1563     /** Write class `c' to outstream `out'.
1564      */
1565     public void writeClassFile(OutputStream out, ClassSymbol c)
1566         throws IOException, PoolOverflow, StringOverflow {
1567         Assert.check((c.flags() & COMPOUND) == 0);
1568         databuf.reset();
1569         poolbuf.reset();
1570 
1571         Type supertype = types.supertype(c.type);
1572         List<Type> interfaces = types.interfaces(c.type);
1573         List<Type> typarams = c.type.getTypeArguments();
1574 
1575         int flags;
1576         if (c.owner.kind == MDL) {
1577             flags = ACC_MODULE;
1578         } else {
1579             flags = adjustFlags(c.flags() & ~DEFAULT);
1580             if ((flags & PROTECTED) != 0) flags |= PUBLIC;
1581             flags = flags & ClassFlags & ~STRICTFP;
1582             if ((flags & INTERFACE) == 0) flags |= ACC_SUPER;
1583         }
1584 
1585         if (dumpClassModifiers) {
1586             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1587             pw.println();
1588             pw.println("CLASSFILE  " + c.getQualifiedName());
1589             pw.println("---" + flagNames(flags));
1590         }
1591         databuf.appendChar(flags);
1592 
1593         if (c.owner.kind == MDL) {
1594             PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage;
1595             databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed)));
1596         } else {
1597             databuf.appendChar(poolWriter.putClass(c));
1598         }
1599         databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0);
1600         databuf.appendChar(interfaces.length());
1601         for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1602             databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym));
1603         int fieldsCount = 0;
1604         int methodsCount = 0;
1605         for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
1606             switch (sym.kind) {
1607             case VAR: fieldsCount++; break;
1608             case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
1609                       break;
1610             case TYP: poolWriter.enterInner((ClassSymbol)sym); break;
1611             default : Assert.error();
1612             }
1613         }
1614 
1615         if (c.trans_local != null) {
1616             for (ClassSymbol local : c.trans_local) {
1617                 poolWriter.enterInner(local);
1618             }
1619         }
1620 
1621         databuf.appendChar(fieldsCount);
1622         writeFields(c.members());
1623         databuf.appendChar(methodsCount);
1624         writeMethods(c.members());
1625 
1626         int acountIdx = beginAttrs();
1627         int acount = 0;
1628 
1629         boolean sigReq =
1630             typarams.length() != 0 || supertype.allparams().length() != 0;
1631         for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
1632             sigReq = l.head.allparams().length() != 0;
1633         if (sigReq) {
1634             int alenIdx = writeAttr(names.Signature);
1635             databuf.appendChar(poolWriter.putSignature(c));
1636             endAttr(alenIdx);
1637             acount++;

1688         }
1689 
1690         if (c.isRecord()) {
1691             acount += writeRecordAttribute(c);
1692         }
1693 
1694         if (target.hasSealedClasses()) {
1695             acount += writePermittedSubclassesIfNeeded(c);
1696         }
1697 
1698         if (!poolWriter.bootstrapMethods.isEmpty()) {
1699             writeBootstrapMethods();
1700             acount++;
1701         }
1702 
1703         if (!poolWriter.innerClasses.isEmpty()) {
1704             writeInnerClasses();
1705             acount++;
1706         }
1707 





1708         endAttrs(acountIdx, acount);
1709 
1710         out.write(poolbuf.elems, 0, poolbuf.length);
1711 
1712         poolWriter.writePool(out);
1713         poolWriter.reset(); // to save space
1714 
1715         out.write(databuf.elems, 0, databuf.length);
1716     }
1717 
1718      /**Allows subclasses to write additional class attributes
1719       *
1720       * @return the number of attributes written
1721       */
1722     protected int writeExtraClassAttributes(ClassSymbol c) {
1723         return 0;
1724     }
1725 
1726     /**Allows friends to write additional attributes
1727      *

1731         int i = 0;
1732         for (ToIntFunction<Symbol> hook : extraAttributeHooks) {
1733             i += hook.applyAsInt(sym);
1734         }
1735         return i;
1736     }
1737 
1738     int adjustFlags(final long flags) {
1739         int result = (int)flags;
1740 
1741         // Elide strictfp bit in class files
1742         if (target.obsoleteAccStrict())
1743             result &= ~STRICTFP;
1744 
1745         if ((flags & BRIDGE) != 0)
1746             result |= ACC_BRIDGE;
1747         if ((flags & VARARGS) != 0)
1748             result |= ACC_VARARGS;
1749         if ((flags & DEFAULT) != 0)
1750             result &= ~ABSTRACT;






1751         return result;
1752     }
1753 
1754     long getLastModified(FileObject filename) {
1755         long mod = 0;
1756         try {
1757             mod = filename.getLastModified();
1758         } catch (SecurityException e) {
1759             throw new AssertionError("CRT: couldn't get source file modification date: " + e.getMessage());
1760         }
1761         return mod;
1762     }
1763 }

  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;
  64 

  93 
  94     /** Preview language level.
  95      */
  96     private Preview preview;
  97 
  98     /**
  99      * Target class version.
 100      */
 101     private Target target;
 102 
 103     /**
 104      * Source language version.
 105      */
 106     private Source source;
 107 
 108     /** Type utilities. */
 109     private Types types;
 110 
 111     private Check check;
 112 
 113     private boolean allowPrimitiveClasses;
 114 
 115     /**
 116      * If true, class files will be written in module-specific subdirectories
 117      * of the CLASS_OUTPUT location.
 118      */
 119     public boolean multiModuleMode;
 120 
 121     private List<ToIntFunction<Symbol>> extraAttributeHooks = List.nil();
 122 
 123     /** The initial sizes of the data and constant pool buffers.
 124      *  Sizes are increased when buffers get full.
 125      */
 126     static final int DATA_BUF_SIZE = 0x0fff0;
 127     static final int CLASS_BUF_SIZE = 0x1fff0;
 128 
 129     /** An output buffer for member info.
 130      */
 131     public ByteBuffer databuf = new ByteBuffer(DATA_BUF_SIZE);
 132 
 133     /** An output buffer for the constant pool.
 134      */
 135     ByteBuffer poolbuf = new ByteBuffer(CLASS_BUF_SIZE);
 136 
 137     /** The constant pool writer.
 138      */
 139     final PoolWriter poolWriter;
 140 
 141     /** The log to use for verbose output.
 142      */
 143     private final Log log;
 144 
 145     /** The name table. */
 146     private final Names names;
 147 
 148     private final Symtab syms;
 149 
 150     /** Access to files. */
 151     private final JavaFileManager fileManager;
 152 
 153     /** The tags and constants used in compressed stackmap. */
 154     static final int SAME_FRAME_SIZE = 64;
 155     static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
 156     static final int SAME_FRAME_EXTENDED = 251;
 157     static final int FULL_FRAME = 255;
 158     static final int MAX_LOCAL_LENGTH_DIFF = 4;
 159 
 160     /** Get the ClassWriter instance for this context. */
 161     public static ClassWriter instance(Context context) {
 162         ClassWriter instance = context.get(classWriterKey);
 163         if (instance == null)
 164             instance = new ClassWriter(context);
 165         return instance;
 166     }
 167 
 168     /** Construct a class writer, given an options table.
 169      */
 170     @SuppressWarnings("this-escape")
 171     protected ClassWriter(Context context) {
 172         context.put(classWriterKey, this);
 173 
 174         log = Log.instance(context);
 175         names = Names.instance(context);
 176         options = Options.instance(context);
 177         preview = Preview.instance(context);
 178         target = Target.instance(context);
 179         source = Source.instance(context);
 180         types = Types.instance(context);
 181         check = Check.instance(context);
 182         fileManager = context.get(JavaFileManager.class);
 183         poolWriter = Gen.instance(context).poolWriter;
 184         syms = Symtab.instance(context);
 185 
 186         verbose        = options.isSet(VERBOSE);
 187         genCrt         = options.isSet(XJCOV);
 188         debugstackmap = options.isSet("debug.stackmap");
 189 
 190         emitSourceFile = options.isUnset(G_CUSTOM) ||
 191                             options.isSet(G_CUSTOM, "source");
 192 
 193         String modifierFlags = options.get("debug.dumpmodifiers");
 194         if (modifierFlags != null) {
 195             dumpClassModifiers = modifierFlags.indexOf('c') != -1;
 196             dumpFieldModifiers = modifierFlags.indexOf('f') != -1;
 197             dumpInnerClassModifiers = modifierFlags.indexOf('i') != -1;
 198             dumpMethodModifiers = modifierFlags.indexOf('m') != -1;
 199         }
 200         Source source = Source.instance(context);
 201         allowPrimitiveClasses = Feature.PRIMITIVE_CLASSES.allowedInSource(source) && options.isSet("enablePrimitiveClasses");
 202     }
 203 
 204     public void addExtraAttributes(ToIntFunction<Symbol> addExtraAttributes) {
 205         extraAttributeHooks = extraAttributeHooks.prepend(addExtraAttributes);
 206     }
 207 
 208 /******************************************************************
 209  * Diagnostics: dump generated class names and modifiers
 210  ******************************************************************/
 211 
 212     /** Value of option 'dumpmodifiers' is a string
 213      *  indicating which modifiers should be dumped for debugging:
 214      *    'c' -- classes
 215      *    'f' -- fields
 216      *    'i' -- innerclass attributes
 217      *    'm' -- methods
 218      *  For example, to dump everything:
 219      *    javac -XDdumpmodifiers=cifm MyProg.java
 220      */
 221     private boolean dumpClassModifiers; // -XDdumpmodifiers=c

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

 828             impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl)));
 829         });
 830 
 831         endAttr(alenIdx);
 832         return 1;
 833     }
 834 
 835 /**********************************************************************
 836  * Writing Objects
 837  **********************************************************************/
 838 
 839     /** Write "inner classes" attribute.
 840      */
 841     void writeInnerClasses() {
 842         int alenIdx = writeAttr(names.InnerClasses);
 843         databuf.appendChar(poolWriter.innerClasses.size());
 844         for (ClassSymbol inner : poolWriter.innerClasses) {
 845             inner.markAbstractIfNeeded(types);
 846             int flags = adjustFlags(inner.flags_field);
 847             if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT

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

 976             //write static args array
 977             for (LoadableConstant arg : uniqueArgs) {
 978                 databuf.appendChar(poolWriter.putConstant(arg));
 979             }
 980         }
 981         endAttr(alenIdx);
 982     }
 983 
 984     /** Write field symbol, entering all references into constant pool.
 985      */
 986     void writeField(VarSymbol v) {
 987         int flags = adjustFlags(v.flags());
 988         databuf.appendChar(flags);
 989         if (dumpFieldModifiers) {
 990             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 991             pw.println("FIELD  " + v.name);
 992             pw.println("---" + flagNames(v.flags()));
 993         }
 994         databuf.appendChar(poolWriter.putName(v.name));
 995         databuf.appendChar(poolWriter.putDescriptor(v));
 996         Type fldType = v.erasure(types);
 997         if (fldType.requiresPreload(v.owner)) {
 998             poolWriter.enterPreloadClass((ClassSymbol) fldType.tsym);
 999         }
1000         int acountIdx = beginAttrs();
1001         int acount = 0;
1002         if (v.getConstValue() != null) {
1003             int alenIdx = writeAttr(names.ConstantValue);
1004             databuf.appendChar(poolWriter.putConstant(v.getConstValue()));
1005             endAttr(alenIdx);
1006             acount++;
1007         }
1008         acount += writeMemberAttrs(v, false);
1009         acount += writeExtraAttributes(v);
1010         endAttrs(acountIdx, acount);
1011     }
1012 
1013     /** Write method symbol, entering all references into constant pool.
1014      */
1015     void writeMethod(MethodSymbol m) {
1016         int flags = adjustFlags(m.flags());
1017         databuf.appendChar(flags);
1018         if (dumpMethodModifiers) {
1019             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1020             pw.println("METHOD  " + m.name);
1021             pw.println("---" + flagNames(m.flags()));
1022         }
1023         databuf.appendChar(poolWriter.putName(m.name));
1024         databuf.appendChar(poolWriter.putDescriptor(m));
1025         MethodType mtype = (MethodType) m.externalType(types);
1026         for (Type t : mtype.getParameterTypes()) {
1027             if (t.requiresPreload(m.owner)) {
1028                 poolWriter.enterPreloadClass((ClassSymbol) t.tsym);
1029             }
1030         }
1031         Type returnType = mtype.getReturnType();
1032         if (returnType.requiresPreload(m.owner)) {
1033             poolWriter.enterPreloadClass((ClassSymbol) returnType.tsym);
1034         }
1035         int acountIdx = beginAttrs();
1036         int acount = 0;
1037         if (m.code != null) {
1038             int alenIdx = writeAttr(names.Code);
1039             writeCode(m.code);
1040             m.code = null; // to conserve space
1041             endAttr(alenIdx);
1042             acount++;
1043         }
1044         List<Type> thrown = m.erasure(types).getThrownTypes();
1045         if (thrown.nonEmpty()) {
1046             int alenIdx = writeAttr(names.Exceptions);
1047             databuf.appendChar(thrown.length());
1048             for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
1049                 databuf.appendChar(poolWriter.putClass(l.head));
1050             endAttr(alenIdx);
1051             acount++;
1052         }
1053         if (m.defaultValue != null) {
1054             int alenIdx = writeAttr(names.AnnotationDefault);

1056             endAttr(alenIdx);
1057             acount++;
1058         }
1059         if (target.hasMethodParameters()) {
1060             if (!m.isLambdaMethod()) { // Per JDK-8138729, do not emit parameters table for lambda bodies.
1061                 boolean requiresParamNames = requiresParamNames(m);
1062                 if (requiresParamNames || requiresParamFlags(m))
1063                     acount += writeMethodParametersAttr(m, requiresParamNames);
1064             }
1065         }
1066         acount += writeMemberAttrs(m, false);
1067         if (!m.isLambdaMethod())
1068             acount += writeParameterAttrs(m.params);
1069         acount += writeExtraAttributes(m);
1070         endAttrs(acountIdx, acount);
1071     }
1072 
1073     private boolean requiresParamNames(MethodSymbol m) {
1074         if (options.isSet(PARAMETERS))
1075             return true;
1076         if ((m.isInitOrVNew() || m.isValueObjectFactory()) && (m.flags_field & RECORD) != 0)
1077             return true;
1078         return false;
1079     }
1080 
1081     private boolean requiresParamFlags(MethodSymbol m) {
1082         if (!m.extraParams.isEmpty()) {
1083             return m.extraParams.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0);
1084         }
1085         if (m.params != null) {
1086             // parameter is stored in params for Enum#valueOf(name)
1087             return m.params.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0);
1088         }
1089         return false;
1090     }
1091 
1092     /** Write code attribute of method.
1093      */
1094     void writeCode(Code code) {
1095         databuf.appendChar(code.max_stack);
1096         databuf.appendChar(code.max_locals);

1281                 databuf.appendByte(1);
1282                 break;
1283             case FLOAT:
1284                 if (debugstackmap) System.out.print("float");
1285                 databuf.appendByte(2);
1286                 break;
1287             case DOUBLE:
1288                 if (debugstackmap) System.out.print("double");
1289                 databuf.appendByte(3);
1290                 break;
1291             case LONG:
1292                 if (debugstackmap) System.out.print("long");
1293                 databuf.appendByte(4);
1294                 break;
1295             case BOT: // null
1296                 if (debugstackmap) System.out.print("null");
1297                 databuf.appendByte(5);
1298                 break;
1299             case CLASS:
1300             case ARRAY:
1301                 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1302                 databuf.appendByte(7);
1303                 databuf.appendChar(allowPrimitiveClasses && t.isPrimitiveClass() ? poolWriter.putClass(new ConstantPoolQType(types.erasure(t), types)) : poolWriter.putClass(types.erasure(t)));
1304                 break;
1305             case TYPEVAR:
1306                 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1307                 databuf.appendByte(7);
1308                 databuf.appendChar(poolWriter.putClass(types.erasure(t)));
1309                 break;
1310             case UNINITIALIZED_THIS:
1311                 if (debugstackmap) System.out.print("uninit_this");
1312                 databuf.appendByte(6);
1313                 break;
1314             case UNINITIALIZED_OBJECT:
1315                 { UninitializedType uninitType = (UninitializedType)t;
1316                 databuf.appendByte(8);
1317                 if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset);
1318                 databuf.appendChar(uninitType.offset);
1319                 }
1320                 break;
1321             default:
1322                 throw new AssertionError();
1323             }
1324         }

1596         }
1597         return outFile; // may be null if write failed
1598     }
1599 
1600     /** Write class `c' to outstream `out'.
1601      */
1602     public void writeClassFile(OutputStream out, ClassSymbol c)
1603         throws IOException, PoolOverflow, StringOverflow {
1604         Assert.check((c.flags() & COMPOUND) == 0);
1605         databuf.reset();
1606         poolbuf.reset();
1607 
1608         Type supertype = types.supertype(c.type);
1609         List<Type> interfaces = types.interfaces(c.type);
1610         List<Type> typarams = c.type.getTypeArguments();
1611 
1612         int flags;
1613         if (c.owner.kind == MDL) {
1614             flags = ACC_MODULE;
1615         } else {
1616             flags = adjustFlags(c.flags() & ~(DEFAULT | STRICTFP));
1617             if ((flags & PROTECTED) != 0) flags |= PUBLIC;
1618             flags = flags & AdjustedClassFlags;

1619         }
1620 
1621         if (dumpClassModifiers) {
1622             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1623             pw.println();
1624             pw.println("CLASSFILE  " + c.getQualifiedName());
1625             pw.println("---" + flagNames(flags));
1626         }
1627         databuf.appendChar(flags);
1628 
1629         if (c.owner.kind == MDL) {
1630             PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage;
1631             databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed)));
1632         } else {
1633             databuf.appendChar(poolWriter.putClass(c));
1634         }
1635         databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0);
1636         databuf.appendChar(interfaces.length());
1637         for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1638             databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym));
1639         int fieldsCount = 0;
1640         int methodsCount = 0;
1641         for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
1642             switch (sym.kind) {
1643             case VAR: fieldsCount++; break;
1644             case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
1645                       break;
1646             case TYP: poolWriter.enterInnerClass((ClassSymbol)sym); break;
1647             default : Assert.error();
1648             }
1649         }
1650 
1651         if (c.trans_local != null) {
1652             for (ClassSymbol local : c.trans_local) {
1653                 poolWriter.enterInnerClass(local);
1654             }
1655         }
1656 
1657         databuf.appendChar(fieldsCount);
1658         writeFields(c.members());
1659         databuf.appendChar(methodsCount);
1660         writeMethods(c.members());
1661 
1662         int acountIdx = beginAttrs();
1663         int acount = 0;
1664 
1665         boolean sigReq =
1666             typarams.length() != 0 || supertype.allparams().length() != 0;
1667         for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
1668             sigReq = l.head.allparams().length() != 0;
1669         if (sigReq) {
1670             int alenIdx = writeAttr(names.Signature);
1671             databuf.appendChar(poolWriter.putSignature(c));
1672             endAttr(alenIdx);
1673             acount++;

1724         }
1725 
1726         if (c.isRecord()) {
1727             acount += writeRecordAttribute(c);
1728         }
1729 
1730         if (target.hasSealedClasses()) {
1731             acount += writePermittedSubclassesIfNeeded(c);
1732         }
1733 
1734         if (!poolWriter.bootstrapMethods.isEmpty()) {
1735             writeBootstrapMethods();
1736             acount++;
1737         }
1738 
1739         if (!poolWriter.innerClasses.isEmpty()) {
1740             writeInnerClasses();
1741             acount++;
1742         }
1743 
1744         if (!poolWriter.preloadClasses.isEmpty()) {
1745             writePreloadAttribute();
1746             acount++;
1747         }
1748 
1749         endAttrs(acountIdx, acount);
1750 
1751         out.write(poolbuf.elems, 0, poolbuf.length);
1752 
1753         poolWriter.writePool(out);
1754         poolWriter.reset(); // to save space
1755 
1756         out.write(databuf.elems, 0, databuf.length);
1757     }
1758 
1759      /**Allows subclasses to write additional class attributes
1760       *
1761       * @return the number of attributes written
1762       */
1763     protected int writeExtraClassAttributes(ClassSymbol c) {
1764         return 0;
1765     }
1766 
1767     /**Allows friends to write additional attributes
1768      *

1772         int i = 0;
1773         for (ToIntFunction<Symbol> hook : extraAttributeHooks) {
1774             i += hook.applyAsInt(sym);
1775         }
1776         return i;
1777     }
1778 
1779     int adjustFlags(final long flags) {
1780         int result = (int)flags;
1781 
1782         // Elide strictfp bit in class files
1783         if (target.obsoleteAccStrict())
1784             result &= ~STRICTFP;
1785 
1786         if ((flags & BRIDGE) != 0)
1787             result |= ACC_BRIDGE;
1788         if ((flags & VARARGS) != 0)
1789             result |= ACC_VARARGS;
1790         if ((flags & DEFAULT) != 0)
1791             result &= ~ABSTRACT;
1792         if ((flags & PRIMITIVE_CLASS) != 0)
1793             result |= ACC_PRIMITIVE;
1794         if ((flags & VALUE_CLASS) != 0)
1795             result |= ACC_VALUE;
1796         if ((flags & IDENTITY_TYPE) != 0)
1797             result |= ACC_IDENTITY;
1798         return result;
1799     }
1800 
1801     long getLastModified(FileObject filename) {
1802         long mod = 0;
1803         try {
1804             mod = filename.getLastModified();
1805         } catch (SecurityException e) {
1806             throw new AssertionError("CRT: couldn't get source file modification date: " + e.getMessage());
1807         }
1808         return mod;
1809     }
1810 }
< prev index next >