1 /*
2  * Copyright (c) 1999, 2019, 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 
34 import javax.tools.JavaFileManager;
35 import javax.tools.FileObject;
36 import javax.tools.JavaFileManager.Location;
37 import javax.tools.JavaFileObject;
38 
39 import com.sun.tools.javac.code.*;
40 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
41 import com.sun.tools.javac.code.Directive.*;
42 import com.sun.tools.javac.code.Symbol.*;
43 import com.sun.tools.javac.code.Type.*;
44 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
45 import com.sun.tools.javac.comp.Check;
46 import com.sun.tools.javac.file.PathFileObject;
47 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
48 import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey;
49 import com.sun.tools.javac.resources.CompilerProperties.Errors;
50 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
51 import com.sun.tools.javac.util.*;
52 
53 import static com.sun.tools.javac.code.Flags.*;
54 import static com.sun.tools.javac.code.Kinds.Kind.*;
55 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
56 import static com.sun.tools.javac.code.TypeTag.*;
57 import static com.sun.tools.javac.main.Option.*;
58 
59 import static javax.tools.StandardLocation.CLASS_OUTPUT;
60 
61 /** This class provides operations to map an internal symbol table graph
62  *  rooted in a ClassSymbol into a classfile.
63  *
64  *  <p><b>This is NOT part of any supported API.
65  *  If you write code that depends on this, you do so at your own risk.
66  *  This code and its internal interfaces are subject to change or
67  *  deletion without notice.</b>
68  */
69 public class ClassWriter extends ClassFile {
70     protected static final Context.Key<ClassWriter> classWriterKey = new Context.Key<>();
71 
72     private final Options options;
73 
74     /** Switch: verbose output.
75      */
76     private boolean verbose;
77 
78     /** Switch: emit source file attribute.
79      */
80     private boolean emitSourceFile;
81 
82     /** Switch: generate CharacterRangeTable attribute.
83      */
84     private boolean genCrt;
85 
86     /** Switch: describe the generated stackmap.
87      */
88     private boolean debugstackmap;
89 
90     /** Preview language level.
91      */
92     private Preview preview;
93 
94     /**
95      * Target class version.
96      */
97     private Target target;
98 
99     /**
100      * Source language version.
101      */
102     private Source source;
103 
104     /** Type utilities. */
105     private Types types;
106 
107     private Check check;
108 
109     /**
110      * If true, class files will be written in module-specific subdirectories
111      * of the CLASS_OUTPUT location.
112      */
113     public boolean multiModuleMode;
114 
115     /** The initial sizes of the data and constant pool buffers.
116      *  Sizes are increased when buffers get full.
117      */
118     static final int DATA_BUF_SIZE = 0x0fff0;
119     static final int CLASS_BUF_SIZE = 0x1fff0;
120 
121     /** An output buffer for member info.
122      */
123     ByteBuffer databuf = new ByteBuffer(DATA_BUF_SIZE);
124 
125     /** An output buffer for the constant pool.
126      */
127     ByteBuffer poolbuf = new ByteBuffer(CLASS_BUF_SIZE);
128 
129     /** The constant pool writer.
130      */
131     final PoolWriter poolWriter;
132 
133     /** The log to use for verbose output.
134      */
135     private final Log log;
136 
137     /** The name table. */
138     private final Names names;
139 
140     /** Access to files. */
141     private final JavaFileManager fileManager;
142 
143     /** The tags and constants used in compressed stackmap. */
144     static final int SAME_FRAME_SIZE = 64;
145     static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
146     static final int SAME_FRAME_EXTENDED = 251;
147     static final int FULL_FRAME = 255;
148     static final int MAX_LOCAL_LENGTH_DIFF = 4;
149 
150     /** Get the ClassWriter instance for this context. */
instance(Context context)151     public static ClassWriter instance(Context context) {
152         ClassWriter instance = context.get(classWriterKey);
153         if (instance == null)
154             instance = new ClassWriter(context);
155         return instance;
156     }
157 
158     /** Construct a class writer, given an options table.
159      */
ClassWriter(Context context)160     protected ClassWriter(Context context) {
161         context.put(classWriterKey, this);
162 
163         log = Log.instance(context);
164         names = Names.instance(context);
165         options = Options.instance(context);
166         preview = Preview.instance(context);
167         target = Target.instance(context);
168         source = Source.instance(context);
169         types = Types.instance(context);
170         check = Check.instance(context);
171         fileManager = context.get(JavaFileManager.class);
172         poolWriter = Gen.instance(context).poolWriter;
173 
174         verbose        = options.isSet(VERBOSE);
175         genCrt         = options.isSet(XJCOV);
176         debugstackmap = options.isSet("debug.stackmap");
177 
178         emitSourceFile = options.isUnset(G_CUSTOM) ||
179                             options.isSet(G_CUSTOM, "source");
180 
181         String modifierFlags = options.get("debug.dumpmodifiers");
182         if (modifierFlags != null) {
183             dumpClassModifiers = modifierFlags.indexOf('c') != -1;
184             dumpFieldModifiers = modifierFlags.indexOf('f') != -1;
185             dumpInnerClassModifiers = modifierFlags.indexOf('i') != -1;
186             dumpMethodModifiers = modifierFlags.indexOf('m') != -1;
187         }
188     }
189 
190 /******************************************************************
191  * Diagnostics: dump generated class names and modifiers
192  ******************************************************************/
193 
194     /** Value of option 'dumpmodifiers' is a string
195      *  indicating which modifiers should be dumped for debugging:
196      *    'c' -- classes
197      *    'f' -- fields
198      *    'i' -- innerclass attributes
199      *    'm' -- methods
200      *  For example, to dump everything:
201      *    javac -XDdumpmodifiers=cifm MyProg.java
202      */
203     private boolean dumpClassModifiers; // -XDdumpmodifiers=c
204     private boolean dumpFieldModifiers; // -XDdumpmodifiers=f
205     private boolean dumpInnerClassModifiers; // -XDdumpmodifiers=i
206     private boolean dumpMethodModifiers; // -XDdumpmodifiers=m
207 
208 
209     /** Return flags as a string, separated by " ".
210      */
flagNames(long flags)211     public static String flagNames(long flags) {
212         StringBuilder sbuf = new StringBuilder();
213         int i = 0;
214         long f = flags & StandardFlags;
215         while (f != 0) {
216             if ((f & 1) != 0) {
217                 sbuf.append(" ");
218                 sbuf.append(flagName[i]);
219             }
220             f = f >> 1;
221             i++;
222         }
223         return sbuf.toString();
224     }
225     //where
226         private final static String[] flagName = {
227             "PUBLIC", "PRIVATE", "PROTECTED", "STATIC", "FINAL",
228             "SUPER", "VOLATILE", "TRANSIENT", "NATIVE", "INTERFACE",
229             "ABSTRACT", "STRICTFP"};
230 
231 /******************************************************************
232  * Output routines
233  ******************************************************************/
234 
235     /** Write a character into given byte buffer;
236      *  byte buffer will not be grown.
237      */
putChar(ByteBuffer buf, int op, int x)238     void putChar(ByteBuffer buf, int op, int x) {
239         buf.elems[op  ] = (byte)((x >>  8) & 0xFF);
240         buf.elems[op+1] = (byte)((x      ) & 0xFF);
241     }
242 
243     /** Write an integer into given byte buffer;
244      *  byte buffer will not be grown.
245      */
putInt(ByteBuffer buf, int adr, int x)246     void putInt(ByteBuffer buf, int adr, int x) {
247         buf.elems[adr  ] = (byte)((x >> 24) & 0xFF);
248         buf.elems[adr+1] = (byte)((x >> 16) & 0xFF);
249         buf.elems[adr+2] = (byte)((x >>  8) & 0xFF);
250         buf.elems[adr+3] = (byte)((x      ) & 0xFF);
251     }
252 
253 /******************************************************************
254  * Writing the Constant Pool
255  ******************************************************************/
256 
257     /** Thrown when the constant pool is over full.
258      */
259     public static class PoolOverflow extends RuntimeException {
260         private static final long serialVersionUID = 0;
PoolOverflow()261         public PoolOverflow() {}
262     }
263     public static class StringOverflow extends RuntimeException {
264         private static final long serialVersionUID = 0;
265         public final String value;
StringOverflow(String s)266         public StringOverflow(String s) {
267             value = s;
268         }
269     }
270 
271 /******************************************************************
272  * Writing Attributes
273  ******************************************************************/
274 
275     /** Write header for an attribute to data buffer and return
276      *  position past attribute length index.
277      */
writeAttr(Name attrName)278     int writeAttr(Name attrName) {
279         int index = poolWriter.putName(attrName);
280         databuf.appendChar(index);
281         databuf.appendInt(0);
282         return databuf.length;
283     }
284 
285     /** Fill in attribute length.
286      */
endAttr(int index)287     void endAttr(int index) {
288         putInt(databuf, index - 4, databuf.length - index);
289     }
290 
291     /** Leave space for attribute count and return index for
292      *  number of attributes field.
293      */
beginAttrs()294     int beginAttrs() {
295         databuf.appendChar(0);
296         return databuf.length;
297     }
298 
299     /** Fill in number of attributes.
300      */
endAttrs(int index, int count)301     void endAttrs(int index, int count) {
302         putChar(databuf, index - 2, count);
303     }
304 
305     /** Write the EnclosingMethod attribute if needed.
306      *  Returns the number of attributes written (0 or 1).
307      */
writeEnclosingMethodAttribute(ClassSymbol c)308     int writeEnclosingMethodAttribute(ClassSymbol c) {
309         return writeEnclosingMethodAttribute(names.EnclosingMethod, c);
310     }
311 
312     /** Write the EnclosingMethod attribute with a specified name.
313      *  Returns the number of attributes written (0 or 1).
314      */
writeEnclosingMethodAttribute(Name attributeName, ClassSymbol c)315     protected int writeEnclosingMethodAttribute(Name attributeName, ClassSymbol c) {
316         if (c.owner.kind != MTH && // neither a local class
317             c.name != names.empty) // nor anonymous
318             return 0;
319 
320         int alenIdx = writeAttr(attributeName);
321         ClassSymbol enclClass = c.owner.enclClass();
322         MethodSymbol enclMethod =
323             (c.owner.type == null // local to init block
324              || c.owner.kind != MTH) // or member init
325             ? null
326             : ((MethodSymbol)c.owner).originalEnclosingMethod();
327         databuf.appendChar(poolWriter.putClass(enclClass));
328         databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(enclMethod));
329         endAttr(alenIdx);
330         return 1;
331     }
332 
333     /** Write flag attributes; return number of attributes written.
334      */
writeFlagAttrs(long flags)335     int writeFlagAttrs(long flags) {
336         int acount = 0;
337         if ((flags & DEPRECATED) != 0) {
338             int alenIdx = writeAttr(names.Deprecated);
339             endAttr(alenIdx);
340             acount++;
341         }
342         return acount;
343     }
344 
345     /** Write member (field or method) attributes;
346      *  return number of attributes written.
347      */
writeMemberAttrs(Symbol sym)348     int writeMemberAttrs(Symbol sym) {
349         int acount = writeFlagAttrs(sym.flags());
350         long flags = sym.flags();
351         if ((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC &&
352             (flags & ANONCONSTR) == 0 &&
353             (!types.isSameType(sym.type, sym.erasure(types)) ||
354              poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()))) {
355             // note that a local class with captured variables
356             // will get a signature attribute
357             int alenIdx = writeAttr(names.Signature);
358             databuf.appendChar(poolWriter.putSignature(sym));
359             endAttr(alenIdx);
360             acount++;
361         }
362         acount += writeJavaAnnotations(sym.getRawAttributes());
363         acount += writeTypeAnnotations(sym.getRawTypeAttributes(), false);
364         return acount;
365     }
366 
367     /**
368      * Write method parameter names attribute.
369      */
writeMethodParametersAttr(MethodSymbol m)370     int writeMethodParametersAttr(MethodSymbol m) {
371         MethodType ty = m.externalType(types).asMethodType();
372         final int allparams = ty.argtypes.size();
373         if (m.params != null && allparams != 0) {
374             final int attrIndex = writeAttr(names.MethodParameters);
375             databuf.appendByte(allparams);
376             // Write extra parameters first
377             for (VarSymbol s : m.extraParams) {
378                 final int flags =
379                     ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
380                     ((int) m.flags() & SYNTHETIC);
381                 databuf.appendChar(poolWriter.putName(s.name));
382                 databuf.appendChar(flags);
383             }
384             // Now write the real parameters
385             for (VarSymbol s : m.params) {
386                 final int flags =
387                     ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
388                     ((int) m.flags() & SYNTHETIC);
389                 databuf.appendChar(poolWriter.putName(s.name));
390                 databuf.appendChar(flags);
391             }
392             // Now write the captured locals
393             for (VarSymbol s : m.capturedLocals) {
394                 final int flags =
395                     ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
396                     ((int) m.flags() & SYNTHETIC);
397                 databuf.appendChar(poolWriter.putName(s.name));
398                 databuf.appendChar(flags);
399             }
400             endAttr(attrIndex);
401             return 1;
402         } else
403             return 0;
404     }
405 
406 
writeParamAnnotations(List<VarSymbol> params, RetentionPolicy retention)407     private void writeParamAnnotations(List<VarSymbol> params,
408                                        RetentionPolicy retention) {
409         for (VarSymbol s : params) {
410             ListBuffer<Attribute.Compound> buf = new ListBuffer<>();
411             for (Attribute.Compound a : s.getRawAttributes())
412                 if (types.getRetention(a) == retention)
413                     buf.append(a);
414             databuf.appendChar(buf.length());
415             for (Attribute.Compound a : buf)
416                 writeCompoundAttribute(a);
417         }
418 
419     }
420 
writeParamAnnotations(MethodSymbol m, RetentionPolicy retention)421     private void writeParamAnnotations(MethodSymbol m,
422                                        RetentionPolicy retention) {
423         databuf.appendByte(m.params.length());
424         writeParamAnnotations(m.params, retention);
425     }
426 
427     /** Write method parameter annotations;
428      *  return number of attributes written.
429      */
writeParameterAttrs(MethodSymbol m)430     int writeParameterAttrs(MethodSymbol m) {
431         boolean hasVisible = false;
432         boolean hasInvisible = false;
433         if (m.params != null) {
434             for (VarSymbol s : m.params) {
435                 for (Attribute.Compound a : s.getRawAttributes()) {
436                     switch (types.getRetention(a)) {
437                     case SOURCE: break;
438                     case CLASS: hasInvisible = true; break;
439                     case RUNTIME: hasVisible = true; break;
440                     default: // /* fail soft */ throw new AssertionError(vis);
441                     }
442                 }
443             }
444         }
445 
446         int attrCount = 0;
447         if (hasVisible) {
448             int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations);
449             writeParamAnnotations(m, RetentionPolicy.RUNTIME);
450             endAttr(attrIndex);
451             attrCount++;
452         }
453         if (hasInvisible) {
454             int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations);
455             writeParamAnnotations(m, RetentionPolicy.CLASS);
456             endAttr(attrIndex);
457             attrCount++;
458         }
459         return attrCount;
460     }
461 
462 /**********************************************************************
463  * Writing Java-language annotations (aka metadata, attributes)
464  **********************************************************************/
465 
466     /** Write Java-language annotations; return number of JVM
467      *  attributes written (zero or one).
468      */
writeJavaAnnotations(List<Attribute.Compound> attrs)469     int writeJavaAnnotations(List<Attribute.Compound> attrs) {
470         if (attrs.isEmpty()) return 0;
471         ListBuffer<Attribute.Compound> visibles = new ListBuffer<>();
472         ListBuffer<Attribute.Compound> invisibles = new ListBuffer<>();
473         for (Attribute.Compound a : attrs) {
474             switch (types.getRetention(a)) {
475             case SOURCE: break;
476             case CLASS: invisibles.append(a); break;
477             case RUNTIME: visibles.append(a); break;
478             default: // /* fail soft */ throw new AssertionError(vis);
479             }
480         }
481 
482         int attrCount = 0;
483         if (visibles.length() != 0) {
484             int attrIndex = writeAttr(names.RuntimeVisibleAnnotations);
485             databuf.appendChar(visibles.length());
486             for (Attribute.Compound a : visibles)
487                 writeCompoundAttribute(a);
488             endAttr(attrIndex);
489             attrCount++;
490         }
491         if (invisibles.length() != 0) {
492             int attrIndex = writeAttr(names.RuntimeInvisibleAnnotations);
493             databuf.appendChar(invisibles.length());
494             for (Attribute.Compound a : invisibles)
495                 writeCompoundAttribute(a);
496             endAttr(attrIndex);
497             attrCount++;
498         }
499         return attrCount;
500     }
501 
writeTypeAnnotations(List<Attribute.TypeCompound> typeAnnos, boolean inCode)502     int writeTypeAnnotations(List<Attribute.TypeCompound> typeAnnos, boolean inCode) {
503         if (typeAnnos.isEmpty()) return 0;
504 
505         ListBuffer<Attribute.TypeCompound> visibles = new ListBuffer<>();
506         ListBuffer<Attribute.TypeCompound> invisibles = new ListBuffer<>();
507 
508         for (Attribute.TypeCompound tc : typeAnnos) {
509             if (tc.hasUnknownPosition()) {
510                 boolean fixed = tc.tryFixPosition();
511 
512                 // Could we fix it?
513                 if (!fixed) {
514                     // This happens for nested types like @A Outer. @B Inner.
515                     // For method parameters we get the annotation twice! Once with
516                     // a valid position, once unknown.
517                     // TODO: find a cleaner solution.
518                     PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
519                     pw.println("ClassWriter: Position UNKNOWN in type annotation: " + tc);
520                     continue;
521                 }
522             }
523 
524             if (tc.position.type.isLocal() != inCode)
525                 continue;
526             if (!tc.position.emitToClassfile())
527                 continue;
528             switch (types.getRetention(tc)) {
529             case SOURCE: break;
530             case CLASS: invisibles.append(tc); break;
531             case RUNTIME: visibles.append(tc); break;
532             default: // /* fail soft */ throw new AssertionError(vis);
533             }
534         }
535 
536         int attrCount = 0;
537         if (visibles.length() != 0) {
538             int attrIndex = writeAttr(names.RuntimeVisibleTypeAnnotations);
539             databuf.appendChar(visibles.length());
540             for (Attribute.TypeCompound p : visibles)
541                 writeTypeAnnotation(p);
542             endAttr(attrIndex);
543             attrCount++;
544         }
545 
546         if (invisibles.length() != 0) {
547             int attrIndex = writeAttr(names.RuntimeInvisibleTypeAnnotations);
548             databuf.appendChar(invisibles.length());
549             for (Attribute.TypeCompound p : invisibles)
550                 writeTypeAnnotation(p);
551             endAttr(attrIndex);
552             attrCount++;
553         }
554 
555         return attrCount;
556     }
557 
558     /** A visitor to write an attribute including its leading
559      *  single-character marker.
560      */
561     class AttributeWriter implements Attribute.Visitor {
visitConstant(Attribute.Constant _value)562         public void visitConstant(Attribute.Constant _value) {
563             if (_value.type.getTag() == CLASS) {
564                 Assert.check(_value.value instanceof String);
565                 String s = (String)_value.value;
566                 databuf.appendByte('s');
567                 databuf.appendChar(poolWriter.putName(names.fromString(s)));
568             } else {
569                 switch (_value.type.getTag()) {
570                     case BYTE:
571                         databuf.appendByte('B');
572                         break;
573                     case CHAR:
574                         databuf.appendByte('C');
575                         break;
576                     case SHORT:
577                         databuf.appendByte('S');
578                         break;
579                     case INT:
580                         databuf.appendByte('I');
581                         break;
582                     case LONG:
583                         databuf.appendByte('J');
584                         break;
585                     case FLOAT:
586                         databuf.appendByte('F');
587                         break;
588                     case DOUBLE:
589                         databuf.appendByte('D');
590                         break;
591                     case BOOLEAN:
592                         databuf.appendByte('Z');
593                         break;
594                     default:
595                         throw new AssertionError(_value.type);
596                 }
597                 databuf.appendChar(poolWriter.putConstant(_value.value));
598             }
599         }
visitEnum(Attribute.Enum e)600         public void visitEnum(Attribute.Enum e) {
601             databuf.appendByte('e');
602             databuf.appendChar(poolWriter.putDescriptor(e.value.type));
603             databuf.appendChar(poolWriter.putName(e.value.name));
604         }
visitClass(Attribute.Class clazz)605         public void visitClass(Attribute.Class clazz) {
606             databuf.appendByte('c');
607             databuf.appendChar(poolWriter.putDescriptor(clazz.classType));
608         }
visitCompound(Attribute.Compound compound)609         public void visitCompound(Attribute.Compound compound) {
610             databuf.appendByte('@');
611             writeCompoundAttribute(compound);
612         }
visitError(Attribute.Error x)613         public void visitError(Attribute.Error x) {
614             throw new AssertionError(x);
615         }
visitArray(Attribute.Array array)616         public void visitArray(Attribute.Array array) {
617             databuf.appendByte('[');
618             databuf.appendChar(array.values.length);
619             for (Attribute a : array.values) {
620                 a.accept(this);
621             }
622         }
623     }
624     AttributeWriter awriter = new AttributeWriter();
625 
626     /** Write a compound attribute excluding the '@' marker. */
writeCompoundAttribute(Attribute.Compound c)627     void writeCompoundAttribute(Attribute.Compound c) {
628         databuf.appendChar(poolWriter.putDescriptor(c.type));
629         databuf.appendChar(c.values.length());
630         for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) {
631             databuf.appendChar(poolWriter.putName(p.fst.name));
632             p.snd.accept(awriter);
633         }
634     }
635 
writeTypeAnnotation(Attribute.TypeCompound c)636     void writeTypeAnnotation(Attribute.TypeCompound c) {
637         writePosition(c.position);
638         writeCompoundAttribute(c);
639     }
640 
writePosition(TypeAnnotationPosition p)641     void writePosition(TypeAnnotationPosition p) {
642         databuf.appendByte(p.type.targetTypeValue()); // TargetType tag is a byte
643         switch (p.type) {
644         // instanceof
645         case INSTANCEOF:
646         // new expression
647         case NEW:
648         // constructor/method reference receiver
649         case CONSTRUCTOR_REFERENCE:
650         case METHOD_REFERENCE:
651             databuf.appendChar(p.offset);
652             break;
653         // local variable
654         case LOCAL_VARIABLE:
655         // resource variable
656         case RESOURCE_VARIABLE:
657             databuf.appendChar(p.lvarOffset.length);  // for table length
658             for (int i = 0; i < p.lvarOffset.length; ++i) {
659                 databuf.appendChar(p.lvarOffset[i]);
660                 databuf.appendChar(p.lvarLength[i]);
661                 databuf.appendChar(p.lvarIndex[i]);
662             }
663             break;
664         // exception parameter
665         case EXCEPTION_PARAMETER:
666             databuf.appendChar(p.getExceptionIndex());
667             break;
668         // method receiver
669         case METHOD_RECEIVER:
670             // Do nothing
671             break;
672         // type parameter
673         case CLASS_TYPE_PARAMETER:
674         case METHOD_TYPE_PARAMETER:
675             databuf.appendByte(p.parameter_index);
676             break;
677         // type parameter bound
678         case CLASS_TYPE_PARAMETER_BOUND:
679         case METHOD_TYPE_PARAMETER_BOUND:
680             databuf.appendByte(p.parameter_index);
681             databuf.appendByte(p.bound_index);
682             break;
683         // class extends or implements clause
684         case CLASS_EXTENDS:
685             databuf.appendChar(p.type_index);
686             break;
687         // throws
688         case THROWS:
689             databuf.appendChar(p.type_index);
690             break;
691         // method parameter
692         case METHOD_FORMAL_PARAMETER:
693             databuf.appendByte(p.parameter_index);
694             break;
695         // type cast
696         case CAST:
697         // method/constructor/reference type argument
698         case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
699         case METHOD_INVOCATION_TYPE_ARGUMENT:
700         case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
701         case METHOD_REFERENCE_TYPE_ARGUMENT:
702             databuf.appendChar(p.offset);
703             databuf.appendByte(p.type_index);
704             break;
705         // We don't need to worry about these
706         case METHOD_RETURN:
707         case FIELD:
708             break;
709         case UNKNOWN:
710             throw new AssertionError("jvm.ClassWriter: UNKNOWN target type should never occur!");
711         default:
712             throw new AssertionError("jvm.ClassWriter: Unknown target type for position: " + p);
713         }
714 
715         { // Append location data for generics/arrays.
716             databuf.appendByte(p.location.size());
717             java.util.List<Integer> loc = TypeAnnotationPosition.getBinaryFromTypePath(p.location);
718             for (int i : loc)
719                 databuf.appendByte((byte)i);
720         }
721     }
722 
723 /**********************************************************************
724  * Writing module attributes
725  **********************************************************************/
726 
727     /** Write the Module attribute if needed.
728      *  Returns the number of attributes written (0 or 1).
729      */
writeModuleAttribute(ClassSymbol c)730     int writeModuleAttribute(ClassSymbol c) {
731         ModuleSymbol m = (ModuleSymbol) c.owner;
732 
733         int alenIdx = writeAttr(names.Module);
734 
735         databuf.appendChar(poolWriter.putModule(m));
736         databuf.appendChar(ModuleFlags.value(m.flags)); // module_flags
737         databuf.appendChar(m.version != null ? poolWriter.putName(m.version) : 0);
738 
739         ListBuffer<RequiresDirective> requires = new ListBuffer<>();
740         for (RequiresDirective r: m.requires) {
741             if (!r.flags.contains(RequiresFlag.EXTRA))
742                 requires.add(r);
743         }
744         databuf.appendChar(requires.size());
745         for (RequiresDirective r: requires) {
746             databuf.appendChar(poolWriter.putModule(r.module));
747             databuf.appendChar(RequiresFlag.value(r.flags));
748             databuf.appendChar(r.module.version != null ? poolWriter.putName(r.module.version) : 0);
749         }
750 
751         List<ExportsDirective> exports = m.exports;
752         databuf.appendChar(exports.size());
753         for (ExportsDirective e: exports) {
754             databuf.appendChar(poolWriter.putPackage(e.packge));
755             databuf.appendChar(ExportsFlag.value(e.flags));
756             if (e.modules == null) {
757                 databuf.appendChar(0);
758             } else {
759                 databuf.appendChar(e.modules.size());
760                 for (ModuleSymbol msym: e.modules) {
761                     databuf.appendChar(poolWriter.putModule(msym));
762                 }
763             }
764         }
765 
766         List<OpensDirective> opens = m.opens;
767         databuf.appendChar(opens.size());
768         for (OpensDirective o: opens) {
769             databuf.appendChar(poolWriter.putPackage(o.packge));
770             databuf.appendChar(OpensFlag.value(o.flags));
771             if (o.modules == null) {
772                 databuf.appendChar(0);
773             } else {
774                 databuf.appendChar(o.modules.size());
775                 for (ModuleSymbol msym: o.modules) {
776                     databuf.appendChar(poolWriter.putModule(msym));
777                 }
778             }
779         }
780 
781         List<UsesDirective> uses = m.uses;
782         databuf.appendChar(uses.size());
783         for (UsesDirective s: uses) {
784             databuf.appendChar(poolWriter.putClass(s.service));
785         }
786 
787         // temporary fix to merge repeated provides clause for same service;
788         // eventually this should be disallowed when analyzing the module,
789         // so that each service type only appears once.
790         Map<ClassSymbol, Set<ClassSymbol>> mergedProvides = new LinkedHashMap<>();
791         for (ProvidesDirective p : m.provides) {
792             mergedProvides.computeIfAbsent(p.service, s -> new LinkedHashSet<>()).addAll(p.impls);
793         }
794         databuf.appendChar(mergedProvides.size());
795         mergedProvides.forEach((srvc, impls) -> {
796             databuf.appendChar(poolWriter.putClass(srvc));
797             databuf.appendChar(impls.size());
798             impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl)));
799         });
800 
801         endAttr(alenIdx);
802         return 1;
803     }
804 
805 /**********************************************************************
806  * Writing Objects
807  **********************************************************************/
808 
809     /** Write "inner classes" attribute.
810      */
writeInnerClasses()811     void writeInnerClasses() {
812         int alenIdx = writeAttr(names.InnerClasses);
813         databuf.appendChar(poolWriter.innerClasses.size());
814         for (ClassSymbol inner : poolWriter.innerClasses) {
815             inner.markAbstractIfNeeded(types);
816             char flags = (char) adjustFlags(inner.flags_field);
817             if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT
818             flags &= ~STRICTFP; //inner classes should not have the strictfp flag set.
819             if (dumpInnerClassModifiers) {
820                 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
821                 pw.println("INNERCLASS  " + inner.name);
822                 pw.println("---" + flagNames(flags));
823             }
824             databuf.appendChar(poolWriter.putClass(inner));
825             databuf.appendChar(
826                 inner.owner.kind == TYP && !inner.name.isEmpty() ? poolWriter.putClass((ClassSymbol)inner.owner) : 0);
827             databuf.appendChar(
828                 !inner.name.isEmpty() ? poolWriter.putName(inner.name) : 0);
829             databuf.appendChar(flags);
830         }
831         endAttr(alenIdx);
832     }
833 
834     /**
835      * Write NestMembers attribute (if needed)
836      */
writeNestMembersIfNeeded(ClassSymbol csym)837     int writeNestMembersIfNeeded(ClassSymbol csym) {
838         ListBuffer<ClassSymbol> nested = new ListBuffer<>();
839         listNested(csym, nested);
840         Set<ClassSymbol> nestedUnique = new LinkedHashSet<>(nested);
841         if (csym.owner.kind == PCK && !nestedUnique.isEmpty()) {
842             int alenIdx = writeAttr(names.NestMembers);
843             databuf.appendChar(nestedUnique.size());
844             for (ClassSymbol s : nestedUnique) {
845                 databuf.appendChar(poolWriter.putClass(s));
846             }
847             endAttr(alenIdx);
848             return 1;
849         }
850         return 0;
851     }
852 
853     /**
854      * Write NestHost attribute (if needed)
855      */
writeNestHostIfNeeded(ClassSymbol csym)856     int writeNestHostIfNeeded(ClassSymbol csym) {
857         if (csym.owner.kind != PCK) {
858             int alenIdx = writeAttr(names.NestHost);
859             databuf.appendChar(poolWriter.putClass(csym.outermostClass()));
860             endAttr(alenIdx);
861             return 1;
862         }
863         return 0;
864     }
865 
listNested(Symbol sym, ListBuffer<ClassSymbol> seen)866     private void listNested(Symbol sym, ListBuffer<ClassSymbol> seen) {
867         if (sym.kind != TYP) return;
868         ClassSymbol csym = (ClassSymbol)sym;
869         if (csym.owner.kind != PCK) {
870             seen.add(csym);
871         }
872         if (csym.members() != null) {
873             for (Symbol s : sym.members().getSymbols()) {
874                 listNested(s, seen);
875             }
876         }
877         if (csym.trans_local != null) {
878             for (Symbol s : csym.trans_local) {
879                 listNested(s, seen);
880             }
881         }
882     }
883 
884     /** Write "bootstrapMethods" attribute.
885      */
writeBootstrapMethods()886     void writeBootstrapMethods() {
887         int alenIdx = writeAttr(names.BootstrapMethods);
888         databuf.appendChar(poolWriter.bootstrapMethods.size());
889         for (BsmKey bsmKey : poolWriter.bootstrapMethods.keySet()) {
890             //write BSM handle
891             databuf.appendChar(poolWriter.putConstant(bsmKey.bsm));
892             LoadableConstant[] uniqueArgs = bsmKey.staticArgs;
893             //write static args length
894             databuf.appendChar(uniqueArgs.length);
895             //write static args array
896             for (LoadableConstant arg : uniqueArgs) {
897                 databuf.appendChar(poolWriter.putConstant(arg));
898             }
899         }
900         endAttr(alenIdx);
901     }
902 
903     /** Write field symbol, entering all references into constant pool.
904      */
writeField(VarSymbol v)905     void writeField(VarSymbol v) {
906         int flags = adjustFlags(v.flags());
907         databuf.appendChar(flags);
908         if (dumpFieldModifiers) {
909             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
910             pw.println("FIELD  " + v.name);
911             pw.println("---" + flagNames(v.flags()));
912         }
913         databuf.appendChar(poolWriter.putName(v.name));
914         databuf.appendChar(poolWriter.putDescriptor(v));
915         int acountIdx = beginAttrs();
916         int acount = 0;
917         if (v.getConstValue() != null) {
918             int alenIdx = writeAttr(names.ConstantValue);
919             databuf.appendChar(poolWriter.putConstant(v.getConstValue()));
920             endAttr(alenIdx);
921             acount++;
922         }
923         acount += writeMemberAttrs(v);
924         endAttrs(acountIdx, acount);
925     }
926 
927     /** Write method symbol, entering all references into constant pool.
928      */
writeMethod(MethodSymbol m)929     void writeMethod(MethodSymbol m) {
930         int flags = adjustFlags(m.flags());
931         databuf.appendChar(flags);
932         if (dumpMethodModifiers) {
933             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
934             pw.println("METHOD  " + m.name);
935             pw.println("---" + flagNames(m.flags()));
936         }
937         databuf.appendChar(poolWriter.putName(m.name));
938         databuf.appendChar(poolWriter.putDescriptor(m));
939         int acountIdx = beginAttrs();
940         int acount = 0;
941         if (m.code != null) {
942             int alenIdx = writeAttr(names.Code);
943             writeCode(m.code);
944             m.code = null; // to conserve space
945             endAttr(alenIdx);
946             acount++;
947         }
948         List<Type> thrown = m.erasure(types).getThrownTypes();
949         if (thrown.nonEmpty()) {
950             int alenIdx = writeAttr(names.Exceptions);
951             databuf.appendChar(thrown.length());
952             for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
953                 databuf.appendChar(poolWriter.putClass(l.head));
954             endAttr(alenIdx);
955             acount++;
956         }
957         if (m.defaultValue != null) {
958             int alenIdx = writeAttr(names.AnnotationDefault);
959             m.defaultValue.accept(awriter);
960             endAttr(alenIdx);
961             acount++;
962         }
963         if (options.isSet(PARAMETERS) && target.hasMethodParameters()) {
964             if (!m.isLambdaMethod()) // Per JDK-8138729, do not emit parameters table for lambda bodies.
965                 acount += writeMethodParametersAttr(m);
966         }
967         acount += writeMemberAttrs(m);
968         if (!m.isLambdaMethod())
969             acount += writeParameterAttrs(m);
970         endAttrs(acountIdx, acount);
971     }
972 
973     /** Write code attribute of method.
974      */
writeCode(Code code)975     void writeCode(Code code) {
976         databuf.appendChar(code.max_stack);
977         databuf.appendChar(code.max_locals);
978         databuf.appendInt(code.cp);
979         databuf.appendBytes(code.code, 0, code.cp);
980         databuf.appendChar(code.catchInfo.length());
981         for (List<char[]> l = code.catchInfo.toList();
982              l.nonEmpty();
983              l = l.tail) {
984             for (int i = 0; i < l.head.length; i++)
985                 databuf.appendChar(l.head[i]);
986         }
987         int acountIdx = beginAttrs();
988         int acount = 0;
989 
990         if (code.lineInfo.nonEmpty()) {
991             int alenIdx = writeAttr(names.LineNumberTable);
992             databuf.appendChar(code.lineInfo.length());
993             for (List<char[]> l = code.lineInfo.reverse();
994                  l.nonEmpty();
995                  l = l.tail)
996                 for (int i = 0; i < l.head.length; i++)
997                     databuf.appendChar(l.head[i]);
998             endAttr(alenIdx);
999             acount++;
1000         }
1001 
1002         if (genCrt && (code.crt != null)) {
1003             CRTable crt = code.crt;
1004             int alenIdx = writeAttr(names.CharacterRangeTable);
1005             int crtIdx = beginAttrs();
1006             int crtEntries = crt.writeCRT(databuf, code.lineMap, log);
1007             endAttrs(crtIdx, crtEntries);
1008             endAttr(alenIdx);
1009             acount++;
1010         }
1011 
1012         // counter for number of generic local variables
1013         if (code.varDebugInfo && code.varBufferSize > 0) {
1014             int nGenericVars = 0;
1015             int alenIdx = writeAttr(names.LocalVariableTable);
1016             databuf.appendChar(code.getLVTSize());
1017             for (int i=0; i<code.varBufferSize; i++) {
1018                 Code.LocalVar var = code.varBuffer[i];
1019 
1020                 for (Code.LocalVar.Range r: var.aliveRanges) {
1021                     // write variable info
1022                     Assert.check(r.start_pc >= 0
1023                             && r.start_pc <= code.cp);
1024                     databuf.appendChar(r.start_pc);
1025                     Assert.check(r.length > 0
1026                             && (r.start_pc + r.length) <= code.cp);
1027                     databuf.appendChar(r.length);
1028                     VarSymbol sym = var.sym;
1029                     databuf.appendChar(poolWriter.putName(sym.name));
1030                     databuf.appendChar(poolWriter.putDescriptor(sym));
1031                     databuf.appendChar(var.reg);
1032                     if (needsLocalVariableTypeEntry(var.sym.type)) {
1033                         nGenericVars++;
1034                     }
1035                 }
1036             }
1037             endAttr(alenIdx);
1038             acount++;
1039 
1040             if (nGenericVars > 0) {
1041                 alenIdx = writeAttr(names.LocalVariableTypeTable);
1042                 databuf.appendChar(nGenericVars);
1043                 int count = 0;
1044 
1045                 for (int i=0; i<code.varBufferSize; i++) {
1046                     Code.LocalVar var = code.varBuffer[i];
1047                     VarSymbol sym = var.sym;
1048                     if (!needsLocalVariableTypeEntry(sym.type))
1049                         continue;
1050                     for (Code.LocalVar.Range r : var.aliveRanges) {
1051                         // write variable info
1052                         databuf.appendChar(r.start_pc);
1053                         databuf.appendChar(r.length);
1054                         databuf.appendChar(poolWriter.putName(sym.name));
1055                         databuf.appendChar(poolWriter.putSignature(sym));
1056                         databuf.appendChar(var.reg);
1057                         count++;
1058                     }
1059                 }
1060                 Assert.check(count == nGenericVars);
1061                 endAttr(alenIdx);
1062                 acount++;
1063             }
1064         }
1065 
1066         if (code.stackMapBufferSize > 0) {
1067             if (debugstackmap) System.out.println("Stack map for " + code.meth);
1068             int alenIdx = writeAttr(code.stackMap.getAttributeName(names));
1069             writeStackMap(code);
1070             endAttr(alenIdx);
1071             acount++;
1072         }
1073 
1074         acount += writeTypeAnnotations(code.meth.getRawTypeAttributes(), true);
1075 
1076         endAttrs(acountIdx, acount);
1077     }
1078     //where
needsLocalVariableTypeEntry(Type t)1079     private boolean needsLocalVariableTypeEntry(Type t) {
1080         //a local variable needs a type-entry if its type T is generic
1081         //(i.e. |T| != T) and if it's not an non-denotable type (non-denotable
1082         // types are not supported in signature attribute grammar!)
1083         return !types.isSameType(t, types.erasure(t)) &&
1084                 check.checkDenotable(t);
1085     }
1086 
writeStackMap(Code code)1087     void writeStackMap(Code code) {
1088         int nframes = code.stackMapBufferSize;
1089         if (debugstackmap) System.out.println(" nframes = " + nframes);
1090         databuf.appendChar(nframes);
1091 
1092         switch (code.stackMap) {
1093         case CLDC:
1094             for (int i=0; i<nframes; i++) {
1095                 if (debugstackmap) System.out.print("  " + i + ":");
1096                 Code.StackMapFrame frame = code.stackMapBuffer[i];
1097 
1098                 // output PC
1099                 if (debugstackmap) System.out.print(" pc=" + frame.pc);
1100                 databuf.appendChar(frame.pc);
1101 
1102                 // output locals
1103                 int localCount = 0;
1104                 for (int j=0; j<frame.locals.length;
1105                      j += Code.width(frame.locals[j])) {
1106                     localCount++;
1107                 }
1108                 if (debugstackmap) System.out.print(" nlocals=" +
1109                                                     localCount);
1110                 databuf.appendChar(localCount);
1111                 for (int j=0; j<frame.locals.length;
1112                      j += Code.width(frame.locals[j])) {
1113                     if (debugstackmap) System.out.print(" local[" + j + "]=");
1114                     writeStackMapType(frame.locals[j]);
1115                 }
1116 
1117                 // output stack
1118                 int stackCount = 0;
1119                 for (int j=0; j<frame.stack.length;
1120                      j += Code.width(frame.stack[j])) {
1121                     stackCount++;
1122                 }
1123                 if (debugstackmap) System.out.print(" nstack=" +
1124                                                     stackCount);
1125                 databuf.appendChar(stackCount);
1126                 for (int j=0; j<frame.stack.length;
1127                      j += Code.width(frame.stack[j])) {
1128                     if (debugstackmap) System.out.print(" stack[" + j + "]=");
1129                     writeStackMapType(frame.stack[j]);
1130                 }
1131                 if (debugstackmap) System.out.println();
1132             }
1133             break;
1134         case JSR202: {
1135             Assert.checkNull(code.stackMapBuffer);
1136             for (int i=0; i<nframes; i++) {
1137                 if (debugstackmap) System.out.print("  " + i + ":");
1138                 StackMapTableFrame frame = code.stackMapTableBuffer[i];
1139                 frame.write(this);
1140                 if (debugstackmap) System.out.println();
1141             }
1142             break;
1143         }
1144         default:
1145             throw new AssertionError("Unexpected stackmap format value");
1146         }
1147     }
1148 
1149         //where
writeStackMapType(Type t)1150         void writeStackMapType(Type t) {
1151             if (t == null) {
1152                 if (debugstackmap) System.out.print("empty");
1153                 databuf.appendByte(0);
1154             }
1155             else switch(t.getTag()) {
1156             case BYTE:
1157             case CHAR:
1158             case SHORT:
1159             case INT:
1160             case BOOLEAN:
1161                 if (debugstackmap) System.out.print("int");
1162                 databuf.appendByte(1);
1163                 break;
1164             case FLOAT:
1165                 if (debugstackmap) System.out.print("float");
1166                 databuf.appendByte(2);
1167                 break;
1168             case DOUBLE:
1169                 if (debugstackmap) System.out.print("double");
1170                 databuf.appendByte(3);
1171                 break;
1172             case LONG:
1173                 if (debugstackmap) System.out.print("long");
1174                 databuf.appendByte(4);
1175                 break;
1176             case BOT: // null
1177                 if (debugstackmap) System.out.print("null");
1178                 databuf.appendByte(5);
1179                 break;
1180             case CLASS:
1181             case ARRAY:
1182             case TYPEVAR:
1183                 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1184                 databuf.appendByte(7);
1185                 databuf.appendChar(poolWriter.putClass(types.erasure(t)));
1186                 break;
1187             case UNINITIALIZED_THIS:
1188                 if (debugstackmap) System.out.print("uninit_this");
1189                 databuf.appendByte(6);
1190                 break;
1191             case UNINITIALIZED_OBJECT:
1192                 { UninitializedType uninitType = (UninitializedType)t;
1193                 databuf.appendByte(8);
1194                 if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset);
1195                 databuf.appendChar(uninitType.offset);
1196                 }
1197                 break;
1198             default:
1199                 throw new AssertionError();
1200             }
1201         }
1202 
1203     /** An entry in the JSR202 StackMapTable */
1204     abstract static class StackMapTableFrame {
getFrameType()1205         abstract int getFrameType();
1206 
write(ClassWriter writer)1207         void write(ClassWriter writer) {
1208             int frameType = getFrameType();
1209             writer.databuf.appendByte(frameType);
1210             if (writer.debugstackmap) System.out.print(" frame_type=" + frameType);
1211         }
1212 
1213         static class SameFrame extends StackMapTableFrame {
1214             final int offsetDelta;
SameFrame(int offsetDelta)1215             SameFrame(int offsetDelta) {
1216                 this.offsetDelta = offsetDelta;
1217             }
getFrameType()1218             int getFrameType() {
1219                 return (offsetDelta < SAME_FRAME_SIZE) ? offsetDelta : SAME_FRAME_EXTENDED;
1220             }
1221             @Override
write(ClassWriter writer)1222             void write(ClassWriter writer) {
1223                 super.write(writer);
1224                 if (getFrameType() == SAME_FRAME_EXTENDED) {
1225                     writer.databuf.appendChar(offsetDelta);
1226                     if (writer.debugstackmap){
1227                         System.out.print(" offset_delta=" + offsetDelta);
1228                     }
1229                 }
1230             }
1231         }
1232 
1233         static class SameLocals1StackItemFrame extends StackMapTableFrame {
1234             final int offsetDelta;
1235             final Type stack;
SameLocals1StackItemFrame(int offsetDelta, Type stack)1236             SameLocals1StackItemFrame(int offsetDelta, Type stack) {
1237                 this.offsetDelta = offsetDelta;
1238                 this.stack = stack;
1239             }
getFrameType()1240             int getFrameType() {
1241                 return (offsetDelta < SAME_FRAME_SIZE) ?
1242                        (SAME_FRAME_SIZE + offsetDelta) :
1243                        SAME_LOCALS_1_STACK_ITEM_EXTENDED;
1244             }
1245             @Override
write(ClassWriter writer)1246             void write(ClassWriter writer) {
1247                 super.write(writer);
1248                 if (getFrameType() == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
1249                     writer.databuf.appendChar(offsetDelta);
1250                     if (writer.debugstackmap) {
1251                         System.out.print(" offset_delta=" + offsetDelta);
1252                     }
1253                 }
1254                 if (writer.debugstackmap) {
1255                     System.out.print(" stack[" + 0 + "]=");
1256                 }
1257                 writer.writeStackMapType(stack);
1258             }
1259         }
1260 
1261         static class ChopFrame extends StackMapTableFrame {
1262             final int frameType;
1263             final int offsetDelta;
ChopFrame(int frameType, int offsetDelta)1264             ChopFrame(int frameType, int offsetDelta) {
1265                 this.frameType = frameType;
1266                 this.offsetDelta = offsetDelta;
1267             }
getFrameType()1268             int getFrameType() { return frameType; }
1269             @Override
write(ClassWriter writer)1270             void write(ClassWriter writer) {
1271                 super.write(writer);
1272                 writer.databuf.appendChar(offsetDelta);
1273                 if (writer.debugstackmap) {
1274                     System.out.print(" offset_delta=" + offsetDelta);
1275                 }
1276             }
1277         }
1278 
1279         static class AppendFrame extends StackMapTableFrame {
1280             final int frameType;
1281             final int offsetDelta;
1282             final Type[] locals;
AppendFrame(int frameType, int offsetDelta, Type[] locals)1283             AppendFrame(int frameType, int offsetDelta, Type[] locals) {
1284                 this.frameType = frameType;
1285                 this.offsetDelta = offsetDelta;
1286                 this.locals = locals;
1287             }
getFrameType()1288             int getFrameType() { return frameType; }
1289             @Override
write(ClassWriter writer)1290             void write(ClassWriter writer) {
1291                 super.write(writer);
1292                 writer.databuf.appendChar(offsetDelta);
1293                 if (writer.debugstackmap) {
1294                     System.out.print(" offset_delta=" + offsetDelta);
1295                 }
1296                 for (int i=0; i<locals.length; i++) {
1297                      if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1298                      writer.writeStackMapType(locals[i]);
1299                 }
1300             }
1301         }
1302 
1303         static class FullFrame extends StackMapTableFrame {
1304             final int offsetDelta;
1305             final Type[] locals;
1306             final Type[] stack;
FullFrame(int offsetDelta, Type[] locals, Type[] stack)1307             FullFrame(int offsetDelta, Type[] locals, Type[] stack) {
1308                 this.offsetDelta = offsetDelta;
1309                 this.locals = locals;
1310                 this.stack = stack;
1311             }
getFrameType()1312             int getFrameType() { return FULL_FRAME; }
1313             @Override
write(ClassWriter writer)1314             void write(ClassWriter writer) {
1315                 super.write(writer);
1316                 writer.databuf.appendChar(offsetDelta);
1317                 writer.databuf.appendChar(locals.length);
1318                 if (writer.debugstackmap) {
1319                     System.out.print(" offset_delta=" + offsetDelta);
1320                     System.out.print(" nlocals=" + locals.length);
1321                 }
1322                 for (int i=0; i<locals.length; i++) {
1323                     if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1324                     writer.writeStackMapType(locals[i]);
1325                 }
1326 
1327                 writer.databuf.appendChar(stack.length);
1328                 if (writer.debugstackmap) { System.out.print(" nstack=" + stack.length); }
1329                 for (int i=0; i<stack.length; i++) {
1330                     if (writer.debugstackmap) System.out.print(" stack[" + i + "]=");
1331                     writer.writeStackMapType(stack[i]);
1332                 }
1333             }
1334         }
1335 
1336        /** Compare this frame with the previous frame and produce
1337         *  an entry of compressed stack map frame. */
getInstance(Code.StackMapFrame this_frame, int prev_pc, Type[] prev_locals, Types types)1338         static StackMapTableFrame getInstance(Code.StackMapFrame this_frame,
1339                                               int prev_pc,
1340                                               Type[] prev_locals,
1341                                               Types types) {
1342             Type[] locals = this_frame.locals;
1343             Type[] stack = this_frame.stack;
1344             int offset_delta = this_frame.pc - prev_pc - 1;
1345             if (stack.length == 1) {
1346                 if (locals.length == prev_locals.length
1347                     && compare(prev_locals, locals, types) == 0) {
1348                     return new SameLocals1StackItemFrame(offset_delta, stack[0]);
1349                 }
1350             } else if (stack.length == 0) {
1351                 int diff_length = compare(prev_locals, locals, types);
1352                 if (diff_length == 0) {
1353                     return new SameFrame(offset_delta);
1354                 } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) {
1355                     // APPEND
1356                     Type[] local_diff = new Type[-diff_length];
1357                     for (int i=prev_locals.length, j=0; i<locals.length; i++,j++) {
1358                         local_diff[j] = locals[i];
1359                     }
1360                     return new AppendFrame(SAME_FRAME_EXTENDED - diff_length,
1361                                            offset_delta,
1362                                            local_diff);
1363                 } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) {
1364                     // CHOP
1365                     return new ChopFrame(SAME_FRAME_EXTENDED - diff_length,
1366                                          offset_delta);
1367                 }
1368             }
1369             // FULL_FRAME
1370             return new FullFrame(offset_delta, locals, stack);
1371         }
1372 
isInt(Type t)1373         static boolean isInt(Type t) {
1374             return (t.getTag().isStrictSubRangeOf(INT)  || t.hasTag(BOOLEAN));
1375         }
1376 
isSameType(Type t1, Type t2, Types types)1377         static boolean isSameType(Type t1, Type t2, Types types) {
1378             if (t1 == null) { return t2 == null; }
1379             if (t2 == null) { return false; }
1380 
1381             if (isInt(t1) && isInt(t2)) { return true; }
1382 
1383             if (t1.hasTag(UNINITIALIZED_THIS)) {
1384                 return t2.hasTag(UNINITIALIZED_THIS);
1385             } else if (t1.hasTag(UNINITIALIZED_OBJECT)) {
1386                 if (t2.hasTag(UNINITIALIZED_OBJECT)) {
1387                     return ((UninitializedType)t1).offset == ((UninitializedType)t2).offset;
1388                 } else {
1389                     return false;
1390                 }
1391             } else if (t2.hasTag(UNINITIALIZED_THIS) || t2.hasTag(UNINITIALIZED_OBJECT)) {
1392                 return false;
1393             }
1394 
1395             return types.isSameType(t1, t2);
1396         }
1397 
compare(Type[] arr1, Type[] arr2, Types types)1398         static int compare(Type[] arr1, Type[] arr2, Types types) {
1399             int diff_length = arr1.length - arr2.length;
1400             if (diff_length > MAX_LOCAL_LENGTH_DIFF || diff_length < -MAX_LOCAL_LENGTH_DIFF) {
1401                 return Integer.MAX_VALUE;
1402             }
1403             int len = (diff_length > 0) ? arr2.length : arr1.length;
1404             for (int i=0; i<len; i++) {
1405                 if (!isSameType(arr1[i], arr2[i], types)) {
1406                     return Integer.MAX_VALUE;
1407                 }
1408             }
1409             return diff_length;
1410         }
1411     }
1412 
writeFields(Scope s)1413     void writeFields(Scope s) {
1414         // process them in reverse sibling order;
1415         // i.e., process them in declaration order.
1416         List<VarSymbol> vars = List.nil();
1417         for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
1418             if (sym.kind == VAR) vars = vars.prepend((VarSymbol)sym);
1419         }
1420         while (vars.nonEmpty()) {
1421             writeField(vars.head);
1422             vars = vars.tail;
1423         }
1424     }
1425 
writeMethods(Scope s)1426     void writeMethods(Scope s) {
1427         List<MethodSymbol> methods = List.nil();
1428         for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
1429             if (sym.kind == MTH && (sym.flags() & HYPOTHETICAL) == 0)
1430                 methods = methods.prepend((MethodSymbol)sym);
1431         }
1432         while (methods.nonEmpty()) {
1433             writeMethod(methods.head);
1434             methods = methods.tail;
1435         }
1436     }
1437 
1438     /** Emit a class file for a given class.
1439      *  @param c      The class from which a class file is generated.
1440      */
writeClass(ClassSymbol c)1441     public JavaFileObject writeClass(ClassSymbol c)
1442         throws IOException, PoolOverflow, StringOverflow
1443     {
1444         String name = (c.owner.kind == MDL ? c.name : c.flatname).toString();
1445         Location outLocn;
1446         if (multiModuleMode) {
1447             ModuleSymbol msym = c.owner.kind == MDL ? (ModuleSymbol) c.owner : c.packge().modle;
1448             outLocn = fileManager.getLocationForModule(CLASS_OUTPUT, msym.name.toString());
1449         } else {
1450             outLocn = CLASS_OUTPUT;
1451         }
1452         JavaFileObject outFile
1453             = fileManager.getJavaFileForOutput(outLocn,
1454                                                name,
1455                                                JavaFileObject.Kind.CLASS,
1456                                                c.sourcefile);
1457         OutputStream out = outFile.openOutputStream();
1458         try {
1459             writeClassFile(out, c);
1460             if (verbose)
1461                 log.printVerbose("wrote.file", outFile.getName());
1462             out.close();
1463             out = null;
1464         } catch (InvalidSignatureException ex) {
1465             log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type())));
1466         } finally {
1467             if (out != null) {
1468                 // if we are propagating an exception, delete the file
1469                 out.close();
1470                 outFile.delete();
1471                 outFile = null;
1472             }
1473         }
1474         return outFile; // may be null if write failed
1475     }
1476 
1477     /** Write class `c' to outstream `out'.
1478      */
writeClassFile(OutputStream out, ClassSymbol c)1479     public void writeClassFile(OutputStream out, ClassSymbol c)
1480         throws IOException, PoolOverflow, StringOverflow {
1481         Assert.check((c.flags() & COMPOUND) == 0);
1482         databuf.reset();
1483         poolbuf.reset();
1484 
1485         Type supertype = types.supertype(c.type);
1486         List<Type> interfaces = types.interfaces(c.type);
1487         List<Type> typarams = c.type.getTypeArguments();
1488 
1489         int flags;
1490         if (c.owner.kind == MDL) {
1491             flags = ACC_MODULE;
1492         } else {
1493             flags = adjustFlags(c.flags() & ~DEFAULT);
1494             if ((flags & PROTECTED) != 0) flags |= PUBLIC;
1495             flags = flags & ClassFlags & ~STRICTFP;
1496             if ((flags & INTERFACE) == 0) flags |= ACC_SUPER;
1497         }
1498 
1499         if (dumpClassModifiers) {
1500             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1501             pw.println();
1502             pw.println("CLASSFILE  " + c.getQualifiedName());
1503             pw.println("---" + flagNames(flags));
1504         }
1505         databuf.appendChar(flags);
1506 
1507         if (c.owner.kind == MDL) {
1508             PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage;
1509             databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed)));
1510         } else {
1511             databuf.appendChar(poolWriter.putClass(c));
1512         }
1513         databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0);
1514         databuf.appendChar(interfaces.length());
1515         for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1516             databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym));
1517         int fieldsCount = 0;
1518         int methodsCount = 0;
1519         for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
1520             switch (sym.kind) {
1521             case VAR: fieldsCount++; break;
1522             case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
1523                       break;
1524             case TYP: poolWriter.enterInner((ClassSymbol)sym); break;
1525             default : Assert.error();
1526             }
1527         }
1528 
1529         if (c.trans_local != null) {
1530             for (ClassSymbol local : c.trans_local) {
1531                 poolWriter.enterInner(local);
1532             }
1533         }
1534 
1535         databuf.appendChar(fieldsCount);
1536         writeFields(c.members());
1537         databuf.appendChar(methodsCount);
1538         writeMethods(c.members());
1539 
1540         int acountIdx = beginAttrs();
1541         int acount = 0;
1542 
1543         boolean sigReq =
1544             typarams.length() != 0 || supertype.allparams().length() != 0;
1545         for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
1546             sigReq = l.head.allparams().length() != 0;
1547         if (sigReq) {
1548             int alenIdx = writeAttr(names.Signature);
1549             databuf.appendChar(poolWriter.putSignature(c));
1550             endAttr(alenIdx);
1551             acount++;
1552         }
1553 
1554         if (c.sourcefile != null && emitSourceFile) {
1555             int alenIdx = writeAttr(names.SourceFile);
1556             // WHM 6/29/1999: Strip file path prefix.  We do it here at
1557             // the last possible moment because the sourcefile may be used
1558             // elsewhere in error diagnostics. Fixes 4241573.
1559             String simpleName = PathFileObject.getSimpleName(c.sourcefile);
1560             databuf.appendChar(poolWriter.putName(names.fromString(simpleName)));
1561             endAttr(alenIdx);
1562             acount++;
1563         }
1564 
1565         if (genCrt) {
1566             // Append SourceID attribute
1567             int alenIdx = writeAttr(names.SourceID);
1568             databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
1569             endAttr(alenIdx);
1570             acount++;
1571             // Append CompilationID attribute
1572             alenIdx = writeAttr(names.CompilationID);
1573             databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(System.currentTimeMillis()))));
1574             endAttr(alenIdx);
1575             acount++;
1576         }
1577 
1578         acount += writeFlagAttrs(c.flags());
1579         acount += writeJavaAnnotations(c.getRawAttributes());
1580         acount += writeTypeAnnotations(c.getRawTypeAttributes(), false);
1581         acount += writeEnclosingMethodAttribute(c);
1582         if (c.owner.kind == MDL) {
1583             acount += writeModuleAttribute(c);
1584             acount += writeFlagAttrs(c.owner.flags() & ~DEPRECATED);
1585         }
1586         acount += writeExtraClassAttributes(c);
1587 
1588         poolbuf.appendInt(JAVA_MAGIC);
1589         if (preview.isEnabled()) {
1590             poolbuf.appendChar(ClassFile.PREVIEW_MINOR_VERSION);
1591         } else {
1592             poolbuf.appendChar(target.minorVersion);
1593         }
1594         poolbuf.appendChar(target.majorVersion);
1595 
1596         if (c.owner.kind != MDL) {
1597             if (target.hasNestmateAccess()) {
1598                 acount += writeNestMembersIfNeeded(c);
1599                 acount += writeNestHostIfNeeded(c);
1600             }
1601         }
1602 
1603         if (!poolWriter.bootstrapMethods.isEmpty()) {
1604             writeBootstrapMethods();
1605             acount++;
1606         }
1607 
1608         if (!poolWriter.innerClasses.isEmpty()) {
1609             writeInnerClasses();
1610             acount++;
1611         }
1612 
1613         endAttrs(acountIdx, acount);
1614 
1615         out.write(poolbuf.elems, 0, poolbuf.length);
1616 
1617         poolWriter.writePool(out);
1618         poolWriter.reset(); // to save space
1619 
1620         out.write(databuf.elems, 0, databuf.length);
1621      }
1622 
1623     /**Allows subclasses to write additional class attributes
1624      *
1625      * @return the number of attributes written
1626      */
writeExtraClassAttributes(ClassSymbol c)1627     protected int writeExtraClassAttributes(ClassSymbol c) {
1628         return 0;
1629     }
1630 
adjustFlags(final long flags)1631     int adjustFlags(final long flags) {
1632         int result = (int)flags;
1633 
1634         if ((flags & BRIDGE) != 0)
1635             result |= ACC_BRIDGE;
1636         if ((flags & VARARGS) != 0)
1637             result |= ACC_VARARGS;
1638         if ((flags & DEFAULT) != 0)
1639             result &= ~ABSTRACT;
1640         return result;
1641     }
1642 
getLastModified(FileObject filename)1643     long getLastModified(FileObject filename) {
1644         long mod = 0;
1645         try {
1646             mod = filename.getLastModified();
1647         } catch (SecurityException e) {
1648             throw new AssertionError("CRT: couldn't get source file modification date: " + e.getMessage());
1649         }
1650         return mod;
1651     }
1652 }
1653