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