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