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