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