1 /*
2 * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
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);
205 * 'c' -- classes
206 * 'f' -- fields
207 * 'i' -- innerclass attributes
208 * 'm' -- methods
209 * For example, to dump everything:
210 * javac -XDdumpmodifiers=cifm MyProg.java
211 */
212 private boolean dumpClassModifiers; // -XDdumpmodifiers=c
213 private boolean dumpFieldModifiers; // -XDdumpmodifiers=f
214 private boolean dumpInnerClassModifiers; // -XDdumpmodifiers=i
215 private boolean dumpMethodModifiers; // -XDdumpmodifiers=m
216
217
218 /** Return flags as a string, separated by " ".
219 */
220 public static String flagNames(long flags) {
221 StringBuilder sbuf = new StringBuilder();
222 int i = 0;
223 long f = flags & StandardFlags;
224 while (f != 0) {
225 if ((f & 1) != 0) {
226 sbuf.append(" ");
227 sbuf.append(flagName[i]);
228 }
229 f = f >> 1;
230 i++;
231 }
232 return sbuf.toString();
233 }
234 //where
235 private static final String[] flagName = {
236 "PUBLIC", "PRIVATE", "PROTECTED", "STATIC", "FINAL",
237 "SUPER", "VOLATILE", "TRANSIENT", "NATIVE", "INTERFACE",
238 "ABSTRACT", "STRICTFP"};
239
240 /* ****************************************************************
241 * Output routines
242 ******************************************************************/
243
244 /** Write a character into given byte buffer;
245 * byte buffer will not be grown.
246 */
247 void putChar(ByteBuffer buf, int op, int x) {
248 buf.elems[op ] = (byte)((x >> 8) & 0xFF);
249 buf.elems[op+1] = (byte)((x ) & 0xFF);
250 }
251
252 /** Write an integer into given byte buffer;
253 * byte buffer will not be grown.
254 */
255 void putInt(ByteBuffer buf, int adr, int x) {
256 buf.elems[adr ] = (byte)((x >> 24) & 0xFF);
257 buf.elems[adr+1] = (byte)((x >> 16) & 0xFF);
820 for (ProvidesDirective p : m.provides) {
821 mergedProvides.computeIfAbsent(p.service, s -> new LinkedHashSet<>()).addAll(p.impls);
822 }
823 databuf.appendChar(mergedProvides.size());
824 mergedProvides.forEach((srvc, impls) -> {
825 databuf.appendChar(poolWriter.putClass(srvc));
826 databuf.appendChar(impls.size());
827 impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl)));
828 });
829
830 endAttr(alenIdx);
831 return 1;
832 }
833
834 /* ********************************************************************
835 * Writing Objects
836 **********************************************************************/
837
838 /** Write "inner classes" attribute.
839 */
840 void writeInnerClasses() {
841 int alenIdx = writeAttr(names.InnerClasses);
842 databuf.appendChar(poolWriter.innerClasses.size());
843 for (ClassSymbol inner : poolWriter.innerClasses) {
844 inner.markAbstractIfNeeded(types);
845 int flags = adjustFlags(inner.flags_field);
846 if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT
847 flags &= ~STRICTFP; //inner classes should not have the strictfp flag set.
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 int writeRecordAttribute(ClassSymbol csym) {
864 int alenIdx = writeAttr(names.Record);
865 Scope s = csym.members();
866 databuf.appendChar(csym.getRecordComponents().size());
867 for (VarSymbol v: csym.getRecordComponents()) {
868 //databuf.appendChar(poolWriter.putMember(v.accessor.head.snd));
869 databuf.appendChar(poolWriter.putName(v.name));
870 databuf.appendChar(poolWriter.putDescriptor(v));
871 int acountIdx = beginAttrs();
872 int acount = 0;
873 acount += writeMemberAttrs(v, true);
874 endAttrs(acountIdx, acount);
875 }
876 endAttr(alenIdx);
877 return 1;
878 }
879
880 /**
881 * Write NestMembers attribute (if needed)
882 */
956 }
957 } while (lastBootstrapMethods < poolWriter.bootstrapMethods.size());
958 databuf.appendChar(poolWriter.bootstrapMethods.size());
959 for (BsmKey bsmKey : poolWriter.bootstrapMethods.keySet()) {
960 //write BSM handle
961 databuf.appendChar(poolWriter.putConstant(bsmKey.bsm));
962 LoadableConstant[] uniqueArgs = bsmKey.staticArgs;
963 //write static args length
964 databuf.appendChar(uniqueArgs.length);
965 //write static args array
966 for (LoadableConstant arg : uniqueArgs) {
967 databuf.appendChar(poolWriter.putConstant(arg));
968 }
969 }
970 endAttr(alenIdx);
971 }
972
973 /** Write field symbol, entering all references into constant pool.
974 */
975 void writeField(VarSymbol v) {
976 int flags = adjustFlags(v.flags());
977 databuf.appendChar(flags);
978 if (dumpFieldModifiers) {
979 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
980 pw.println("FIELD " + v.name);
981 pw.println("---" + flagNames(v.flags()));
982 }
983 databuf.appendChar(poolWriter.putName(v.name));
984 databuf.appendChar(poolWriter.putDescriptor(v));
985 int acountIdx = beginAttrs();
986 int acount = 0;
987 if (v.getConstValue() != null) {
988 int alenIdx = writeAttr(names.ConstantValue);
989 databuf.appendChar(poolWriter.putConstant(v.getConstValue()));
990 endAttr(alenIdx);
991 acount++;
992 }
993 acount += writeMemberAttrs(v, false);
994 acount += writeExtraAttributes(v);
995 endAttrs(acountIdx, acount);
996 }
997
998 /** Write method symbol, entering all references into constant pool.
999 */
1000 void writeMethod(MethodSymbol m) {
1001 int flags = adjustFlags(m.flags());
1002 databuf.appendChar(flags);
1003 if (dumpMethodModifiers) {
1004 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1005 pw.println("METHOD " + m.name);
1006 pw.println("---" + flagNames(m.flags()));
1007 }
1008 databuf.appendChar(poolWriter.putName(m.name));
1009 databuf.appendChar(poolWriter.putDescriptor(m));
1010 int acountIdx = beginAttrs();
1011 int acount = 0;
1012 if (m.code != null) {
1013 int alenIdx = writeAttr(names.Code);
1014 writeCode(m.code);
1015 m.code = null; // to conserve space
1016 endAttr(alenIdx);
1017 acount++;
1018 }
1019 List<Type> thrown = m.erasure(types).getThrownTypes();
1020 if (thrown.nonEmpty()) {
1021 int alenIdx = writeAttr(names.Exceptions);
1022 databuf.appendChar(thrown.length());
1023 for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
1024 databuf.appendChar(poolWriter.putClass(l.head));
1025 endAttr(alenIdx);
1026 acount++;
1027 }
1028 if (m.defaultValue != null) {
1029 int alenIdx = writeAttr(names.AnnotationDefault);
1280 break;
1281 case UNINITIALIZED_THIS:
1282 if (debugstackmap) System.out.print("uninit_this");
1283 databuf.appendByte(6);
1284 break;
1285 case UNINITIALIZED_OBJECT:
1286 { UninitializedType uninitType = (UninitializedType)t;
1287 databuf.appendByte(8);
1288 if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset);
1289 databuf.appendChar(uninitType.offset);
1290 }
1291 break;
1292 default:
1293 throw new AssertionError();
1294 }
1295 }
1296
1297 /** An entry in the JSR202 StackMapTable */
1298 abstract static class StackMapTableFrame {
1299 abstract int getFrameType();
1300
1301 void write(ClassWriter writer) {
1302 int frameType = getFrameType();
1303 writer.databuf.appendByte(frameType);
1304 if (writer.debugstackmap) System.out.print(" frame_type=" + frameType);
1305 }
1306
1307 static class SameFrame extends StackMapTableFrame {
1308 final int offsetDelta;
1309 SameFrame(int offsetDelta) {
1310 this.offsetDelta = offsetDelta;
1311 }
1312 int getFrameType() {
1313 return (offsetDelta < SAME_FRAME_SIZE) ? offsetDelta : SAME_FRAME_EXTENDED;
1314 }
1315 @Override
1316 void write(ClassWriter writer) {
1317 super.write(writer);
1318 if (getFrameType() == SAME_FRAME_EXTENDED) {
1319 writer.databuf.appendChar(offsetDelta);
1320 if (writer.debugstackmap){
1321 System.out.print(" offset_delta=" + offsetDelta);
1322 }
1323 }
1324 }
1325 }
1326
1327 static class SameLocals1StackItemFrame extends StackMapTableFrame {
1328 final int offsetDelta;
1329 final Type stack;
1330 SameLocals1StackItemFrame(int offsetDelta, Type stack) {
1331 this.offsetDelta = offsetDelta;
1332 this.stack = stack;
1333 }
1334 int getFrameType() {
1335 return (offsetDelta < SAME_FRAME_SIZE) ?
1336 (SAME_FRAME_SIZE + offsetDelta) :
1337 SAME_LOCALS_1_STACK_ITEM_EXTENDED;
1338 }
1339 @Override
1340 void write(ClassWriter writer) {
1341 super.write(writer);
1342 if (getFrameType() == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
1343 writer.databuf.appendChar(offsetDelta);
1344 if (writer.debugstackmap) {
1345 System.out.print(" offset_delta=" + offsetDelta);
1346 }
1347 }
1348 if (writer.debugstackmap) {
1349 System.out.print(" stack[" + 0 + "]=");
1350 }
1351 writer.writeStackMapType(stack);
1352 }
1353 }
1354
1355 static class ChopFrame extends StackMapTableFrame {
1356 final int frameType;
1357 final int offsetDelta;
1358 ChopFrame(int frameType, int offsetDelta) {
1359 this.frameType = frameType;
1360 this.offsetDelta = offsetDelta;
1361 }
1362 int getFrameType() { return frameType; }
1363 @Override
1364 void write(ClassWriter writer) {
1365 super.write(writer);
1366 writer.databuf.appendChar(offsetDelta);
1367 if (writer.debugstackmap) {
1368 System.out.print(" offset_delta=" + offsetDelta);
1369 }
1370 }
1371 }
1372
1373 static class AppendFrame extends StackMapTableFrame {
1374 final int frameType;
1375 final int offsetDelta;
1376 final Type[] locals;
1377 AppendFrame(int frameType, int offsetDelta, Type[] locals) {
1378 this.frameType = frameType;
1379 this.offsetDelta = offsetDelta;
1380 this.locals = locals;
1381 }
1382 int getFrameType() { return frameType; }
1383 @Override
1384 void write(ClassWriter writer) {
1385 super.write(writer);
1386 writer.databuf.appendChar(offsetDelta);
1387 if (writer.debugstackmap) {
1388 System.out.print(" offset_delta=" + offsetDelta);
1389 }
1390 for (int i=0; i<locals.length; i++) {
1391 if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1392 writer.writeStackMapType(locals[i]);
1393 }
1394 }
1395 }
1396
1397 static class FullFrame extends StackMapTableFrame {
1398 final int offsetDelta;
1399 final Type[] locals;
1400 final Type[] stack;
1401 FullFrame(int offsetDelta, Type[] locals, Type[] stack) {
1402 this.offsetDelta = offsetDelta;
1403 this.locals = locals;
1404 this.stack = stack;
1405 }
1406 int getFrameType() { return FULL_FRAME; }
1407 @Override
1408 void write(ClassWriter writer) {
1409 super.write(writer);
1410 writer.databuf.appendChar(offsetDelta);
1411 writer.databuf.appendChar(locals.length);
1412 if (writer.debugstackmap) {
1413 System.out.print(" offset_delta=" + offsetDelta);
1414 System.out.print(" nlocals=" + locals.length);
1415 }
1416 for (int i=0; i<locals.length; i++) {
1417 if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1418 writer.writeStackMapType(locals[i]);
1419 }
1420
1421 writer.databuf.appendChar(stack.length);
1422 if (writer.debugstackmap) { System.out.print(" nstack=" + stack.length); }
1423 for (int i=0; i<stack.length; i++) {
1424 if (writer.debugstackmap) System.out.print(" stack[" + i + "]=");
1425 writer.writeStackMapType(stack[i]);
1426 }
1427 }
1428 }
1429
1430 /** Compare this frame with the previous frame and produce
1431 * an entry of compressed stack map frame. */
1432 static StackMapTableFrame getInstance(Code.StackMapFrame this_frame,
1433 int prev_pc,
1434 Type[] prev_locals,
1435 Types types) {
1436 Type[] locals = this_frame.locals;
1437 Type[] stack = this_frame.stack;
1438 int offset_delta = this_frame.pc - prev_pc - 1;
1439 if (stack.length == 1) {
1440 if (locals.length == prev_locals.length
1441 && compare(prev_locals, locals, types) == 0) {
1442 return new SameLocals1StackItemFrame(offset_delta, stack[0]);
1443 }
1444 } else if (stack.length == 0) {
1445 int diff_length = compare(prev_locals, locals, types);
1446 if (diff_length == 0) {
1447 return new SameFrame(offset_delta);
1448 } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) {
1449 // APPEND
1450 Type[] local_diff = new Type[-diff_length];
1451 for (int i=prev_locals.length, j=0; i<locals.length; i++,j++) {
1452 local_diff[j] = locals[i];
1453 }
1454 return new AppendFrame(SAME_FRAME_EXTENDED - diff_length,
1455 offset_delta,
1456 local_diff);
1457 } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) {
1458 // CHOP
1459 return new ChopFrame(SAME_FRAME_EXTENDED - diff_length,
1460 offset_delta);
1461 }
1462 }
1463 // FULL_FRAME
1464 return new FullFrame(offset_delta, locals, stack);
1465 }
1466
1467 static boolean isInt(Type t) {
1468 return (t.getTag().isStrictSubRangeOf(INT) || t.hasTag(BOOLEAN));
1469 }
1470
1471 static boolean isSameType(Type t1, Type t2, Types types) {
1472 if (t1 == null) { return t2 == null; }
1473 if (t2 == null) { return false; }
1474
1475 if (isInt(t1) && isInt(t2)) { return true; }
1476
1477 if (t1.hasTag(UNINITIALIZED_THIS)) {
1478 return t2.hasTag(UNINITIALIZED_THIS);
1479 } else if (t1.hasTag(UNINITIALIZED_OBJECT)) {
1480 if (t2.hasTag(UNINITIALIZED_OBJECT)) {
1481 return ((UninitializedType)t1).offset == ((UninitializedType)t2).offset;
1482 } else {
1483 return false;
1484 }
1567 }
1568 return outFile; // may be null if write failed
1569 }
1570
1571 /** Write class `c' to outstream `out'.
1572 */
1573 public void writeClassFile(OutputStream out, ClassSymbol c)
1574 throws IOException, PoolOverflow, StringOverflow {
1575 Assert.check((c.flags() & COMPOUND) == 0);
1576 databuf.reset();
1577 poolbuf.reset();
1578
1579 Type supertype = types.supertype(c.type);
1580 List<Type> interfaces = types.interfaces(c.type);
1581 List<Type> typarams = c.type.getTypeArguments();
1582
1583 int flags;
1584 if (c.owner.kind == MDL) {
1585 flags = ACC_MODULE;
1586 } else {
1587 flags = adjustFlags(c.flags() & ~DEFAULT);
1588 if ((flags & PROTECTED) != 0) flags |= PUBLIC;
1589 flags = flags & ClassFlags & ~STRICTFP;
1590 if ((flags & INTERFACE) == 0) flags |= ACC_SUPER;
1591 }
1592
1593 if (dumpClassModifiers) {
1594 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1595 pw.println();
1596 pw.println("CLASSFILE " + c.getQualifiedName());
1597 pw.println("---" + flagNames(flags));
1598 }
1599 databuf.appendChar(flags);
1600
1601 if (c.owner.kind == MDL) {
1602 PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage;
1603 databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed)));
1604 } else {
1605 databuf.appendChar(poolWriter.putClass(c));
1606 }
1607 databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0);
1608 databuf.appendChar(interfaces.length());
1609 for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1610 databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym));
1664 acount++;
1665 // Append CompilationID attribute
1666 alenIdx = writeAttr(names.CompilationID);
1667 databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(System.currentTimeMillis()))));
1668 endAttr(alenIdx);
1669 acount++;
1670 }
1671
1672 acount += writeFlagAttrs(c.flags());
1673 acount += writeJavaAnnotations(c.getRawAttributes());
1674 acount += writeTypeAnnotations(c.getRawTypeAttributes(), false);
1675 acount += writeEnclosingMethodAttribute(c);
1676 if (c.owner.kind == MDL) {
1677 acount += writeModuleAttribute(c);
1678 acount += writeFlagAttrs(c.owner.flags() & ~DEPRECATED);
1679 }
1680 acount += writeExtraClassAttributes(c);
1681 acount += writeExtraAttributes(c);
1682
1683 poolbuf.appendInt(JAVA_MAGIC);
1684 if (preview.isEnabled() && preview.usesPreview(c.sourcefile)) {
1685 poolbuf.appendChar(ClassFile.PREVIEW_MINOR_VERSION);
1686 } else {
1687 poolbuf.appendChar(target.minorVersion);
1688 }
1689 poolbuf.appendChar(target.majorVersion);
1690
1691 if (c.owner.kind != MDL) {
1692 if (target.hasNestmateAccess()) {
1693 acount += writeNestMembersIfNeeded(c);
1694 acount += writeNestHostIfNeeded(c);
1695 }
1696 }
1697
1698 if (c.isRecord()) {
1699 acount += writeRecordAttribute(c);
1700 }
1701
1702 if (target.hasSealedClasses()) {
1703 acount += writePermittedSubclassesIfNeeded(c);
1704 }
1705
1706 if (!poolWriter.bootstrapMethods.isEmpty()) {
1707 writeBootstrapMethods();
1708 acount++;
1709 }
1710
1711 if (!poolWriter.innerClasses.isEmpty()) {
1712 writeInnerClasses();
1713 acount++;
1714 }
1715
1716 endAttrs(acountIdx, acount);
1717
1718 out.write(poolbuf.elems, 0, poolbuf.length);
1719
1720 poolWriter.writePool(out);
1721 poolWriter.reset(); // to save space
1722
1723 out.write(databuf.elems, 0, databuf.length);
1724 }
1725
1726 /**Allows subclasses to write additional class attributes
1727 *
1728 * @return the number of attributes written
1729 */
1730 protected int writeExtraClassAttributes(ClassSymbol c) {
1731 return 0;
1732 }
1733
1734 /**Allows friends to write additional attributes
1735 *
1736 * @return the number of attributes written
1737 */
1738 protected int writeExtraAttributes(Symbol sym) {
1739 int i = 0;
1740 for (ToIntFunction<Symbol> hook : extraAttributeHooks) {
1741 i += hook.applyAsInt(sym);
1742 }
1743 return i;
1744 }
1745
1746 int adjustFlags(final long flags) {
1747 int result = (int)flags;
1748
1749 // Elide strictfp bit in class files
1750 if (target.obsoleteAccStrict())
1751 result &= ~STRICTFP;
1752
1753 if ((flags & BRIDGE) != 0)
1754 result |= ACC_BRIDGE;
1755 if ((flags & VARARGS) != 0)
1756 result |= ACC_VARARGS;
1757 if ((flags & DEFAULT) != 0)
1758 result &= ~ABSTRACT;
1759 return result;
1760 }
1761
1762 long getLastModified(FileObject filename) {
1763 return filename.getLastModified();
1764 }
1765 }
|
1 /*
2 * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
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 EARLY_LARVAL = 246;
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 @SuppressWarnings("this-escape")
166 protected ClassWriter(Context context) {
167 context.put(classWriterKey, this);
168
169 log = Log.instance(context);
206 * 'c' -- classes
207 * 'f' -- fields
208 * 'i' -- innerclass attributes
209 * 'm' -- methods
210 * For example, to dump everything:
211 * javac -XDdumpmodifiers=cifm MyProg.java
212 */
213 private boolean dumpClassModifiers; // -XDdumpmodifiers=c
214 private boolean dumpFieldModifiers; // -XDdumpmodifiers=f
215 private boolean dumpInnerClassModifiers; // -XDdumpmodifiers=i
216 private boolean dumpMethodModifiers; // -XDdumpmodifiers=m
217
218
219 /** Return flags as a string, separated by " ".
220 */
221 public static String flagNames(long flags) {
222 StringBuilder sbuf = new StringBuilder();
223 int i = 0;
224 long f = flags & StandardFlags;
225 while (f != 0) {
226 if ((f & 1) != 0 && flagName[i] != "") {
227 sbuf.append(" ");
228 sbuf.append(flagName[i]);
229 }
230 f = f >> 1;
231 i++;
232 }
233 return sbuf.toString();
234 }
235 //where
236 private static final String[] flagName = {
237 "PUBLIC", "PRIVATE", "PROTECTED", "STATIC", "FINAL",
238 // the empty position should be for synchronized but right now we don't have any test checking it
239 "", "VOLATILE", "TRANSIENT", "NATIVE", "INTERFACE",
240 "ABSTRACT", "STRICTFP"};
241
242 /* ****************************************************************
243 * Output routines
244 ******************************************************************/
245
246 /** Write a character into given byte buffer;
247 * byte buffer will not be grown.
248 */
249 void putChar(ByteBuffer buf, int op, int x) {
250 buf.elems[op ] = (byte)((x >> 8) & 0xFF);
251 buf.elems[op+1] = (byte)((x ) & 0xFF);
252 }
253
254 /** Write an integer into given byte buffer;
255 * byte buffer will not be grown.
256 */
257 void putInt(ByteBuffer buf, int adr, int x) {
258 buf.elems[adr ] = (byte)((x >> 24) & 0xFF);
259 buf.elems[adr+1] = (byte)((x >> 16) & 0xFF);
822 for (ProvidesDirective p : m.provides) {
823 mergedProvides.computeIfAbsent(p.service, s -> new LinkedHashSet<>()).addAll(p.impls);
824 }
825 databuf.appendChar(mergedProvides.size());
826 mergedProvides.forEach((srvc, impls) -> {
827 databuf.appendChar(poolWriter.putClass(srvc));
828 databuf.appendChar(impls.size());
829 impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl)));
830 });
831
832 endAttr(alenIdx);
833 return 1;
834 }
835
836 /* ********************************************************************
837 * Writing Objects
838 **********************************************************************/
839
840 /** Write "inner classes" attribute.
841 */
842 void writeInnerClasses(boolean markedPreview) {
843 int alenIdx = writeAttr(names.InnerClasses);
844 databuf.appendChar(poolWriter.innerClasses.size());
845 for (ClassSymbol inner : poolWriter.innerClasses) {
846 inner.markAbstractIfNeeded(types);
847 int flags = adjustFlags(inner, inner.flags_field);
848 if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT
849 if ((flags & ACC_IDENTITY) != 0) {
850 if (!markedPreview) {
851 flags &= ~ACC_IDENTITY; // No SUPER for InnerClasses
852 }
853 }
854 if (dumpInnerClassModifiers) {
855 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
856 pw.println("INNERCLASS " + inner.name);
857 pw.println("---" + flagNames(flags));
858 }
859 databuf.appendChar(poolWriter.putClass(inner));
860 databuf.appendChar(
861 inner.owner.kind == TYP && !inner.name.isEmpty() ? poolWriter.putClass((ClassSymbol)inner.owner) : 0);
862 databuf.appendChar(
863 !inner.name.isEmpty() ? poolWriter.putName(inner.name) : 0);
864 databuf.appendChar(flags);
865 }
866 endAttr(alenIdx);
867 }
868
869 /** Write out "LoadableDescriptors" attribute by enumerating the value classes encountered in field/method descriptors during this compilation.
870 */
871 void writeLoadableDescriptorsAttribute() {
872 int alenIdx = writeAttr(names.LoadableDescriptors);
873 databuf.appendChar(poolWriter.loadableDescriptors.size());
874 for (Symbol c : poolWriter.loadableDescriptors) {
875 databuf.appendChar(poolWriter.putDescriptor(c));
876 }
877 endAttr(alenIdx);
878 }
879
880 int writeRecordAttribute(ClassSymbol csym) {
881 int alenIdx = writeAttr(names.Record);
882 Scope s = csym.members();
883 databuf.appendChar(csym.getRecordComponents().size());
884 for (VarSymbol v: csym.getRecordComponents()) {
885 //databuf.appendChar(poolWriter.putMember(v.accessor.head.snd));
886 databuf.appendChar(poolWriter.putName(v.name));
887 databuf.appendChar(poolWriter.putDescriptor(v));
888 int acountIdx = beginAttrs();
889 int acount = 0;
890 acount += writeMemberAttrs(v, true);
891 endAttrs(acountIdx, acount);
892 }
893 endAttr(alenIdx);
894 return 1;
895 }
896
897 /**
898 * Write NestMembers attribute (if needed)
899 */
973 }
974 } while (lastBootstrapMethods < poolWriter.bootstrapMethods.size());
975 databuf.appendChar(poolWriter.bootstrapMethods.size());
976 for (BsmKey bsmKey : poolWriter.bootstrapMethods.keySet()) {
977 //write BSM handle
978 databuf.appendChar(poolWriter.putConstant(bsmKey.bsm));
979 LoadableConstant[] uniqueArgs = bsmKey.staticArgs;
980 //write static args length
981 databuf.appendChar(uniqueArgs.length);
982 //write static args array
983 for (LoadableConstant arg : uniqueArgs) {
984 databuf.appendChar(poolWriter.putConstant(arg));
985 }
986 }
987 endAttr(alenIdx);
988 }
989
990 /** Write field symbol, entering all references into constant pool.
991 */
992 void writeField(VarSymbol v) {
993 int flags = adjustFlags(v, v.flags());
994 databuf.appendChar(flags);
995 if (dumpFieldModifiers) {
996 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
997 pw.println("FIELD " + v.name);
998 pw.println("---" + flagNames(v.flags()));
999 }
1000 databuf.appendChar(poolWriter.putName(v.name));
1001 databuf.appendChar(poolWriter.putDescriptor(v));
1002 Type fldType = v.erasure(types);
1003 if (fldType.requiresLoadableDescriptors(v.owner)) {
1004 poolWriter.enterLoadableDescriptorsClass(fldType.tsym);
1005 if (preview.isPreview(Source.Feature.VALUE_CLASSES)) {
1006 preview.markUsesPreview(null);
1007 }
1008 }
1009 int acountIdx = beginAttrs();
1010 int acount = 0;
1011 if (v.getConstValue() != null) {
1012 int alenIdx = writeAttr(names.ConstantValue);
1013 databuf.appendChar(poolWriter.putConstant(v.getConstValue()));
1014 endAttr(alenIdx);
1015 acount++;
1016 }
1017 acount += writeMemberAttrs(v, false);
1018 acount += writeExtraAttributes(v);
1019 endAttrs(acountIdx, acount);
1020 }
1021
1022 /** Write method symbol, entering all references into constant pool.
1023 */
1024 void writeMethod(MethodSymbol m) {
1025 int flags = adjustFlags(m, m.flags());
1026 databuf.appendChar(flags);
1027 if (dumpMethodModifiers) {
1028 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1029 pw.println("METHOD " + m.name);
1030 pw.println("---" + flagNames(m.flags()));
1031 }
1032 databuf.appendChar(poolWriter.putName(m.name));
1033 databuf.appendChar(poolWriter.putDescriptor(m));
1034 MethodType mtype = (MethodType) m.externalType(types);
1035 for (Type t : mtype.getParameterTypes()) {
1036 if (t.requiresLoadableDescriptors(m.owner)) {
1037 poolWriter.enterLoadableDescriptorsClass(t.tsym);
1038 if (preview.isPreview(Source.Feature.VALUE_CLASSES)) {
1039 preview.markUsesPreview(null);
1040 }
1041 }
1042 }
1043 Type returnType = mtype.getReturnType();
1044 if (returnType.requiresLoadableDescriptors(m.owner)) {
1045 poolWriter.enterLoadableDescriptorsClass(returnType.tsym);
1046 if (preview.isPreview(Source.Feature.VALUE_CLASSES)) {
1047 preview.markUsesPreview(null);
1048 }
1049 }
1050 int acountIdx = beginAttrs();
1051 int acount = 0;
1052 if (m.code != null) {
1053 int alenIdx = writeAttr(names.Code);
1054 writeCode(m.code);
1055 m.code = null; // to conserve space
1056 endAttr(alenIdx);
1057 acount++;
1058 }
1059 List<Type> thrown = m.erasure(types).getThrownTypes();
1060 if (thrown.nonEmpty()) {
1061 int alenIdx = writeAttr(names.Exceptions);
1062 databuf.appendChar(thrown.length());
1063 for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
1064 databuf.appendChar(poolWriter.putClass(l.head));
1065 endAttr(alenIdx);
1066 acount++;
1067 }
1068 if (m.defaultValue != null) {
1069 int alenIdx = writeAttr(names.AnnotationDefault);
1320 break;
1321 case UNINITIALIZED_THIS:
1322 if (debugstackmap) System.out.print("uninit_this");
1323 databuf.appendByte(6);
1324 break;
1325 case UNINITIALIZED_OBJECT:
1326 { UninitializedType uninitType = (UninitializedType)t;
1327 databuf.appendByte(8);
1328 if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset);
1329 databuf.appendChar(uninitType.offset);
1330 }
1331 break;
1332 default:
1333 throw new AssertionError();
1334 }
1335 }
1336
1337 /** An entry in the JSR202 StackMapTable */
1338 abstract static class StackMapTableFrame {
1339 abstract int getFrameType();
1340 int pc;
1341
1342 StackMapTableFrame(int pc) {
1343 this.pc = pc;
1344 }
1345
1346 void write(ClassWriter writer) {
1347 int frameType = getFrameType();
1348 writer.databuf.appendByte(frameType);
1349 if (writer.debugstackmap) System.out.println(" frame_type=" + frameType + " bytecode offset " + pc);
1350 }
1351
1352 static class SameFrame extends StackMapTableFrame {
1353 final int offsetDelta;
1354 SameFrame(int pc, int offsetDelta) {
1355 super(pc);
1356 this.offsetDelta = offsetDelta;
1357 }
1358 int getFrameType() {
1359 return (offsetDelta < SAME_FRAME_SIZE) ? offsetDelta : SAME_FRAME_EXTENDED;
1360 }
1361 @Override
1362 void write(ClassWriter writer) {
1363 super.write(writer);
1364 if (getFrameType() == SAME_FRAME_EXTENDED) {
1365 writer.databuf.appendChar(offsetDelta);
1366 if (writer.debugstackmap){
1367 System.out.print(" offset_delta=" + offsetDelta);
1368 }
1369 }
1370 }
1371 }
1372
1373 static class SameLocals1StackItemFrame extends StackMapTableFrame {
1374 final int offsetDelta;
1375 final Type stack;
1376 SameLocals1StackItemFrame(int pc, int offsetDelta, Type stack) {
1377 super(pc);
1378 this.offsetDelta = offsetDelta;
1379 this.stack = stack;
1380 }
1381 int getFrameType() {
1382 return (offsetDelta < SAME_FRAME_SIZE) ?
1383 (SAME_FRAME_SIZE + offsetDelta) :
1384 SAME_LOCALS_1_STACK_ITEM_EXTENDED;
1385 }
1386 @Override
1387 void write(ClassWriter writer) {
1388 super.write(writer);
1389 if (getFrameType() == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
1390 writer.databuf.appendChar(offsetDelta);
1391 if (writer.debugstackmap) {
1392 System.out.print(" offset_delta=" + offsetDelta);
1393 }
1394 }
1395 if (writer.debugstackmap) {
1396 System.out.print(" stack[" + 0 + "]=");
1397 }
1398 writer.writeStackMapType(stack);
1399 }
1400 }
1401
1402 static class ChopFrame extends StackMapTableFrame {
1403 final int frameType;
1404 final int offsetDelta;
1405 ChopFrame(int pc, int frameType, int offsetDelta) {
1406 super(pc);
1407 this.frameType = frameType;
1408 this.offsetDelta = offsetDelta;
1409 }
1410 int getFrameType() { return frameType; }
1411 @Override
1412 void write(ClassWriter writer) {
1413 super.write(writer);
1414 writer.databuf.appendChar(offsetDelta);
1415 if (writer.debugstackmap) {
1416 System.out.print(" offset_delta=" + offsetDelta);
1417 }
1418 }
1419 }
1420
1421 static class AppendFrame extends StackMapTableFrame {
1422 final int frameType;
1423 final int offsetDelta;
1424 final Type[] locals;
1425 AppendFrame(int pc, int frameType, int offsetDelta, Type[] locals) {
1426 super(pc);
1427 this.frameType = frameType;
1428 this.offsetDelta = offsetDelta;
1429 this.locals = locals;
1430 }
1431 int getFrameType() { return frameType; }
1432 @Override
1433 void write(ClassWriter writer) {
1434 super.write(writer);
1435 writer.databuf.appendChar(offsetDelta);
1436 if (writer.debugstackmap) {
1437 System.out.print(" offset_delta=" + offsetDelta);
1438 }
1439 for (int i=0; i<locals.length; i++) {
1440 if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1441 writer.writeStackMapType(locals[i]);
1442 }
1443 }
1444 }
1445
1446 static class FullFrame extends StackMapTableFrame {
1447 final int offsetDelta;
1448 final Type[] locals;
1449 final Type[] stack;
1450 FullFrame(int pc, int offsetDelta, Type[] locals, Type[] stack) {
1451 super(pc);
1452 this.offsetDelta = offsetDelta;
1453 this.locals = locals;
1454 this.stack = stack;
1455 }
1456 int getFrameType() { return FULL_FRAME; }
1457 @Override
1458 void write(ClassWriter writer) {
1459 super.write(writer);
1460 writer.databuf.appendChar(offsetDelta);
1461 writer.databuf.appendChar(locals.length);
1462 if (writer.debugstackmap) {
1463 System.out.print(" offset_delta=" + offsetDelta);
1464 System.out.print(" nlocals=" + locals.length);
1465 }
1466 for (int i=0; i<locals.length; i++) {
1467 if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1468 writer.writeStackMapType(locals[i]);
1469 }
1470
1471 writer.databuf.appendChar(stack.length);
1472 if (writer.debugstackmap) { System.out.print(" nstack=" + stack.length); }
1473 for (int i=0; i<stack.length; i++) {
1474 if (writer.debugstackmap) System.out.print(" stack[" + i + "]=");
1475 writer.writeStackMapType(stack[i]);
1476 }
1477 }
1478 }
1479
1480 static class EarlyLarvalFrame extends StackMapTableFrame {
1481 final StackMapTableFrame base;
1482 Set<VarSymbol> unsetFields;
1483
1484 EarlyLarvalFrame(StackMapTableFrame base, Set<VarSymbol> unsetFields) {
1485 super(base.pc);
1486 Assert.check(!(base instanceof EarlyLarvalFrame));
1487 this.base = base;
1488 this.unsetFields = unsetFields == null ? Set.of() : unsetFields;
1489 }
1490
1491 int getFrameType() { return EARLY_LARVAL; }
1492
1493 @Override
1494 void write(ClassWriter writer) {
1495 super.write(writer);
1496 writer.databuf.appendChar(unsetFields.size());
1497 if (writer.debugstackmap) {
1498 System.out.println(" # writing: EarlyLarval stackmap frame with " + unsetFields.size() + " fields");
1499 }
1500 for (VarSymbol vsym : unsetFields) {
1501 int index = writer.poolWriter.putNameAndType(vsym);
1502 writer.databuf.appendChar(index);
1503 if (writer.debugstackmap) {
1504 System.out.println(" #writing unset field: " + index + ", with name: " + vsym.name.toString());
1505 }
1506 }
1507 base.write(writer);
1508 }
1509 }
1510
1511 /** Compare this frame with the previous frame and produce
1512 * an entry of compressed stack map frame. */
1513 static StackMapTableFrame getInstance(Code.StackMapFrame this_frame,
1514 Code.StackMapFrame prevFrame,
1515 Types types,
1516 int pc) {
1517 Type[] locals = this_frame.locals;
1518 Type[] stack = this_frame.stack;
1519 int offset_delta = this_frame.pc - prevFrame.pc - 1;
1520 if (stack.length == 1) {
1521 if (locals.length == prevFrame.locals.length
1522 && compare(prevFrame.locals, locals, types) == 0) {
1523 return new SameLocals1StackItemFrame(pc, offset_delta, stack[0]);
1524 }
1525 } else if (stack.length == 0) {
1526 int diff_length = compare(prevFrame.locals, locals, types);
1527 if (diff_length == 0) {
1528 return new SameFrame(pc, offset_delta);
1529 } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) {
1530 // APPEND
1531 Type[] local_diff = new Type[-diff_length];
1532 for (int i=prevFrame.locals.length, j=0; i<locals.length; i++,j++) {
1533 local_diff[j] = locals[i];
1534 }
1535 return new AppendFrame(pc, SAME_FRAME_EXTENDED - diff_length,
1536 offset_delta,
1537 local_diff);
1538 } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) {
1539 // CHOP
1540 return new ChopFrame(pc, SAME_FRAME_EXTENDED - diff_length,
1541 offset_delta);
1542 }
1543 }
1544 // FULL_FRAME
1545 return new FullFrame(pc, offset_delta, locals, stack);
1546 }
1547
1548 static boolean isInt(Type t) {
1549 return (t.getTag().isStrictSubRangeOf(INT) || t.hasTag(BOOLEAN));
1550 }
1551
1552 static boolean isSameType(Type t1, Type t2, Types types) {
1553 if (t1 == null) { return t2 == null; }
1554 if (t2 == null) { return false; }
1555
1556 if (isInt(t1) && isInt(t2)) { return true; }
1557
1558 if (t1.hasTag(UNINITIALIZED_THIS)) {
1559 return t2.hasTag(UNINITIALIZED_THIS);
1560 } else if (t1.hasTag(UNINITIALIZED_OBJECT)) {
1561 if (t2.hasTag(UNINITIALIZED_OBJECT)) {
1562 return ((UninitializedType)t1).offset == ((UninitializedType)t2).offset;
1563 } else {
1564 return false;
1565 }
1648 }
1649 return outFile; // may be null if write failed
1650 }
1651
1652 /** Write class `c' to outstream `out'.
1653 */
1654 public void writeClassFile(OutputStream out, ClassSymbol c)
1655 throws IOException, PoolOverflow, StringOverflow {
1656 Assert.check((c.flags() & COMPOUND) == 0);
1657 databuf.reset();
1658 poolbuf.reset();
1659
1660 Type supertype = types.supertype(c.type);
1661 List<Type> interfaces = types.interfaces(c.type);
1662 List<Type> typarams = c.type.getTypeArguments();
1663
1664 int flags;
1665 if (c.owner.kind == MDL) {
1666 flags = ACC_MODULE;
1667 } else {
1668 long originalFlags = c.flags();
1669 flags = adjustFlags(c, c.flags() & ~(DEFAULT | STRICTFP));
1670 if ((flags & PROTECTED) != 0) flags |= PUBLIC;
1671 flags = flags & ClassFlags;
1672 flags |= (originalFlags & IDENTITY_TYPE) != 0 ? ACC_IDENTITY : flags;
1673 }
1674
1675 if (dumpClassModifiers) {
1676 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1677 pw.println();
1678 pw.println("CLASSFILE " + c.getQualifiedName());
1679 pw.println("---" + flagNames(flags));
1680 }
1681 databuf.appendChar(flags);
1682
1683 if (c.owner.kind == MDL) {
1684 PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage;
1685 databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed)));
1686 } else {
1687 databuf.appendChar(poolWriter.putClass(c));
1688 }
1689 databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0);
1690 databuf.appendChar(interfaces.length());
1691 for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1692 databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym));
1746 acount++;
1747 // Append CompilationID attribute
1748 alenIdx = writeAttr(names.CompilationID);
1749 databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(System.currentTimeMillis()))));
1750 endAttr(alenIdx);
1751 acount++;
1752 }
1753
1754 acount += writeFlagAttrs(c.flags());
1755 acount += writeJavaAnnotations(c.getRawAttributes());
1756 acount += writeTypeAnnotations(c.getRawTypeAttributes(), false);
1757 acount += writeEnclosingMethodAttribute(c);
1758 if (c.owner.kind == MDL) {
1759 acount += writeModuleAttribute(c);
1760 acount += writeFlagAttrs(c.owner.flags() & ~DEPRECATED);
1761 }
1762 acount += writeExtraClassAttributes(c);
1763 acount += writeExtraAttributes(c);
1764
1765 poolbuf.appendInt(JAVA_MAGIC);
1766 boolean markedPreview = preview.isEnabled() && preview.usesPreview(c.sourcefile);
1767 if (markedPreview) {
1768 poolbuf.appendChar(ClassFile.PREVIEW_MINOR_VERSION);
1769 } else {
1770 poolbuf.appendChar(target.minorVersion);
1771 }
1772 poolbuf.appendChar(target.majorVersion);
1773
1774 if (c.owner.kind != MDL) {
1775 if (target.hasNestmateAccess()) {
1776 acount += writeNestMembersIfNeeded(c);
1777 acount += writeNestHostIfNeeded(c);
1778 }
1779 }
1780
1781 if (c.isRecord()) {
1782 acount += writeRecordAttribute(c);
1783 }
1784
1785 if (target.hasSealedClasses()) {
1786 acount += writePermittedSubclassesIfNeeded(c);
1787 }
1788
1789 if (!poolWriter.bootstrapMethods.isEmpty()) {
1790 writeBootstrapMethods();
1791 acount++;
1792 }
1793
1794 if (!poolWriter.innerClasses.isEmpty()) {
1795 writeInnerClasses(markedPreview);
1796 acount++;
1797 }
1798
1799 if (!poolWriter.loadableDescriptors.isEmpty()) {
1800 writeLoadableDescriptorsAttribute();
1801 acount++;
1802 }
1803
1804 endAttrs(acountIdx, acount);
1805
1806 out.write(poolbuf.elems, 0, poolbuf.length);
1807
1808 poolWriter.writePool(out);
1809 poolWriter.reset(); // to save space
1810
1811 out.write(databuf.elems, 0, databuf.length);
1812 }
1813
1814 /**Allows subclasses to write additional class attributes
1815 *
1816 * @return the number of attributes written
1817 */
1818 protected int writeExtraClassAttributes(ClassSymbol c) {
1819 return 0;
1820 }
1821
1822 /**Allows friends to write additional attributes
1823 *
1824 * @return the number of attributes written
1825 */
1826 protected int writeExtraAttributes(Symbol sym) {
1827 int i = 0;
1828 for (ToIntFunction<Symbol> hook : extraAttributeHooks) {
1829 i += hook.applyAsInt(sym);
1830 }
1831 return i;
1832 }
1833
1834 int adjustFlags(Symbol sym, final long flags) {
1835 int result = (int)flags;
1836
1837 // Elide strictfp bit in class files
1838 if (target.obsoleteAccStrict())
1839 result &= ~STRICTFP;
1840
1841 if ((flags & BRIDGE) != 0)
1842 result |= ACC_BRIDGE;
1843 if ((flags & VARARGS) != 0)
1844 result |= ACC_VARARGS;
1845 if ((flags & DEFAULT) != 0)
1846 result &= ~ABSTRACT;
1847 if ((flags & IDENTITY_TYPE) != 0) {
1848 result |= ACC_IDENTITY;
1849 }
1850 if (sym.kind == VAR) {
1851 if ((flags & STRICT) != 0) {
1852 result |= ACC_STRICT;
1853 }
1854 }
1855 return result;
1856 }
1857
1858 long getLastModified(FileObject filename) {
1859 return filename.getLastModified();
1860 }
1861 }
|