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
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 SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
150 static final int SAME_FRAME_EXTENDED = 251;
151 static final int FULL_FRAME = 255;
152 static final int MAX_LOCAL_LENGTH_DIFF = 4;
153
154 /** Get the ClassWriter instance for this context. */
155 public static ClassWriter instance(Context context) {
156 ClassWriter instance = context.get(classWriterKey);
157 if (instance == null)
158 instance = new ClassWriter(context);
159 return instance;
160 }
161
162 /** Construct a class writer, given an options table.
163 */
164 @SuppressWarnings("this-escape")
165 protected ClassWriter(Context context) {
166 context.put(classWriterKey, this);
167
168 log = Log.instance(context);
169 names = Names.instance(context);
170 options = Options.instance(context);
171 preview = Preview.instance(context);
172 target = Target.instance(context);
173 source = Source.instance(context);
174 types = Types.instance(context);
175 check = Check.instance(context);
176 fileManager = context.get(JavaFileManager.class);
177 poolWriter = Gen.instance(context).poolWriter;
178
179 verbose = options.isSet(VERBOSE);
180 genCrt = options.isSet(XJCOV);
181 debugstackmap = options.isSet("debug.stackmap");
182
183 emitSourceFile = options.isUnset(G_CUSTOM) ||
184 options.isSet(G_CUSTOM, "source");
185
186 String modifierFlags = options.get("debug.dumpmodifiers");
187 if (modifierFlags != null) {
188 dumpClassModifiers = modifierFlags.indexOf('c') != -1;
189 dumpFieldModifiers = modifierFlags.indexOf('f') != -1;
190 dumpInnerClassModifiers = modifierFlags.indexOf('i') != -1;
191 dumpMethodModifiers = modifierFlags.indexOf('m') != -1;
192 }
193 }
194
195 public void addExtraAttributes(ToIntFunction<Symbol> addExtraAttributes) {
196 extraAttributeHooks = extraAttributeHooks.prepend(addExtraAttributes);
197 }
198
199 /* ****************************************************************
200 * Diagnostics: dump generated class names and modifiers
201 ******************************************************************/
202
203 /** Value of option 'dumpmodifiers' is a string
204 * indicating which modifiers should be dumped for debugging:
205 * 'c' -- classes
206 * 'f' -- fields
207 * 'i' -- innerclass attributes
208 * 'm' -- methods
209 * For example, to dump everything:
210 * javac -XDdumpmodifiers=cifm MyProg.java
211 */
212 private boolean dumpClassModifiers; // -XDdumpmodifiers=c
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);
258 buf.elems[adr+2] = (byte)((x >> 8) & 0xFF);
259 buf.elems[adr+3] = (byte)((x ) & 0xFF);
260 }
261
262 /* ****************************************************************
263 * Writing the Constant Pool
264 ******************************************************************/
265
266 /** Thrown when the constant pool is over full.
267 */
268 public static class PoolOverflow extends RuntimeException {
269 private static final long serialVersionUID = 0;
270 public PoolOverflow() {}
271 }
272 public static class StringOverflow extends RuntimeException {
273 private static final long serialVersionUID = 0;
274 public final String value;
275 public StringOverflow(String s) {
276 value = s;
277 }
278 }
279
280 /* ****************************************************************
281 * Writing Attributes
282 ******************************************************************/
283
284 /** Write header for an attribute to data buffer and return
285 * position past attribute length index.
286 */
287 public int writeAttr(Name attrName) {
288 int index = poolWriter.putName(attrName);
289 databuf.appendChar(index);
290 databuf.appendInt(0);
291 return databuf.length;
292 }
293
294 /** Fill in attribute length.
295 */
296 public void endAttr(int index) {
297 putInt(databuf, index - 4, databuf.length - index);
298 }
299
300 /** Leave space for attribute count and return index for
301 * number of attributes field.
302 */
303 int beginAttrs() {
304 databuf.appendChar(0);
305 return databuf.length;
306 }
307
308 /** Fill in number of attributes.
309 */
310 void endAttrs(int index, int count) {
311 putChar(databuf, index - 2, count);
312 }
313
314 /** Write the EnclosingMethod attribute if needed.
315 * Returns the number of attributes written (0 or 1).
316 */
317 int writeEnclosingMethodAttribute(ClassSymbol c) {
318 return writeEnclosingMethodAttribute(names.EnclosingMethod, c);
319 }
320
321 /** Write the EnclosingMethod attribute with a specified name.
322 * Returns the number of attributes written (0 or 1).
323 */
324 protected int writeEnclosingMethodAttribute(Name attributeName, ClassSymbol c) {
325 if (c.owner.kind != MTH && // neither a local class
326 c.name != names.empty) // nor anonymous
327 return 0;
328
329 int alenIdx = writeAttr(attributeName);
330 ClassSymbol enclClass = c.owner.enclClass();
331 MethodSymbol enclMethod =
332 ((c.owner.flags() & BLOCK) != 0 // local to init block
333 || c.owner.kind != MTH) // or member init
334 ? null
335 : ((MethodSymbol)c.owner).originalEnclosingMethod();
336 databuf.appendChar(poolWriter.putClass(enclClass));
337 databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(enclMethod));
338 endAttr(alenIdx);
339 return 1;
340 }
341
342 /** Write flag attributes; return number of attributes written.
343 */
344 int writeFlagAttrs(long flags) {
345 int acount = 0;
346 if ((flags & DEPRECATED) != 0) {
347 int alenIdx = writeAttr(names.Deprecated);
348 endAttr(alenIdx);
349 acount++;
350 }
351 return acount;
352 }
353
354 /** Write member (field or method) attributes;
355 * return number of attributes written.
356 */
357 int writeMemberAttrs(Symbol sym, boolean isRecordComponent) {
358 int acount = 0;
359 if (!isRecordComponent) {
360 acount = writeFlagAttrs(sym.flags());
361 }
362 long flags = sym.flags();
363 if ((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC &&
364 (flags & ANONCONSTR) == 0 &&
365 (!types.isSameType(sym.type, sym.erasure(types)) ||
366 poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()))) {
367 // note that a local class with captured variables
368 // will get a signature attribute
369 int alenIdx = writeAttr(names.Signature);
370 databuf.appendChar(poolWriter.putSignature(sym));
371 endAttr(alenIdx);
372 acount++;
373 }
374 acount += writeJavaAnnotations(sym.getRawAttributes());
375 acount += writeTypeAnnotations(sym.getRawTypeAttributes(), false);
376 return acount;
377 }
378
379 /**
380 * Write method parameter names attribute.
381 */
382 int writeMethodParametersAttr(MethodSymbol m, boolean writeParamNames) {
383 MethodType ty = m.externalType(types).asMethodType();
384 final int allparams = ty.argtypes.size();
385 if (m.params != null && allparams != 0) {
386 final int attrIndex = writeAttr(names.MethodParameters);
387 databuf.appendByte(allparams);
388 // Write extra parameters first
389 for (VarSymbol s : m.extraParams) {
390 final int flags =
391 ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
392 ((int) m.flags() & SYNTHETIC);
393 if (writeParamNames)
394 databuf.appendChar(poolWriter.putName(s.name));
395 else
396 databuf.appendChar(0);
397 databuf.appendChar(flags);
398 }
399 // Now write the real parameters
400 for (VarSymbol s : m.params) {
401 final int flags =
402 ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
403 ((int) m.flags() & SYNTHETIC);
404 if (writeParamNames)
405 databuf.appendChar(poolWriter.putName(s.name));
406 else
407 databuf.appendChar(0);
408 databuf.appendChar(flags);
409 }
410 // Now write the captured locals
411 for (VarSymbol s : m.capturedLocals) {
412 final int flags =
413 ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
414 ((int) m.flags() & SYNTHETIC);
415 if (writeParamNames)
416 databuf.appendChar(poolWriter.putName(s.name));
417 else
418 databuf.appendChar(0);
419 databuf.appendChar(flags);
420 }
421 endAttr(attrIndex);
422 return 1;
423 } else
424 return 0;
425 }
426
427 private void writeParamAnnotations(List<VarSymbol> params,
428 RetentionPolicy retention) {
429 databuf.appendByte(params.length());
430 for (VarSymbol s : params) {
431 ListBuffer<Attribute.Compound> buf = new ListBuffer<>();
432 for (Attribute.Compound a : s.getRawAttributes())
433 if (types.getRetention(a) == retention)
434 buf.append(a);
435 databuf.appendChar(buf.length());
436 for (Attribute.Compound a : buf)
437 writeCompoundAttribute(a);
438 }
439
440 }
441
442 private void writeParamAnnotations(MethodSymbol m,
443 RetentionPolicy retention) {
444 databuf.appendByte(m.params.length());
445 writeParamAnnotations(m.params, retention);
446 }
447
448 /** Write method parameter annotations;
449 * return number of attributes written.
450 */
451 int writeParameterAttrs(List<VarSymbol> vars) {
452 boolean hasVisible = false;
453 boolean hasInvisible = false;
454 if (vars != null) {
455 for (VarSymbol s : vars) {
456 for (Attribute.Compound a : s.getRawAttributes()) {
457 switch (types.getRetention(a)) {
458 case SOURCE: break;
459 case CLASS: hasInvisible = true; break;
460 case RUNTIME: hasVisible = true; break;
461 default: // /* fail soft */ throw new AssertionError(vis);
462 }
463 }
464 }
465 }
466
467 int attrCount = 0;
468 if (hasVisible) {
469 int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations);
470 writeParamAnnotations(vars, RetentionPolicy.RUNTIME);
471 endAttr(attrIndex);
472 attrCount++;
473 }
474 if (hasInvisible) {
475 int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations);
476 writeParamAnnotations(vars, RetentionPolicy.CLASS);
477 endAttr(attrIndex);
478 attrCount++;
479 }
480 return attrCount;
481 }
482
483 /* ********************************************************************
484 * Writing Java-language annotations (aka metadata, attributes)
485 **********************************************************************/
486
487 /** Write Java-language annotations; return number of JVM
488 * attributes written (zero or one).
489 */
490 int writeJavaAnnotations(List<Attribute.Compound> attrs) {
491 if (attrs.isEmpty()) return 0;
492 ListBuffer<Attribute.Compound> visibles = new ListBuffer<>();
493 ListBuffer<Attribute.Compound> invisibles = new ListBuffer<>();
494 for (Attribute.Compound a : attrs) {
495 switch (types.getRetention(a)) {
496 case SOURCE: break;
497 case CLASS: invisibles.append(a); break;
498 case RUNTIME: visibles.append(a); break;
499 default: // /* fail soft */ throw new AssertionError(vis);
500 }
501 }
502
503 int attrCount = 0;
504 if (visibles.length() != 0) {
505 int attrIndex = writeAttr(names.RuntimeVisibleAnnotations);
506 databuf.appendChar(visibles.length());
507 for (Attribute.Compound a : visibles)
508 writeCompoundAttribute(a);
509 endAttr(attrIndex);
510 attrCount++;
511 }
512 if (invisibles.length() != 0) {
513 int attrIndex = writeAttr(names.RuntimeInvisibleAnnotations);
514 databuf.appendChar(invisibles.length());
515 for (Attribute.Compound a : invisibles)
516 writeCompoundAttribute(a);
517 endAttr(attrIndex);
518 attrCount++;
519 }
520 return attrCount;
521 }
522
523 int writeTypeAnnotations(List<Attribute.TypeCompound> typeAnnos, boolean inCode) {
524 if (typeAnnos.isEmpty()) return 0;
525
526 ListBuffer<Attribute.TypeCompound> visibles = new ListBuffer<>();
527 ListBuffer<Attribute.TypeCompound> invisibles = new ListBuffer<>();
528
529 for (Attribute.TypeCompound tc : typeAnnos) {
530 if (tc.hasUnknownPosition()) {
531 boolean fixed = tc.tryFixPosition();
532
533 // Could we fix it?
534 if (!fixed) {
535 // This happens for nested types like @A Outer. @B Inner.
536 // For method parameters we get the annotation twice! Once with
537 // a valid position, once unknown.
538 // TODO: find a cleaner solution.
539 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
540 pw.println("ClassWriter: Position UNKNOWN in type annotation: " + tc);
541 continue;
542 }
543 }
544
545 if (tc.position.type.isLocal() != inCode)
546 continue;
547 if (!tc.position.emitToClassfile())
548 continue;
549 switch (types.getRetention(tc)) {
550 case SOURCE: break;
551 case CLASS: invisibles.append(tc); break;
552 case RUNTIME: visibles.append(tc); break;
553 default: // /* fail soft */ throw new AssertionError(vis);
554 }
555 }
556
557 int attrCount = 0;
558 if (visibles.length() != 0) {
559 int attrIndex = writeAttr(names.RuntimeVisibleTypeAnnotations);
560 databuf.appendChar(visibles.length());
561 for (Attribute.TypeCompound p : visibles)
562 writeTypeAnnotation(p);
563 endAttr(attrIndex);
564 attrCount++;
565 }
566
567 if (invisibles.length() != 0) {
568 int attrIndex = writeAttr(names.RuntimeInvisibleTypeAnnotations);
569 databuf.appendChar(invisibles.length());
570 for (Attribute.TypeCompound p : invisibles)
571 writeTypeAnnotation(p);
572 endAttr(attrIndex);
573 attrCount++;
574 }
575
576 return attrCount;
577 }
578
579 /** A visitor to write an attribute including its leading
580 * single-character marker.
581 */
582 class AttributeWriter implements Attribute.Visitor {
583 public void visitConstant(Attribute.Constant _value) {
584 if (_value.type.getTag() == CLASS) {
585 Assert.check(_value.value instanceof String);
586 String s = (String)_value.value;
587 databuf.appendByte('s');
588 databuf.appendChar(poolWriter.putName(names.fromString(s)));
589 } else {
590 switch (_value.type.getTag()) {
591 case BYTE:
592 databuf.appendByte('B');
593 break;
594 case CHAR:
595 databuf.appendByte('C');
596 break;
597 case SHORT:
598 databuf.appendByte('S');
599 break;
600 case INT:
601 databuf.appendByte('I');
602 break;
603 case LONG:
604 databuf.appendByte('J');
605 break;
606 case FLOAT:
607 databuf.appendByte('F');
608 break;
609 case DOUBLE:
610 databuf.appendByte('D');
611 break;
612 case BOOLEAN:
613 databuf.appendByte('Z');
614 break;
615 default:
616 throw new AssertionError(_value.type);
617 }
618 databuf.appendChar(poolWriter.putConstant(_value.value));
619 }
620 }
621 public void visitEnum(Attribute.Enum e) {
622 databuf.appendByte('e');
623 databuf.appendChar(poolWriter.putDescriptor(e.value.type));
624 databuf.appendChar(poolWriter.putName(e.value.name));
625 }
626 public void visitClass(Attribute.Class clazz) {
627 databuf.appendByte('c');
628 databuf.appendChar(poolWriter.putDescriptor(clazz.classType));
629 }
630 public void visitCompound(Attribute.Compound compound) {
631 databuf.appendByte('@');
632 writeCompoundAttribute(compound);
633 }
634 public void visitError(Attribute.Error x) {
635 throw new AssertionError(x);
636 }
637 public void visitArray(Attribute.Array array) {
638 databuf.appendByte('[');
639 databuf.appendChar(array.values.length);
640 for (Attribute a : array.values) {
641 a.accept(this);
642 }
643 }
644 }
645 AttributeWriter awriter = new AttributeWriter();
646
647 /** Write a compound attribute excluding the '@' marker. */
648 void writeCompoundAttribute(Attribute.Compound c) {
649 databuf.appendChar(poolWriter.putDescriptor(c.type));
650 databuf.appendChar(c.values.length());
651 for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) {
652 checkAnnotationArraySizeInternal(p);
653 databuf.appendChar(poolWriter.putName(p.fst.name));
654 p.snd.accept(awriter);
655 }
656 }
657
658 private void checkAnnotationArraySizeInternal(Pair<Symbol.MethodSymbol, Attribute> p) {
659 if (p.snd instanceof Attribute.Array arrAttr &&
660 arrAttr.values.length > ClassFile.MAX_ANNOTATIONS) {
661 log.error(Errors.AnnotationArrayTooLarge(p.fst.owner));
662 }
663 }
664
665 void writeTypeAnnotation(Attribute.TypeCompound c) {
666 writePosition(c.position);
667 writeCompoundAttribute(c);
668 }
669
670 void writePosition(TypeAnnotationPosition p) {
671 databuf.appendByte(p.type.targetTypeValue()); // TargetType tag is a byte
672 switch (p.type) {
673 // instanceof
674 case INSTANCEOF:
675 // new expression
676 case NEW:
677 // constructor/method reference receiver
678 case CONSTRUCTOR_REFERENCE:
679 case METHOD_REFERENCE:
680 databuf.appendChar(p.offset);
681 break;
682 // local variable
683 case LOCAL_VARIABLE:
684 // resource variable
685 case RESOURCE_VARIABLE:
686 databuf.appendChar(p.lvarOffset.length); // for table length
687 for (int i = 0; i < p.lvarOffset.length; ++i) {
688 databuf.appendChar(p.lvarOffset[i]);
689 databuf.appendChar(p.lvarLength[i]);
690 databuf.appendChar(p.lvarIndex[i]);
691 }
692 break;
693 // exception parameter
694 case EXCEPTION_PARAMETER:
695 databuf.appendChar(p.getExceptionIndex());
696 break;
697 // method receiver
698 case METHOD_RECEIVER:
699 // Do nothing
700 break;
701 // type parameter
702 case CLASS_TYPE_PARAMETER:
703 case METHOD_TYPE_PARAMETER:
704 databuf.appendByte(p.parameter_index);
705 break;
706 // type parameter bound
707 case CLASS_TYPE_PARAMETER_BOUND:
708 case METHOD_TYPE_PARAMETER_BOUND:
709 databuf.appendByte(p.parameter_index);
710 databuf.appendByte(p.bound_index);
711 break;
712 // class extends or implements clause
713 case CLASS_EXTENDS:
714 databuf.appendChar(p.type_index);
715 break;
716 // throws
717 case THROWS:
718 databuf.appendChar(p.type_index);
719 break;
720 // method parameter
721 case METHOD_FORMAL_PARAMETER:
722 databuf.appendByte(p.parameter_index);
723 break;
724 // type cast
725 case CAST:
726 // method/constructor/reference type argument
727 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
728 case METHOD_INVOCATION_TYPE_ARGUMENT:
729 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
730 case METHOD_REFERENCE_TYPE_ARGUMENT:
731 databuf.appendChar(p.offset);
732 databuf.appendByte(p.type_index);
733 break;
734 // We don't need to worry about these
735 case METHOD_RETURN:
736 case FIELD:
737 break;
738 case UNKNOWN:
739 throw new AssertionError("jvm.ClassWriter: UNKNOWN target type should never occur!");
740 default:
741 throw new AssertionError("jvm.ClassWriter: Unknown target type for position: " + p);
742 }
743
744 { // Append location data for generics/arrays.
745 databuf.appendByte(p.location.size());
746 java.util.List<Integer> loc = TypeAnnotationPosition.getBinaryFromTypePath(p.location);
747 for (int i : loc)
748 databuf.appendByte((byte)i);
749 }
750 }
751
752 /* ********************************************************************
753 * Writing module attributes
754 **********************************************************************/
755
756 /** Write the Module attribute if needed.
757 * Returns the number of attributes written (0 or 1).
758 */
759 int writeModuleAttribute(ClassSymbol c) {
760 ModuleSymbol m = (ModuleSymbol) c.owner;
761
762 int alenIdx = writeAttr(names.Module);
763
764 databuf.appendChar(poolWriter.putModule(m));
765 databuf.appendChar(ModuleFlags.value(m.flags)); // module_flags
766 databuf.appendChar(m.version != null ? poolWriter.putName(m.version) : 0);
767
768 ListBuffer<RequiresDirective> requires = new ListBuffer<>();
769 for (RequiresDirective r: m.requires) {
770 if (!r.flags.contains(RequiresFlag.EXTRA))
771 requires.add(r);
772 }
773 databuf.appendChar(requires.size());
774 for (RequiresDirective r: requires) {
775 databuf.appendChar(poolWriter.putModule(r.module));
776 databuf.appendChar(RequiresFlag.value(r.flags));
777 databuf.appendChar(r.module.version != null ? poolWriter.putName(r.module.version) : 0);
778 }
779
780 List<ExportsDirective> exports = m.exports;
781 databuf.appendChar(exports.size());
782 for (ExportsDirective e: exports) {
783 databuf.appendChar(poolWriter.putPackage(e.packge));
784 databuf.appendChar(ExportsFlag.value(e.flags));
785 if (e.modules == null) {
786 databuf.appendChar(0);
787 } else {
788 databuf.appendChar(e.modules.size());
789 for (ModuleSymbol msym: e.modules) {
790 databuf.appendChar(poolWriter.putModule(msym));
791 }
792 }
793 }
794
795 List<OpensDirective> opens = m.opens;
796 databuf.appendChar(opens.size());
797 for (OpensDirective o: opens) {
798 databuf.appendChar(poolWriter.putPackage(o.packge));
799 databuf.appendChar(OpensFlag.value(o.flags));
800 if (o.modules == null) {
801 databuf.appendChar(0);
802 } else {
803 databuf.appendChar(o.modules.size());
804 for (ModuleSymbol msym: o.modules) {
805 databuf.appendChar(poolWriter.putModule(msym));
806 }
807 }
808 }
809
810 List<UsesDirective> uses = m.uses;
811 databuf.appendChar(uses.size());
812 for (UsesDirective s: uses) {
813 databuf.appendChar(poolWriter.putClass(s.service));
814 }
815
816 // temporary fix to merge repeated provides clause for same service;
817 // eventually this should be disallowed when analyzing the module,
818 // so that each service type only appears once.
819 Map<ClassSymbol, Set<ClassSymbol>> mergedProvides = new LinkedHashMap<>();
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 */
883 int writeNestMembersIfNeeded(ClassSymbol csym) {
884 ListBuffer<ClassSymbol> nested = new ListBuffer<>();
885 listNested(csym, nested);
886 Set<ClassSymbol> nestedUnique = new LinkedHashSet<>(nested);
887 if (csym.owner.kind == PCK && !nestedUnique.isEmpty()) {
888 int alenIdx = writeAttr(names.NestMembers);
889 databuf.appendChar(nestedUnique.size());
890 for (ClassSymbol s : nestedUnique) {
891 databuf.appendChar(poolWriter.putClass(s));
892 }
893 endAttr(alenIdx);
894 return 1;
895 }
896 return 0;
897 }
898
899 /**
900 * Write NestHost attribute (if needed)
901 */
902 int writeNestHostIfNeeded(ClassSymbol csym) {
903 if (csym.owner.kind != PCK) {
904 int alenIdx = writeAttr(names.NestHost);
905 databuf.appendChar(poolWriter.putClass(csym.outermostClass()));
906 endAttr(alenIdx);
907 return 1;
908 }
909 return 0;
910 }
911
912 private void listNested(Symbol sym, ListBuffer<ClassSymbol> seen) {
913 if (sym.kind != TYP) return;
914 ClassSymbol csym = (ClassSymbol)sym;
915 if (csym.owner.kind != PCK) {
916 seen.add(csym);
917 }
918 if (csym.members() != null) {
919 for (Symbol s : sym.members().getSymbols()) {
920 listNested(s, seen);
921 }
922 }
923 if (csym.trans_local != null) {
924 for (Symbol s : csym.trans_local) {
925 listNested(s, seen);
926 }
927 }
928 }
929
930 /** Write "PermittedSubclasses" attribute.
931 */
932 int writePermittedSubclassesIfNeeded(ClassSymbol csym) {
933 if (csym.getPermittedSubclasses().nonEmpty()) {
934 int alenIdx = writeAttr(names.PermittedSubclasses);
935 databuf.appendChar(csym.getPermittedSubclasses().size());
936 for (Type t : csym.getPermittedSubclasses()) {
937 databuf.appendChar(poolWriter.putClass((ClassSymbol) t.tsym));
938 }
939 endAttr(alenIdx);
940 return 1;
941 }
942 return 0;
943 }
944
945 /** Write "bootstrapMethods" attribute.
946 */
947 void writeBootstrapMethods() {
948 int alenIdx = writeAttr(names.BootstrapMethods);
949 int lastBootstrapMethods;
950 do {
951 lastBootstrapMethods = poolWriter.bootstrapMethods.size();
952 for (BsmKey bsmKey : java.util.List.copyOf(poolWriter.bootstrapMethods.keySet())) {
953 for (LoadableConstant arg : bsmKey.staticArgs) {
954 poolWriter.putConstant(arg);
955 }
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);
1030 m.defaultValue.accept(awriter);
1031 endAttr(alenIdx);
1032 acount++;
1033 }
1034 if (target.hasMethodParameters()) {
1035 if (!m.isLambdaMethod()) { // Per JDK-8138729, do not emit parameters table for lambda bodies.
1036 boolean requiresParamNames = requiresParamNames(m);
1037 if (requiresParamNames || requiresParamFlags(m))
1038 acount += writeMethodParametersAttr(m, requiresParamNames);
1039 }
1040 }
1041 acount += writeMemberAttrs(m, false);
1042 if (!m.isLambdaMethod())
1043 acount += writeParameterAttrs(m.params);
1044 acount += writeExtraAttributes(m);
1045 endAttrs(acountIdx, acount);
1046 }
1047
1048 private boolean requiresParamNames(MethodSymbol m) {
1049 if (options.isSet(PARAMETERS))
1050 return true;
1051 if (m.isConstructor() && (m.flags_field & RECORD) != 0)
1052 return true;
1053 return false;
1054 }
1055
1056 private boolean requiresParamFlags(MethodSymbol m) {
1057 if (!m.extraParams.isEmpty()) {
1058 return m.extraParams.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0);
1059 }
1060 if (m.params != null) {
1061 // parameter is stored in params for Enum#valueOf(name)
1062 return m.params.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0);
1063 }
1064 return false;
1065 }
1066
1067 /** Write code attribute of method.
1068 */
1069 void writeCode(Code code) {
1070 databuf.appendChar(code.max_stack);
1071 databuf.appendChar(code.max_locals);
1072 databuf.appendInt(code.cp);
1073 databuf.appendBytes(code.code, 0, code.cp);
1074 databuf.appendChar(code.catchInfo.length());
1075 for (List<char[]> l = code.catchInfo.toList();
1076 l.nonEmpty();
1077 l = l.tail) {
1078 for (int i = 0; i < l.head.length; i++)
1079 databuf.appendChar(l.head[i]);
1080 }
1081 int acountIdx = beginAttrs();
1082 int acount = 0;
1083
1084 if (code.lineInfo.nonEmpty()) {
1085 int alenIdx = writeAttr(names.LineNumberTable);
1086 databuf.appendChar(code.lineInfo.length());
1087 for (List<char[]> l = code.lineInfo.reverse();
1088 l.nonEmpty();
1089 l = l.tail)
1090 for (int i = 0; i < l.head.length; i++)
1091 databuf.appendChar(l.head[i]);
1092 endAttr(alenIdx);
1093 acount++;
1094 }
1095
1096 if (genCrt && (code.crt != null)) {
1097 CRTable crt = code.crt;
1098 int alenIdx = writeAttr(names.CharacterRangeTable);
1099 int crtIdx = beginAttrs();
1100 int crtEntries = crt.writeCRT(databuf, code.lineMap, log);
1101 endAttrs(crtIdx, crtEntries);
1102 endAttr(alenIdx);
1103 acount++;
1104 }
1105
1106 // counter for number of generic local variables
1107 if (code.varDebugInfo && code.varBufferSize > 0) {
1108 int nGenericVars = 0;
1109 int alenIdx = writeAttr(names.LocalVariableTable);
1110 databuf.appendChar(code.getLVTSize());
1111 for (int i=0; i<code.varBufferSize; i++) {
1112 Code.LocalVar var = code.varBuffer[i];
1113
1114 for (Code.LocalVar.Range r: var.aliveRanges) {
1115 // write variable info
1116 Assert.check(r.start_pc >= 0
1117 && r.start_pc <= code.cp);
1118 databuf.appendChar(r.start_pc);
1119 Assert.check(r.length > 0
1120 && (r.start_pc + r.length) <= code.cp);
1121 databuf.appendChar(r.length);
1122 VarSymbol sym = var.sym;
1123 databuf.appendChar(poolWriter.putName(sym.name));
1124 databuf.appendChar(poolWriter.putDescriptor(sym));
1125 databuf.appendChar(var.reg);
1126 if (needsLocalVariableTypeEntry(var.sym.type)) {
1127 nGenericVars++;
1128 }
1129 }
1130 }
1131 endAttr(alenIdx);
1132 acount++;
1133
1134 if (nGenericVars > 0) {
1135 alenIdx = writeAttr(names.LocalVariableTypeTable);
1136 databuf.appendChar(nGenericVars);
1137 int count = 0;
1138
1139 for (int i=0; i<code.varBufferSize; i++) {
1140 Code.LocalVar var = code.varBuffer[i];
1141 VarSymbol sym = var.sym;
1142 if (!needsLocalVariableTypeEntry(sym.type))
1143 continue;
1144 for (Code.LocalVar.Range r : var.aliveRanges) {
1145 // write variable info
1146 databuf.appendChar(r.start_pc);
1147 databuf.appendChar(r.length);
1148 databuf.appendChar(poolWriter.putName(sym.name));
1149 databuf.appendChar(poolWriter.putSignature(sym));
1150 databuf.appendChar(var.reg);
1151 count++;
1152 }
1153 }
1154 Assert.check(count == nGenericVars);
1155 endAttr(alenIdx);
1156 acount++;
1157 }
1158 }
1159
1160 if (code.stackMapBufferSize > 0) {
1161 if (debugstackmap) System.out.println("Stack map for " + code.meth);
1162 int alenIdx = writeAttr(code.stackMap.getAttributeName(names));
1163 writeStackMap(code);
1164 endAttr(alenIdx);
1165 acount++;
1166 }
1167
1168 acount += writeTypeAnnotations(code.meth.getRawTypeAttributes(), true);
1169
1170 endAttrs(acountIdx, acount);
1171 }
1172 //where
1173 private boolean needsLocalVariableTypeEntry(Type t) {
1174 //a local variable needs a type-entry if its type T is generic
1175 //(i.e. |T| != T) and if it's not an non-denotable type (non-denotable
1176 // types are not supported in signature attribute grammar!)
1177 return !types.isSameType(t, types.erasure(t)) &&
1178 check.checkDenotable(t);
1179 }
1180
1181 void writeStackMap(Code code) {
1182 int nframes = code.stackMapBufferSize;
1183 if (debugstackmap) System.out.println(" nframes = " + nframes);
1184 databuf.appendChar(nframes);
1185
1186 switch (code.stackMap) {
1187 case CLDC:
1188 for (int i=0; i<nframes; i++) {
1189 if (debugstackmap) System.out.print(" " + i + ":");
1190 Code.StackMapFrame frame = code.stackMapBuffer[i];
1191
1192 // output PC
1193 if (debugstackmap) System.out.print(" pc=" + frame.pc);
1194 databuf.appendChar(frame.pc);
1195
1196 // output locals
1197 int localCount = 0;
1198 for (int j=0; j<frame.locals.length;
1199 j += Code.width(frame.locals[j])) {
1200 localCount++;
1201 }
1202 if (debugstackmap) System.out.print(" nlocals=" +
1203 localCount);
1204 databuf.appendChar(localCount);
1205 for (int j=0; j<frame.locals.length;
1206 j += Code.width(frame.locals[j])) {
1207 if (debugstackmap) System.out.print(" local[" + j + "]=");
1208 writeStackMapType(frame.locals[j]);
1209 }
1210
1211 // output stack
1212 int stackCount = 0;
1213 for (int j=0; j<frame.stack.length;
1214 j += Code.width(frame.stack[j])) {
1215 stackCount++;
1216 }
1217 if (debugstackmap) System.out.print(" nstack=" +
1218 stackCount);
1219 databuf.appendChar(stackCount);
1220 for (int j=0; j<frame.stack.length;
1221 j += Code.width(frame.stack[j])) {
1222 if (debugstackmap) System.out.print(" stack[" + j + "]=");
1223 writeStackMapType(frame.stack[j]);
1224 }
1225 if (debugstackmap) System.out.println();
1226 }
1227 break;
1228 case JSR202: {
1229 Assert.checkNull(code.stackMapBuffer);
1230 for (int i=0; i<nframes; i++) {
1231 if (debugstackmap) System.out.print(" " + i + ":");
1232 StackMapTableFrame frame = code.stackMapTableBuffer[i];
1233 frame.write(this);
1234 if (debugstackmap) System.out.println();
1235 }
1236 break;
1237 }
1238 default:
1239 throw new AssertionError("Unexpected stackmap format value");
1240 }
1241 }
1242
1243 //where
1244 void writeStackMapType(Type t) {
1245 if (t == null) {
1246 if (debugstackmap) System.out.print("empty");
1247 databuf.appendByte(0);
1248 }
1249 else switch(t.getTag()) {
1250 case BYTE:
1251 case CHAR:
1252 case SHORT:
1253 case INT:
1254 case BOOLEAN:
1255 if (debugstackmap) System.out.print("int");
1256 databuf.appendByte(1);
1257 break;
1258 case FLOAT:
1259 if (debugstackmap) System.out.print("float");
1260 databuf.appendByte(2);
1261 break;
1262 case DOUBLE:
1263 if (debugstackmap) System.out.print("double");
1264 databuf.appendByte(3);
1265 break;
1266 case LONG:
1267 if (debugstackmap) System.out.print("long");
1268 databuf.appendByte(4);
1269 break;
1270 case BOT: // null
1271 if (debugstackmap) System.out.print("null");
1272 databuf.appendByte(5);
1273 break;
1274 case CLASS:
1275 case ARRAY:
1276 case TYPEVAR:
1277 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1278 databuf.appendByte(7);
1279 databuf.appendChar(poolWriter.putClass(types.erasure(t)));
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 }
1485 } else if (t2.hasTag(UNINITIALIZED_THIS) || t2.hasTag(UNINITIALIZED_OBJECT)) {
1486 return false;
1487 }
1488
1489 return types.isSameType(t1, t2);
1490 }
1491
1492 static int compare(Type[] arr1, Type[] arr2, Types types) {
1493 int diff_length = arr1.length - arr2.length;
1494 if (diff_length > MAX_LOCAL_LENGTH_DIFF || diff_length < -MAX_LOCAL_LENGTH_DIFF) {
1495 return Integer.MAX_VALUE;
1496 }
1497 int len = (diff_length > 0) ? arr2.length : arr1.length;
1498 for (int i=0; i<len; i++) {
1499 if (!isSameType(arr1[i], arr2[i], types)) {
1500 return Integer.MAX_VALUE;
1501 }
1502 }
1503 return diff_length;
1504 }
1505 }
1506
1507 void writeFields(Scope s) {
1508 // process them in reverse sibling order;
1509 // i.e., process them in declaration order.
1510 List<VarSymbol> vars = List.nil();
1511 for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
1512 if (sym.kind == VAR) vars = vars.prepend((VarSymbol)sym);
1513 }
1514 while (vars.nonEmpty()) {
1515 writeField(vars.head);
1516 vars = vars.tail;
1517 }
1518 }
1519
1520 void writeMethods(Scope s) {
1521 List<MethodSymbol> methods = List.nil();
1522 for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
1523 if (sym.kind == MTH && (sym.flags() & HYPOTHETICAL) == 0)
1524 methods = methods.prepend((MethodSymbol)sym);
1525 }
1526 while (methods.nonEmpty()) {
1527 writeMethod(methods.head);
1528 methods = methods.tail;
1529 }
1530 }
1531
1532 /** Emit a class file for a given class.
1533 * @param c The class from which a class file is generated.
1534 */
1535 public JavaFileObject writeClass(ClassSymbol c)
1536 throws IOException, PoolOverflow, StringOverflow
1537 {
1538 String name = (c.owner.kind == MDL ? c.name : c.flatname).toString();
1539 Location outLocn;
1540 if (multiModuleMode) {
1541 ModuleSymbol msym = c.owner.kind == MDL ? (ModuleSymbol) c.owner : c.packge().modle;
1542 outLocn = fileManager.getLocationForModule(CLASS_OUTPUT, msym.name.toString());
1543 } else {
1544 outLocn = CLASS_OUTPUT;
1545 }
1546 JavaFileObject outFile
1547 = fileManager.getJavaFileForOutput(outLocn,
1548 name,
1549 JavaFileObject.Kind.CLASS,
1550 c.sourcefile);
1551 OutputStream out = outFile.openOutputStream();
1552 try {
1553 writeClassFile(out, c);
1554 if (verbose)
1555 log.printVerbose("wrote.file", outFile.getName());
1556 out.close();
1557 out = null;
1558 } catch (InvalidSignatureException ex) {
1559 log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type())));
1560 } finally {
1561 if (out != null) {
1562 // if we are propagating an exception, delete the file
1563 out.close();
1564 outFile.delete();
1565 outFile = null;
1566 }
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));
1611 int fieldsCount = 0;
1612 int methodsCount = 0;
1613 for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
1614 switch (sym.kind) {
1615 case VAR: fieldsCount++; break;
1616 case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
1617 break;
1618 case TYP: poolWriter.enterInner((ClassSymbol)sym); break;
1619 default : Assert.error();
1620 }
1621 }
1622
1623 if (c.trans_local != null) {
1624 for (ClassSymbol local : c.trans_local) {
1625 poolWriter.enterInner(local);
1626 }
1627 }
1628
1629 databuf.appendChar(fieldsCount);
1630 writeFields(c.members());
1631 databuf.appendChar(methodsCount);
1632 writeMethods(c.members());
1633
1634 int acountIdx = beginAttrs();
1635 int acount = 0;
1636
1637 boolean sigReq =
1638 typarams.length() != 0 || supertype.allparams().length() != 0;
1639 for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
1640 sigReq = l.head.allparams().length() != 0;
1641 if (sigReq) {
1642 int alenIdx = writeAttr(names.Signature);
1643 databuf.appendChar(poolWriter.putSignature(c));
1644 endAttr(alenIdx);
1645 acount++;
1646 }
1647
1648 if (c.sourcefile != null && emitSourceFile) {
1649 int alenIdx = writeAttr(names.SourceFile);
1650 // WHM 6/29/1999: Strip file path prefix. We do it here at
1651 // the last possible moment because the sourcefile may be used
1652 // elsewhere in error diagnostics. Fixes 4241573.
1653 String simpleName = PathFileObject.getSimpleName(c.sourcefile);
1654 databuf.appendChar(poolWriter.putName(names.fromString(simpleName)));
1655 endAttr(alenIdx);
1656 acount++;
1657 }
1658
1659 if (genCrt) {
1660 // Append SourceID attribute
1661 int alenIdx = writeAttr(names.SourceID);
1662 databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
1663 endAttr(alenIdx);
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 }