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