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