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