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
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
63 /** This class provides operations to map an internal symbol table graph
64 * rooted in a ClassSymbol into a classfile.
65 *
66 * <p><b>This is NOT part of any supported API.
67 * If you write code that depends on this, you do so at your own risk.
68 * This code and its internal interfaces are subject to change or
69 * deletion without notice.</b>
70 */
71 public class ClassWriter extends ClassFile {
72 protected static final Context.Key<ClassWriter> classWriterKey = new Context.Key<>();
73
74 private final Options options;
75
76 /** Switch: verbose output.
77 */
78 private boolean verbose;
79
80 /** Switch: emit source file attribute.
81 */
82 private boolean emitSourceFile;
83
84 /** Switch: generate CharacterRangeTable attribute.
85 */
86 private boolean genCrt;
87
88 /** Switch: describe the generated stackmap.
89 */
90 private boolean debugstackmap;
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 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);
170 names = Names.instance(context);
171 options = Options.instance(context);
172 preview = Preview.instance(context);
173 target = Target.instance(context);
174 source = Source.instance(context);
175 types = Types.instance(context);
176 check = Check.instance(context);
177 fileManager = context.get(JavaFileManager.class);
178 poolWriter = Gen.instance(context).poolWriter;
179
180 verbose = options.isSet(VERBOSE);
181 genCrt = options.isSet(XJCOV);
182 debugstackmap = options.isSet("debug.stackmap");
183
184 emitSourceFile = options.isUnset(G_CUSTOM) ||
185 options.isSet(G_CUSTOM, "source");
186
187 String modifierFlags = options.get("debug.dumpmodifiers");
188 if (modifierFlags != null) {
189 dumpClassModifiers = modifierFlags.indexOf('c') != -1;
190 dumpFieldModifiers = modifierFlags.indexOf('f') != -1;
191 dumpInnerClassModifiers = modifierFlags.indexOf('i') != -1;
192 dumpMethodModifiers = modifierFlags.indexOf('m') != -1;
193 }
194 }
195
196 public void addExtraAttributes(ToIntFunction<Symbol> addExtraAttributes) {
197 extraAttributeHooks = extraAttributeHooks.prepend(addExtraAttributes);
198 }
199
200 /* ****************************************************************
201 * Diagnostics: dump generated class names and modifiers
202 ******************************************************************/
203
204 /** Value of option 'dumpmodifiers' is a string
205 * indicating which modifiers should be dumped for debugging:
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);
260 buf.elems[adr+2] = (byte)((x >> 8) & 0xFF);
261 buf.elems[adr+3] = (byte)((x ) & 0xFF);
262 }
263
264 /* ****************************************************************
265 * Writing the Constant Pool
266 ******************************************************************/
267
268 /** Thrown when the constant pool is over full.
269 */
270 public static class PoolOverflow extends RuntimeException {
271 private static final long serialVersionUID = 0;
272 public PoolOverflow() {}
273 }
274 public static class StringOverflow extends RuntimeException {
275 private static final long serialVersionUID = 0;
276 public final String value;
277 public StringOverflow(String s) {
278 value = s;
279 }
280 }
281
282 /* ****************************************************************
283 * Writing Attributes
284 ******************************************************************/
285
286 /** Write header for an attribute to data buffer and return
287 * position past attribute length index.
288 */
289 public int writeAttr(Name attrName) {
290 int index = poolWriter.putName(attrName);
291 databuf.appendChar(index);
292 databuf.appendInt(0);
293 return databuf.length;
294 }
295
296 /** Fill in attribute length.
297 */
298 public void endAttr(int index) {
299 putInt(databuf, index - 4, databuf.length - index);
300 }
301
302 /** Leave space for attribute count and return index for
303 * number of attributes field.
304 */
305 int beginAttrs() {
306 databuf.appendChar(0);
307 return databuf.length;
308 }
309
310 /** Fill in number of attributes.
311 */
312 void endAttrs(int index, int count) {
313 putChar(databuf, index - 2, count);
314 }
315
316 /** Write the EnclosingMethod attribute if needed.
317 * Returns the number of attributes written (0 or 1).
318 */
319 int writeEnclosingMethodAttribute(ClassSymbol c) {
320 return writeEnclosingMethodAttribute(names.EnclosingMethod, c);
321 }
322
323 /** Write the EnclosingMethod attribute with a specified name.
324 * Returns the number of attributes written (0 or 1).
325 */
326 protected int writeEnclosingMethodAttribute(Name attributeName, ClassSymbol c) {
327 if (c.owner.kind != MTH && // neither a local class
328 c.name != names.empty) // nor anonymous
329 return 0;
330
331 int alenIdx = writeAttr(attributeName);
332 ClassSymbol enclClass = c.owner.enclClass();
333 MethodSymbol enclMethod =
334 ((c.owner.flags() & BLOCK) != 0 // local to init block
335 || c.owner.kind != MTH) // or member init
336 ? null
337 : ((MethodSymbol)c.owner).originalEnclosingMethod();
338 databuf.appendChar(poolWriter.putClass(enclClass));
339 databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(enclMethod));
340 endAttr(alenIdx);
341 return 1;
342 }
343
344 /** Write flag attributes; return number of attributes written.
345 */
346 int writeFlagAttrs(long flags) {
347 int acount = 0;
348 if ((flags & DEPRECATED) != 0) {
349 int alenIdx = writeAttr(names.Deprecated);
350 endAttr(alenIdx);
351 acount++;
352 }
353 return acount;
354 }
355
356 /** Write member (field or method) attributes;
357 * return number of attributes written.
358 */
359 int writeMemberAttrs(Symbol sym, boolean isRecordComponent) {
360 int acount = 0;
361 if (!isRecordComponent) {
362 acount = writeFlagAttrs(sym.flags());
363 }
364 long flags = sym.flags();
365 if ((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC &&
366 (flags & ANONCONSTR) == 0 &&
367 (!types.isSameType(sym.type, sym.erasure(types)) ||
368 poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()))) {
369 // note that a local class with captured variables
370 // will get a signature attribute
371 int alenIdx = writeAttr(names.Signature);
372 databuf.appendChar(poolWriter.putSignature(sym));
373 endAttr(alenIdx);
374 acount++;
375 }
376 acount += writeJavaAnnotations(sym.getRawAttributes());
377 acount += writeTypeAnnotations(sym.getRawTypeAttributes(), false);
378 return acount;
379 }
380
381 /**
382 * Write method parameter names attribute.
383 */
384 int writeMethodParametersAttr(MethodSymbol m, boolean writeParamNames) {
385 MethodType ty = m.externalType(types).asMethodType();
386 final int allparams = ty.argtypes.size();
387 if (m.params != null && allparams != 0) {
388 final int attrIndex = writeAttr(names.MethodParameters);
389 databuf.appendByte(allparams);
390 // Write extra parameters first
391 for (VarSymbol s : m.extraParams) {
392 final int flags =
393 ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
394 ((int) m.flags() & SYNTHETIC);
395 if (writeParamNames)
396 databuf.appendChar(poolWriter.putName(s.name));
397 else
398 databuf.appendChar(0);
399 databuf.appendChar(flags);
400 }
401 // Now write the real parameters
402 for (VarSymbol s : m.params) {
403 final int flags =
404 ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
405 ((int) m.flags() & SYNTHETIC);
406 if (writeParamNames)
407 databuf.appendChar(poolWriter.putName(s.name));
408 else
409 databuf.appendChar(0);
410 databuf.appendChar(flags);
411 }
412 // Now write the captured locals
413 for (VarSymbol s : m.capturedLocals) {
414 final int flags =
415 ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
416 ((int) m.flags() & SYNTHETIC);
417 if (writeParamNames)
418 databuf.appendChar(poolWriter.putName(s.name));
419 else
420 databuf.appendChar(0);
421 databuf.appendChar(flags);
422 }
423 endAttr(attrIndex);
424 return 1;
425 } else
426 return 0;
427 }
428
429 private void writeParamAnnotations(List<VarSymbol> params,
430 RetentionPolicy retention) {
431 databuf.appendByte(params.length());
432 for (VarSymbol s : params) {
433 ListBuffer<Attribute.Compound> buf = new ListBuffer<>();
434 for (Attribute.Compound a : s.getRawAttributes())
435 if (types.getRetention(a) == retention)
436 buf.append(a);
437 databuf.appendChar(buf.length());
438 for (Attribute.Compound a : buf)
439 writeCompoundAttribute(a);
440 }
441
442 }
443
444 private void writeParamAnnotations(MethodSymbol m,
445 RetentionPolicy retention) {
446 databuf.appendByte(m.params.length());
447 writeParamAnnotations(m.params, retention);
448 }
449
450 /** Write method parameter annotations;
451 * return number of attributes written.
452 */
453 int writeParameterAttrs(List<VarSymbol> vars) {
454 boolean hasVisible = false;
455 boolean hasInvisible = false;
456 if (vars != null) {
457 for (VarSymbol s : vars) {
458 for (Attribute.Compound a : s.getRawAttributes()) {
459 switch (types.getRetention(a)) {
460 case SOURCE: break;
461 case CLASS: hasInvisible = true; break;
462 case RUNTIME: hasVisible = true; break;
463 default: // /* fail soft */ throw new AssertionError(vis);
464 }
465 }
466 }
467 }
468
469 int attrCount = 0;
470 if (hasVisible) {
471 int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations);
472 writeParamAnnotations(vars, RetentionPolicy.RUNTIME);
473 endAttr(attrIndex);
474 attrCount++;
475 }
476 if (hasInvisible) {
477 int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations);
478 writeParamAnnotations(vars, RetentionPolicy.CLASS);
479 endAttr(attrIndex);
480 attrCount++;
481 }
482 return attrCount;
483 }
484
485 /* ********************************************************************
486 * Writing Java-language annotations (aka metadata, attributes)
487 **********************************************************************/
488
489 /** Write Java-language annotations; return number of JVM
490 * attributes written (zero or one).
491 */
492 int writeJavaAnnotations(List<Attribute.Compound> attrs) {
493 if (attrs.isEmpty()) return 0;
494 ListBuffer<Attribute.Compound> visibles = new ListBuffer<>();
495 ListBuffer<Attribute.Compound> invisibles = new ListBuffer<>();
496 for (Attribute.Compound a : attrs) {
497 switch (types.getRetention(a)) {
498 case SOURCE: break;
499 case CLASS: invisibles.append(a); break;
500 case RUNTIME: visibles.append(a); break;
501 default: // /* fail soft */ throw new AssertionError(vis);
502 }
503 }
504
505 int attrCount = 0;
506 if (visibles.length() != 0) {
507 int attrIndex = writeAttr(names.RuntimeVisibleAnnotations);
508 databuf.appendChar(visibles.length());
509 for (Attribute.Compound a : visibles)
510 writeCompoundAttribute(a);
511 endAttr(attrIndex);
512 attrCount++;
513 }
514 if (invisibles.length() != 0) {
515 int attrIndex = writeAttr(names.RuntimeInvisibleAnnotations);
516 databuf.appendChar(invisibles.length());
517 for (Attribute.Compound a : invisibles)
518 writeCompoundAttribute(a);
519 endAttr(attrIndex);
520 attrCount++;
521 }
522 return attrCount;
523 }
524
525 int writeTypeAnnotations(List<Attribute.TypeCompound> typeAnnos, boolean inCode) {
526 if (typeAnnos.isEmpty()) return 0;
527
528 ListBuffer<Attribute.TypeCompound> visibles = new ListBuffer<>();
529 ListBuffer<Attribute.TypeCompound> invisibles = new ListBuffer<>();
530
531 for (Attribute.TypeCompound tc : typeAnnos) {
532 if (tc.hasUnknownPosition()) {
533 boolean fixed = tc.tryFixPosition();
534
535 // Could we fix it?
536 if (!fixed) {
537 // This happens for nested types like @A Outer. @B Inner.
538 // For method parameters we get the annotation twice! Once with
539 // a valid position, once unknown.
540 // TODO: find a cleaner solution.
541 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
542 pw.println("ClassWriter: Position UNKNOWN in type annotation: " + tc);
543 continue;
544 }
545 }
546
547 if (tc.position.type.isLocal() != inCode)
548 continue;
549 if (!tc.position.emitToClassfile())
550 continue;
551 switch (types.getRetention(tc)) {
552 case SOURCE: break;
553 case CLASS: invisibles.append(tc); break;
554 case RUNTIME: visibles.append(tc); break;
555 default: // /* fail soft */ throw new AssertionError(vis);
556 }
557 }
558
559 int attrCount = 0;
560 if (visibles.length() != 0) {
561 int attrIndex = writeAttr(names.RuntimeVisibleTypeAnnotations);
562 databuf.appendChar(visibles.length());
563 for (Attribute.TypeCompound p : visibles)
564 writeTypeAnnotation(p);
565 endAttr(attrIndex);
566 attrCount++;
567 }
568
569 if (invisibles.length() != 0) {
570 int attrIndex = writeAttr(names.RuntimeInvisibleTypeAnnotations);
571 databuf.appendChar(invisibles.length());
572 for (Attribute.TypeCompound p : invisibles)
573 writeTypeAnnotation(p);
574 endAttr(attrIndex);
575 attrCount++;
576 }
577
578 return attrCount;
579 }
580
581 /** A visitor to write an attribute including its leading
582 * single-character marker.
583 */
584 class AttributeWriter implements Attribute.Visitor {
585 public void visitConstant(Attribute.Constant _value) {
586 if (_value.type.getTag() == CLASS) {
587 Assert.check(_value.value instanceof String);
588 String s = (String)_value.value;
589 databuf.appendByte('s');
590 databuf.appendChar(poolWriter.putName(names.fromString(s)));
591 } else {
592 switch (_value.type.getTag()) {
593 case BYTE:
594 databuf.appendByte('B');
595 break;
596 case CHAR:
597 databuf.appendByte('C');
598 break;
599 case SHORT:
600 databuf.appendByte('S');
601 break;
602 case INT:
603 databuf.appendByte('I');
604 break;
605 case LONG:
606 databuf.appendByte('J');
607 break;
608 case FLOAT:
609 databuf.appendByte('F');
610 break;
611 case DOUBLE:
612 databuf.appendByte('D');
613 break;
614 case BOOLEAN:
615 databuf.appendByte('Z');
616 break;
617 default:
618 throw new AssertionError(_value.type);
619 }
620 databuf.appendChar(poolWriter.putConstant(_value.value));
621 }
622 }
623 public void visitEnum(Attribute.Enum e) {
624 databuf.appendByte('e');
625 databuf.appendChar(poolWriter.putDescriptor(e.value.type));
626 databuf.appendChar(poolWriter.putName(e.value.name));
627 }
628 public void visitClass(Attribute.Class clazz) {
629 databuf.appendByte('c');
630 databuf.appendChar(poolWriter.putDescriptor(clazz.classType));
631 }
632 public void visitCompound(Attribute.Compound compound) {
633 databuf.appendByte('@');
634 writeCompoundAttribute(compound);
635 }
636 public void visitError(Attribute.Error x) {
637 throw new AssertionError(x);
638 }
639 public void visitArray(Attribute.Array array) {
640 databuf.appendByte('[');
641 databuf.appendChar(array.values.length);
642 for (Attribute a : array.values) {
643 a.accept(this);
644 }
645 }
646 }
647 AttributeWriter awriter = new AttributeWriter();
648
649 /** Write a compound attribute excluding the '@' marker. */
650 void writeCompoundAttribute(Attribute.Compound c) {
651 databuf.appendChar(poolWriter.putDescriptor(c.type));
652 databuf.appendChar(c.values.length());
653 for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) {
654 checkAnnotationArraySizeInternal(p);
655 databuf.appendChar(poolWriter.putName(p.fst.name));
656 p.snd.accept(awriter);
657 }
658 }
659
660 private void checkAnnotationArraySizeInternal(Pair<Symbol.MethodSymbol, Attribute> p) {
661 if (p.snd instanceof Attribute.Array arrAttr &&
662 arrAttr.values.length > ClassFile.MAX_ANNOTATIONS) {
663 log.error(Errors.AnnotationArrayTooLarge(p.fst.owner));
664 }
665 }
666
667 void writeTypeAnnotation(Attribute.TypeCompound c) {
668 writePosition(c.position);
669 writeCompoundAttribute(c);
670 }
671
672 void writePosition(TypeAnnotationPosition p) {
673 databuf.appendByte(p.type.targetTypeValue()); // TargetType tag is a byte
674 switch (p.type) {
675 // instanceof
676 case INSTANCEOF:
677 // new expression
678 case NEW:
679 // constructor/method reference receiver
680 case CONSTRUCTOR_REFERENCE:
681 case METHOD_REFERENCE:
682 databuf.appendChar(p.offset);
683 break;
684 // local variable
685 case LOCAL_VARIABLE:
686 // resource variable
687 case RESOURCE_VARIABLE:
688 databuf.appendChar(p.lvarOffset.length); // for table length
689 for (int i = 0; i < p.lvarOffset.length; ++i) {
690 databuf.appendChar(p.lvarOffset[i]);
691 databuf.appendChar(p.lvarLength[i]);
692 databuf.appendChar(p.lvarIndex[i]);
693 }
694 break;
695 // exception parameter
696 case EXCEPTION_PARAMETER:
697 databuf.appendChar(p.getExceptionIndex());
698 break;
699 // method receiver
700 case METHOD_RECEIVER:
701 // Do nothing
702 break;
703 // type parameter
704 case CLASS_TYPE_PARAMETER:
705 case METHOD_TYPE_PARAMETER:
706 databuf.appendByte(p.parameter_index);
707 break;
708 // type parameter bound
709 case CLASS_TYPE_PARAMETER_BOUND:
710 case METHOD_TYPE_PARAMETER_BOUND:
711 databuf.appendByte(p.parameter_index);
712 databuf.appendByte(p.bound_index);
713 break;
714 // class extends or implements clause
715 case CLASS_EXTENDS:
716 databuf.appendChar(p.type_index);
717 break;
718 // throws
719 case THROWS:
720 databuf.appendChar(p.type_index);
721 break;
722 // method parameter
723 case METHOD_FORMAL_PARAMETER:
724 databuf.appendByte(p.parameter_index);
725 break;
726 // type cast
727 case CAST:
728 // method/constructor/reference type argument
729 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
730 case METHOD_INVOCATION_TYPE_ARGUMENT:
731 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
732 case METHOD_REFERENCE_TYPE_ARGUMENT:
733 databuf.appendChar(p.offset);
734 databuf.appendByte(p.type_index);
735 break;
736 // We don't need to worry about these
737 case METHOD_RETURN:
738 case FIELD:
739 break;
740 case UNKNOWN:
741 throw new AssertionError("jvm.ClassWriter: UNKNOWN target type should never occur!");
742 default:
743 throw new AssertionError("jvm.ClassWriter: Unknown target type for position: " + p);
744 }
745
746 { // Append location data for generics/arrays.
747 databuf.appendByte(p.location.size());
748 java.util.List<Integer> loc = TypeAnnotationPosition.getBinaryFromTypePath(p.location);
749 for (int i : loc)
750 databuf.appendByte((byte)i);
751 }
752 }
753
754 /* ********************************************************************
755 * Writing module attributes
756 **********************************************************************/
757
758 /** Write the Module attribute if needed.
759 * Returns the number of attributes written (0 or 1).
760 */
761 int writeModuleAttribute(ClassSymbol c) {
762 ModuleSymbol m = (ModuleSymbol) c.owner;
763
764 int alenIdx = writeAttr(names.Module);
765
766 databuf.appendChar(poolWriter.putModule(m));
767 databuf.appendChar(ModuleFlags.value(m.flags)); // module_flags
768 databuf.appendChar(m.version != null ? poolWriter.putName(m.version) : 0);
769
770 ListBuffer<RequiresDirective> requires = new ListBuffer<>();
771 for (RequiresDirective r: m.requires) {
772 if (!r.flags.contains(RequiresFlag.EXTRA))
773 requires.add(r);
774 }
775 databuf.appendChar(requires.size());
776 for (RequiresDirective r: requires) {
777 databuf.appendChar(poolWriter.putModule(r.module));
778 databuf.appendChar(RequiresFlag.value(r.flags));
779 databuf.appendChar(r.module.version != null ? poolWriter.putName(r.module.version) : 0);
780 }
781
782 List<ExportsDirective> exports = m.exports;
783 databuf.appendChar(exports.size());
784 for (ExportsDirective e: exports) {
785 databuf.appendChar(poolWriter.putPackage(e.packge));
786 databuf.appendChar(ExportsFlag.value(e.flags));
787 if (e.modules == null) {
788 databuf.appendChar(0);
789 } else {
790 databuf.appendChar(e.modules.size());
791 for (ModuleSymbol msym: e.modules) {
792 databuf.appendChar(poolWriter.putModule(msym));
793 }
794 }
795 }
796
797 List<OpensDirective> opens = m.opens;
798 databuf.appendChar(opens.size());
799 for (OpensDirective o: opens) {
800 databuf.appendChar(poolWriter.putPackage(o.packge));
801 databuf.appendChar(OpensFlag.value(o.flags));
802 if (o.modules == null) {
803 databuf.appendChar(0);
804 } else {
805 databuf.appendChar(o.modules.size());
806 for (ModuleSymbol msym: o.modules) {
807 databuf.appendChar(poolWriter.putModule(msym));
808 }
809 }
810 }
811
812 List<UsesDirective> uses = m.uses;
813 databuf.appendChar(uses.size());
814 for (UsesDirective s: uses) {
815 databuf.appendChar(poolWriter.putClass(s.service));
816 }
817
818 // temporary fix to merge repeated provides clause for same service;
819 // eventually this should be disallowed when analyzing the module,
820 // so that each service type only appears once.
821 Map<ClassSymbol, Set<ClassSymbol>> mergedProvides = new LinkedHashMap<>();
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 */
900 int writeNestMembersIfNeeded(ClassSymbol csym) {
901 ListBuffer<ClassSymbol> nested = new ListBuffer<>();
902 listNested(csym, nested);
903 Set<ClassSymbol> nestedUnique = new LinkedHashSet<>(nested);
904 if (csym.owner.kind == PCK && !nestedUnique.isEmpty()) {
905 int alenIdx = writeAttr(names.NestMembers);
906 databuf.appendChar(nestedUnique.size());
907 for (ClassSymbol s : nestedUnique) {
908 databuf.appendChar(poolWriter.putClass(s));
909 }
910 endAttr(alenIdx);
911 return 1;
912 }
913 return 0;
914 }
915
916 /**
917 * Write NestHost attribute (if needed)
918 */
919 int writeNestHostIfNeeded(ClassSymbol csym) {
920 if (csym.owner.kind != PCK) {
921 int alenIdx = writeAttr(names.NestHost);
922 databuf.appendChar(poolWriter.putClass(csym.outermostClass()));
923 endAttr(alenIdx);
924 return 1;
925 }
926 return 0;
927 }
928
929 private void listNested(Symbol sym, ListBuffer<ClassSymbol> seen) {
930 if (sym.kind != TYP) return;
931 ClassSymbol csym = (ClassSymbol)sym;
932 if (csym.owner.kind != PCK) {
933 seen.add(csym);
934 }
935 if (csym.members() != null) {
936 for (Symbol s : sym.members().getSymbols()) {
937 listNested(s, seen);
938 }
939 }
940 if (csym.trans_local != null) {
941 for (Symbol s : csym.trans_local) {
942 listNested(s, seen);
943 }
944 }
945 }
946
947 /** Write "PermittedSubclasses" attribute.
948 */
949 int writePermittedSubclassesIfNeeded(ClassSymbol csym) {
950 if (csym.getPermittedSubclasses().nonEmpty()) {
951 int alenIdx = writeAttr(names.PermittedSubclasses);
952 databuf.appendChar(csym.getPermittedSubclasses().size());
953 for (Type t : csym.getPermittedSubclasses()) {
954 databuf.appendChar(poolWriter.putClass((ClassSymbol) t.tsym));
955 }
956 endAttr(alenIdx);
957 return 1;
958 }
959 return 0;
960 }
961
962 /** Write "bootstrapMethods" attribute.
963 */
964 void writeBootstrapMethods() {
965 int alenIdx = writeAttr(names.BootstrapMethods);
966 int lastBootstrapMethods;
967 do {
968 lastBootstrapMethods = poolWriter.bootstrapMethods.size();
969 for (BsmKey bsmKey : java.util.List.copyOf(poolWriter.bootstrapMethods.keySet())) {
970 for (LoadableConstant arg : bsmKey.staticArgs) {
971 poolWriter.putConstant(arg);
972 }
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);
1070 m.defaultValue.accept(awriter);
1071 endAttr(alenIdx);
1072 acount++;
1073 }
1074 if (target.hasMethodParameters()) {
1075 if (!m.isLambdaMethod()) { // Per JDK-8138729, do not emit parameters table for lambda bodies.
1076 boolean requiresParamNames = requiresParamNames(m);
1077 if (requiresParamNames || requiresParamFlags(m))
1078 acount += writeMethodParametersAttr(m, requiresParamNames);
1079 }
1080 }
1081 acount += writeMemberAttrs(m, false);
1082 if (!m.isLambdaMethod())
1083 acount += writeParameterAttrs(m.params);
1084 acount += writeExtraAttributes(m);
1085 endAttrs(acountIdx, acount);
1086 }
1087
1088 private boolean requiresParamNames(MethodSymbol m) {
1089 if (options.isSet(PARAMETERS))
1090 return true;
1091 if (m.isConstructor() && (m.flags_field & RECORD) != 0)
1092 return true;
1093 return false;
1094 }
1095
1096 private boolean requiresParamFlags(MethodSymbol m) {
1097 if (!m.extraParams.isEmpty()) {
1098 return m.extraParams.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0);
1099 }
1100 if (m.params != null) {
1101 // parameter is stored in params for Enum#valueOf(name)
1102 return m.params.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0);
1103 }
1104 return false;
1105 }
1106
1107 /** Write code attribute of method.
1108 */
1109 void writeCode(Code code) {
1110 databuf.appendChar(code.max_stack);
1111 databuf.appendChar(code.max_locals);
1112 databuf.appendInt(code.cp);
1113 databuf.appendBytes(code.code, 0, code.cp);
1114 databuf.appendChar(code.catchInfo.length());
1115 for (List<char[]> l = code.catchInfo.toList();
1116 l.nonEmpty();
1117 l = l.tail) {
1118 for (int i = 0; i < l.head.length; i++)
1119 databuf.appendChar(l.head[i]);
1120 }
1121 int acountIdx = beginAttrs();
1122 int acount = 0;
1123
1124 if (code.lineInfo.nonEmpty()) {
1125 int alenIdx = writeAttr(names.LineNumberTable);
1126 databuf.appendChar(code.lineInfo.length());
1127 for (List<char[]> l = code.lineInfo.reverse();
1128 l.nonEmpty();
1129 l = l.tail)
1130 for (int i = 0; i < l.head.length; i++)
1131 databuf.appendChar(l.head[i]);
1132 endAttr(alenIdx);
1133 acount++;
1134 }
1135
1136 if (genCrt && (code.crt != null)) {
1137 CRTable crt = code.crt;
1138 int alenIdx = writeAttr(names.CharacterRangeTable);
1139 int crtIdx = beginAttrs();
1140 int crtEntries = crt.writeCRT(databuf, code.lineMap, log);
1141 endAttrs(crtIdx, crtEntries);
1142 endAttr(alenIdx);
1143 acount++;
1144 }
1145
1146 // counter for number of generic local variables
1147 if (code.varDebugInfo && code.varBufferSize > 0) {
1148 int nGenericVars = 0;
1149 int alenIdx = writeAttr(names.LocalVariableTable);
1150 databuf.appendChar(code.getLVTSize());
1151 for (int i=0; i<code.varBufferSize; i++) {
1152 Code.LocalVar var = code.varBuffer[i];
1153
1154 for (Code.LocalVar.Range r: var.aliveRanges) {
1155 // write variable info
1156 Assert.check(r.start_pc >= 0
1157 && r.start_pc <= code.cp);
1158 databuf.appendChar(r.start_pc);
1159 Assert.check(r.length > 0
1160 && (r.start_pc + r.length) <= code.cp);
1161 databuf.appendChar(r.length);
1162 VarSymbol sym = var.sym;
1163 databuf.appendChar(poolWriter.putName(sym.name));
1164 databuf.appendChar(poolWriter.putDescriptor(sym));
1165 databuf.appendChar(var.reg);
1166 if (needsLocalVariableTypeEntry(var.sym.type)) {
1167 nGenericVars++;
1168 }
1169 }
1170 }
1171 endAttr(alenIdx);
1172 acount++;
1173
1174 if (nGenericVars > 0) {
1175 alenIdx = writeAttr(names.LocalVariableTypeTable);
1176 databuf.appendChar(nGenericVars);
1177 int count = 0;
1178
1179 for (int i=0; i<code.varBufferSize; i++) {
1180 Code.LocalVar var = code.varBuffer[i];
1181 VarSymbol sym = var.sym;
1182 if (!needsLocalVariableTypeEntry(sym.type))
1183 continue;
1184 for (Code.LocalVar.Range r : var.aliveRanges) {
1185 // write variable info
1186 databuf.appendChar(r.start_pc);
1187 databuf.appendChar(r.length);
1188 databuf.appendChar(poolWriter.putName(sym.name));
1189 databuf.appendChar(poolWriter.putSignature(sym));
1190 databuf.appendChar(var.reg);
1191 count++;
1192 }
1193 }
1194 Assert.check(count == nGenericVars);
1195 endAttr(alenIdx);
1196 acount++;
1197 }
1198 }
1199
1200 if (code.stackMapBufferSize > 0) {
1201 if (debugstackmap) System.out.println("Stack map for " + code.meth);
1202 int alenIdx = writeAttr(code.stackMap.getAttributeName(names));
1203 writeStackMap(code);
1204 endAttr(alenIdx);
1205 acount++;
1206 }
1207
1208 acount += writeTypeAnnotations(code.meth.getRawTypeAttributes(), true);
1209
1210 endAttrs(acountIdx, acount);
1211 }
1212 //where
1213 private boolean needsLocalVariableTypeEntry(Type t) {
1214 //a local variable needs a type-entry if its type T is generic
1215 //(i.e. |T| != T) and if it's not an non-denotable type (non-denotable
1216 // types are not supported in signature attribute grammar!)
1217 return !types.isSameType(t, types.erasure(t)) &&
1218 check.checkDenotable(t);
1219 }
1220
1221 void writeStackMap(Code code) {
1222 int nframes = code.stackMapBufferSize;
1223 if (debugstackmap) System.out.println(" nframes = " + nframes);
1224 databuf.appendChar(nframes);
1225
1226 switch (code.stackMap) {
1227 case CLDC:
1228 for (int i=0; i<nframes; i++) {
1229 if (debugstackmap) System.out.print(" " + i + ":");
1230 Code.StackMapFrame frame = code.stackMapBuffer[i];
1231
1232 // output PC
1233 if (debugstackmap) System.out.print(" pc=" + frame.pc);
1234 databuf.appendChar(frame.pc);
1235
1236 // output locals
1237 int localCount = 0;
1238 for (int j=0; j<frame.locals.length;
1239 j += Code.width(frame.locals[j])) {
1240 localCount++;
1241 }
1242 if (debugstackmap) System.out.print(" nlocals=" +
1243 localCount);
1244 databuf.appendChar(localCount);
1245 for (int j=0; j<frame.locals.length;
1246 j += Code.width(frame.locals[j])) {
1247 if (debugstackmap) System.out.print(" local[" + j + "]=");
1248 writeStackMapType(frame.locals[j]);
1249 }
1250
1251 // output stack
1252 int stackCount = 0;
1253 for (int j=0; j<frame.stack.length;
1254 j += Code.width(frame.stack[j])) {
1255 stackCount++;
1256 }
1257 if (debugstackmap) System.out.print(" nstack=" +
1258 stackCount);
1259 databuf.appendChar(stackCount);
1260 for (int j=0; j<frame.stack.length;
1261 j += Code.width(frame.stack[j])) {
1262 if (debugstackmap) System.out.print(" stack[" + j + "]=");
1263 writeStackMapType(frame.stack[j]);
1264 }
1265 if (debugstackmap) System.out.println();
1266 }
1267 break;
1268 case JSR202: {
1269 Assert.checkNull(code.stackMapBuffer);
1270 for (int i=0; i<nframes; i++) {
1271 if (debugstackmap) System.out.print(" " + i + ":");
1272 StackMapTableFrame frame = code.stackMapTableBuffer[i];
1273 frame.write(this);
1274 if (debugstackmap) System.out.println();
1275 }
1276 break;
1277 }
1278 default:
1279 throw new AssertionError("Unexpected stackmap format value");
1280 }
1281 }
1282
1283 //where
1284 void writeStackMapType(Type t) {
1285 if (t == null) {
1286 if (debugstackmap) System.out.print("empty");
1287 databuf.appendByte(0);
1288 }
1289 else switch(t.getTag()) {
1290 case BYTE:
1291 case CHAR:
1292 case SHORT:
1293 case INT:
1294 case BOOLEAN:
1295 if (debugstackmap) System.out.print("int");
1296 databuf.appendByte(1);
1297 break;
1298 case FLOAT:
1299 if (debugstackmap) System.out.print("float");
1300 databuf.appendByte(2);
1301 break;
1302 case DOUBLE:
1303 if (debugstackmap) System.out.print("double");
1304 databuf.appendByte(3);
1305 break;
1306 case LONG:
1307 if (debugstackmap) System.out.print("long");
1308 databuf.appendByte(4);
1309 break;
1310 case BOT: // null
1311 if (debugstackmap) System.out.print("null");
1312 databuf.appendByte(5);
1313 break;
1314 case CLASS:
1315 case ARRAY:
1316 case TYPEVAR:
1317 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1318 databuf.appendByte(7);
1319 databuf.appendChar(poolWriter.putClass(types.erasure(t)));
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 }
1566 } else if (t2.hasTag(UNINITIALIZED_THIS) || t2.hasTag(UNINITIALIZED_OBJECT)) {
1567 return false;
1568 }
1569
1570 return types.isSameType(t1, t2);
1571 }
1572
1573 static int compare(Type[] arr1, Type[] arr2, Types types) {
1574 int diff_length = arr1.length - arr2.length;
1575 if (diff_length > MAX_LOCAL_LENGTH_DIFF || diff_length < -MAX_LOCAL_LENGTH_DIFF) {
1576 return Integer.MAX_VALUE;
1577 }
1578 int len = (diff_length > 0) ? arr2.length : arr1.length;
1579 for (int i=0; i<len; i++) {
1580 if (!isSameType(arr1[i], arr2[i], types)) {
1581 return Integer.MAX_VALUE;
1582 }
1583 }
1584 return diff_length;
1585 }
1586 }
1587
1588 void writeFields(Scope s) {
1589 // process them in reverse sibling order;
1590 // i.e., process them in declaration order.
1591 List<VarSymbol> vars = List.nil();
1592 for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
1593 if (sym.kind == VAR) vars = vars.prepend((VarSymbol)sym);
1594 }
1595 while (vars.nonEmpty()) {
1596 writeField(vars.head);
1597 vars = vars.tail;
1598 }
1599 }
1600
1601 void writeMethods(Scope s) {
1602 List<MethodSymbol> methods = List.nil();
1603 for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
1604 if (sym.kind == MTH && (sym.flags() & HYPOTHETICAL) == 0)
1605 methods = methods.prepend((MethodSymbol)sym);
1606 }
1607 while (methods.nonEmpty()) {
1608 writeMethod(methods.head);
1609 methods = methods.tail;
1610 }
1611 }
1612
1613 /** Emit a class file for a given class.
1614 * @param c The class from which a class file is generated.
1615 */
1616 public JavaFileObject writeClass(ClassSymbol c)
1617 throws IOException, PoolOverflow, StringOverflow
1618 {
1619 String name = (c.owner.kind == MDL ? c.name : c.flatname).toString();
1620 Location outLocn;
1621 if (multiModuleMode) {
1622 ModuleSymbol msym = c.owner.kind == MDL ? (ModuleSymbol) c.owner : c.packge().modle;
1623 outLocn = fileManager.getLocationForModule(CLASS_OUTPUT, msym.name.toString());
1624 } else {
1625 outLocn = CLASS_OUTPUT;
1626 }
1627 JavaFileObject outFile
1628 = fileManager.getJavaFileForOutput(outLocn,
1629 name,
1630 JavaFileObject.Kind.CLASS,
1631 c.sourcefile);
1632 OutputStream out = outFile.openOutputStream();
1633 try {
1634 writeClassFile(out, c);
1635 if (verbose)
1636 log.printVerbose("wrote.file", outFile.getName());
1637 out.close();
1638 out = null;
1639 } catch (InvalidSignatureException ex) {
1640 log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type())));
1641 } finally {
1642 if (out != null) {
1643 // if we are propagating an exception, delete the file
1644 out.close();
1645 outFile.delete();
1646 outFile = null;
1647 }
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));
1693 int fieldsCount = 0;
1694 int methodsCount = 0;
1695 for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
1696 switch (sym.kind) {
1697 case VAR: fieldsCount++; break;
1698 case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
1699 break;
1700 case TYP: poolWriter.enterInner((ClassSymbol)sym); break;
1701 default : Assert.error();
1702 }
1703 }
1704
1705 if (c.trans_local != null) {
1706 for (ClassSymbol local : c.trans_local) {
1707 poolWriter.enterInner(local);
1708 }
1709 }
1710
1711 databuf.appendChar(fieldsCount);
1712 writeFields(c.members());
1713 databuf.appendChar(methodsCount);
1714 writeMethods(c.members());
1715
1716 int acountIdx = beginAttrs();
1717 int acount = 0;
1718
1719 boolean sigReq =
1720 typarams.length() != 0 || supertype.allparams().length() != 0;
1721 for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
1722 sigReq = l.head.allparams().length() != 0;
1723 if (sigReq) {
1724 int alenIdx = writeAttr(names.Signature);
1725 databuf.appendChar(poolWriter.putSignature(c));
1726 endAttr(alenIdx);
1727 acount++;
1728 }
1729
1730 if (c.sourcefile != null && emitSourceFile) {
1731 int alenIdx = writeAttr(names.SourceFile);
1732 // WHM 6/29/1999: Strip file path prefix. We do it here at
1733 // the last possible moment because the sourcefile may be used
1734 // elsewhere in error diagnostics. Fixes 4241573.
1735 String simpleName = PathFileObject.getSimpleName(c.sourcefile);
1736 databuf.appendChar(poolWriter.putName(names.fromString(simpleName)));
1737 endAttr(alenIdx);
1738 acount++;
1739 }
1740
1741 if (genCrt) {
1742 // Append SourceID attribute
1743 int alenIdx = writeAttr(names.SourceID);
1744 databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
1745 endAttr(alenIdx);
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 (sym.kind == TYP) {
1848 /* flags IDENTITY_TYPE and HAS_INIT share the same value, this is why we need first to double check that
1849 * we are dealing with a type
1850 */
1851 if ((flags & IDENTITY_TYPE) != 0) {
1852 result |= ACC_IDENTITY;
1853 }
1854 }
1855 if (sym.kind == VAR) {
1856 if ((flags & STRICT) != 0) {
1857 result |= ACC_STRICT;
1858 }
1859 }
1860 return result;
1861 }
1862
1863 long getLastModified(FileObject filename) {
1864 return filename.getLastModified();
1865 }
1866 }