1 /*
   2  * Copyright (c) 2001, 2012, 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.java.util.jar.pack;
  27 
  28 import com.sun.java.util.jar.pack.ConstantPool.*;
  29 import com.sun.java.util.jar.pack.Package.Class;
  30 import com.sun.java.util.jar.pack.Package.File;
  31 import com.sun.java.util.jar.pack.Package.InnerClass;
  32 import java.io.IOException;
  33 import java.io.OutputStream;
  34 import java.io.PrintStream;
  35 import java.util.ArrayList;
  36 import java.util.Arrays;
  37 import java.util.Comparator;
  38 import java.util.HashMap;
  39 import java.util.HashSet;
  40 import java.util.List;
  41 import java.util.Map;
  42 import java.util.Set;
  43 import static com.sun.java.util.jar.pack.Constants.*;
  44 
  45 /**
  46  * Writer for a package file.
  47  * @author John Rose
  48  */
  49 class PackageWriter extends BandStructure {
  50     Package pkg;
  51     OutputStream finalOut;
  52     Package.Version packageVersion;
  53 
  54     PackageWriter(Package pkg, OutputStream out) throws IOException {
  55         this.pkg = pkg;
  56         this.finalOut = out;
  57         // Caller has specified maximum class file version in the package:
  58         initHighestClassVersion(pkg.getHighestClassVersion());
  59     }
  60 
  61     void write() throws IOException {
  62         boolean ok = false;
  63         try {
  64             if (verbose > 0) {
  65                 Utils.log.info("Setting up constant pool...");
  66             }
  67             setup();
  68 
  69             if (verbose > 0) {
  70                 Utils.log.info("Packing...");
  71             }
  72 
  73             // writeFileHeader() is done last, since it has ultimate counts
  74             // writeBandHeaders() is called after all other bands are done
  75             writeConstantPool();
  76             writeFiles();
  77             writeAttrDefs();
  78             writeInnerClasses();
  79             writeClassesAndByteCodes();
  80             writeAttrCounts();
  81 
  82             if (verbose > 1)  printCodeHist();
  83 
  84             // choose codings (fill band_headers if needed)
  85             if (verbose > 0) {
  86                 Utils.log.info("Coding...");
  87             }
  88             all_bands.chooseBandCodings();
  89 
  90             // now we can write the headers:
  91             writeFileHeader();
  92 
  93             writeAllBandsTo(finalOut);
  94 
  95             ok = true;
  96         } catch (Exception ee) {
  97             Utils.log.warning("Error on output: "+ee, ee);
  98             //if (verbose > 0)  ee.printStackTrace();
  99             // Write partial output only if we are verbose.
 100             if (verbose > 0)  finalOut.close();
 101             if (ee instanceof IOException)  throw (IOException)ee;
 102             if (ee instanceof RuntimeException)  throw (RuntimeException)ee;
 103             throw new Error("error packing", ee);
 104         }
 105     }
 106 
 107     Set<Entry>                       requiredEntries;  // for the CP
 108     Map<Attribute.Layout, int[]>     backCountTable;   // for layout callables
 109     int[][]     attrCounts;       // count attr. occurences
 110 
 111     void setup() {
 112         requiredEntries = new HashSet<>();
 113         setArchiveOptions();
 114         trimClassAttributes();
 115         collectAttributeLayouts();
 116         pkg.buildGlobalConstantPool(requiredEntries);
 117         setBandIndexes();
 118         makeNewAttributeBands();
 119         collectInnerClasses();
 120     }
 121 
 122     /*
 123      * Convenience function to choose an archive version based
 124      * on the class file versions observed within the archive
 125      * or set the user defined version preset via properties.
 126      */
 127     void chooseDefaultPackageVersion() throws IOException {
 128         if (pkg.packageVersion != null) {
 129             packageVersion = pkg.packageVersion;
 130             if (verbose > 0) {
 131                 Utils.log.info("package version overridden with: "
 132                                 + packageVersion);
 133             }
 134             return;
 135         }
 136 
 137         Package.Version highV = getHighestClassVersion();
 138         // set the package version now
 139         if (highV.lessThan(JAVA6_MAX_CLASS_VERSION)) {
 140             // There are only old classfiles in this segment or resources
 141             packageVersion = JAVA5_PACKAGE_VERSION;
 142         } else if (highV.equals(JAVA6_MAX_CLASS_VERSION) ||
 143                 (highV.equals(JAVA7_MAX_CLASS_VERSION) && !pkg.cp.haveExtraTags())) {
 144             // force down the package version if we have jdk7 classes without
 145             // any Indy references, this is because jdk7 class file (52.0) without
 146             // Indy is identical to jdk6 class file (51.0).
 147             packageVersion = JAVA6_PACKAGE_VERSION;
 148         } else {
 149             // Normal case.  Use the newest archive format, when available
 150             packageVersion = JAVA7_PACKAGE_VERSION;
 151         }
 152 
 153         if (verbose > 0) {
 154             Utils.log.info("Highest version class file: " + highV
 155                     + " package version: " + packageVersion);
 156         }
 157     }
 158 
 159     void checkVersion() throws IOException {
 160         assert(packageVersion != null);
 161 
 162         if (packageVersion.lessThan(JAVA7_PACKAGE_VERSION)) {
 163             // this bit was reserved for future use in previous versions
 164             if (testBit(archiveOptions, AO_HAVE_CP_EXTRAS)) {
 165                 throw new IOException("Format bits for Java 7 must be zero in previous releases");
 166             }
 167         }
 168         if (testBit(archiveOptions, AO_UNUSED_MBZ)) {
 169             throw new IOException("High archive option bits are reserved and must be zero: " + Integer.toHexString(archiveOptions));
 170         }
 171     }
 172 
 173     void setArchiveOptions() {
 174         // Decide on some archive options early.
 175         // Does not decide on: AO_HAVE_SPECIAL_FORMATS,
 176         // AO_HAVE_CP_NUMBERS, AO_HAVE_FILE_HEADERS.
 177         // Also, AO_HAVE_FILE_OPTIONS may be forced on later.
 178         int minModtime = pkg.default_modtime;
 179         int maxModtime = pkg.default_modtime;
 180         int minOptions = -1;
 181         int maxOptions = 0;
 182 
 183         // Import defaults from package (deflate hint, etc.).
 184         archiveOptions |= pkg.default_options;
 185 
 186         for (File file : pkg.files) {
 187             int modtime = file.modtime;
 188             int options = file.options;
 189 
 190             if (minModtime == NO_MODTIME) {
 191                 minModtime = maxModtime = modtime;
 192             } else {
 193                 if (minModtime > modtime)  minModtime = modtime;
 194                 if (maxModtime < modtime)  maxModtime = modtime;
 195             }
 196             minOptions &= options;
 197             maxOptions |= options;
 198         }
 199         if (pkg.default_modtime == NO_MODTIME) {
 200             // Make everything else be a positive offset from here.
 201             pkg.default_modtime = minModtime;
 202         }
 203         if (minModtime != NO_MODTIME && minModtime != maxModtime) {
 204             // Put them into a band.
 205             archiveOptions |= AO_HAVE_FILE_MODTIME;
 206         }
 207         // If the archive deflation is set do not bother with each file.
 208         if (!testBit(archiveOptions,AO_DEFLATE_HINT) && minOptions != -1) {
 209             if (testBit(minOptions, FO_DEFLATE_HINT)) {
 210                 // Every file has the deflate_hint set.
 211                 // Set it for the whole archive, and omit options.
 212                 archiveOptions |= AO_DEFLATE_HINT;
 213                 minOptions -= FO_DEFLATE_HINT;
 214                 maxOptions -= FO_DEFLATE_HINT;
 215             }
 216             pkg.default_options |= minOptions;
 217             if (minOptions != maxOptions
 218                 || minOptions != pkg.default_options) {
 219                 archiveOptions |= AO_HAVE_FILE_OPTIONS;
 220             }
 221         }
 222         // Decide on default version number (majority rule).
 223         Map<Package.Version, int[]> verCounts = new HashMap<>();
 224         int bestCount = 0;
 225         Package.Version bestVersion = null;
 226         for (Class cls : pkg.classes) {
 227             Package.Version version = cls.getVersion();
 228             int[] var = verCounts.get(version);
 229             if (var == null) {
 230                 var = new int[1];
 231                 verCounts.put(version, var);
 232             }
 233             int count = (var[0] += 1);
 234             //System.out.println("version="+version+" count="+count);
 235             if (bestCount < count) {
 236                 bestCount = count;
 237                 bestVersion = version;
 238             }
 239         }
 240         verCounts.clear();
 241         if (bestVersion == null)  bestVersion = JAVA_MIN_CLASS_VERSION;  // degenerate case
 242         pkg.defaultClassVersion = bestVersion;
 243         if (verbose > 0)
 244            Utils.log.info("Consensus version number in segment is " + bestVersion);
 245         if (verbose > 0)
 246             Utils.log.info("Highest version number in segment is "
 247                             + pkg.getHighestClassVersion());
 248 
 249         // Now add explicit pseudo-attrs. to classes with odd versions.
 250         for (Class cls : pkg.classes) {
 251             if (!cls.getVersion().equals(bestVersion)) {
 252                 Attribute a = makeClassFileVersionAttr(cls.getVersion());
 253                 if (verbose > 1) {
 254                     Utils.log.fine("Version "+cls.getVersion() + " of " + cls
 255                                      + " doesn't match package version "
 256                                      + bestVersion);
 257                 }
 258                 // Note:  Does not add in "natural" order.  (Who cares?)
 259                 cls.addAttribute(a);
 260             }
 261         }
 262 
 263         // Decide if we are transmitting a huge resource file:
 264         for (File file : pkg.files) {
 265             long len = file.getFileLength();
 266             if (len != (int)len) {
 267                 archiveOptions |= AO_HAVE_FILE_SIZE_HI;
 268                 if (verbose > 0)
 269                    Utils.log.info("Note: Huge resource file "+file.getFileName()+" forces 64-bit sizing");
 270                 break;
 271             }
 272         }
 273 
 274         // Decide if code attributes typically have sub-attributes.
 275         // In that case, to preserve compact 1-byte code headers,
 276         // we must declare unconditional presence of code flags.
 277         int cost0 = 0;
 278         int cost1 = 0;
 279         for (Class cls : pkg.classes) {
 280             for (Class.Method m : cls.getMethods()) {
 281                 if (m.code != null) {
 282                     if (m.code.attributeSize() == 0) {
 283                         // cost of a useless unconditional flags byte
 284                         cost1 += 1;
 285                     } else if (shortCodeHeader(m.code) != LONG_CODE_HEADER) {
 286                         // cost of inflating a short header
 287                         cost0 += 3;
 288                     }
 289                 }
 290             }
 291         }
 292         if (cost0 > cost1) {
 293             archiveOptions |= AO_HAVE_ALL_CODE_FLAGS;
 294         }
 295         if (verbose > 0)
 296             Utils.log.info("archiveOptions = "
 297                              +"0b"+Integer.toBinaryString(archiveOptions));
 298     }
 299 
 300     void writeFileHeader() throws IOException {
 301         chooseDefaultPackageVersion();
 302         writeArchiveMagic();
 303         writeArchiveHeader();
 304     }
 305 
 306     // Local routine used to format fixed-format scalars
 307     // in the file_header:
 308     private void putMagicInt32(int val) throws IOException {
 309         int res = val;
 310         for (int i = 0; i < 4; i++) {
 311             archive_magic.putByte(0xFF & (res >>> 24));
 312             res <<= 8;
 313         }
 314     }
 315 
 316     void writeArchiveMagic() throws IOException {
 317         putMagicInt32(pkg.magic);
 318     }
 319 
 320     void writeArchiveHeader() throws IOException {
 321         // for debug only:  number of words optimized away
 322         int headerSizeForDebug = AH_LENGTH_MIN;
 323 
 324         // AO_HAVE_SPECIAL_FORMATS is set if non-default
 325         // coding techniques are used, or if there are
 326         // compressor-defined attributes transmitted.
 327         boolean haveSpecial = testBit(archiveOptions, AO_HAVE_SPECIAL_FORMATS);
 328         if (!haveSpecial) {
 329             haveSpecial |= (band_headers.length() != 0);
 330             haveSpecial |= (attrDefsWritten.length != 0);
 331             if (haveSpecial)
 332                 archiveOptions |= AO_HAVE_SPECIAL_FORMATS;
 333         }
 334         if (haveSpecial)
 335             headerSizeForDebug += AH_SPECIAL_FORMAT_LEN;
 336 
 337         // AO_HAVE_FILE_HEADERS is set if there is any
 338         // file or segment envelope information present.
 339         boolean haveFiles = testBit(archiveOptions, AO_HAVE_FILE_HEADERS);
 340         if (!haveFiles) {
 341             haveFiles |= (archiveNextCount > 0);
 342             haveFiles |= (pkg.default_modtime != NO_MODTIME);
 343             if (haveFiles)
 344                 archiveOptions |= AO_HAVE_FILE_HEADERS;
 345         }
 346         if (haveFiles)
 347             headerSizeForDebug += AH_FILE_HEADER_LEN;
 348 
 349         // AO_HAVE_CP_NUMBERS is set if there are any numbers
 350         // in the global constant pool.  (Numbers are in 15% of classes.)
 351         boolean haveNumbers = testBit(archiveOptions, AO_HAVE_CP_NUMBERS);
 352         if (!haveNumbers) {
 353             haveNumbers |= pkg.cp.haveNumbers();
 354             if (haveNumbers)
 355                 archiveOptions |= AO_HAVE_CP_NUMBERS;
 356         }
 357         if (haveNumbers)
 358             headerSizeForDebug += AH_CP_NUMBER_LEN;
 359 
 360         // AO_HAVE_CP_EXTRAS is set if there are constant pool entries
 361         // beyond the Java 6 version of the class file format.
 362         boolean haveCPExtra = testBit(archiveOptions, AO_HAVE_CP_EXTRAS);
 363         if (!haveCPExtra) {
 364             haveCPExtra |= pkg.cp.haveExtraTags();
 365             if (haveCPExtra)
 366                 archiveOptions |= AO_HAVE_CP_EXTRAS;
 367         }
 368         if (haveCPExtra)
 369             headerSizeForDebug += AH_CP_EXTRA_LEN;
 370 
 371         // the archiveOptions are all initialized, sanity check now!.
 372         checkVersion();
 373 
 374         archive_header_0.putInt(packageVersion.minor);
 375         archive_header_0.putInt(packageVersion.major);
 376         if (verbose > 0)
 377             Utils.log.info("Package Version for this segment:" + packageVersion);
 378         archive_header_0.putInt(archiveOptions); // controls header format
 379         assert(archive_header_0.length() == AH_LENGTH_0);
 380 
 381         final int DUMMY = 0;
 382         if (haveFiles) {
 383             assert(archive_header_S.length() == AH_ARCHIVE_SIZE_HI);
 384             archive_header_S.putInt(DUMMY); // (archiveSize1 >>> 32)
 385             assert(archive_header_S.length() == AH_ARCHIVE_SIZE_LO);
 386             archive_header_S.putInt(DUMMY); // (archiveSize1 >>> 0)
 387             assert(archive_header_S.length() == AH_LENGTH_S);
 388         }
 389 
 390         // Done with unsized part of header....
 391 
 392         if (haveFiles) {
 393             archive_header_1.putInt(archiveNextCount);  // usually zero
 394             archive_header_1.putInt(pkg.default_modtime);
 395             archive_header_1.putInt(pkg.files.size());
 396         } else {
 397             assert(pkg.files.isEmpty());
 398         }
 399 
 400         if (haveSpecial) {
 401             archive_header_1.putInt(band_headers.length());
 402             archive_header_1.putInt(attrDefsWritten.length);
 403         } else {
 404             assert(band_headers.length() == 0);
 405             assert(attrDefsWritten.length == 0);
 406         }
 407 
 408         writeConstantPoolCounts(haveNumbers, haveCPExtra);
 409 
 410         archive_header_1.putInt(pkg.getAllInnerClasses().size());
 411         archive_header_1.putInt(pkg.defaultClassVersion.minor);
 412         archive_header_1.putInt(pkg.defaultClassVersion.major);
 413         archive_header_1.putInt(pkg.classes.size());
 414 
 415         // Sanity:  Make sure we came out to 29 (less optional fields):
 416         assert(archive_header_0.length() +
 417                archive_header_S.length() +
 418                archive_header_1.length()
 419                == headerSizeForDebug);
 420 
 421         // Figure out all the sizes now, first cut:
 422         archiveSize0 = 0;
 423         archiveSize1 = all_bands.outputSize();
 424         // Second cut:
 425         archiveSize0 += archive_magic.outputSize();
 426         archiveSize0 += archive_header_0.outputSize();
 427         archiveSize0 += archive_header_S.outputSize();
 428         // Make the adjustments:
 429         archiveSize1 -= archiveSize0;
 430 
 431         // Patch the header:
 432         if (haveFiles) {
 433             int archiveSizeHi = (int)(archiveSize1 >>> 32);
 434             int archiveSizeLo = (int)(archiveSize1 >>> 0);
 435             archive_header_S.patchValue(AH_ARCHIVE_SIZE_HI, archiveSizeHi);
 436             archive_header_S.patchValue(AH_ARCHIVE_SIZE_LO, archiveSizeLo);
 437             int zeroLen = UNSIGNED5.getLength(DUMMY);
 438             archiveSize0 += UNSIGNED5.getLength(archiveSizeHi) - zeroLen;
 439             archiveSize0 += UNSIGNED5.getLength(archiveSizeLo) - zeroLen;
 440         }
 441         if (verbose > 1)
 442             Utils.log.fine("archive sizes: "+
 443                              archiveSize0+"+"+archiveSize1);
 444         assert(all_bands.outputSize() == archiveSize0+archiveSize1);
 445     }
 446 
 447     void writeConstantPoolCounts(boolean haveNumbers, boolean haveCPExtra) throws IOException {
 448         for (byte tag : ConstantPool.TAGS_IN_ORDER) {
 449             int count = pkg.cp.getIndexByTag(tag).size();
 450             switch (tag) {
 451             case CONSTANT_Utf8:
 452                 // The null string is always first.
 453                 if (count > 0)
 454                     assert(pkg.cp.getIndexByTag(tag).get(0)
 455                            == ConstantPool.getUtf8Entry(""));
 456                 break;
 457 
 458             case CONSTANT_Integer:
 459             case CONSTANT_Float:
 460             case CONSTANT_Long:
 461             case CONSTANT_Double:
 462                 // Omit counts for numbers if possible.
 463                 if (!haveNumbers) {
 464                     assert(count == 0);
 465                     continue;
 466                 }
 467                 break;
 468 
 469             case CONSTANT_MethodHandle:
 470             case CONSTANT_MethodType:
 471             case CONSTANT_InvokeDynamic:
 472             case CONSTANT_BootstrapMethod:
 473                 // Omit counts for newer entities if possible.
 474                 if (!haveCPExtra) {
 475                     assert(count == 0);
 476                     continue;
 477                 }
 478                 break;
 479             }
 480             archive_header_1.putInt(count);
 481         }
 482     }
 483 
 484     protected Index getCPIndex(byte tag) {
 485         return pkg.cp.getIndexByTag(tag);
 486     }
 487 
 488 // (The following observations are out of date; they apply only to
 489 // "banding" the constant pool itself.  Later revisions of this algorithm
 490 // applied the banding technique to every part of the package file,
 491 // applying the benefits more broadly.)
 492 
 493 // Note:  Keeping the data separate in passes (or "bands") allows the
 494 // compressor to issue significantly shorter indexes for repeated data.
 495 // The difference in zipped size is 4%, which is remarkable since the
 496 // unzipped sizes are the same (only the byte order differs).
 497 
 498 // After moving similar data into bands, it becomes natural to delta-encode
 499 // each band.  (This is especially useful if we sort the constant pool first.)
 500 // Delta encoding saves an extra 5% in the output size (13% of the CP itself).
 501 // Because a typical delta usees much less data than a byte, the savings after
 502 // zipping is even better:  A zipped delta-encoded package is 8% smaller than
 503 // a zipped non-delta-encoded package.  Thus, in the zipped file, a banded,
 504 // delta-encoded constant pool saves over 11% (of the total file size) compared
 505 // with a zipped unbanded file.
 506 
 507     void writeConstantPool() throws IOException {
 508         IndexGroup cp = pkg.cp;
 509 
 510         if (verbose > 0)  Utils.log.info("Writing CP");
 511 
 512         for (byte tag : ConstantPool.TAGS_IN_ORDER) {
 513             Index index = cp.getIndexByTag(tag);
 514 
 515             Entry[] cpMap = index.cpMap;
 516             if (verbose > 0)
 517                 Utils.log.info("Writing "+cpMap.length+" "+ConstantPool.tagName(tag)+" entries...");
 518 
 519             if (optDumpBands) {
 520                 try (PrintStream ps = new PrintStream(getDumpStream(index, ".idx"))) {
 521                     printArrayTo(ps, cpMap, 0, cpMap.length);
 522                 }
 523             }
 524 
 525             switch (tag) {
 526             case CONSTANT_Utf8:
 527                 writeUtf8Bands(cpMap);
 528                 break;
 529             case CONSTANT_Integer:
 530                 for (int i = 0; i < cpMap.length; i++) {
 531                     NumberEntry e = (NumberEntry) cpMap[i];
 532                     int x = ((Integer)e.numberValue()).intValue();
 533                     cp_Int.putInt(x);
 534                 }
 535                 break;
 536             case CONSTANT_Float:
 537                 for (int i = 0; i < cpMap.length; i++) {
 538                     NumberEntry e = (NumberEntry) cpMap[i];
 539                     float fx = ((Float)e.numberValue()).floatValue();
 540                     int x = Float.floatToIntBits(fx);
 541                     cp_Float.putInt(x);
 542                 }
 543                 break;
 544             case CONSTANT_Long:
 545                 for (int i = 0; i < cpMap.length; i++) {
 546                     NumberEntry e = (NumberEntry) cpMap[i];
 547                     long x = ((Long)e.numberValue()).longValue();
 548                     cp_Long_hi.putInt((int)(x >>> 32));
 549                     cp_Long_lo.putInt((int)(x >>> 0));
 550                 }
 551                 break;
 552             case CONSTANT_Double:
 553                 for (int i = 0; i < cpMap.length; i++) {
 554                     NumberEntry e = (NumberEntry) cpMap[i];
 555                     double dx = ((Double)e.numberValue()).doubleValue();
 556                     long x = Double.doubleToLongBits(dx);
 557                     cp_Double_hi.putInt((int)(x >>> 32));
 558                     cp_Double_lo.putInt((int)(x >>> 0));
 559                 }
 560                 break;
 561             case CONSTANT_String:
 562                 for (int i = 0; i < cpMap.length; i++) {
 563                     StringEntry e = (StringEntry) cpMap[i];
 564                     cp_String.putRef(e.ref);
 565                 }
 566                 break;
 567             case CONSTANT_Class:
 568                 for (int i = 0; i < cpMap.length; i++) {
 569                     ClassEntry e = (ClassEntry) cpMap[i];
 570                     cp_Class.putRef(e.ref);
 571                 }
 572                 break;
 573             case CONSTANT_Signature:
 574                 writeSignatureBands(cpMap);
 575                 break;
 576             case CONSTANT_NameandType:
 577                 for (int i = 0; i < cpMap.length; i++) {
 578                     DescriptorEntry e = (DescriptorEntry) cpMap[i];
 579                     cp_Descr_name.putRef(e.nameRef);
 580                     cp_Descr_type.putRef(e.typeRef);
 581                 }
 582                 break;
 583             case CONSTANT_Fieldref:
 584                 writeMemberRefs(tag, cpMap, cp_Field_class, cp_Field_desc);
 585                 break;
 586             case CONSTANT_Methodref:
 587                 writeMemberRefs(tag, cpMap, cp_Method_class, cp_Method_desc);
 588                 break;
 589             case CONSTANT_InterfaceMethodref:
 590                 writeMemberRefs(tag, cpMap, cp_Imethod_class, cp_Imethod_desc);
 591                 break;
 592             case CONSTANT_MethodHandle:
 593                 for (int i = 0; i < cpMap.length; i++) {
 594                     MethodHandleEntry e = (MethodHandleEntry) cpMap[i];
 595                     cp_MethodHandle_refkind.putInt(e.refKind);
 596                     cp_MethodHandle_member.putRef(e.memRef);
 597                 }
 598                 break;
 599             case CONSTANT_MethodType:
 600                 for (int i = 0; i < cpMap.length; i++) {
 601                     MethodTypeEntry e = (MethodTypeEntry) cpMap[i];
 602                     cp_MethodType.putRef(e.typeRef);
 603                 }
 604                 break;
 605             case CONSTANT_InvokeDynamic:
 606                 for (int i = 0; i < cpMap.length; i++) {
 607                     InvokeDynamicEntry e = (InvokeDynamicEntry) cpMap[i];
 608                     cp_InvokeDynamic_spec.putRef(e.bssRef);
 609                     cp_InvokeDynamic_desc.putRef(e.descRef);
 610                 }
 611                 break;
 612             case CONSTANT_BootstrapMethod:
 613                 for (int i = 0; i < cpMap.length; i++) {
 614                     BootstrapMethodEntry e = (BootstrapMethodEntry) cpMap[i];
 615                     cp_BootstrapMethod_ref.putRef(e.bsmRef);
 616                     cp_BootstrapMethod_arg_count.putInt(e.argRefs.length);
 617                     for (Entry argRef : e.argRefs) {
 618                         cp_BootstrapMethod_arg.putRef(argRef);
 619                     }
 620                 }
 621                 break;
 622             default:
 623                 throw new AssertionError("unexpected CP tag in package");
 624             }
 625         }
 626         if (optDumpBands || verbose > 1) {
 627             for (byte tag = CONSTANT_GroupFirst; tag < CONSTANT_GroupLimit; tag++) {
 628                 Index index = cp.getIndexByTag(tag);
 629                 if (index == null || index.isEmpty())  continue;
 630                 Entry[] cpMap = index.cpMap;
 631                 if (verbose > 1)
 632                     Utils.log.info("Index group "+ConstantPool.tagName(tag)+" contains "+cpMap.length+" entries.");
 633                 if (optDumpBands) {
 634                     try (PrintStream ps = new PrintStream(getDumpStream(index.debugName, tag, ".gidx", index))) {
 635                         printArrayTo(ps, cpMap, 0, cpMap.length, true);
 636                     }
 637                 }
 638             }
 639         }
 640     }
 641 
 642     void writeUtf8Bands(Entry[] cpMap) throws IOException {
 643         if (cpMap.length == 0)
 644             return;  // nothing to write
 645 
 646         // The first element must always be the empty string.
 647         assert(cpMap[0].stringValue().equals(""));
 648         final int SUFFIX_SKIP_1 = 1;
 649         final int PREFIX_SKIP_2 = 2;
 650 
 651         // Fetch the char arrays, first of all.
 652         char[][] chars = new char[cpMap.length][];
 653         for (int i = 0; i < chars.length; i++) {
 654             chars[i] = cpMap[i].stringValue().toCharArray();
 655         }
 656 
 657         // First band:  Write lengths of shared prefixes.
 658         int[] prefixes = new int[cpMap.length];  // includes 2 skipped zeroes
 659         char[] prevChars = {};
 660         for (int i = 0; i < chars.length; i++) {
 661             int prefix = 0;
 662             char[] curChars = chars[i];
 663             int limit = Math.min(curChars.length, prevChars.length);
 664             while (prefix < limit && curChars[prefix] == prevChars[prefix])
 665                 prefix++;
 666             prefixes[i] = prefix;
 667             if (i >= PREFIX_SKIP_2)
 668                 cp_Utf8_prefix.putInt(prefix);
 669             else
 670                 assert(prefix == 0);
 671             prevChars = curChars;
 672         }
 673 
 674         // Second band:  Write lengths of unshared suffixes.
 675         // Third band:  Write the char values in the unshared suffixes.
 676         for (int i = 0; i < chars.length; i++) {
 677             char[] str = chars[i];
 678             int prefix = prefixes[i];
 679             int suffix = str.length - prefixes[i];
 680             boolean isPacked = false;
 681             if (suffix == 0) {
 682                 // Zero suffix length is special flag to indicate
 683                 // separate treatment in cp_Utf8_big bands.
 684                 // This suffix length never occurs naturally,
 685                 // except in the one case of a zero-length string.
 686                 // (If it occurs, it is the first, due to sorting.)
 687                 // The zero length string must, paradoxically, be
 688                 // encoded as a zero-length cp_Utf8_big band.
 689                 // This wastes exactly (& tolerably) one null byte.
 690                 isPacked = (i >= SUFFIX_SKIP_1);
 691                 // Do not bother to add an empty "(Utf8_big_0)" band.
 692                 // Also, the initial empty string does not require a band.
 693             } else if (optBigStrings && effort > 1 && suffix > 100) {
 694                 int numWide = 0;
 695                 for (int n = 0; n < suffix; n++) {
 696                     if (str[prefix+n] > 127) {
 697                         numWide++;
 698                     }
 699                 }
 700                 if (numWide > 100) {
 701                     // Try packing the chars with an alternate encoding.
 702                     isPacked = tryAlternateEncoding(i, numWide, str, prefix);
 703                 }
 704             }
 705             if (i < SUFFIX_SKIP_1) {
 706                 // No output.
 707                 assert(!isPacked);
 708                 assert(suffix == 0);
 709             } else if (isPacked) {
 710                 // Mark packed string with zero-length suffix count.
 711                 // This tells the unpacker to go elsewhere for the suffix bits.
 712                 // Fourth band:  Write unshared suffix with alternate coding.
 713                 cp_Utf8_suffix.putInt(0);
 714                 cp_Utf8_big_suffix.putInt(suffix);
 715             } else {
 716                 assert(suffix != 0);  // would be ambiguous
 717                 // Normal string.  Save suffix in third and fourth bands.
 718                 cp_Utf8_suffix.putInt(suffix);
 719                 for (int n = 0; n < suffix; n++) {
 720                     int ch = str[prefix+n];
 721                     cp_Utf8_chars.putInt(ch);
 722                 }
 723             }
 724         }
 725         if (verbose > 0) {
 726             int normCharCount = cp_Utf8_chars.length();
 727             int packCharCount = cp_Utf8_big_chars.length();
 728             int charCount = normCharCount + packCharCount;
 729             Utils.log.info("Utf8string #CHARS="+charCount+" #PACKEDCHARS="+packCharCount);
 730         }
 731     }
 732 
 733     private boolean tryAlternateEncoding(int i, int numWide,
 734                                          char[] str, int prefix) {
 735         int suffix = str.length - prefix;
 736         int[] cvals = new int[suffix];
 737         for (int n = 0; n < suffix; n++) {
 738             cvals[n] = str[prefix+n];
 739         }
 740         CodingChooser cc = getCodingChooser();
 741         Coding bigRegular = cp_Utf8_big_chars.regularCoding;
 742         String bandName = "(Utf8_big_"+i+")";
 743         int[] sizes = { 0, 0 };
 744         final int BYTE_SIZE = CodingChooser.BYTE_SIZE;
 745         final int ZIP_SIZE = CodingChooser.ZIP_SIZE;
 746         if (verbose > 1 || cc.verbose > 1) {
 747             Utils.log.fine("--- chooseCoding "+bandName);
 748         }
 749         CodingMethod special = cc.choose(cvals, bigRegular, sizes);
 750         Coding charRegular = cp_Utf8_chars.regularCoding;
 751         if (verbose > 1)
 752             Utils.log.fine("big string["+i+"] len="+suffix+" #wide="+numWide+" size="+sizes[BYTE_SIZE]+"/z="+sizes[ZIP_SIZE]+" coding "+special);
 753         if (special != charRegular) {
 754             int specialZipSize = sizes[ZIP_SIZE];
 755             int[] normalSizes = cc.computeSize(charRegular, cvals);
 756             int normalZipSize = normalSizes[ZIP_SIZE];
 757             int minWin = Math.max(5, normalZipSize/1000);
 758             if (verbose > 1)
 759                 Utils.log.fine("big string["+i+"] normalSize="+normalSizes[BYTE_SIZE]+"/z="+normalSizes[ZIP_SIZE]+" win="+(specialZipSize<normalZipSize-minWin));
 760             if (specialZipSize < normalZipSize-minWin) {
 761                 IntBand big = cp_Utf8_big_chars.newIntBand(bandName);
 762                 big.initializeValues(cvals);
 763                 return true;
 764             }
 765         }
 766         return false;
 767     }
 768 
 769     void writeSignatureBands(Entry[] cpMap) throws IOException {
 770         for (int i = 0; i < cpMap.length; i++) {
 771             SignatureEntry e = (SignatureEntry) cpMap[i];
 772             cp_Signature_form.putRef(e.formRef);
 773             for (int j = 0; j < e.classRefs.length; j++) {
 774                 cp_Signature_classes.putRef(e.classRefs[j]);
 775             }
 776         }
 777     }
 778 
 779     void writeMemberRefs(byte tag, Entry[] cpMap, CPRefBand cp_class, CPRefBand cp_desc) throws IOException {
 780         for (int i = 0; i < cpMap.length; i++) {
 781             MemberEntry e = (MemberEntry) cpMap[i];
 782             cp_class.putRef(e.classRef);
 783             cp_desc.putRef(e.descRef);
 784         }
 785     }
 786 
 787     void writeFiles() throws IOException {
 788         int numFiles = pkg.files.size();
 789         if (numFiles == 0)  return;
 790         int options = archiveOptions;
 791         boolean haveSizeHi  = testBit(options, AO_HAVE_FILE_SIZE_HI);
 792         boolean haveModtime = testBit(options, AO_HAVE_FILE_MODTIME);
 793         boolean haveOptions = testBit(options, AO_HAVE_FILE_OPTIONS);
 794         if (!haveOptions) {
 795             for (File file : pkg.files) {
 796                 if (file.isClassStub()) {
 797                     haveOptions = true;
 798                     options |= AO_HAVE_FILE_OPTIONS;
 799                     archiveOptions = options;
 800                     break;
 801                 }
 802             }
 803         }
 804         if (haveSizeHi || haveModtime || haveOptions || !pkg.files.isEmpty()) {
 805             options |= AO_HAVE_FILE_HEADERS;
 806             archiveOptions = options;
 807         }
 808         for (File file : pkg.files) {
 809             file_name.putRef(file.name);
 810             long len = file.getFileLength();
 811             file_size_lo.putInt((int)len);
 812             if (haveSizeHi)
 813                 file_size_hi.putInt((int)(len >>> 32));
 814             if (haveModtime)
 815                 file_modtime.putInt(file.modtime - pkg.default_modtime);
 816             if (haveOptions)
 817                 file_options.putInt(file.options);
 818             file.writeTo(file_bits.collectorStream());
 819             if (verbose > 1)
 820                 Utils.log.fine("Wrote "+len+" bytes of "+file.name.stringValue());
 821         }
 822         if (verbose > 0)
 823             Utils.log.info("Wrote "+numFiles+" resource files");
 824     }
 825 
 826     void collectAttributeLayouts() {
 827         maxFlags = new int[ATTR_CONTEXT_LIMIT];
 828         allLayouts = new FixedList<>(ATTR_CONTEXT_LIMIT);
 829         for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
 830             allLayouts.set(i, new HashMap<Attribute.Layout, int[]>());
 831         }
 832         // Collect maxFlags and allLayouts.
 833         for (Class cls : pkg.classes) {
 834             visitAttributeLayoutsIn(ATTR_CONTEXT_CLASS, cls);
 835             for (Class.Field f : cls.getFields()) {
 836                 visitAttributeLayoutsIn(ATTR_CONTEXT_FIELD, f);
 837             }
 838             for (Class.Method m : cls.getMethods()) {
 839                 visitAttributeLayoutsIn(ATTR_CONTEXT_METHOD, m);
 840                 if (m.code != null) {
 841                     visitAttributeLayoutsIn(ATTR_CONTEXT_CODE, m.code);
 842                 }
 843             }
 844         }
 845         // If there are many species of attributes, use 63-bit flags.
 846         for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
 847             int nl = allLayouts.get(i).size();
 848             boolean haveLongFlags = haveFlagsHi(i);
 849             final int TOO_MANY_ATTRS = 32 /*int flag size*/
 850                 - 12 /*typical flag bits in use*/
 851                 + 4  /*typical number of OK overflows*/;
 852             if (nl >= TOO_MANY_ATTRS) {  // heuristic
 853                 int mask = 1<<(LG_AO_HAVE_XXX_FLAGS_HI+i);
 854                 archiveOptions |= mask;
 855                 haveLongFlags = true;
 856                 if (verbose > 0)
 857                    Utils.log.info("Note: Many "+Attribute.contextName(i)+" attributes forces 63-bit flags");
 858             }
 859             if (verbose > 1) {
 860                 Utils.log.fine(Attribute.contextName(i)+".maxFlags = 0x"+Integer.toHexString(maxFlags[i]));
 861                 Utils.log.fine(Attribute.contextName(i)+".#layouts = "+nl);
 862             }
 863             assert(haveFlagsHi(i) == haveLongFlags);
 864         }
 865         initAttrIndexLimit();
 866 
 867         // Standard indexes can never conflict with flag bits.  Assert it.
 868         for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
 869             assert((attrFlagMask[i] & maxFlags[i]) == 0);
 870         }
 871         // Collect counts for both predefs. and custom defs.
 872         // Decide on custom, local attribute definitions.
 873         backCountTable = new HashMap<>();
 874         attrCounts = new int[ATTR_CONTEXT_LIMIT][];
 875         for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
 876             // Now the remaining defs in allLayouts[i] need attr. indexes.
 877             // Fill up unused flag bits with new defs.
 878             // Unused bits are those which are not used by predefined attrs,
 879             // and which are always clear in the classfiles.
 880             long avHiBits = ~(maxFlags[i] | attrFlagMask[i]);
 881             assert(attrIndexLimit[i] > 0);
 882             assert(attrIndexLimit[i] < 64);  // all bits fit into a Java long
 883             avHiBits &= (1L<<attrIndexLimit[i])-1;
 884             int nextLoBit = 0;
 885             Map<Attribute.Layout, int[]> defMap = allLayouts.get(i);
 886             @SuppressWarnings({"unchecked", "rawtypes"})
 887             Map.Entry<Attribute.Layout, int[]>[] layoutsAndCounts =
 888                     new Map.Entry[defMap.size()];
 889             defMap.entrySet().toArray(layoutsAndCounts);
 890             // Sort by count, most frequent first.
 891             // Predefs. participate in this sort, though it does not matter.
 892             Arrays.sort(layoutsAndCounts,
 893                         new Comparator<Map.Entry<Attribute.Layout, int[]>>() {
 894                 public int compare(Map.Entry<Attribute.Layout, int[]> e0,
 895                                    Map.Entry<Attribute.Layout, int[]> e1) {
 896                     // Primary sort key is count, reversed.
 897                     int r = -(e0.getValue()[0] - e1.getValue()[0]);
 898                     if (r != 0)  return r;
 899                     return e0.getKey().compareTo(e1.getKey());
 900                 }
 901             });
 902             attrCounts[i] = new int[attrIndexLimit[i]+layoutsAndCounts.length];
 903             for (int j = 0; j < layoutsAndCounts.length; j++) {
 904                 Map.Entry<Attribute.Layout, int[]> e = layoutsAndCounts[j];
 905                 Attribute.Layout def = e.getKey();
 906                 int count = e.getValue()[0];
 907                 int index;
 908                 Integer predefIndex = attrIndexTable.get(def);
 909                 if (predefIndex != null) {
 910                     // The index is already set.
 911                     index = predefIndex.intValue();
 912                 } else if (avHiBits != 0) {
 913                     while ((avHiBits & 1) == 0) {
 914                         avHiBits >>>= 1;
 915                         nextLoBit += 1;
 916                     }
 917                     avHiBits -= 1;  // clear low bit; we are using it now
 918                     // Update attrIndexTable:
 919                     index = setAttributeLayoutIndex(def, nextLoBit);
 920                 } else {
 921                     // Update attrIndexTable:
 922                     index = setAttributeLayoutIndex(def, ATTR_INDEX_OVERFLOW);
 923                 }
 924 
 925                 // Now that we know the index, record the count of this def.
 926                 attrCounts[i][index] = count;
 927 
 928                 // For all callables in the def, keep a tally of back-calls.
 929                 Attribute.Layout.Element[] cbles = def.getCallables();
 930                 final int[] bc = new int[cbles.length];
 931                 for (int k = 0; k < cbles.length; k++) {
 932                     assert(cbles[k].kind == Attribute.EK_CBLE);
 933                     if (!cbles[k].flagTest(Attribute.EF_BACK)) {
 934                         bc[k] = -1;  // no count to accumulate here
 935                     }
 936                 }
 937                 backCountTable.put(def, bc);
 938 
 939                 if (predefIndex == null) {
 940                     // Make sure the package CP can name the local attribute.
 941                     Entry ne = ConstantPool.getUtf8Entry(def.name());
 942                     String layout = def.layoutForClassVersion(getHighestClassVersion());
 943                     Entry le = ConstantPool.getUtf8Entry(layout);
 944                     requiredEntries.add(ne);
 945                     requiredEntries.add(le);
 946                     if (verbose > 0) {
 947                         if (index < attrIndexLimit[i])
 948                            Utils.log.info("Using free flag bit 1<<"+index+" for "+count+" occurrences of "+def);
 949                         else
 950                             Utils.log.info("Using overflow index "+index+" for "+count+" occurrences of "+def);
 951                     }
 952                 }
 953             }
 954         }
 955         // Later, when emitting attr_definition_bands, we will look at
 956         // attrDefSeen and attrDefs at position 32/63 and beyond.
 957         // The attrIndexTable will provide elements of xxx_attr_indexes bands.
 958 
 959         // Done with scratch variables:
 960         maxFlags = null;
 961         allLayouts = null;
 962     }
 963 
 964     // Scratch variables for processing attributes and flags.
 965     int[] maxFlags;
 966     List<Map<Attribute.Layout, int[]>> allLayouts;
 967 
 968     void visitAttributeLayoutsIn(int ctype, Attribute.Holder h) {
 969         // Make note of which flags appear in the class file.
 970         // Set them in maxFlags.
 971         maxFlags[ctype] |= h.flags;
 972         for (Attribute a : h.getAttributes()) {
 973             Attribute.Layout def = a.layout();
 974             Map<Attribute.Layout, int[]> defMap = allLayouts.get(ctype);
 975             int[] count = defMap.get(def);
 976             if (count == null) {
 977                 defMap.put(def, count = new int[1]);
 978             }
 979             if (count[0] < Integer.MAX_VALUE) {
 980                 count[0] += 1;
 981             }
 982         }
 983     }
 984 
 985     Attribute.Layout[] attrDefsWritten;
 986 
 987     void writeAttrDefs() throws IOException {
 988         List<Object[]> defList = new ArrayList<>();
 989         for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
 990             int limit = attrDefs.get(i).size();
 991             for (int j = 0; j < limit; j++) {
 992                 int header = i;  // ctype
 993                 if (j < attrIndexLimit[i]) {
 994                     header |= ((j + ADH_BIT_IS_LSB) << ADH_BIT_SHIFT);
 995                     assert(header < 0x100);  // must fit into a byte
 996                     // (...else header is simply ctype, with zero high bits.)
 997                     if (!testBit(attrDefSeen[i], 1L<<j)) {
 998                         // either undefined or predefined; nothing to write
 999                         continue;
1000                     }
1001                 }
1002                 Attribute.Layout def = attrDefs.get(i).get(j);
1003                 defList.add(new Object[]{ Integer.valueOf(header), def });
1004                 assert(Integer.valueOf(j).equals(attrIndexTable.get(def)));
1005             }
1006         }
1007         // Sort the new attr defs into some "natural" order.
1008         int numAttrDefs = defList.size();
1009         Object[][] defs = new Object[numAttrDefs][];
1010         defList.toArray(defs);
1011         Arrays.sort(defs, new Comparator<Object[]>() {
1012             public int compare(Object[] a0, Object[] a1) {
1013                 // Primary sort key is attr def header.
1014                 @SuppressWarnings("unchecked")
1015                 int r = ((Comparable)a0[0]).compareTo(a1[0]);
1016                 if (r != 0)  return r;
1017                 Integer ind0 = attrIndexTable.get(a0[1]);
1018                 Integer ind1 = attrIndexTable.get(a1[1]);
1019                 // Secondary sort key is attribute index.
1020                 // (This must be so, in order to keep overflow attr order.)
1021                 assert(ind0 != null);
1022                 assert(ind1 != null);
1023                 return ind0.compareTo(ind1);
1024             }
1025         });
1026         attrDefsWritten = new Attribute.Layout[numAttrDefs];
1027         try (PrintStream dump = !optDumpBands ? null
1028                  : new PrintStream(getDumpStream(attr_definition_headers, ".def")))
1029         {
1030             int[] indexForDebug = Arrays.copyOf(attrIndexLimit, ATTR_CONTEXT_LIMIT);
1031             for (int i = 0; i < defs.length; i++) {
1032                 int header = ((Integer)defs[i][0]).intValue();
1033                 Attribute.Layout def = (Attribute.Layout) defs[i][1];
1034                 attrDefsWritten[i] = def;
1035                 assert((header & ADH_CONTEXT_MASK) == def.ctype());
1036                 attr_definition_headers.putByte(header);
1037                 attr_definition_name.putRef(ConstantPool.getUtf8Entry(def.name()));
1038                 String layout = def.layoutForClassVersion(getHighestClassVersion());
1039                 attr_definition_layout.putRef(ConstantPool.getUtf8Entry(layout));
1040                 // Check that we are transmitting that correct attribute index:
1041                 boolean debug = false;
1042                 assert(debug = true);
1043                 if (debug) {
1044                     int hdrIndex = (header >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB;
1045                     if (hdrIndex < 0)  hdrIndex = indexForDebug[def.ctype()]++;
1046                     int realIndex = (attrIndexTable.get(def)).intValue();
1047                     assert(hdrIndex == realIndex);
1048                 }
1049                 if (dump != null) {
1050                     int index = (header >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB;
1051                     dump.println(index+" "+def);
1052                 }
1053             }
1054         }
1055     }
1056 
1057     void writeAttrCounts() throws IOException {
1058         // Write the four xxx_attr_calls bands.
1059         for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) {
1060             MultiBand xxx_attr_bands = attrBands[ctype];
1061             IntBand xxx_attr_calls = getAttrBand(xxx_attr_bands, AB_ATTR_CALLS);
1062             Attribute.Layout[] defs = new Attribute.Layout[attrDefs.get(ctype).size()];
1063             attrDefs.get(ctype).toArray(defs);
1064             for (boolean predef = true; ; predef = false) {
1065                 for (int ai = 0; ai < defs.length; ai++) {
1066                     Attribute.Layout def = defs[ai];
1067                     if (def == null)  continue;  // unused index
1068                     if (predef != isPredefinedAttr(ctype, ai))
1069                         continue;  // wrong pass
1070                     int totalCount = attrCounts[ctype][ai];
1071                     if (totalCount == 0)
1072                         continue;  // irrelevant
1073                     int[] bc = backCountTable.get(def);
1074                     for (int j = 0; j < bc.length; j++) {
1075                         if (bc[j] >= 0) {
1076                             int backCount = bc[j];
1077                             bc[j] = -1;  // close out; do not collect further counts
1078                             xxx_attr_calls.putInt(backCount);
1079                             assert(def.getCallables()[j].flagTest(Attribute.EF_BACK));
1080                         } else {
1081                             assert(!def.getCallables()[j].flagTest(Attribute.EF_BACK));
1082                         }
1083                     }
1084                 }
1085                 if (!predef)  break;
1086             }
1087         }
1088     }
1089 
1090     void trimClassAttributes() {
1091         for (Class cls : pkg.classes) {
1092             // Replace "obvious" SourceFile attrs by null.
1093             cls.minimizeSourceFile();
1094             // BootstrapMethods should never have been inserted.
1095             assert(cls.getAttribute(Package.attrBootstrapMethodsEmpty) == null);
1096         }
1097     }
1098 
1099     void collectInnerClasses() {
1100         // Capture inner classes, removing them from individual classes.
1101         // Irregular inner classes must stay local, though.
1102         Map<ClassEntry, InnerClass> allICMap = new HashMap<>();
1103         // First, collect a consistent global set.
1104         for (Class cls : pkg.classes) {
1105             if (!cls.hasInnerClasses())  continue;
1106             for (InnerClass ic : cls.getInnerClasses()) {
1107                 InnerClass pic = allICMap.put(ic.thisClass, ic);
1108                 if (pic != null && !pic.equals(ic) && pic.predictable) {
1109                     // Different ICs.  Choose the better to make global.
1110                     allICMap.put(pic.thisClass, pic);
1111                 }
1112             }
1113         }
1114 
1115         InnerClass[] allICs = new InnerClass[allICMap.size()];
1116         allICMap.values().toArray(allICs);
1117         allICMap = null;  // done with it
1118 
1119         // Note: The InnerClasses attribute must be in a valid order,
1120         // so that A$B always occurs earlier than A$B$C.  This is an
1121         // important side-effect of sorting lexically by class name.
1122         Arrays.sort(allICs);  // put in canonical order
1123         pkg.setAllInnerClasses(Arrays.asList(allICs));
1124 
1125         // Next, empty out of every local set the consistent entries.
1126         // Calculate whether there is any remaining need to have a local
1127         // set, and whether it needs to be locked.
1128         for (Class cls : pkg.classes) {
1129             cls.minimizeLocalICs();
1130         }
1131     }
1132 
1133     void writeInnerClasses() throws IOException {
1134         for (InnerClass ic : pkg.getAllInnerClasses()) {
1135             int flags = ic.flags;
1136             assert((flags & ACC_IC_LONG_FORM) == 0);
1137             if (!ic.predictable) {
1138                 flags |= ACC_IC_LONG_FORM;
1139             }
1140             ic_this_class.putRef(ic.thisClass);
1141             ic_flags.putInt(flags);
1142             if (!ic.predictable) {
1143                 ic_outer_class.putRef(ic.outerClass);
1144                 ic_name.putRef(ic.name);
1145             }
1146         }
1147     }
1148 
1149     /** If there are any extra InnerClasses entries to write which are
1150      *  not already implied by the global table, put them into a
1151      *  local attribute.  This is expected to be rare.
1152      */
1153     void writeLocalInnerClasses(Class cls) throws IOException {
1154         List<InnerClass> localICs = cls.getInnerClasses();
1155         class_InnerClasses_N.putInt(localICs.size());
1156         for(InnerClass ic : localICs) {
1157             class_InnerClasses_RC.putRef(ic.thisClass);
1158             // Is it redundant with the global version?
1159             if (ic.equals(pkg.getGlobalInnerClass(ic.thisClass))) {
1160                 // A zero flag means copy a global IC here.
1161                 class_InnerClasses_F.putInt(0);
1162             } else {
1163                 int flags = ic.flags;
1164                 if (flags == 0)
1165                     flags = ACC_IC_LONG_FORM;  // force it to be non-zero
1166                 class_InnerClasses_F.putInt(flags);
1167                 class_InnerClasses_outer_RCN.putRef(ic.outerClass);
1168                 class_InnerClasses_name_RUN.putRef(ic.name);
1169             }
1170         }
1171     }
1172 
1173     void writeClassesAndByteCodes() throws IOException {
1174         Class[] classes = new Class[pkg.classes.size()];
1175         pkg.classes.toArray(classes);
1176         // Note:  This code respects the order in which caller put classes.
1177         if (verbose > 0)
1178             Utils.log.info("  ...scanning "+classes.length+" classes...");
1179 
1180         int nwritten = 0;
1181         for (int i = 0; i < classes.length; i++) {
1182             // Collect the class body, sans bytecodes.
1183             Class cls = classes[i];
1184             if (verbose > 1)
1185                 Utils.log.fine("Scanning "+cls);
1186 
1187             ClassEntry   thisClass  = cls.thisClass;
1188             ClassEntry   superClass = cls.superClass;
1189             ClassEntry[] interfaces = cls.interfaces;
1190             // Encode rare case of null superClass as thisClass:
1191             assert(superClass != thisClass);  // bad class file!?
1192             if (superClass == null)  superClass = thisClass;
1193             class_this.putRef(thisClass);
1194             class_super.putRef(superClass);
1195             class_interface_count.putInt(cls.interfaces.length);
1196             for (int j = 0; j < interfaces.length; j++) {
1197                 class_interface.putRef(interfaces[j]);
1198             }
1199 
1200             writeMembers(cls);
1201             writeAttrs(ATTR_CONTEXT_CLASS, cls, cls);
1202 
1203             nwritten++;
1204             if (verbose > 0 && (nwritten % 1000) == 0)
1205                 Utils.log.info("Have scanned "+nwritten+" classes...");
1206         }
1207     }
1208 
1209     void writeMembers(Class cls) throws IOException {
1210         List<Class.Field> fields = cls.getFields();
1211         class_field_count.putInt(fields.size());
1212         for (Class.Field f : fields) {
1213             field_descr.putRef(f.getDescriptor());
1214             writeAttrs(ATTR_CONTEXT_FIELD, f, cls);
1215         }
1216 
1217         List<Class.Method> methods = cls.getMethods();
1218         class_method_count.putInt(methods.size());
1219         for (Class.Method m : methods) {
1220             method_descr.putRef(m.getDescriptor());
1221             writeAttrs(ATTR_CONTEXT_METHOD, m, cls);
1222             assert((m.code != null) == (m.getAttribute(attrCodeEmpty) != null));
1223             if (m.code != null) {
1224                 writeCodeHeader(m.code);
1225                 writeByteCodes(m.code);
1226             }
1227         }
1228     }
1229 
1230     void writeCodeHeader(Code c) throws IOException {
1231         boolean attrsOK = testBit(archiveOptions, AO_HAVE_ALL_CODE_FLAGS);
1232         int na = c.attributeSize();
1233         int sc = shortCodeHeader(c);
1234         if (!attrsOK && na > 0)
1235             // We must write flags, and can only do so for long headers.
1236             sc = LONG_CODE_HEADER;
1237         if (verbose > 2) {
1238             int siglen = c.getMethod().getArgumentSize();
1239             Utils.log.fine("Code sizes info "+c.max_stack+" "+c.max_locals+" "+c.getHandlerCount()+" "+siglen+" "+na+(sc > 0 ? " SHORT="+sc : ""));
1240         }
1241         code_headers.putByte(sc);
1242         if (sc == LONG_CODE_HEADER) {
1243             code_max_stack.putInt(c.getMaxStack());
1244             code_max_na_locals.putInt(c.getMaxNALocals());
1245             code_handler_count.putInt(c.getHandlerCount());
1246         } else {
1247             assert(attrsOK || na == 0);
1248             assert(c.getHandlerCount() < shortCodeHeader_h_limit);
1249         }
1250         writeCodeHandlers(c);
1251         if (sc == LONG_CODE_HEADER || attrsOK)
1252             writeAttrs(ATTR_CONTEXT_CODE, c, c.thisClass());
1253     }
1254 
1255     void writeCodeHandlers(Code c) throws IOException {
1256         int sum, del;
1257         for (int j = 0, jmax = c.getHandlerCount(); j < jmax; j++) {
1258             code_handler_class_RCN.putRef(c.handler_class[j]); // null OK
1259             // Encode end as offset from start, and catch as offset from end,
1260             // because they are strongly correlated.
1261             sum = c.encodeBCI(c.handler_start[j]);
1262             code_handler_start_P.putInt(sum);
1263             del = c.encodeBCI(c.handler_end[j]) - sum;
1264             code_handler_end_PO.putInt(del);
1265             sum += del;
1266             del = c.encodeBCI(c.handler_catch[j]) - sum;
1267             code_handler_catch_PO.putInt(del);
1268         }
1269     }
1270 
1271     // Generic routines for writing attributes and flags of
1272     // classes, fields, methods, and codes.
1273     void writeAttrs(int ctype,
1274                     final Attribute.Holder h,
1275                     Class cls) throws IOException {
1276         MultiBand xxx_attr_bands = attrBands[ctype];
1277         IntBand xxx_flags_hi = getAttrBand(xxx_attr_bands, AB_FLAGS_HI);
1278         IntBand xxx_flags_lo = getAttrBand(xxx_attr_bands, AB_FLAGS_LO);
1279         boolean haveLongFlags = haveFlagsHi(ctype);
1280         assert(attrIndexLimit[ctype] == (haveLongFlags? 63: 32));
1281         if (h.attributes == null) {
1282             xxx_flags_lo.putInt(h.flags);  // no extra bits to set here
1283             if (haveLongFlags)
1284                 xxx_flags_hi.putInt(0);
1285             return;
1286         }
1287         if (verbose > 3)
1288             Utils.log.fine("Transmitting attrs for "+h+" flags="+Integer.toHexString(h.flags));
1289 
1290         long flagMask = attrFlagMask[ctype];  // which flags are attr bits?
1291         long flagsToAdd = 0;
1292         int overflowCount = 0;
1293         for (Attribute a : h.attributes) {
1294             Attribute.Layout def = a.layout();
1295             int index = (attrIndexTable.get(def)).intValue();
1296             assert(attrDefs.get(ctype).get(index) == def);
1297             if (verbose > 3)
1298                 Utils.log.fine("add attr @"+index+" "+a+" in "+h);
1299             if (index < attrIndexLimit[ctype] && testBit(flagMask, 1L<<index)) {
1300                 if (verbose > 3)
1301                     Utils.log.fine("Adding flag bit 1<<"+index+" in "+Long.toHexString(flagMask));
1302                 assert(!testBit(h.flags, 1L<<index));
1303                 flagsToAdd |= (1L<<index);
1304                 flagMask -= (1L<<index);  // do not use this bit twice here
1305             } else {
1306                 // an overflow attr.
1307                 flagsToAdd |= (1L<<X_ATTR_OVERFLOW);
1308                 overflowCount += 1;
1309                 if (verbose > 3)
1310                     Utils.log.fine("Adding overflow attr #"+overflowCount);
1311                 IntBand xxx_attr_indexes = getAttrBand(xxx_attr_bands, AB_ATTR_INDEXES);
1312                 xxx_attr_indexes.putInt(index);
1313                 // System.out.println("overflow @"+index);
1314             }
1315             if (def.bandCount == 0) {
1316                 if (def == attrInnerClassesEmpty) {
1317                     // Special logic to write this attr.
1318                     writeLocalInnerClasses((Class) h);
1319                     continue;
1320                 }
1321                 // Empty attr; nothing more to write here.
1322                 continue;
1323             }
1324             assert(a.fixups == null);
1325             final Band[] ab = attrBandTable.get(def);
1326             assert(ab != null);
1327             assert(ab.length == def.bandCount);
1328             final int[] bc = backCountTable.get(def);
1329             assert(bc != null);
1330             assert(bc.length == def.getCallables().length);
1331             // Write one attribute of type def into ab.
1332             if (verbose > 2)  Utils.log.fine("writing "+a+" in "+h);
1333             boolean isCV = (ctype == ATTR_CONTEXT_FIELD && def == attrConstantValue);
1334             if (isCV)  setConstantValueIndex((Class.Field)h);
1335             a.parse(cls, a.bytes(), 0, a.size(),
1336                       new Attribute.ValueStream() {
1337                 public void putInt(int bandIndex, int value) {
1338                     ((IntBand) ab[bandIndex]).putInt(value);
1339                 }
1340                 public void putRef(int bandIndex, Entry ref) {
1341                     ((CPRefBand) ab[bandIndex]).putRef(ref);
1342                 }
1343                 public int encodeBCI(int bci) {
1344                     Code code = (Code) h;
1345                     return code.encodeBCI(bci);
1346                 }
1347                 public void noteBackCall(int whichCallable) {
1348                     assert(bc[whichCallable] >= 0);
1349                     bc[whichCallable] += 1;
1350                 }
1351             });
1352             if (isCV)  setConstantValueIndex(null);  // clean up
1353         }
1354 
1355         if (overflowCount > 0) {
1356             IntBand xxx_attr_count = getAttrBand(xxx_attr_bands, AB_ATTR_COUNT);
1357             xxx_attr_count.putInt(overflowCount);
1358         }
1359 
1360         xxx_flags_lo.putInt(h.flags | (int)flagsToAdd);
1361         if (haveLongFlags)
1362             xxx_flags_hi.putInt((int)(flagsToAdd >>> 32));
1363         else
1364             assert((flagsToAdd >>> 32) == 0);
1365         assert((h.flags & flagsToAdd) == 0)
1366             : (h+".flags="
1367                 +Integer.toHexString(h.flags)+"^"
1368                 +Long.toHexString(flagsToAdd));
1369     }
1370 
1371     // temporary scratch variables for processing code blocks
1372     private Code                 curCode;
1373     private Class                curClass;
1374     private Entry[] curCPMap;
1375     private void beginCode(Code c) {
1376         assert(curCode == null);
1377         curCode = c;
1378         curClass = c.m.thisClass();
1379         curCPMap = c.getCPMap();
1380     }
1381     private void endCode() {
1382         curCode = null;
1383         curClass = null;
1384         curCPMap = null;
1385     }
1386 
1387     // Return an _invokeinit_op variant, if the instruction matches one,
1388     // else -1.
1389     private int initOpVariant(Instruction i, Entry newClass) {
1390         if (i.getBC() != _invokespecial)  return -1;
1391         MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
1392         if ("<init>".equals(ref.descRef.nameRef.stringValue()) == false)
1393             return -1;
1394         ClassEntry refClass = ref.classRef;
1395         if (refClass == curClass.thisClass)
1396             return _invokeinit_op+_invokeinit_self_option;
1397         if (refClass == curClass.superClass)
1398             return _invokeinit_op+_invokeinit_super_option;
1399         if (refClass == newClass)
1400             return _invokeinit_op+_invokeinit_new_option;
1401         return -1;
1402     }
1403 
1404     // Return a _self_linker_op variant, if the instruction matches one,
1405     // else -1.
1406     private int selfOpVariant(Instruction i) {
1407         int bc = i.getBC();
1408         if (!(bc >= _first_linker_op && bc <= _last_linker_op))  return -1;
1409         MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
1410         ClassEntry refClass = ref.classRef;
1411         int self_bc = _self_linker_op + (bc - _first_linker_op);
1412         if (refClass == curClass.thisClass)
1413             return self_bc;
1414         if (refClass == curClass.superClass)
1415             return self_bc + _self_linker_super_flag;
1416         return -1;
1417     }
1418 
1419     void writeByteCodes(Code code) throws IOException {
1420         beginCode(code);
1421         IndexGroup cp = pkg.cp;
1422 
1423         // true if the previous instruction is an aload to absorb
1424         boolean prevAload = false;
1425 
1426         // class of most recent new; helps compress <init> calls
1427         Entry newClass = null;
1428 
1429         for (Instruction i = code.instructionAt(0); i != null; i = i.next()) {
1430             // %%% Add a stress mode which issues _ref/_byte_escape.
1431             if (verbose > 3)  Utils.log.fine(i.toString());
1432 
1433             if (i.isNonstandard()) {
1434                 // Crash and burn with a complaint if there are funny
1435                 // bytecodes in this class file.
1436                 String complaint = code.getMethod()
1437                     +" contains an unrecognized bytecode "+i
1438                     +"; please use the pass-file option on this class.";
1439                 Utils.log.warning(complaint);
1440                 throw new IOException(complaint);
1441             }
1442 
1443             if (i.isWide()) {
1444                 if (verbose > 1) {
1445                     Utils.log.fine("_wide opcode in "+code);
1446                     Utils.log.fine(i.toString());
1447                 }
1448                 bc_codes.putByte(_wide);
1449                 codeHist[_wide]++;
1450             }
1451 
1452             int bc = i.getBC();
1453 
1454             // Begin "bc_linker" compression.
1455             if (bc == _aload_0) {
1456                 // Try to group aload_0 with a following operation.
1457                 Instruction ni = code.instructionAt(i.getNextPC());
1458                 if (selfOpVariant(ni) >= 0) {
1459                     prevAload = true;
1460                     continue;
1461                 }
1462             }
1463 
1464             // Test for <init> invocations:
1465             int init_bc = initOpVariant(i, newClass);
1466             if (init_bc >= 0) {
1467                 if (prevAload) {
1468                     // get rid of it
1469                     bc_codes.putByte(_aload_0);
1470                     codeHist[_aload_0]++;
1471                     prevAload = false;  //used up
1472                 }
1473                 // Write special bytecode.
1474                 bc_codes.putByte(init_bc);
1475                 codeHist[init_bc]++;
1476                 MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
1477                 // Write operand to a separate band.
1478                 int coding = cp.getOverloadingIndex(ref);
1479                 bc_initref.putInt(coding);
1480                 continue;
1481             }
1482 
1483             int self_bc = selfOpVariant(i);
1484             if (self_bc >= 0) {
1485                 boolean isField = Instruction.isFieldOp(bc);
1486                 boolean isSuper = (self_bc >= _self_linker_op+_self_linker_super_flag);
1487                 boolean isAload = prevAload;
1488                 prevAload = false;  //used up
1489                 if (isAload)
1490                     self_bc += _self_linker_aload_flag;
1491                 // Write special bytecode.
1492                 bc_codes.putByte(self_bc);
1493                 codeHist[self_bc]++;
1494                 // Write field or method ref to a separate band.
1495                 MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
1496                 CPRefBand bc_which = selfOpRefBand(self_bc);
1497                 Index which_ix = cp.getMemberIndex(ref.tag, ref.classRef);
1498                 bc_which.putRef(ref, which_ix);
1499                 continue;
1500             }
1501             assert(!prevAload);
1502             // End "bc_linker" compression.
1503 
1504             // Normal bytecode.
1505             codeHist[bc]++;
1506             switch (bc) {
1507             case _tableswitch: // apc:  (df, lo, hi, (hi-lo+1)*(label))
1508             case _lookupswitch: // apc:  (df, nc, nc*(case, label))
1509                 bc_codes.putByte(bc);
1510                 Instruction.Switch isw = (Instruction.Switch) i;
1511                 // Note that we do not write the alignment bytes.
1512                 int apc = isw.getAlignedPC();
1513                 int npc = isw.getNextPC();
1514                 // write a length specification into the bytecode stream
1515                 int caseCount = isw.getCaseCount();
1516                 bc_case_count.putInt(caseCount);
1517                 putLabel(bc_label, code, i.getPC(), isw.getDefaultLabel());
1518                 for (int j = 0; j < caseCount; j++) {
1519                     putLabel(bc_label, code, i.getPC(), isw.getCaseLabel(j));
1520                 }
1521                 // Transmit case values in their own band.
1522                 if (bc == _tableswitch) {
1523                     bc_case_value.putInt(isw.getCaseValue(0));
1524                 } else {
1525                     for (int j = 0; j < caseCount; j++) {
1526                         bc_case_value.putInt(isw.getCaseValue(j));
1527                     }
1528                 }
1529                 // Done with the switch.
1530                 continue;
1531             }
1532 
1533             int branch = i.getBranchLabel();
1534             if (branch >= 0) {
1535                 bc_codes.putByte(bc);
1536                 putLabel(bc_label, code, i.getPC(), branch);
1537                 continue;
1538             }
1539             Entry ref = i.getCPRef(curCPMap);
1540             if (ref != null) {
1541                 if (bc == _new)  newClass = ref;
1542                 if (bc == _ldc)  ldcHist[ref.tag]++;
1543                 CPRefBand bc_which;
1544                 int vbc = bc;
1545                 switch (i.getCPTag()) {
1546                 case CONSTANT_LoadableValue:
1547                     switch (ref.tag) {
1548                     case CONSTANT_Integer:
1549                         bc_which = bc_intref;
1550                         switch (bc) {
1551                         case _ldc:    vbc = _ildc; break;
1552                         case _ldc_w:  vbc = _ildc_w; break;
1553                         default:      assert(false);
1554                         }
1555                         break;
1556                     case CONSTANT_Float:
1557                         bc_which = bc_floatref;
1558                         switch (bc) {
1559                         case _ldc:    vbc = _fldc; break;
1560                         case _ldc_w:  vbc = _fldc_w; break;
1561                         default:      assert(false);
1562                         }
1563                         break;
1564                     case CONSTANT_Long:
1565                         bc_which = bc_longref;
1566                         assert(bc == _ldc2_w);
1567                         vbc = _lldc2_w;
1568                         break;
1569                     case CONSTANT_Double:
1570                         bc_which = bc_doubleref;
1571                         assert(bc == _ldc2_w);
1572                         vbc = _dldc2_w;
1573                         break;
1574                     case CONSTANT_String:
1575                         bc_which = bc_stringref;
1576                         switch (bc) {
1577                         case _ldc:    vbc = _sldc; break;
1578                         case _ldc_w:  vbc = _sldc_w; break;
1579                         default:      assert(false);
1580                         }
1581                         break;
1582                     case CONSTANT_Class:
1583                         bc_which = bc_classref;
1584                         switch (bc) {
1585                         case _ldc:    vbc = _cldc; break;
1586                         case _ldc_w:  vbc = _cldc_w; break;
1587                         default:      assert(false);
1588                         }
1589                         break;
1590                     default:
1591                         // CONSTANT_MethodHandle, etc.
1592                         if (getHighestClassVersion().lessThan(JAVA7_MAX_CLASS_VERSION)) {
1593                             throw new IOException("bad class file major version for Java 7 ldc");
1594                         }
1595                         bc_which = bc_loadablevalueref;
1596                         switch (bc) {
1597                         case _ldc:    vbc = _qldc; break;
1598                         case _ldc_w:  vbc = _qldc_w; break;
1599                         default:      assert(false);
1600                         }
1601                     }
1602                     break;
1603                 case CONSTANT_Class:
1604                     // Use a special shorthand for the current class:
1605                     if (ref == curClass.thisClass)  ref = null;
1606                     bc_which = bc_classref; break;
1607                 case CONSTANT_Fieldref:
1608                     bc_which = bc_fieldref; break;
1609                 case CONSTANT_Methodref:
1610                     bc_which = bc_methodref; break;
1611                 case CONSTANT_InterfaceMethodref:
1612                     bc_which = bc_imethodref; break;
1613                 case CONSTANT_InvokeDynamic:
1614                     bc_which = bc_indyref; break;
1615                 default:
1616                     bc_which = null;
1617                     assert(false);
1618                 }
1619                 bc_codes.putByte(vbc);
1620                 bc_which.putRef(ref);
1621                 // handle trailing junk
1622                 if (bc == _multianewarray) {
1623                     assert(i.getConstant() == code.getByte(i.getPC()+3));
1624                     // Just dump the byte into the bipush pile
1625                     bc_byte.putByte(0xFF & i.getConstant());
1626                 } else if (bc == _invokeinterface) {
1627                     assert(i.getLength() == 5);
1628                     // Make sure the discarded bytes are sane:
1629                     assert(i.getConstant() == (1+((MemberEntry)ref).descRef.typeRef.computeSize(true)) << 8);
1630                 } else if (bc == _invokedynamic) {
1631                     if (getHighestClassVersion().lessThan(JAVA7_MAX_CLASS_VERSION)) {
1632                         throw new IOException("bad class major version for Java 7 invokedynamic");
1633                     }
1634                     assert(i.getLength() == 5);
1635                     assert(i.getConstant() == 0);  // last 2 bytes MBZ
1636                 } else {
1637                     // Make sure there is nothing else to write.
1638                     assert(i.getLength() == ((bc == _ldc)?2:3));
1639                 }
1640                 continue;
1641             }
1642             int slot = i.getLocalSlot();
1643             if (slot >= 0) {
1644                 bc_codes.putByte(bc);
1645                 bc_local.putInt(slot);
1646                 int con = i.getConstant();
1647                 if (bc == _iinc) {
1648                     if (!i.isWide()) {
1649                         bc_byte.putByte(0xFF & con);
1650                     } else {
1651                         bc_short.putInt(0xFFFF & con);
1652                     }
1653                 } else {
1654                     assert(con == 0);
1655                 }
1656                 continue;
1657             }
1658             // Generic instruction.  Copy the body.
1659             bc_codes.putByte(bc);
1660             int pc = i.getPC()+1;
1661             int npc = i.getNextPC();
1662             if (pc < npc) {
1663                 // Do a few remaining multi-byte instructions.
1664                 switch (bc) {
1665                 case _sipush:
1666                     bc_short.putInt(0xFFFF & i.getConstant());
1667                     break;
1668                 case _bipush:
1669                     bc_byte.putByte(0xFF & i.getConstant());
1670                     break;
1671                 case _newarray:
1672                     bc_byte.putByte(0xFF & i.getConstant());
1673                     break;
1674                 default:
1675                     assert(false);  // that's it
1676                 }
1677             }
1678         }
1679         bc_codes.putByte(_end_marker);
1680         bc_codes.elementCountForDebug++;
1681         codeHist[_end_marker]++;
1682         endCode();
1683     }
1684 
1685     int[] codeHist = new int[1<<8];
1686     int[] ldcHist  = new int[20];
1687     void printCodeHist() {
1688         assert(verbose > 0);
1689         String[] hist = new String[codeHist.length];
1690         int totalBytes = 0;
1691         for (int bc = 0; bc < codeHist.length; bc++) {
1692             totalBytes += codeHist[bc];
1693         }
1694         for (int bc = 0; bc < codeHist.length; bc++) {
1695             if (codeHist[bc] == 0) { hist[bc] = ""; continue; }
1696             String iname = Instruction.byteName(bc);
1697             String count = "" + codeHist[bc];
1698             count = "         ".substring(count.length()) + count;
1699             String pct = "" + (codeHist[bc] * 10000 / totalBytes);
1700             while (pct.length() < 4) {
1701                 pct = "0" + pct;
1702             }
1703             pct = pct.substring(0, pct.length()-2) + "." + pct.substring(pct.length()-2);
1704             hist[bc] = count + "  " + pct + "%  " + iname;
1705         }
1706         Arrays.sort(hist);
1707         System.out.println("Bytecode histogram ["+totalBytes+"]");
1708         for (int i = hist.length; --i >= 0; ) {
1709             if ("".equals(hist[i]))  continue;
1710             System.out.println(hist[i]);
1711         }
1712         for (int tag = 0; tag < ldcHist.length; tag++) {
1713             int count = ldcHist[tag];
1714             if (count == 0)  continue;
1715             System.out.println("ldc "+ConstantPool.tagName(tag)+" "+count);
1716         }
1717     }
1718 }
--- EOF ---