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