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

  92 
  93     /** Preview language level.
  94      */
  95     private Preview preview;
  96 
  97     /**
  98      * Target class version.
  99      */
 100     private Target target;
 101 
 102     /**
 103      * Source language version.
 104      */
 105     private Source source;
 106 
 107     /** Type utilities. */
 108     private Types types;
 109 
 110     private Check check;
 111 


 112     /**
 113      * If true, class files will be written in module-specific subdirectories
 114      * of the CLASS_OUTPUT location.
 115      */
 116     public boolean multiModuleMode;
 117 
 118     private List<ToIntFunction<Symbol>> extraAttributeHooks = List.nil();
 119 
 120     /** The initial sizes of the data and constant pool buffers.
 121      *  Sizes are increased when buffers get full.
 122      */
 123     static final int DATA_BUF_SIZE = 0x0fff0;
 124     static final int CLASS_BUF_SIZE = 0x1fff0;
 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

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

 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             int flags = 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;

  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     protected ClassWriter(Context context) {
 171         context.put(classWriterKey, this);
 172 
 173         log = Log.instance(context);
 174         names = Names.instance(context);
 175         options = Options.instance(context);
 176         preview = Preview.instance(context);
 177         target = Target.instance(context);
 178         source = Source.instance(context);
 179         types = Types.instance(context);
 180         check = Check.instance(context);
 181         fileManager = context.get(JavaFileManager.class);
 182         poolWriter = Gen.instance(context).poolWriter;
 183         syms = Symtab.instance(context);
 184 
 185         verbose        = options.isSet(VERBOSE);
 186         genCrt         = options.isSet(XJCOV);
 187         debugstackmap = options.isSet("debug.stackmap");
 188 
 189         emitSourceFile = options.isUnset(G_CUSTOM) ||
 190                             options.isSet(G_CUSTOM, "source");
 191 
 192         String modifierFlags = options.get("debug.dumpmodifiers");
 193         if (modifierFlags != null) {
 194             dumpClassModifiers = modifierFlags.indexOf('c') != -1;
 195             dumpFieldModifiers = modifierFlags.indexOf('f') != -1;
 196             dumpInnerClassModifiers = modifierFlags.indexOf('i') != -1;
 197             dumpMethodModifiers = modifierFlags.indexOf('m') != -1;
 198         }
 199         Source source = Source.instance(context);
 200         allowPrimitiveClasses = Feature.PRIMITIVE_CLASSES.allowedInSource(source) && options.isSet("enablePrimitiveClasses");
 201     }
 202 
 203     public void addExtraAttributes(ToIntFunction<Symbol> addExtraAttributes) {
 204         extraAttributeHooks = extraAttributeHooks.prepend(addExtraAttributes);
 205     }
 206 
 207 /******************************************************************
 208  * Diagnostics: dump generated class names and modifiers
 209  ******************************************************************/
 210 
 211     /** Value of option 'dumpmodifiers' is a string
 212      *  indicating which modifiers should be dumped for debugging:
 213      *    'c' -- classes
 214      *    'f' -- fields
 215      *    'i' -- innerclass attributes
 216      *    'm' -- methods
 217      *  For example, to dump everything:
 218      *    javac -XDdumpmodifiers=cifm MyProg.java
 219      */
 220     private boolean dumpClassModifiers; // -XDdumpmodifiers=c

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

 818             impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl)));
 819         });
 820 
 821         endAttr(alenIdx);
 822         return 1;
 823     }
 824 
 825 /**********************************************************************
 826  * Writing Objects
 827  **********************************************************************/
 828 
 829     /** Write "inner classes" attribute.
 830      */
 831     void writeInnerClasses() {
 832         int alenIdx = writeAttr(names.InnerClasses);
 833         databuf.appendChar(poolWriter.innerClasses.size());
 834         for (ClassSymbol inner : poolWriter.innerClasses) {
 835             inner.markAbstractIfNeeded(types);
 836             int flags = adjustFlags(inner.flags_field);
 837             if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT

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

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

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

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

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

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

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