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. */
 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      */
 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      */
 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      */
 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      */
 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;
 261         public PoolOverflow() {}
 262     }
 263     public static class StringOverflow extends RuntimeException {
 264         private static final long serialVersionUID = 0;
 265         public final String value;
 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      */
 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      */
 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      */
 294     int beginAttrs() {
 295         databuf.appendChar(0);
 296         return databuf.length;
 297     }
 298 
 299     /** Fill in number of attributes.
 300      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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 
 407     private void writeParamAnnotations(List<VarSymbol> params,
 408                                        RetentionPolicy retention) {
 409         databuf.appendByte(params.length());
 410         for (VarSymbol s : params) {
 411             ListBuffer<Attribute.Compound> buf = new ListBuffer<>();
 412             for (Attribute.Compound a : s.getRawAttributes())
 413                 if (types.getRetention(a) == retention)
 414                     buf.append(a);
 415             databuf.appendChar(buf.length());
 416             for (Attribute.Compound a : buf)
 417                 writeCompoundAttribute(a);
 418         }
 419 
 420     }
 421 
 422     private void writeParamAnnotations(MethodSymbol m,
 423                                        RetentionPolicy retention) {
 424         databuf.appendByte(m.params.length());
 425         writeParamAnnotations(m.params, retention);
 426     }
 427 
 428     /** Write method parameter annotations;
 429      *  return number of attributes written.
 430      */
 431     int writeParameterAttrs(List<VarSymbol> vars) {
 432         boolean hasVisible = false;
 433         boolean hasInvisible = false;
 434         if (vars != null) {
 435             for (VarSymbol s : vars) {
 436                 for (Attribute.Compound a : s.getRawAttributes()) {
 437                     switch (types.getRetention(a)) {
 438                     case SOURCE: break;
 439                     case CLASS: hasInvisible = true; break;
 440                     case RUNTIME: hasVisible = true; break;
 441                     default: // /* fail soft */ throw new AssertionError(vis);
 442                     }
 443                 }
 444             }
 445         }
 446 
 447         int attrCount = 0;
 448         if (hasVisible) {
 449             int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations);
 450             writeParamAnnotations(vars, RetentionPolicy.RUNTIME);
 451             endAttr(attrIndex);
 452             attrCount++;
 453         }
 454         if (hasInvisible) {
 455             int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations);
 456             writeParamAnnotations(vars, RetentionPolicy.CLASS);
 457             endAttr(attrIndex);
 458             attrCount++;
 459         }
 460         return attrCount;
 461     }
 462 
 463 /**********************************************************************
 464  * Writing Java-language annotations (aka metadata, attributes)
 465  **********************************************************************/
 466 
 467     /** Write Java-language annotations; return number of JVM
 468      *  attributes written (zero or one).
 469      */
 470     int writeJavaAnnotations(List<Attribute.Compound> attrs) {
 471         if (attrs.isEmpty()) return 0;
 472         ListBuffer<Attribute.Compound> visibles = new ListBuffer<>();
 473         ListBuffer<Attribute.Compound> invisibles = new ListBuffer<>();
 474         for (Attribute.Compound a : attrs) {
 475             switch (types.getRetention(a)) {
 476             case SOURCE: break;
 477             case CLASS: invisibles.append(a); break;
 478             case RUNTIME: visibles.append(a); break;
 479             default: // /* fail soft */ throw new AssertionError(vis);
 480             }
 481         }
 482 
 483         int attrCount = 0;
 484         if (visibles.length() != 0) {
 485             int attrIndex = writeAttr(names.RuntimeVisibleAnnotations);
 486             databuf.appendChar(visibles.length());
 487             for (Attribute.Compound a : visibles)
 488                 writeCompoundAttribute(a);
 489             endAttr(attrIndex);
 490             attrCount++;
 491         }
 492         if (invisibles.length() != 0) {
 493             int attrIndex = writeAttr(names.RuntimeInvisibleAnnotations);
 494             databuf.appendChar(invisibles.length());
 495             for (Attribute.Compound a : invisibles)
 496                 writeCompoundAttribute(a);
 497             endAttr(attrIndex);
 498             attrCount++;
 499         }
 500         return attrCount;
 501     }
 502 
 503     int writeTypeAnnotations(List<Attribute.TypeCompound> typeAnnos, boolean inCode) {
 504         if (typeAnnos.isEmpty()) return 0;
 505 
 506         ListBuffer<Attribute.TypeCompound> visibles = new ListBuffer<>();
 507         ListBuffer<Attribute.TypeCompound> invisibles = new ListBuffer<>();
 508 
 509         for (Attribute.TypeCompound tc : typeAnnos) {
 510             if (tc.hasUnknownPosition()) {
 511                 boolean fixed = tc.tryFixPosition();
 512 
 513                 // Could we fix it?
 514                 if (!fixed) {
 515                     // This happens for nested types like @A Outer. @B Inner.
 516                     // For method parameters we get the annotation twice! Once with
 517                     // a valid position, once unknown.
 518                     // TODO: find a cleaner solution.
 519                     PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 520                     pw.println("ClassWriter: Position UNKNOWN in type annotation: " + tc);
 521                     continue;
 522                 }
 523             }
 524 
 525             if (tc.position.type.isLocal() != inCode)
 526                 continue;
 527             if (!tc.position.emitToClassfile())
 528                 continue;
 529             switch (types.getRetention(tc)) {
 530             case SOURCE: break;
 531             case CLASS: invisibles.append(tc); break;
 532             case RUNTIME: visibles.append(tc); break;
 533             default: // /* fail soft */ throw new AssertionError(vis);
 534             }
 535         }
 536 
 537         int attrCount = 0;
 538         if (visibles.length() != 0) {
 539             int attrIndex = writeAttr(names.RuntimeVisibleTypeAnnotations);
 540             databuf.appendChar(visibles.length());
 541             for (Attribute.TypeCompound p : visibles)
 542                 writeTypeAnnotation(p);
 543             endAttr(attrIndex);
 544             attrCount++;
 545         }
 546 
 547         if (invisibles.length() != 0) {
 548             int attrIndex = writeAttr(names.RuntimeInvisibleTypeAnnotations);
 549             databuf.appendChar(invisibles.length());
 550             for (Attribute.TypeCompound p : invisibles)
 551                 writeTypeAnnotation(p);
 552             endAttr(attrIndex);
 553             attrCount++;
 554         }
 555 
 556         return attrCount;
 557     }
 558 
 559     /** A visitor to write an attribute including its leading
 560      *  single-character marker.
 561      */
 562     class AttributeWriter implements Attribute.Visitor {
 563         public void visitConstant(Attribute.Constant _value) {
 564             if (_value.type.getTag() == CLASS) {
 565                 Assert.check(_value.value instanceof String);
 566                 String s = (String)_value.value;
 567                 databuf.appendByte('s');
 568                 databuf.appendChar(poolWriter.putName(names.fromString(s)));
 569             } else {
 570                 switch (_value.type.getTag()) {
 571                     case BYTE:
 572                         databuf.appendByte('B');
 573                         break;
 574                     case CHAR:
 575                         databuf.appendByte('C');
 576                         break;
 577                     case SHORT:
 578                         databuf.appendByte('S');
 579                         break;
 580                     case INT:
 581                         databuf.appendByte('I');
 582                         break;
 583                     case LONG:
 584                         databuf.appendByte('J');
 585                         break;
 586                     case FLOAT:
 587                         databuf.appendByte('F');
 588                         break;
 589                     case DOUBLE:
 590                         databuf.appendByte('D');
 591                         break;
 592                     case BOOLEAN:
 593                         databuf.appendByte('Z');
 594                         break;
 595                     default:
 596                         throw new AssertionError(_value.type);
 597                 }
 598                 databuf.appendChar(poolWriter.putConstant(_value.value));
 599             }
 600         }
 601         public void visitEnum(Attribute.Enum e) {
 602             databuf.appendByte('e');
 603             databuf.appendChar(poolWriter.putDescriptor(e.value.type));
 604             databuf.appendChar(poolWriter.putName(e.value.name));
 605         }
 606         public void visitClass(Attribute.Class clazz) {
 607             databuf.appendByte('c');
 608             databuf.appendChar(poolWriter.putDescriptor(clazz.classType));
 609         }
 610         public void visitCompound(Attribute.Compound compound) {
 611             databuf.appendByte('@');
 612             writeCompoundAttribute(compound);
 613         }
 614         public void visitError(Attribute.Error x) {
 615             throw new AssertionError(x);
 616         }
 617         public void visitArray(Attribute.Array array) {
 618             databuf.appendByte('[');
 619             databuf.appendChar(array.values.length);
 620             for (Attribute a : array.values) {
 621                 a.accept(this);
 622             }
 623         }
 624     }
 625     AttributeWriter awriter = new AttributeWriter();
 626 
 627     /** Write a compound attribute excluding the '@' marker. */
 628     void writeCompoundAttribute(Attribute.Compound c) {
 629         databuf.appendChar(poolWriter.putDescriptor(c.type));
 630         databuf.appendChar(c.values.length());
 631         for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) {
 632             databuf.appendChar(poolWriter.putName(p.fst.name));
 633             p.snd.accept(awriter);
 634         }
 635     }
 636 
 637     void writeTypeAnnotation(Attribute.TypeCompound c) {
 638         writePosition(c.position);
 639         writeCompoundAttribute(c);
 640     }
 641 
 642     void writePosition(TypeAnnotationPosition p) {
 643         databuf.appendByte(p.type.targetTypeValue()); // TargetType tag is a byte
 644         switch (p.type) {
 645         // instanceof
 646         case INSTANCEOF:
 647         // new expression
 648         case NEW:
 649         // constructor/method reference receiver
 650         case CONSTRUCTOR_REFERENCE:
 651         case METHOD_REFERENCE:
 652             databuf.appendChar(p.offset);
 653             break;
 654         // local variable
 655         case LOCAL_VARIABLE:
 656         // resource variable
 657         case RESOURCE_VARIABLE:
 658             databuf.appendChar(p.lvarOffset.length);  // for table length
 659             for (int i = 0; i < p.lvarOffset.length; ++i) {
 660                 databuf.appendChar(p.lvarOffset[i]);
 661                 databuf.appendChar(p.lvarLength[i]);
 662                 databuf.appendChar(p.lvarIndex[i]);
 663             }
 664             break;
 665         // exception parameter
 666         case EXCEPTION_PARAMETER:
 667             databuf.appendChar(p.getExceptionIndex());
 668             break;
 669         // method receiver
 670         case METHOD_RECEIVER:
 671             // Do nothing
 672             break;
 673         // type parameter
 674         case CLASS_TYPE_PARAMETER:
 675         case METHOD_TYPE_PARAMETER:
 676             databuf.appendByte(p.parameter_index);
 677             break;
 678         // type parameter bound
 679         case CLASS_TYPE_PARAMETER_BOUND:
 680         case METHOD_TYPE_PARAMETER_BOUND:
 681             databuf.appendByte(p.parameter_index);
 682             databuf.appendByte(p.bound_index);
 683             break;
 684         // class extends or implements clause
 685         case CLASS_EXTENDS:
 686             databuf.appendChar(p.type_index);
 687             break;
 688         // throws
 689         case THROWS:
 690             databuf.appendChar(p.type_index);
 691             break;
 692         // method parameter
 693         case METHOD_FORMAL_PARAMETER:
 694             databuf.appendByte(p.parameter_index);
 695             break;
 696         // type cast
 697         case CAST:
 698         // method/constructor/reference type argument
 699         case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
 700         case METHOD_INVOCATION_TYPE_ARGUMENT:
 701         case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
 702         case METHOD_REFERENCE_TYPE_ARGUMENT:
 703             databuf.appendChar(p.offset);
 704             databuf.appendByte(p.type_index);
 705             break;
 706         // We don't need to worry about these
 707         case METHOD_RETURN:
 708         case FIELD:
 709             break;
 710         case UNKNOWN:
 711             throw new AssertionError("jvm.ClassWriter: UNKNOWN target type should never occur!");
 712         default:
 713             throw new AssertionError("jvm.ClassWriter: Unknown target type for position: " + p);
 714         }
 715 
 716         { // Append location data for generics/arrays.
 717             databuf.appendByte(p.location.size());
 718             java.util.List<Integer> loc = TypeAnnotationPosition.getBinaryFromTypePath(p.location);
 719             for (int i : loc)
 720                 databuf.appendByte((byte)i);
 721         }
 722     }
 723 
 724 /**********************************************************************
 725  * Writing module attributes
 726  **********************************************************************/
 727 
 728     /** Write the Module attribute if needed.
 729      *  Returns the number of attributes written (0 or 1).
 730      */
 731     int writeModuleAttribute(ClassSymbol c) {
 732         ModuleSymbol m = (ModuleSymbol) c.owner;
 733 
 734         int alenIdx = writeAttr(names.Module);
 735 
 736         databuf.appendChar(poolWriter.putModule(m));
 737         databuf.appendChar(ModuleFlags.value(m.flags)); // module_flags
 738         databuf.appendChar(m.version != null ? poolWriter.putName(m.version) : 0);
 739 
 740         ListBuffer<RequiresDirective> requires = new ListBuffer<>();
 741         for (RequiresDirective r: m.requires) {
 742             if (!r.flags.contains(RequiresFlag.EXTRA))
 743                 requires.add(r);
 744         }
 745         databuf.appendChar(requires.size());
 746         for (RequiresDirective r: requires) {
 747             databuf.appendChar(poolWriter.putModule(r.module));
 748             databuf.appendChar(RequiresFlag.value(r.flags));
 749             databuf.appendChar(r.module.version != null ? poolWriter.putName(r.module.version) : 0);
 750         }
 751 
 752         List<ExportsDirective> exports = m.exports;
 753         databuf.appendChar(exports.size());
 754         for (ExportsDirective e: exports) {
 755             databuf.appendChar(poolWriter.putPackage(e.packge));
 756             databuf.appendChar(ExportsFlag.value(e.flags));
 757             if (e.modules == null) {
 758                 databuf.appendChar(0);
 759             } else {
 760                 databuf.appendChar(e.modules.size());
 761                 for (ModuleSymbol msym: e.modules) {
 762                     databuf.appendChar(poolWriter.putModule(msym));
 763                 }
 764             }
 765         }
 766 
 767         List<OpensDirective> opens = m.opens;
 768         databuf.appendChar(opens.size());
 769         for (OpensDirective o: opens) {
 770             databuf.appendChar(poolWriter.putPackage(o.packge));
 771             databuf.appendChar(OpensFlag.value(o.flags));
 772             if (o.modules == null) {
 773                 databuf.appendChar(0);
 774             } else {
 775                 databuf.appendChar(o.modules.size());
 776                 for (ModuleSymbol msym: o.modules) {
 777                     databuf.appendChar(poolWriter.putModule(msym));
 778                 }
 779             }
 780         }
 781 
 782         List<UsesDirective> uses = m.uses;
 783         databuf.appendChar(uses.size());
 784         for (UsesDirective s: uses) {
 785             databuf.appendChar(poolWriter.putClass(s.service));
 786         }
 787 
 788         // temporary fix to merge repeated provides clause for same service;
 789         // eventually this should be disallowed when analyzing the module,
 790         // so that each service type only appears once.
 791         Map<ClassSymbol, Set<ClassSymbol>> mergedProvides = new LinkedHashMap<>();
 792         for (ProvidesDirective p : m.provides) {
 793             mergedProvides.computeIfAbsent(p.service, s -> new LinkedHashSet<>()).addAll(p.impls);
 794         }
 795         databuf.appendChar(mergedProvides.size());
 796         mergedProvides.forEach((srvc, impls) -> {
 797             databuf.appendChar(poolWriter.putClass(srvc));
 798             databuf.appendChar(impls.size());
 799             impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl)));
 800         });
 801 
 802         endAttr(alenIdx);
 803         return 1;
 804     }
 805 
 806 /**********************************************************************
 807  * Writing Objects
 808  **********************************************************************/
 809 
 810     /** Write "inner classes" attribute.
 811      */
 812     void writeInnerClasses() {
 813         int alenIdx = writeAttr(names.InnerClasses);
 814         databuf.appendChar(poolWriter.innerClasses.size());
 815         for (ClassSymbol inner : poolWriter.innerClasses) {
 816             inner.markAbstractIfNeeded(types);
 817             char flags = (char) adjustFlags(inner.flags_field);
 818             if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT
 819             flags &= ~STRICTFP; //inner classes should not have the strictfp flag set.
 820             if (dumpInnerClassModifiers) {
 821                 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 822                 pw.println("INNERCLASS  " + inner.name);
 823                 pw.println("---" + flagNames(flags));
 824             }
 825             databuf.appendChar(poolWriter.putClass(inner));
 826             databuf.appendChar(
 827                 inner.owner.kind == TYP && !inner.name.isEmpty() ? poolWriter.putClass((ClassSymbol)inner.owner) : 0);
 828             databuf.appendChar(
 829                 !inner.name.isEmpty() ? poolWriter.putName(inner.name) : 0);
 830             databuf.appendChar(flags);
 831         }
 832         endAttr(alenIdx);
 833     }
 834 
 835     int writeRecordAttribute(ClassSymbol csym) {
 836         int alenIdx = writeAttr(names.Record);
 837         Scope s = csym.members();
 838         List<VarSymbol> vars = List.nil();
 839         int numParams = 0;
 840         for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
 841             if (sym.kind == VAR && sym.isRecord()) {
 842                 vars = vars.prepend((VarSymbol)sym);
 843                 numParams++;
 844             }
 845         }
 846         databuf.appendChar(numParams);
 847         for (VarSymbol v: vars) {
 848             databuf.appendChar(poolWriter.putMember(v.accessors.head.snd));
 849         }
 850         endAttr(alenIdx);
 851         return 1;
 852     }
 853 
 854     /**
 855      * Write NestMembers attribute (if needed)
 856      */
 857     int writeNestMembersIfNeeded(ClassSymbol csym) {
 858         ListBuffer<ClassSymbol> nested = new ListBuffer<>();
 859         listNested(csym, nested);
 860         Set<ClassSymbol> nestedUnique = new LinkedHashSet<>(nested);
 861         if (csym.owner.kind == PCK && !nestedUnique.isEmpty()) {
 862             int alenIdx = writeAttr(names.NestMembers);
 863             databuf.appendChar(nestedUnique.size());
 864             for (ClassSymbol s : nestedUnique) {
 865                 databuf.appendChar(poolWriter.putClass(s));
 866             }
 867             endAttr(alenIdx);
 868             return 1;
 869         }
 870         return 0;
 871     }
 872 
 873     /**
 874      * Write NestHost attribute (if needed)
 875      */
 876     int writeNestHostIfNeeded(ClassSymbol csym) {
 877         if (csym.owner.kind != PCK) {
 878             int alenIdx = writeAttr(names.NestHost);
 879             databuf.appendChar(poolWriter.putClass(csym.outermostClass()));
 880             endAttr(alenIdx);
 881             return 1;
 882         }
 883         return 0;
 884     }
 885 
 886     private void listNested(Symbol sym, ListBuffer<ClassSymbol> seen) {
 887         if (sym.kind != TYP) return;
 888         ClassSymbol csym = (ClassSymbol)sym;
 889         if (csym.owner.kind != PCK) {
 890             seen.add(csym);
 891         }
 892         if (csym.members() != null) {
 893             for (Symbol s : sym.members().getSymbols()) {
 894                 listNested(s, seen);
 895             }
 896         }
 897         if (csym.trans_local != null) {
 898             for (Symbol s : csym.trans_local) {
 899                 listNested(s, seen);
 900             }
 901         }
 902     }
 903 
 904     /** Write "PermittedSubtypes" attribute.
 905      */
 906     int writePermittedSubtypesIfNeeded(ClassSymbol csym) {
 907         ClassType ct = (ClassType)csym.type;
 908         if (ct.permitted.nonEmpty()) {
 909             int alenIdx = writeAttr(names.PermittedSubtypes);
 910             databuf.appendChar(ct.permitted.size());
 911             for (Type t : ct.permitted) {
 912                 databuf.appendChar(poolWriter.putClass((ClassSymbol)t.tsym));
 913             }
 914             endAttr(alenIdx);
 915             return 1;
 916         }
 917         return 0;
 918     }
 919 
 920     /** Write "bootstrapMethods" attribute.
 921      */
 922     void writeBootstrapMethods() {
 923         int alenIdx = writeAttr(names.BootstrapMethods);
 924         databuf.appendChar(poolWriter.bootstrapMethods.size());
 925         for (BsmKey bsmKey : poolWriter.bootstrapMethods.keySet()) {
 926             //write BSM handle
 927             databuf.appendChar(poolWriter.putConstant(bsmKey.bsm));
 928             LoadableConstant[] uniqueArgs = bsmKey.staticArgs;
 929             //write static args length
 930             databuf.appendChar(uniqueArgs.length);
 931             //write static args array
 932             for (LoadableConstant arg : uniqueArgs) {
 933                 databuf.appendChar(poolWriter.putConstant(arg));
 934             }
 935         }
 936         endAttr(alenIdx);
 937     }
 938 
 939     /** Write field symbol, entering all references into constant pool.
 940      */
 941     void writeField(VarSymbol v) {
 942         int flags = adjustFlags(v.flags());
 943         databuf.appendChar(flags);
 944         if (dumpFieldModifiers) {
 945             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 946             pw.println("FIELD  " + v.name);
 947             pw.println("---" + flagNames(v.flags()));
 948         }
 949         databuf.appendChar(poolWriter.putName(v.name));
 950         databuf.appendChar(poolWriter.putDescriptor(v));
 951         int acountIdx = beginAttrs();
 952         int acount = 0;
 953         if (v.getConstValue() != null) {
 954             int alenIdx = writeAttr(names.ConstantValue);
 955             databuf.appendChar(poolWriter.putConstant(v.getConstValue()));
 956             endAttr(alenIdx);
 957             acount++;
 958         }
 959         acount += writeMemberAttrs(v);
 960         endAttrs(acountIdx, acount);
 961     }
 962 
 963     /** Write method symbol, entering all references into constant pool.
 964      */
 965     void writeMethod(MethodSymbol m) {
 966         int flags = adjustFlags(m.flags());
 967         databuf.appendChar(flags);
 968         if (dumpMethodModifiers) {
 969             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
 970             pw.println("METHOD  " + m.name);
 971             pw.println("---" + flagNames(m.flags()));
 972         }
 973         databuf.appendChar(poolWriter.putName(m.name));
 974         databuf.appendChar(poolWriter.putDescriptor(m));
 975         int acountIdx = beginAttrs();
 976         int acount = 0;
 977         if (m.code != null) {
 978             int alenIdx = writeAttr(names.Code);
 979             writeCode(m.code);
 980             m.code = null; // to conserve space
 981             endAttr(alenIdx);
 982             acount++;
 983         }
 984         List<Type> thrown = m.erasure(types).getThrownTypes();
 985         if (thrown.nonEmpty()) {
 986             int alenIdx = writeAttr(names.Exceptions);
 987             databuf.appendChar(thrown.length());
 988             for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
 989                 databuf.appendChar(poolWriter.putClass(l.head));
 990             endAttr(alenIdx);
 991             acount++;
 992         }
 993         if (m.defaultValue != null) {
 994             int alenIdx = writeAttr(names.AnnotationDefault);
 995             m.defaultValue.accept(awriter);
 996             endAttr(alenIdx);
 997             acount++;
 998         }
 999         if (target.hasMethodParameters() && (options.isSet(PARAMETERS) || m.isConstructor() && m.isRecord())) {
1000             if (!m.isLambdaMethod()) // Per JDK-8138729, do not emit parameters table for lambda bodies.
1001                 acount += writeMethodParametersAttr(m);
1002         }
1003         acount += writeMemberAttrs(m);
1004         if (!m.isLambdaMethod())
1005             acount += writeParameterAttrs(m.params);
1006         endAttrs(acountIdx, acount);
1007     }
1008 
1009     /** Write code attribute of method.
1010      */
1011     void writeCode(Code code) {
1012         databuf.appendChar(code.max_stack);
1013         databuf.appendChar(code.max_locals);
1014         databuf.appendInt(code.cp);
1015         databuf.appendBytes(code.code, 0, code.cp);
1016         databuf.appendChar(code.catchInfo.length());
1017         for (List<char[]> l = code.catchInfo.toList();
1018              l.nonEmpty();
1019              l = l.tail) {
1020             for (int i = 0; i < l.head.length; i++)
1021                 databuf.appendChar(l.head[i]);
1022         }
1023         int acountIdx = beginAttrs();
1024         int acount = 0;
1025 
1026         if (code.lineInfo.nonEmpty()) {
1027             int alenIdx = writeAttr(names.LineNumberTable);
1028             databuf.appendChar(code.lineInfo.length());
1029             for (List<char[]> l = code.lineInfo.reverse();
1030                  l.nonEmpty();
1031                  l = l.tail)
1032                 for (int i = 0; i < l.head.length; i++)
1033                     databuf.appendChar(l.head[i]);
1034             endAttr(alenIdx);
1035             acount++;
1036         }
1037 
1038         if (genCrt && (code.crt != null)) {
1039             CRTable crt = code.crt;
1040             int alenIdx = writeAttr(names.CharacterRangeTable);
1041             int crtIdx = beginAttrs();
1042             int crtEntries = crt.writeCRT(databuf, code.lineMap, log);
1043             endAttrs(crtIdx, crtEntries);
1044             endAttr(alenIdx);
1045             acount++;
1046         }
1047 
1048         // counter for number of generic local variables
1049         if (code.varDebugInfo && code.varBufferSize > 0) {
1050             int nGenericVars = 0;
1051             int alenIdx = writeAttr(names.LocalVariableTable);
1052             databuf.appendChar(code.getLVTSize());
1053             for (int i=0; i<code.varBufferSize; i++) {
1054                 Code.LocalVar var = code.varBuffer[i];
1055 
1056                 for (Code.LocalVar.Range r: var.aliveRanges) {
1057                     // write variable info
1058                     Assert.check(r.start_pc >= 0
1059                             && r.start_pc <= code.cp);
1060                     databuf.appendChar(r.start_pc);
1061                     Assert.check(r.length > 0
1062                             && (r.start_pc + r.length) <= code.cp);
1063                     databuf.appendChar(r.length);
1064                     VarSymbol sym = var.sym;
1065                     databuf.appendChar(poolWriter.putName(sym.name));
1066                     databuf.appendChar(poolWriter.putDescriptor(sym));
1067                     databuf.appendChar(var.reg);
1068                     if (needsLocalVariableTypeEntry(var.sym.type)) {
1069                         nGenericVars++;
1070                     }
1071                 }
1072             }
1073             endAttr(alenIdx);
1074             acount++;
1075 
1076             if (nGenericVars > 0) {
1077                 alenIdx = writeAttr(names.LocalVariableTypeTable);
1078                 databuf.appendChar(nGenericVars);
1079                 int count = 0;
1080 
1081                 for (int i=0; i<code.varBufferSize; i++) {
1082                     Code.LocalVar var = code.varBuffer[i];
1083                     VarSymbol sym = var.sym;
1084                     if (!needsLocalVariableTypeEntry(sym.type))
1085                         continue;
1086                     for (Code.LocalVar.Range r : var.aliveRanges) {
1087                         // write variable info
1088                         databuf.appendChar(r.start_pc);
1089                         databuf.appendChar(r.length);
1090                         databuf.appendChar(poolWriter.putName(sym.name));
1091                         databuf.appendChar(poolWriter.putSignature(sym));
1092                         databuf.appendChar(var.reg);
1093                         count++;
1094                     }
1095                 }
1096                 Assert.check(count == nGenericVars);
1097                 endAttr(alenIdx);
1098                 acount++;
1099             }
1100         }
1101 
1102         if (code.stackMapBufferSize > 0) {
1103             if (debugstackmap) System.out.println("Stack map for " + code.meth);
1104             int alenIdx = writeAttr(code.stackMap.getAttributeName(names));
1105             writeStackMap(code);
1106             endAttr(alenIdx);
1107             acount++;
1108         }
1109 
1110         acount += writeTypeAnnotations(code.meth.getRawTypeAttributes(), true);
1111 
1112         endAttrs(acountIdx, acount);
1113     }
1114     //where
1115     private boolean needsLocalVariableTypeEntry(Type t) {
1116         //a local variable needs a type-entry if its type T is generic
1117         //(i.e. |T| != T) and if it's not an non-denotable type (non-denotable
1118         // types are not supported in signature attribute grammar!)
1119         return !types.isSameType(t, types.erasure(t)) &&
1120                 check.checkDenotable(t);
1121     }
1122 
1123     void writeStackMap(Code code) {
1124         int nframes = code.stackMapBufferSize;
1125         if (debugstackmap) System.out.println(" nframes = " + nframes);
1126         databuf.appendChar(nframes);
1127 
1128         switch (code.stackMap) {
1129         case CLDC:
1130             for (int i=0; i<nframes; i++) {
1131                 if (debugstackmap) System.out.print("  " + i + ":");
1132                 Code.StackMapFrame frame = code.stackMapBuffer[i];
1133 
1134                 // output PC
1135                 if (debugstackmap) System.out.print(" pc=" + frame.pc);
1136                 databuf.appendChar(frame.pc);
1137 
1138                 // output locals
1139                 int localCount = 0;
1140                 for (int j=0; j<frame.locals.length;
1141                      j += Code.width(frame.locals[j])) {
1142                     localCount++;
1143                 }
1144                 if (debugstackmap) System.out.print(" nlocals=" +
1145                                                     localCount);
1146                 databuf.appendChar(localCount);
1147                 for (int j=0; j<frame.locals.length;
1148                      j += Code.width(frame.locals[j])) {
1149                     if (debugstackmap) System.out.print(" local[" + j + "]=");
1150                     writeStackMapType(frame.locals[j]);
1151                 }
1152 
1153                 // output stack
1154                 int stackCount = 0;
1155                 for (int j=0; j<frame.stack.length;
1156                      j += Code.width(frame.stack[j])) {
1157                     stackCount++;
1158                 }
1159                 if (debugstackmap) System.out.print(" nstack=" +
1160                                                     stackCount);
1161                 databuf.appendChar(stackCount);
1162                 for (int j=0; j<frame.stack.length;
1163                      j += Code.width(frame.stack[j])) {
1164                     if (debugstackmap) System.out.print(" stack[" + j + "]=");
1165                     writeStackMapType(frame.stack[j]);
1166                 }
1167                 if (debugstackmap) System.out.println();
1168             }
1169             break;
1170         case JSR202: {
1171             Assert.checkNull(code.stackMapBuffer);
1172             for (int i=0; i<nframes; i++) {
1173                 if (debugstackmap) System.out.print("  " + i + ":");
1174                 StackMapTableFrame frame = code.stackMapTableBuffer[i];
1175                 frame.write(this);
1176                 if (debugstackmap) System.out.println();
1177             }
1178             break;
1179         }
1180         default:
1181             throw new AssertionError("Unexpected stackmap format value");
1182         }
1183     }
1184 
1185         //where
1186         void writeStackMapType(Type t) {
1187             if (t == null) {
1188                 if (debugstackmap) System.out.print("empty");
1189                 databuf.appendByte(0);
1190             }
1191             else switch(t.getTag()) {
1192             case BYTE:
1193             case CHAR:
1194             case SHORT:
1195             case INT:
1196             case BOOLEAN:
1197                 if (debugstackmap) System.out.print("int");
1198                 databuf.appendByte(1);
1199                 break;
1200             case FLOAT:
1201                 if (debugstackmap) System.out.print("float");
1202                 databuf.appendByte(2);
1203                 break;
1204             case DOUBLE:
1205                 if (debugstackmap) System.out.print("double");
1206                 databuf.appendByte(3);
1207                 break;
1208             case LONG:
1209                 if (debugstackmap) System.out.print("long");
1210                 databuf.appendByte(4);
1211                 break;
1212             case BOT: // null
1213                 if (debugstackmap) System.out.print("null");
1214                 databuf.appendByte(5);
1215                 break;
1216             case CLASS:
1217             case ARRAY:
1218             case TYPEVAR:
1219                 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
1220                 databuf.appendByte(7);
1221                 databuf.appendChar(poolWriter.putClass(types.erasure(t)));
1222                 break;
1223             case UNINITIALIZED_THIS:
1224                 if (debugstackmap) System.out.print("uninit_this");
1225                 databuf.appendByte(6);
1226                 break;
1227             case UNINITIALIZED_OBJECT:
1228                 { UninitializedType uninitType = (UninitializedType)t;
1229                 databuf.appendByte(8);
1230                 if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset);
1231                 databuf.appendChar(uninitType.offset);
1232                 }
1233                 break;
1234             default:
1235                 throw new AssertionError();
1236             }
1237         }
1238 
1239     /** An entry in the JSR202 StackMapTable */
1240     abstract static class StackMapTableFrame {
1241         abstract int getFrameType();
1242 
1243         void write(ClassWriter writer) {
1244             int frameType = getFrameType();
1245             writer.databuf.appendByte(frameType);
1246             if (writer.debugstackmap) System.out.print(" frame_type=" + frameType);
1247         }
1248 
1249         static class SameFrame extends StackMapTableFrame {
1250             final int offsetDelta;
1251             SameFrame(int offsetDelta) {
1252                 this.offsetDelta = offsetDelta;
1253             }
1254             int getFrameType() {
1255                 return (offsetDelta < SAME_FRAME_SIZE) ? offsetDelta : SAME_FRAME_EXTENDED;
1256             }
1257             @Override
1258             void write(ClassWriter writer) {
1259                 super.write(writer);
1260                 if (getFrameType() == SAME_FRAME_EXTENDED) {
1261                     writer.databuf.appendChar(offsetDelta);
1262                     if (writer.debugstackmap){
1263                         System.out.print(" offset_delta=" + offsetDelta);
1264                     }
1265                 }
1266             }
1267         }
1268 
1269         static class SameLocals1StackItemFrame extends StackMapTableFrame {
1270             final int offsetDelta;
1271             final Type stack;
1272             SameLocals1StackItemFrame(int offsetDelta, Type stack) {
1273                 this.offsetDelta = offsetDelta;
1274                 this.stack = stack;
1275             }
1276             int getFrameType() {
1277                 return (offsetDelta < SAME_FRAME_SIZE) ?
1278                        (SAME_FRAME_SIZE + offsetDelta) :
1279                        SAME_LOCALS_1_STACK_ITEM_EXTENDED;
1280             }
1281             @Override
1282             void write(ClassWriter writer) {
1283                 super.write(writer);
1284                 if (getFrameType() == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
1285                     writer.databuf.appendChar(offsetDelta);
1286                     if (writer.debugstackmap) {
1287                         System.out.print(" offset_delta=" + offsetDelta);
1288                     }
1289                 }
1290                 if (writer.debugstackmap) {
1291                     System.out.print(" stack[" + 0 + "]=");
1292                 }
1293                 writer.writeStackMapType(stack);
1294             }
1295         }
1296 
1297         static class ChopFrame extends StackMapTableFrame {
1298             final int frameType;
1299             final int offsetDelta;
1300             ChopFrame(int frameType, int offsetDelta) {
1301                 this.frameType = frameType;
1302                 this.offsetDelta = offsetDelta;
1303             }
1304             int getFrameType() { return frameType; }
1305             @Override
1306             void write(ClassWriter writer) {
1307                 super.write(writer);
1308                 writer.databuf.appendChar(offsetDelta);
1309                 if (writer.debugstackmap) {
1310                     System.out.print(" offset_delta=" + offsetDelta);
1311                 }
1312             }
1313         }
1314 
1315         static class AppendFrame extends StackMapTableFrame {
1316             final int frameType;
1317             final int offsetDelta;
1318             final Type[] locals;
1319             AppendFrame(int frameType, int offsetDelta, Type[] locals) {
1320                 this.frameType = frameType;
1321                 this.offsetDelta = offsetDelta;
1322                 this.locals = locals;
1323             }
1324             int getFrameType() { return frameType; }
1325             @Override
1326             void write(ClassWriter writer) {
1327                 super.write(writer);
1328                 writer.databuf.appendChar(offsetDelta);
1329                 if (writer.debugstackmap) {
1330                     System.out.print(" offset_delta=" + offsetDelta);
1331                 }
1332                 for (int i=0; i<locals.length; i++) {
1333                      if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1334                      writer.writeStackMapType(locals[i]);
1335                 }
1336             }
1337         }
1338 
1339         static class FullFrame extends StackMapTableFrame {
1340             final int offsetDelta;
1341             final Type[] locals;
1342             final Type[] stack;
1343             FullFrame(int offsetDelta, Type[] locals, Type[] stack) {
1344                 this.offsetDelta = offsetDelta;
1345                 this.locals = locals;
1346                 this.stack = stack;
1347             }
1348             int getFrameType() { return FULL_FRAME; }
1349             @Override
1350             void write(ClassWriter writer) {
1351                 super.write(writer);
1352                 writer.databuf.appendChar(offsetDelta);
1353                 writer.databuf.appendChar(locals.length);
1354                 if (writer.debugstackmap) {
1355                     System.out.print(" offset_delta=" + offsetDelta);
1356                     System.out.print(" nlocals=" + locals.length);
1357                 }
1358                 for (int i=0; i<locals.length; i++) {
1359                     if (writer.debugstackmap) System.out.print(" locals[" + i + "]=");
1360                     writer.writeStackMapType(locals[i]);
1361                 }
1362 
1363                 writer.databuf.appendChar(stack.length);
1364                 if (writer.debugstackmap) { System.out.print(" nstack=" + stack.length); }
1365                 for (int i=0; i<stack.length; i++) {
1366                     if (writer.debugstackmap) System.out.print(" stack[" + i + "]=");
1367                     writer.writeStackMapType(stack[i]);
1368                 }
1369             }
1370         }
1371 
1372        /** Compare this frame with the previous frame and produce
1373         *  an entry of compressed stack map frame. */
1374         static StackMapTableFrame getInstance(Code.StackMapFrame this_frame,
1375                                               int prev_pc,
1376                                               Type[] prev_locals,
1377                                               Types types) {
1378             Type[] locals = this_frame.locals;
1379             Type[] stack = this_frame.stack;
1380             int offset_delta = this_frame.pc - prev_pc - 1;
1381             if (stack.length == 1) {
1382                 if (locals.length == prev_locals.length
1383                     && compare(prev_locals, locals, types) == 0) {
1384                     return new SameLocals1StackItemFrame(offset_delta, stack[0]);
1385                 }
1386             } else if (stack.length == 0) {
1387                 int diff_length = compare(prev_locals, locals, types);
1388                 if (diff_length == 0) {
1389                     return new SameFrame(offset_delta);
1390                 } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) {
1391                     // APPEND
1392                     Type[] local_diff = new Type[-diff_length];
1393                     for (int i=prev_locals.length, j=0; i<locals.length; i++,j++) {
1394                         local_diff[j] = locals[i];
1395                     }
1396                     return new AppendFrame(SAME_FRAME_EXTENDED - diff_length,
1397                                            offset_delta,
1398                                            local_diff);
1399                 } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) {
1400                     // CHOP
1401                     return new ChopFrame(SAME_FRAME_EXTENDED - diff_length,
1402                                          offset_delta);
1403                 }
1404             }
1405             // FULL_FRAME
1406             return new FullFrame(offset_delta, locals, stack);
1407         }
1408 
1409         static boolean isInt(Type t) {
1410             return (t.getTag().isStrictSubRangeOf(INT)  || t.hasTag(BOOLEAN));
1411         }
1412 
1413         static boolean isSameType(Type t1, Type t2, Types types) {
1414             if (t1 == null) { return t2 == null; }
1415             if (t2 == null) { return false; }
1416 
1417             if (isInt(t1) && isInt(t2)) { return true; }
1418 
1419             if (t1.hasTag(UNINITIALIZED_THIS)) {
1420                 return t2.hasTag(UNINITIALIZED_THIS);
1421             } else if (t1.hasTag(UNINITIALIZED_OBJECT)) {
1422                 if (t2.hasTag(UNINITIALIZED_OBJECT)) {
1423                     return ((UninitializedType)t1).offset == ((UninitializedType)t2).offset;
1424                 } else {
1425                     return false;
1426                 }
1427             } else if (t2.hasTag(UNINITIALIZED_THIS) || t2.hasTag(UNINITIALIZED_OBJECT)) {
1428                 return false;
1429             }
1430 
1431             return types.isSameType(t1, t2);
1432         }
1433 
1434         static int compare(Type[] arr1, Type[] arr2, Types types) {
1435             int diff_length = arr1.length - arr2.length;
1436             if (diff_length > MAX_LOCAL_LENGTH_DIFF || diff_length < -MAX_LOCAL_LENGTH_DIFF) {
1437                 return Integer.MAX_VALUE;
1438             }
1439             int len = (diff_length > 0) ? arr2.length : arr1.length;
1440             for (int i=0; i<len; i++) {
1441                 if (!isSameType(arr1[i], arr2[i], types)) {
1442                     return Integer.MAX_VALUE;
1443                 }
1444             }
1445             return diff_length;
1446         }
1447     }
1448 
1449     void writeFields(Scope s) {
1450         // process them in reverse sibling order;
1451         // i.e., process them in declaration order.
1452         List<VarSymbol> vars = List.nil();
1453         for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
1454             if (sym.kind == VAR) vars = vars.prepend((VarSymbol)sym);
1455         }
1456         while (vars.nonEmpty()) {
1457             writeField(vars.head);
1458             vars = vars.tail;
1459         }
1460     }
1461 
1462     void writeMethods(Scope s) {
1463         List<MethodSymbol> methods = List.nil();
1464         for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
1465             if (sym.kind == MTH && (sym.flags() & HYPOTHETICAL) == 0)
1466                 methods = methods.prepend((MethodSymbol)sym);
1467         }
1468         while (methods.nonEmpty()) {
1469             writeMethod(methods.head);
1470             methods = methods.tail;
1471         }
1472     }
1473 
1474     /** Emit a class file for a given class.
1475      *  @param c      The class from which a class file is generated.
1476      */
1477     public JavaFileObject writeClass(ClassSymbol c)
1478         throws IOException, PoolOverflow, StringOverflow
1479     {
1480         String name = (c.owner.kind == MDL ? c.name : c.flatname).toString();
1481         Location outLocn;
1482         if (multiModuleMode) {
1483             ModuleSymbol msym = c.owner.kind == MDL ? (ModuleSymbol) c.owner : c.packge().modle;
1484             outLocn = fileManager.getLocationForModule(CLASS_OUTPUT, msym.name.toString());
1485         } else {
1486             outLocn = CLASS_OUTPUT;
1487         }
1488         JavaFileObject outFile
1489             = fileManager.getJavaFileForOutput(outLocn,
1490                                                name,
1491                                                JavaFileObject.Kind.CLASS,
1492                                                c.sourcefile);
1493         OutputStream out = outFile.openOutputStream();
1494         try {
1495             writeClassFile(out, c);
1496             if (verbose)
1497                 log.printVerbose("wrote.file", outFile.getName());
1498             out.close();
1499             out = null;
1500         } catch (InvalidSignatureException ex) {
1501             log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type())));
1502         } finally {
1503             if (out != null) {
1504                 // if we are propagating an exception, delete the file
1505                 out.close();
1506                 outFile.delete();
1507                 outFile = null;
1508             }
1509         }
1510         return outFile; // may be null if write failed
1511     }
1512 
1513     /** Write class `c' to outstream `out'.
1514      */
1515     public void writeClassFile(OutputStream out, ClassSymbol c)
1516         throws IOException, PoolOverflow, StringOverflow {
1517         Assert.check((c.flags() & COMPOUND) == 0);
1518         databuf.reset();
1519         poolbuf.reset();
1520 
1521         Type supertype = types.supertype(c.type);
1522         List<Type> interfaces = types.interfaces(c.type);
1523         List<Type> typarams = c.type.getTypeArguments();
1524 
1525         int flags;
1526         if (c.owner.kind == MDL) {
1527             flags = ACC_MODULE;
1528         } else {
1529             flags = adjustFlags(c.flags() & ~DEFAULT);
1530             if (c.isSealed()) {
1531                 flags &= ~SEALED;
1532                 if (((ClassType)c.type).permitted.isEmpty()) {
1533                     flags |= FINAL;
1534                 }
1535             }
1536             if ((flags & PROTECTED) != 0) flags |= PUBLIC;
1537             flags = flags & ClassFlags & ~STRICTFP;
1538             if ((flags & INTERFACE) == 0) flags |= ACC_SUPER;
1539         }
1540 
1541         if (dumpClassModifiers) {
1542             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
1543             pw.println();
1544             pw.println("CLASSFILE  " + c.getQualifiedName());
1545             pw.println("---" + flagNames(flags));
1546         }
1547         databuf.appendChar(flags);
1548 
1549         if (c.owner.kind == MDL) {
1550             PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage;
1551             databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed)));
1552         } else {
1553             databuf.appendChar(poolWriter.putClass(c));
1554         }
1555         databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0);
1556         databuf.appendChar(interfaces.length());
1557         for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
1558             databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym));
1559         int fieldsCount = 0;
1560         int methodsCount = 0;
1561         for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
1562             switch (sym.kind) {
1563             case VAR: fieldsCount++; break;
1564             case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
1565                       break;
1566             case TYP: poolWriter.enterInner((ClassSymbol)sym); break;
1567             default : Assert.error();
1568             }
1569         }
1570 
1571         if (c.trans_local != null) {
1572             for (ClassSymbol local : c.trans_local) {
1573                 poolWriter.enterInner(local);
1574             }
1575         }
1576 
1577         databuf.appendChar(fieldsCount);
1578         writeFields(c.members());
1579         databuf.appendChar(methodsCount);
1580         writeMethods(c.members());
1581 
1582         int acountIdx = beginAttrs();
1583         int acount = 0;
1584 
1585         boolean sigReq =
1586             typarams.length() != 0 || supertype.allparams().length() != 0;
1587         for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail)
1588             sigReq = l.head.allparams().length() != 0;
1589         if (sigReq) {
1590             int alenIdx = writeAttr(names.Signature);
1591             databuf.appendChar(poolWriter.putSignature(c));
1592             endAttr(alenIdx);
1593             acount++;
1594         }
1595 
1596         if (c.sourcefile != null && emitSourceFile) {
1597             int alenIdx = writeAttr(names.SourceFile);
1598             // WHM 6/29/1999: Strip file path prefix.  We do it here at
1599             // the last possible moment because the sourcefile may be used
1600             // elsewhere in error diagnostics. Fixes 4241573.
1601             String simpleName = PathFileObject.getSimpleName(c.sourcefile);
1602             databuf.appendChar(poolWriter.putName(names.fromString(simpleName)));
1603             endAttr(alenIdx);
1604             acount++;
1605         }
1606 
1607         if (genCrt) {
1608             // Append SourceID attribute
1609             int alenIdx = writeAttr(names.SourceID);
1610             databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
1611             endAttr(alenIdx);
1612             acount++;
1613             // Append CompilationID attribute
1614             alenIdx = writeAttr(names.CompilationID);
1615             databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(System.currentTimeMillis()))));
1616             endAttr(alenIdx);
1617             acount++;
1618         }
1619 
1620         acount += writeFlagAttrs(c.flags());
1621         acount += writeJavaAnnotations(c.getRawAttributes());
1622         acount += writeTypeAnnotations(c.getRawTypeAttributes(), false);
1623         acount += writeEnclosingMethodAttribute(c);
1624         if (c.owner.kind == MDL) {
1625             acount += writeModuleAttribute(c);
1626             acount += writeFlagAttrs(c.owner.flags() & ~DEPRECATED);
1627         }
1628         acount += writeExtraClassAttributes(c);
1629 
1630         poolbuf.appendInt(JAVA_MAGIC);
1631         if (preview.isEnabled()) {
1632             poolbuf.appendChar(ClassFile.PREVIEW_MINOR_VERSION);
1633         } else {
1634             poolbuf.appendChar(target.minorVersion);
1635         }
1636         poolbuf.appendChar(target.majorVersion);
1637 
1638         if (c.owner.kind != MDL) {
1639             if (target.hasNestmateAccess()) {
1640                 acount += writeNestMembersIfNeeded(c);
1641                 acount += writeNestHostIfNeeded(c);
1642             }
1643         }
1644 
1645         if (c.isRecord()) {
1646             acount += writeRecordAttribute(c);
1647         }
1648 
1649         if (target.hasSealedTypes()) {
1650             acount += writePermittedSubtypesIfNeeded(c);
1651         }
1652 
1653         if (!poolWriter.bootstrapMethods.isEmpty()) {
1654             writeBootstrapMethods();
1655             acount++;
1656         }
1657 
1658         if (!poolWriter.innerClasses.isEmpty()) {
1659             writeInnerClasses();
1660             acount++;
1661         }
1662 
1663         endAttrs(acountIdx, acount);
1664 
1665         out.write(poolbuf.elems, 0, poolbuf.length);
1666 
1667         poolWriter.writePool(out);
1668         poolWriter.reset(); // to save space
1669 
1670         out.write(databuf.elems, 0, databuf.length);
1671      }
1672 
1673     /**Allows subclasses to write additional class attributes
1674      *
1675      * @return the number of attributes written
1676      */
1677     protected int writeExtraClassAttributes(ClassSymbol c) {
1678         return 0;
1679     }
1680 
1681     int adjustFlags(final long flags) {
1682         int result = (int)flags;
1683 
1684         if ((flags & BRIDGE) != 0)
1685             result |= ACC_BRIDGE;
1686         if ((flags & VARARGS) != 0)
1687             result |= ACC_VARARGS;
1688         if ((flags & DEFAULT) != 0)
1689             result &= ~ABSTRACT;
1690         if ((flags & SEALED) != 0)
1691             result |= FINAL;
1692         return result;
1693     }
1694 
1695     long getLastModified(FileObject filename) {
1696         long mod = 0;
1697         try {
1698             mod = filename.getLastModified();
1699         } catch (SecurityException e) {
1700             throw new AssertionError("CRT: couldn't get source file modification date: " + e.getMessage());
1701         }
1702         return mod;
1703     }
1704 }