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