Source Code Cross Referenced for PackageWriter.java in  » 6.0-JDK-Modules-com.sun.java » util » com » sun » java » util » jar » pack » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules com.sun.java » util » com.sun.java.util.jar.pack 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2001-2005 Sun Microsystems, Inc.  All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004:         *
0005:         * This code is free software; you can redistribute it and/or modify it
0006:         * under the terms of the GNU General Public License version 2 only, as
0007:         * published by the Free Software Foundation.  Sun designates this
0008:         * particular file as subject to the "Classpath" exception as provided
0009:         * by Sun in the LICENSE file that accompanied this code.
0010:         *
0011:         * This code is distributed in the hope that it will be useful, but WITHOUT
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014:         * version 2 for more details (a copy is included in the LICENSE file that
0015:         * accompanied this code).
0016:         *
0017:         * You should have received a copy of the GNU General Public License version
0018:         * 2 along with this work; if not, write to the Free Software Foundation,
0019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020:         *
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022:         * CA 95054 USA or visit www.sun.com if you need additional information or
0023:         * have any questions.
0024:         */
0025:
0026:        package com.sun.java.util.jar.pack;
0027:
0028:        import java.io.*;
0029:        import java.util.*;
0030:        import java.util.logging.Level;
0031:        import com.sun.java.util.jar.pack.Package.Class;
0032:        import com.sun.java.util.jar.pack.Package.File;
0033:        import com.sun.java.util.jar.pack.Package.InnerClass;
0034:        import com.sun.java.util.jar.pack.ConstantPool.*;
0035:
0036:        /**
0037:         * Writer for a package file.
0038:         * @author John Rose
0039:         * @version 1.33, 05/05/07
0040:         */
0041:        class PackageWriter extends BandStructure {
0042:            Package pkg;
0043:            OutputStream finalOut;
0044:
0045:            PackageWriter(Package pkg, OutputStream out) throws IOException {
0046:                this .pkg = pkg;
0047:                this .finalOut = out;
0048:                // Caller has specified archive version in the package:
0049:                initPackageMajver(pkg.package_majver);
0050:            }
0051:
0052:            void write() throws IOException {
0053:                boolean ok = false;
0054:                try {
0055:                    if (verbose > 0) {
0056:                        Utils.log.info("Setting up constant pool...");
0057:                    }
0058:                    setup();
0059:
0060:                    if (verbose > 0) {
0061:                        Utils.log.info("Packing...");
0062:                    }
0063:
0064:                    // writeFileHeader() is done last, since it has ultimate counts
0065:                    // writeBandHeaders() is called after all other bands are done
0066:                    writeConstantPool();
0067:                    writeFiles();
0068:                    writeAttrDefs();
0069:                    writeInnerClasses();
0070:                    writeClassesAndByteCodes();
0071:                    writeAttrCounts();
0072:
0073:                    if (verbose > 1)
0074:                        printCodeHist();
0075:
0076:                    // choose codings (fill band_headers if needed)
0077:                    if (verbose > 0) {
0078:                        Utils.log.info("Coding...");
0079:                    }
0080:                    all_bands.chooseBandCodings();
0081:
0082:                    // now we can write the headers:
0083:                    writeFileHeader();
0084:
0085:                    writeAllBandsTo(finalOut);
0086:
0087:                    ok = true;
0088:                } catch (Exception ee) {
0089:                    Utils.log.log(Level.WARNING, "Error on output: " + ee, ee);
0090:                    //if (verbose > 0)  ee.printStackTrace();
0091:                    // Write partial output only if we are verbose.
0092:                    if (verbose > 0)
0093:                        finalOut.close();
0094:                    if (ee instanceof  IOException)
0095:                        throw (IOException) ee;
0096:                    if (ee instanceof  RuntimeException)
0097:                        throw (RuntimeException) ee;
0098:                    throw new Error("error packing", ee);
0099:                }
0100:            }
0101:
0102:            HashSet requiredEntries; // for the CP
0103:            HashMap backCountTable; // for layout callables
0104:            int[][] attrCounts; // count attr. occurences
0105:
0106:            void setup() {
0107:                requiredEntries = new HashSet();
0108:                setArchiveOptions();
0109:                trimClassAttributes();
0110:                collectAttributeLayouts();
0111:                pkg.buildGlobalConstantPool(requiredEntries);
0112:                setBandIndexes();
0113:                makeNewAttributeBands();
0114:                collectInnerClasses();
0115:            }
0116:
0117:            void setArchiveOptions() {
0118:                // Decide on some archive options early.
0119:                // Does not decide on: AO_HAVE_SPECIAL_FORMATS,
0120:                // AO_HAVE_CP_NUMBERS, AO_HAVE_FILE_HEADERS.
0121:                // Also, AO_HAVE_FILE_OPTIONS may be forced on later.
0122:                int minModtime = pkg.default_modtime;
0123:                int maxModtime = pkg.default_modtime;
0124:                int minOptions = -1;
0125:                int maxOptions = 0;
0126:
0127:                // Import defaults from package (deflate hint, etc.).
0128:                archiveOptions |= pkg.default_options;
0129:
0130:                for (Iterator i = pkg.files.iterator(); i.hasNext();) {
0131:                    File file = (File) i.next();
0132:
0133:                    int modtime = file.modtime;
0134:                    int options = file.options;
0135:
0136:                    if (minModtime == NO_MODTIME) {
0137:                        minModtime = maxModtime = modtime;
0138:                    } else {
0139:                        if (minModtime > modtime)
0140:                            minModtime = modtime;
0141:                        if (maxModtime < modtime)
0142:                            maxModtime = modtime;
0143:                    }
0144:                    minOptions &= options;
0145:                    maxOptions |= options;
0146:                }
0147:                if (pkg.default_modtime == NO_MODTIME) {
0148:                    // Make everything else be a positive offset from here.
0149:                    pkg.default_modtime = minModtime;
0150:                }
0151:                if (minModtime != NO_MODTIME && minModtime != maxModtime) {
0152:                    // Put them into a band.
0153:                    archiveOptions |= AO_HAVE_FILE_MODTIME;
0154:                }
0155:                // If the archive deflation is set do not bother with each file.
0156:                if (!testBit(archiveOptions, AO_DEFLATE_HINT)
0157:                        && minOptions != -1) {
0158:                    if (testBit(minOptions, FO_DEFLATE_HINT)) {
0159:                        // Every file has the deflate_hint set.
0160:                        // Set it for the whole archive, and omit options.
0161:                        archiveOptions |= AO_DEFLATE_HINT;
0162:                        minOptions -= FO_DEFLATE_HINT;
0163:                        maxOptions -= FO_DEFLATE_HINT;
0164:                    }
0165:                    pkg.default_options |= minOptions;
0166:                    if (minOptions != maxOptions
0167:                            || minOptions != pkg.default_options) {
0168:                        archiveOptions |= AO_HAVE_FILE_OPTIONS;
0169:                    }
0170:                }
0171:                // Decide on default version number (majority rule).
0172:                HashMap verCounts = new HashMap();
0173:                int bestCount = 0;
0174:                int bestVersion = -1;
0175:                for (Iterator i = pkg.classes.iterator(); i.hasNext();) {
0176:                    Class cls = (Class) i.next();
0177:                    int version = cls.getVersion();
0178:                    int[] var = (int[]) verCounts.get(new Integer(version));
0179:                    if (var == null) {
0180:                        var = new int[1];
0181:                        verCounts.put(new Integer(version), var);
0182:                    }
0183:                    int count = (var[0] += 1);
0184:                    //System.out.println("version="+version+" count="+count);
0185:                    if (bestCount < count) {
0186:                        bestCount = count;
0187:                        bestVersion = version;
0188:                    }
0189:                }
0190:                verCounts.clear();
0191:                if (bestVersion == -1)
0192:                    bestVersion = 0; // degenerate case
0193:                int bestMajver = (char) (bestVersion >>> 16);
0194:                int bestMinver = (char) (bestVersion);
0195:                pkg.default_class_majver = (short) bestMajver;
0196:                pkg.default_class_minver = (short) bestMinver;
0197:                String bestVerStr = Package.versionStringOf(bestMajver,
0198:                        bestMinver);
0199:                if (verbose > 0)
0200:                    Utils.log.info("Consensus version number in segment is "
0201:                            + bestVerStr);
0202:                if (verbose > 0)
0203:                    Utils.log.info("Highest version number in segment is "
0204:                            + Package.versionStringOf(pkg
0205:                                    .getHighestClassVersion()));
0206:
0207:                // Now add explicit pseudo-attrs. to classes with odd versions.
0208:                for (Iterator i = pkg.classes.iterator(); i.hasNext();) {
0209:                    Class cls = (Class) i.next();
0210:
0211:                    if (cls.getVersion() != bestVersion) {
0212:                        Attribute a = makeClassFileVersionAttr(cls.minver,
0213:                                cls.majver);
0214:                        if (verbose > 1) {
0215:                            String clsVer = cls.getVersionString();
0216:                            String pkgVer = bestVerStr;
0217:                            Utils.log.fine("Version " + clsVer + " of " + cls
0218:                                    + " doesn't match package version "
0219:                                    + pkgVer);
0220:                        }
0221:                        // Note:  Does not add in "natural" order.  (Who cares?)
0222:                        cls.addAttribute(a);
0223:                    }
0224:                }
0225:
0226:                // Decide if we are transmitting a huge resource file:
0227:                for (Iterator i = pkg.files.iterator(); i.hasNext();) {
0228:                    File file = (File) i.next();
0229:                    long len = file.getFileLength();
0230:                    if (len != (int) len) {
0231:                        archiveOptions |= AO_HAVE_FILE_SIZE_HI;
0232:                        if (verbose > 0)
0233:                            Utils.log.info("Note: Huge resource file "
0234:                                    + file.getFileName()
0235:                                    + " forces 64-bit sizing");
0236:                        break;
0237:                    }
0238:                }
0239:
0240:                // Decide if code attributes typically have sub-attributes.
0241:                // In that case, to preserve compact 1-byte code headers,
0242:                // we must declare unconditional presence of code flags.
0243:                int cost0 = 0;
0244:                int cost1 = 0;
0245:                for (Iterator i = pkg.classes.iterator(); i.hasNext();) {
0246:                    Class cls = (Class) i.next();
0247:                    for (Iterator j = cls.getMethods().iterator(); j.hasNext();) {
0248:                        Class.Method m = (Class.Method) j.next();
0249:                        if (m.code != null) {
0250:                            if (m.code.attributeSize() == 0) {
0251:                                // cost of a useless unconditional flags byte
0252:                                cost1 += 1;
0253:                            } else if (shortCodeHeader(m.code) != LONG_CODE_HEADER) {
0254:                                // cost of inflating a short header
0255:                                cost0 += 3;
0256:                            }
0257:                        }
0258:                    }
0259:                }
0260:                if (cost0 > cost1) {
0261:                    archiveOptions |= AO_HAVE_ALL_CODE_FLAGS;
0262:                }
0263:                if (verbose > 0)
0264:                    Utils.log.info("archiveOptions = " + "0b"
0265:                            + Integer.toBinaryString(archiveOptions));
0266:            }
0267:
0268:            void writeFileHeader() throws IOException {
0269:                pkg.checkVersion();
0270:                writeArchiveMagic();
0271:                writeArchiveHeader();
0272:            }
0273:
0274:            // Local routine used to format fixed-format scalars
0275:            // in the file_header:
0276:            private void putMagicInt32(int val) throws IOException {
0277:                int res = val;
0278:                for (int i = 0; i < 4; i++) {
0279:                    archive_magic.putByte(0xFF & (res >>> 24));
0280:                    res <<= 8;
0281:                }
0282:            }
0283:
0284:            void writeArchiveMagic() throws IOException {
0285:                putMagicInt32(pkg.magic);
0286:            }
0287:
0288:            void writeArchiveHeader() throws IOException {
0289:                // for debug only:  number of words optimized away
0290:                int headerDiscountForDebug = 0;
0291:
0292:                // AO_HAVE_SPECIAL_FORMATS is set if non-default
0293:                // coding techniques are used, or if there are
0294:                // compressor-defined attributes transmitted.
0295:                boolean haveSpecial = testBit(archiveOptions,
0296:                        AO_HAVE_SPECIAL_FORMATS);
0297:                if (!haveSpecial) {
0298:                    haveSpecial |= (band_headers.length() != 0);
0299:                    haveSpecial |= (attrDefsWritten.length != 0);
0300:                    if (haveSpecial)
0301:                        archiveOptions |= AO_HAVE_SPECIAL_FORMATS;
0302:                }
0303:                if (!haveSpecial)
0304:                    headerDiscountForDebug += AH_SPECIAL_FORMAT_LEN;
0305:
0306:                // AO_HAVE_FILE_HEADERS is set if there is any
0307:                // file or segment envelope information present.
0308:                boolean haveFiles = testBit(archiveOptions,
0309:                        AO_HAVE_FILE_HEADERS);
0310:                if (!haveFiles) {
0311:                    haveFiles |= (archiveNextCount > 0);
0312:                    haveFiles |= (pkg.default_modtime != NO_MODTIME);
0313:                    if (haveFiles)
0314:                        archiveOptions |= AO_HAVE_FILE_HEADERS;
0315:                }
0316:                if (!haveFiles)
0317:                    headerDiscountForDebug += AH_FILE_HEADER_LEN;
0318:
0319:                // AO_HAVE_CP_NUMBERS is set if there are any numbers
0320:                // in the global constant pool.  (Numbers are in 15% of classes.)
0321:                boolean haveNumbers = testBit(archiveOptions,
0322:                        AO_HAVE_CP_NUMBERS);
0323:                if (!haveNumbers) {
0324:                    haveNumbers |= pkg.cp.haveNumbers();
0325:                    if (haveNumbers)
0326:                        archiveOptions |= AO_HAVE_CP_NUMBERS;
0327:                }
0328:                if (!haveNumbers)
0329:                    headerDiscountForDebug += AH_CP_NUMBER_LEN;
0330:
0331:                assert (pkg.package_majver > 0); // caller must specify!
0332:                archive_header_0.putInt(pkg.package_minver);
0333:                archive_header_0.putInt(pkg.package_majver);
0334:                if (verbose > 0)
0335:                    Utils.log.info("Package Version for this segment:"
0336:                            + Package.versionStringOf(pkg.getPackageVersion()));
0337:                archive_header_0.putInt(archiveOptions); // controls header format
0338:                assert (archive_header_0.length() == AH_LENGTH_0);
0339:
0340:                final int DUMMY = 0;
0341:                if (haveFiles) {
0342:                    assert (archive_header_S.length() == AH_ARCHIVE_SIZE_HI);
0343:                    archive_header_S.putInt(DUMMY); // (archiveSize1 >>> 32)
0344:                    assert (archive_header_S.length() == AH_ARCHIVE_SIZE_LO);
0345:                    archive_header_S.putInt(DUMMY); // (archiveSize1 >>> 0)
0346:                    assert (archive_header_S.length() == AH_LENGTH_S);
0347:                }
0348:
0349:                // Done with unsized part of header....
0350:
0351:                if (haveFiles) {
0352:                    archive_header_1.putInt(archiveNextCount); // usually zero
0353:                    archive_header_1.putInt(pkg.default_modtime);
0354:                    archive_header_1.putInt(pkg.files.size());
0355:                } else {
0356:                    assert (pkg.files.size() == 0);
0357:                }
0358:
0359:                if (haveSpecial) {
0360:                    archive_header_1.putInt(band_headers.length());
0361:                    archive_header_1.putInt(attrDefsWritten.length);
0362:                } else {
0363:                    assert (band_headers.length() == 0);
0364:                    assert (attrDefsWritten.length == 0);
0365:                }
0366:
0367:                writeConstantPoolCounts(haveNumbers);
0368:
0369:                archive_header_1.putInt(pkg.getAllInnerClasses().size());
0370:                archive_header_1.putInt(pkg.default_class_minver);
0371:                archive_header_1.putInt(pkg.default_class_majver);
0372:                archive_header_1.putInt(pkg.classes.size());
0373:
0374:                // Sanity:  Make sure we came out to 26 (less optional fields):
0375:                assert (archive_header_0.length() + archive_header_S.length()
0376:                        + archive_header_1.length() == AH_LENGTH
0377:                        - headerDiscountForDebug);
0378:
0379:                // Figure out all the sizes now, first cut:
0380:                archiveSize0 = 0;
0381:                archiveSize1 = all_bands.outputSize();
0382:                // Second cut:
0383:                archiveSize0 += archive_magic.outputSize();
0384:                archiveSize0 += archive_header_0.outputSize();
0385:                archiveSize0 += archive_header_S.outputSize();
0386:                // Make the adjustments:
0387:                archiveSize1 -= archiveSize0;
0388:
0389:                // Patch the header:
0390:                if (haveFiles) {
0391:                    int archiveSizeHi = (int) (archiveSize1 >>> 32);
0392:                    int archiveSizeLo = (int) (archiveSize1 >>> 0);
0393:                    archive_header_S.patchValue(AH_ARCHIVE_SIZE_HI,
0394:                            archiveSizeHi);
0395:                    archive_header_S.patchValue(AH_ARCHIVE_SIZE_LO,
0396:                            archiveSizeLo);
0397:                    int zeroLen = UNSIGNED5.getLength(DUMMY);
0398:                    archiveSize0 += UNSIGNED5.getLength(archiveSizeHi)
0399:                            - zeroLen;
0400:                    archiveSize0 += UNSIGNED5.getLength(archiveSizeLo)
0401:                            - zeroLen;
0402:                }
0403:                if (verbose > 1)
0404:                    Utils.log.fine("archive sizes: " + archiveSize0 + "+"
0405:                            + archiveSize1);
0406:                assert (all_bands.outputSize() == archiveSize0 + archiveSize1);
0407:            }
0408:
0409:            void writeConstantPoolCounts(boolean haveNumbers)
0410:                    throws IOException {
0411:                for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) {
0412:                    byte tag = ConstantPool.TAGS_IN_ORDER[k];
0413:                    int count = pkg.cp.getIndexByTag(tag).size();
0414:                    switch (tag) {
0415:                    case CONSTANT_Utf8:
0416:                        // The null string is always first.
0417:                        if (count > 0)
0418:                            assert (pkg.cp.getIndexByTag(tag).get(0) == ConstantPool
0419:                                    .getUtf8Entry(""));
0420:                        break;
0421:
0422:                    case CONSTANT_Integer:
0423:                    case CONSTANT_Float:
0424:                    case CONSTANT_Long:
0425:                    case CONSTANT_Double:
0426:                        // Omit counts for numbers if possible.
0427:                        if (!haveNumbers) {
0428:                            assert (count == 0);
0429:                            continue;
0430:                        }
0431:                        break;
0432:                    }
0433:                    archive_header_1.putInt(count);
0434:                }
0435:            }
0436:
0437:            protected Index getCPIndex(byte tag) {
0438:                return pkg.cp.getIndexByTag(tag);
0439:            }
0440:
0441:            // (The following observations are out of date; they apply only to
0442:            // "banding" the constant pool itself.  Later revisions of this algorithm
0443:            // applied the banding technique to every part of the package file,
0444:            // applying the benefits more broadly.)
0445:
0446:            // Note:  Keeping the data separate in passes (or "bands") allows the
0447:            // compressor to issue significantly shorter indexes for repeated data.
0448:            // The difference in zipped size is 4%, which is remarkable since the
0449:            // unzipped sizes are the same (only the byte order differs).
0450:
0451:            // After moving similar data into bands, it becomes natural to delta-encode
0452:            // each band.  (This is especially useful if we sort the constant pool first.)
0453:            // Delta encoding saves an extra 5% in the output size (13% of the CP itself).
0454:            // Because a typical delta usees much less data than a byte, the savings after
0455:            // zipping is even better:  A zipped delta-encoded package is 8% smaller than
0456:            // a zipped non-delta-encoded package.  Thus, in the zipped file, a banded,
0457:            // delta-encoded constant pool saves over 11% (of the total file size) compared
0458:            // with a zipped unbanded file.
0459:
0460:            void writeConstantPool() throws IOException {
0461:                IndexGroup cp = pkg.cp;
0462:
0463:                if (verbose > 0)
0464:                    Utils.log.info("Writing CP");
0465:
0466:                for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) {
0467:                    byte tag = ConstantPool.TAGS_IN_ORDER[k];
0468:                    Index index = cp.getIndexByTag(tag);
0469:
0470:                    Entry[] cpMap = index.cpMap;
0471:                    if (verbose > 0)
0472:                        Utils.log.info("Writing " + cpMap.length + " "
0473:                                + ConstantPool.tagName(tag) + " entries...");
0474:
0475:                    if (optDumpBands) {
0476:                        PrintStream ps = new PrintStream(getDumpStream(index,
0477:                                ".idx"));
0478:                        printArrayTo(ps, cpMap, 0, cpMap.length);
0479:                        ps.close();
0480:                    }
0481:
0482:                    switch (tag) {
0483:                    case CONSTANT_Utf8:
0484:                        writeUtf8Bands(cpMap);
0485:                        break;
0486:                    case CONSTANT_Integer:
0487:                        for (int i = 0; i < cpMap.length; i++) {
0488:                            NumberEntry e = (NumberEntry) cpMap[i];
0489:                            int x = ((Integer) e.numberValue()).intValue();
0490:                            cp_Int.putInt(x);
0491:                        }
0492:                        break;
0493:                    case CONSTANT_Float:
0494:                        for (int i = 0; i < cpMap.length; i++) {
0495:                            NumberEntry e = (NumberEntry) cpMap[i];
0496:                            float fx = ((Float) e.numberValue()).floatValue();
0497:                            int x = Float.floatToIntBits(fx);
0498:                            cp_Float.putInt(x);
0499:                        }
0500:                        break;
0501:                    case CONSTANT_Long:
0502:                        for (int i = 0; i < cpMap.length; i++) {
0503:                            NumberEntry e = (NumberEntry) cpMap[i];
0504:                            long x = ((Long) e.numberValue()).longValue();
0505:                            cp_Long_hi.putInt((int) (x >>> 32));
0506:                            cp_Long_lo.putInt((int) (x >>> 0));
0507:                        }
0508:                        break;
0509:                    case CONSTANT_Double:
0510:                        for (int i = 0; i < cpMap.length; i++) {
0511:                            NumberEntry e = (NumberEntry) cpMap[i];
0512:                            double dx = ((Double) e.numberValue())
0513:                                    .doubleValue();
0514:                            long x = Double.doubleToLongBits(dx);
0515:                            cp_Double_hi.putInt((int) (x >>> 32));
0516:                            cp_Double_lo.putInt((int) (x >>> 0));
0517:                        }
0518:                        break;
0519:                    case CONSTANT_String:
0520:                        for (int i = 0; i < cpMap.length; i++) {
0521:                            StringEntry e = (StringEntry) cpMap[i];
0522:                            cp_String.putRef(e.ref);
0523:                        }
0524:                        break;
0525:                    case CONSTANT_Class:
0526:                        for (int i = 0; i < cpMap.length; i++) {
0527:                            ClassEntry e = (ClassEntry) cpMap[i];
0528:                            cp_Class.putRef(e.ref);
0529:                        }
0530:                        break;
0531:                    case CONSTANT_Signature:
0532:                        writeSignatureBands(cpMap);
0533:                        break;
0534:                    case CONSTANT_NameandType:
0535:                        for (int i = 0; i < cpMap.length; i++) {
0536:                            DescriptorEntry e = (DescriptorEntry) cpMap[i];
0537:                            cp_Descr_name.putRef(e.nameRef);
0538:                            cp_Descr_type.putRef(e.typeRef);
0539:                        }
0540:                        break;
0541:                    case CONSTANT_Fieldref:
0542:                        writeMemberRefs(tag, cpMap, cp_Field_class,
0543:                                cp_Field_desc);
0544:                        break;
0545:                    case CONSTANT_Methodref:
0546:                        writeMemberRefs(tag, cpMap, cp_Method_class,
0547:                                cp_Method_desc);
0548:                        break;
0549:                    case CONSTANT_InterfaceMethodref:
0550:                        writeMemberRefs(tag, cpMap, cp_Imethod_class,
0551:                                cp_Imethod_desc);
0552:                        break;
0553:                    default:
0554:                        assert (false);
0555:                    }
0556:                }
0557:            }
0558:
0559:            void writeUtf8Bands(Entry[] cpMap) throws IOException {
0560:                if (cpMap.length == 0)
0561:                    return; // nothing to write
0562:
0563:                // The first element must always be the empty string.
0564:                assert (cpMap[0].stringValue().equals(""));
0565:                final int SUFFIX_SKIP_1 = 1;
0566:                final int PREFIX_SKIP_2 = 2;
0567:
0568:                // Fetch the char arrays, first of all.
0569:                char[][] chars = new char[cpMap.length][];
0570:                for (int i = 0; i < chars.length; i++) {
0571:                    chars[i] = cpMap[i].stringValue().toCharArray();
0572:                }
0573:
0574:                // First band:  Write lengths of shared prefixes.
0575:                int[] prefixes = new int[cpMap.length]; // includes 2 skipped zeroes
0576:                char[] prevChars = {};
0577:                for (int i = 0; i < chars.length; i++) {
0578:                    int prefix = 0;
0579:                    char[] curChars = chars[i];
0580:                    int limit = Math.min(curChars.length, prevChars.length);
0581:                    while (prefix < limit
0582:                            && curChars[prefix] == prevChars[prefix])
0583:                        prefix++;
0584:                    prefixes[i] = prefix;
0585:                    if (i >= PREFIX_SKIP_2)
0586:                        cp_Utf8_prefix.putInt(prefix);
0587:                    else
0588:                        assert (prefix == 0);
0589:                    prevChars = curChars;
0590:                }
0591:
0592:                // Second band:  Write lengths of unshared suffixes.
0593:                // Third band:  Write the char values in the unshared suffixes.
0594:                for (int i = 0; i < chars.length; i++) {
0595:                    char[] str = chars[i];
0596:                    int prefix = prefixes[i];
0597:                    int suffix = str.length - prefixes[i];
0598:                    boolean isPacked = false;
0599:                    if (suffix == 0) {
0600:                        // Zero suffix length is special flag to indicate
0601:                        // separate treatment in cp_Utf8_big bands.
0602:                        // This suffix length never occurs naturally,
0603:                        // except in the one case of a zero-length string.
0604:                        // (If it occurs, it is the first, due to sorting.)
0605:                        // The zero length string must, paradoxically, be
0606:                        // encoded as a zero-length cp_Utf8_big band.
0607:                        // This wastes exactly (& tolerably) one null byte.
0608:                        isPacked = (i >= SUFFIX_SKIP_1);
0609:                        // Do not bother to add an empty "(Utf8_big_0)" band.
0610:                        // Also, the initial empty string does not require a band.
0611:                    } else if (optBigStrings && effort > 1 && suffix > 100) {
0612:                        int numWide = 0;
0613:                        for (int n = 0; n < suffix; n++) {
0614:                            if (str[prefix + n] > 127) {
0615:                                numWide++;
0616:                            }
0617:                        }
0618:                        if (numWide > 100) {
0619:                            // Try packing the chars with an alternate encoding.
0620:                            isPacked = tryAlternateEncoding(i, numWide, str,
0621:                                    prefix);
0622:                        }
0623:                    }
0624:                    if (i < SUFFIX_SKIP_1) {
0625:                        // No output.
0626:                        assert (!isPacked);
0627:                        assert (suffix == 0);
0628:                    } else if (isPacked) {
0629:                        // Mark packed string with zero-length suffix count.
0630:                        // This tells the unpacker to go elsewhere for the suffix bits.
0631:                        // Fourth band:  Write unshared suffix with alternate coding.
0632:                        cp_Utf8_suffix.putInt(0);
0633:                        cp_Utf8_big_suffix.putInt(suffix);
0634:                    } else {
0635:                        assert (suffix != 0); // would be ambiguous
0636:                        // Normal string.  Save suffix in third and fourth bands.
0637:                        cp_Utf8_suffix.putInt(suffix);
0638:                        for (int n = 0; n < suffix; n++) {
0639:                            int ch = str[prefix + n];
0640:                            cp_Utf8_chars.putInt(ch);
0641:                        }
0642:                    }
0643:                }
0644:                if (verbose > 0) {
0645:                    int normCharCount = cp_Utf8_chars.length();
0646:                    int packCharCount = cp_Utf8_big_chars.length();
0647:                    int charCount = normCharCount + packCharCount;
0648:                    Utils.log.info("Utf8string #CHARS=" + charCount
0649:                            + " #PACKEDCHARS=" + packCharCount);
0650:                }
0651:            }
0652:
0653:            private boolean tryAlternateEncoding(int i, int numWide,
0654:                    char[] str, int prefix) {
0655:                int suffix = str.length - prefix;
0656:                int[] cvals = new int[suffix];
0657:                for (int n = 0; n < suffix; n++) {
0658:                    cvals[n] = str[prefix + n];
0659:                }
0660:                CodingChooser cc = getCodingChooser();
0661:                Coding bigRegular = cp_Utf8_big_chars.regularCoding;
0662:                String bandName = "(Utf8_big_" + i + ")";
0663:                int[] sizes = { 0, 0 };
0664:                final int BYTE_SIZE = CodingChooser.BYTE_SIZE;
0665:                final int ZIP_SIZE = CodingChooser.ZIP_SIZE;
0666:                if (verbose > 1 || cc.verbose > 1) {
0667:                    Utils.log.fine("--- chooseCoding " + bandName);
0668:                }
0669:                CodingMethod special = cc.choose(cvals, bigRegular, sizes);
0670:                Coding charRegular = cp_Utf8_chars.regularCoding;
0671:                if (verbose > 1)
0672:                    Utils.log.fine("big string[" + i + "] len=" + suffix
0673:                            + " #wide=" + numWide + " size=" + sizes[BYTE_SIZE]
0674:                            + "/z=" + sizes[ZIP_SIZE] + " coding " + special);
0675:                if (special != charRegular) {
0676:                    int specialZipSize = sizes[ZIP_SIZE];
0677:                    int[] normalSizes = cc.computeSize(charRegular, cvals);
0678:                    int normalZipSize = normalSizes[ZIP_SIZE];
0679:                    int minWin = Math.max(5, normalZipSize / 1000);
0680:                    if (verbose > 1)
0681:                        Utils.log.fine("big string[" + i + "] normalSize="
0682:                                + normalSizes[BYTE_SIZE] + "/z="
0683:                                + normalSizes[ZIP_SIZE] + " win="
0684:                                + (specialZipSize < normalZipSize - minWin));
0685:                    if (specialZipSize < normalZipSize - minWin) {
0686:                        IntBand big = cp_Utf8_big_chars.newIntBand(bandName);
0687:                        big.initializeValues(cvals);
0688:                        return true;
0689:                    }
0690:                }
0691:                return false;
0692:            }
0693:
0694:            void writeSignatureBands(Entry[] cpMap) throws IOException {
0695:                for (int i = 0; i < cpMap.length; i++) {
0696:                    SignatureEntry e = (SignatureEntry) cpMap[i];
0697:                    cp_Signature_form.putRef(e.formRef);
0698:                    for (int j = 0; j < e.classRefs.length; j++) {
0699:                        cp_Signature_classes.putRef(e.classRefs[j]);
0700:                    }
0701:                }
0702:            }
0703:
0704:            void writeMemberRefs(byte tag, Entry[] cpMap, CPRefBand cp_class,
0705:                    CPRefBand cp_desc) throws IOException {
0706:                for (int i = 0; i < cpMap.length; i++) {
0707:                    MemberEntry e = (MemberEntry) cpMap[i];
0708:                    cp_class.putRef(e.classRef);
0709:                    cp_desc.putRef(e.descRef);
0710:                }
0711:            }
0712:
0713:            void writeFiles() throws IOException {
0714:                int numFiles = pkg.files.size();
0715:                if (numFiles == 0)
0716:                    return;
0717:                int options = archiveOptions;
0718:                boolean haveSizeHi = testBit(options, AO_HAVE_FILE_SIZE_HI);
0719:                boolean haveModtime = testBit(options, AO_HAVE_FILE_MODTIME);
0720:                boolean haveOptions = testBit(options, AO_HAVE_FILE_OPTIONS);
0721:                if (!haveOptions) {
0722:                    for (Iterator i = pkg.files.iterator(); i.hasNext();) {
0723:                        File file = (File) i.next();
0724:                        if (file.isClassStub()) {
0725:                            haveOptions = true;
0726:                            options |= AO_HAVE_FILE_OPTIONS;
0727:                            archiveOptions = options;
0728:                            break;
0729:                        }
0730:                    }
0731:                }
0732:                if (haveSizeHi || haveModtime || haveOptions
0733:                        || !pkg.files.isEmpty()) {
0734:                    options |= AO_HAVE_FILE_HEADERS;
0735:                    archiveOptions = options;
0736:                }
0737:
0738:                for (Iterator i = pkg.files.iterator(); i.hasNext();) {
0739:                    File file = (File) i.next();
0740:                    file_name.putRef(file.name);
0741:                    long len = file.getFileLength();
0742:                    file_size_lo.putInt((int) len);
0743:                    if (haveSizeHi)
0744:                        file_size_hi.putInt((int) (len >>> 32));
0745:                    if (haveModtime)
0746:                        file_modtime.putInt(file.modtime - pkg.default_modtime);
0747:                    if (haveOptions)
0748:                        file_options.putInt(file.options);
0749:                    file.writeTo(file_bits.collectorStream());
0750:                    if (verbose > 1)
0751:                        Utils.log.fine("Wrote " + len + " bytes of "
0752:                                + file.name.stringValue());
0753:                }
0754:                if (verbose > 0)
0755:                    Utils.log.info("Wrote " + numFiles + " resource files");
0756:            }
0757:
0758:            void collectAttributeLayouts() {
0759:                maxFlags = new int[ATTR_CONTEXT_LIMIT];
0760:                allLayouts = new HashMap[ATTR_CONTEXT_LIMIT];
0761:                for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
0762:                    allLayouts[i] = new HashMap();
0763:                }
0764:                // Collect maxFlags and allLayouts.
0765:                for (Iterator i = pkg.classes.iterator(); i.hasNext();) {
0766:                    Class cls = (Class) i.next();
0767:                    visitAttributeLayoutsIn(ATTR_CONTEXT_CLASS, cls);
0768:                    for (Iterator j = cls.getFields().iterator(); j.hasNext();) {
0769:                        Class.Field f = (Class.Field) j.next();
0770:                        visitAttributeLayoutsIn(ATTR_CONTEXT_FIELD, f);
0771:                    }
0772:                    for (Iterator j = cls.getMethods().iterator(); j.hasNext();) {
0773:                        Class.Method m = (Class.Method) j.next();
0774:                        visitAttributeLayoutsIn(ATTR_CONTEXT_METHOD, m);
0775:                        if (m.code != null) {
0776:                            visitAttributeLayoutsIn(ATTR_CONTEXT_CODE, m.code);
0777:                        }
0778:                    }
0779:                }
0780:                // If there are many species of attributes, use 63-bit flags.
0781:                for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
0782:                    int nl = allLayouts[i].size();
0783:                    boolean haveLongFlags = haveFlagsHi(i);
0784:                    final int TOO_MANY_ATTRS = 32 /*int flag size*/
0785:                    - 12 /*typical flag bits in use*/
0786:                    + 4 /*typical number of OK overflows*/;
0787:                    if (nl >= TOO_MANY_ATTRS) { // heuristic
0788:                        int mask = 1 << (LG_AO_HAVE_XXX_FLAGS_HI + i);
0789:                        archiveOptions |= mask;
0790:                        haveLongFlags = true;
0791:                        if (verbose > 0)
0792:                            Utils.log.info("Note: Many "
0793:                                    + Attribute.contextName(i)
0794:                                    + " attributes forces 63-bit flags");
0795:                    }
0796:                    if (verbose > 1) {
0797:                        Utils.log.fine(Attribute.contextName(i)
0798:                                + ".maxFlags = 0x"
0799:                                + Integer.toHexString(maxFlags[i]));
0800:                        Utils.log.fine(Attribute.contextName(i)
0801:                                + ".#layouts = " + nl);
0802:                    }
0803:                    assert (haveFlagsHi(i) == haveLongFlags);
0804:                }
0805:                initAttrIndexLimit();
0806:
0807:                // Standard indexes can never conflict with flag bits.  Assert it.
0808:                for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
0809:                    assert ((attrFlagMask[i] & maxFlags[i]) == 0);
0810:                }
0811:                // Collect counts for both predefs. and custom defs.
0812:                // Decide on custom, local attribute definitions.
0813:                backCountTable = new HashMap();
0814:                attrCounts = new int[ATTR_CONTEXT_LIMIT][];
0815:                for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
0816:                    // Now the remaining defs in allLayouts[i] need attr. indexes.
0817:                    // Fill up unused flag bits with new defs.
0818:                    // Unused bits are those which are not used by predefined attrs,
0819:                    // and which are always clear in the classfiles.
0820:                    long avHiBits = ~(maxFlags[i] | attrFlagMask[i]);
0821:                    assert (attrIndexLimit[i] > 0);
0822:                    assert (attrIndexLimit[i] < 64); // all bits fit into a Java long
0823:                    avHiBits &= (1L << attrIndexLimit[i]) - 1;
0824:                    int nextLoBit = 0;
0825:                    Map.Entry[] layoutsAndCounts = new Map.Entry[allLayouts[i]
0826:                            .size()];
0827:                    allLayouts[i].entrySet().toArray(layoutsAndCounts);
0828:                    // Sort by count, most frequent first.
0829:                    // Predefs. participate in this sort, though it does not matter.
0830:                    Arrays.sort(layoutsAndCounts, new Comparator() {
0831:                        public int compare(Object o0, Object o1) {
0832:                            Map.Entry e0 = (Map.Entry) o0;
0833:                            Map.Entry e1 = (Map.Entry) o1;
0834:                            // Primary sort key is count, reversed.
0835:                            int r = -(((int[]) e0.getValue())[0] - ((int[]) e1
0836:                                    .getValue())[0]);
0837:                            if (r != 0)
0838:                                return r;
0839:                            return ((Comparable) e0.getKey()).compareTo(e1
0840:                                    .getKey());
0841:                        }
0842:                    });
0843:                    attrCounts[i] = new int[attrIndexLimit[i]
0844:                            + layoutsAndCounts.length];
0845:                    for (int j = 0; j < layoutsAndCounts.length; j++) {
0846:                        Map.Entry e = layoutsAndCounts[j];
0847:                        Attribute.Layout def = (Attribute.Layout) e.getKey();
0848:                        int count = ((int[]) e.getValue())[0];
0849:                        int index;
0850:                        Integer predefIndex = (Integer) attrIndexTable.get(def);
0851:                        if (predefIndex != null) {
0852:                            // The index is already set.
0853:                            index = predefIndex.intValue();
0854:                        } else if (avHiBits != 0) {
0855:                            while ((avHiBits & 1) == 0) {
0856:                                avHiBits >>>= 1;
0857:                                nextLoBit += 1;
0858:                            }
0859:                            avHiBits -= 1; // clear low bit; we are using it now
0860:                            // Update attrIndexTable:
0861:                            index = setAttributeLayoutIndex(def, nextLoBit);
0862:                        } else {
0863:                            // Update attrIndexTable:
0864:                            index = setAttributeLayoutIndex(def,
0865:                                    ATTR_INDEX_OVERFLOW);
0866:                        }
0867:
0868:                        // Now that we know the index, record the count of this def.
0869:                        attrCounts[i][index] = count;
0870:
0871:                        // For all callables in the def, keep a tally of back-calls.
0872:                        Attribute.Layout.Element[] cbles = def.getCallables();
0873:                        final int[] bc = new int[cbles.length];
0874:                        for (int k = 0; k < cbles.length; k++) {
0875:                            assert (cbles[k].kind == Attribute.EK_CBLE);
0876:                            if (!cbles[k].flagTest(Attribute.EF_BACK)) {
0877:                                bc[k] = -1; // no count to accumulate here
0878:                            }
0879:                        }
0880:                        backCountTable.put(def, bc);
0881:
0882:                        if (predefIndex == null) {
0883:                            // Make sure the package CP can name the local attribute.
0884:                            Entry ne = ConstantPool.getUtf8Entry(def.name());
0885:                            String layout = def
0886:                                    .layoutForPackageMajver(getPackageMajver());
0887:                            Entry le = ConstantPool.getUtf8Entry(layout);
0888:                            requiredEntries.add(ne);
0889:                            requiredEntries.add(le);
0890:                            if (verbose > 0) {
0891:                                if (index < attrIndexLimit[i])
0892:                                    Utils.log.info("Using free flag bit 1<<"
0893:                                            + index + " for " + count
0894:                                            + " occurrences of " + def);
0895:                                else
0896:                                    Utils.log.info("Using overflow index "
0897:                                            + index + " for " + count
0898:                                            + " occurrences of " + def);
0899:                            }
0900:                        }
0901:                    }
0902:                }
0903:                // Later, when emitting attr_definition_bands, we will look at
0904:                // attrDefSeen and attrDefs at position 32/63 and beyond.
0905:                // The attrIndexTable will provide elements of xxx_attr_indexes bands.
0906:
0907:                // Done with scratch variables:
0908:                maxFlags = null;
0909:                allLayouts = null;
0910:            }
0911:
0912:            // Scratch variables for processing attributes and flags.
0913:            int[] maxFlags;
0914:            HashMap[] allLayouts;
0915:
0916:            void visitAttributeLayoutsIn(int ctype, Attribute.Holder h) {
0917:                // Make note of which flags appear in the class file.
0918:                // Set them in maxFlags.
0919:                maxFlags[ctype] |= h.flags;
0920:                for (Iterator i = h.getAttributes().iterator(); i.hasNext();) {
0921:                    Attribute a = (Attribute) i.next();
0922:                    Attribute.Layout def = a.layout();
0923:                    int[] count = (int[]) allLayouts[ctype].get(def);
0924:                    if (count == null)
0925:                        allLayouts[ctype].put(def, count = new int[1]);
0926:                    if (count[0] < Integer.MAX_VALUE)
0927:                        count[0] += 1;
0928:                }
0929:            }
0930:
0931:            Attribute.Layout[] attrDefsWritten;
0932:
0933:            void writeAttrDefs() throws IOException {
0934:                ArrayList defList = new ArrayList();
0935:                for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
0936:                    int limit = attrDefs[i].size();
0937:                    for (int j = 0; j < limit; j++) {
0938:                        int header = i; // ctype
0939:                        if (j < attrIndexLimit[i]) {
0940:                            header |= ((j + ADH_BIT_IS_LSB) << ADH_BIT_SHIFT);
0941:                            assert (header < 0x100); // must fit into a byte
0942:                            // (...else header is simply ctype, with zero high bits.)
0943:                            if (!testBit(attrDefSeen[i], 1L << j)) {
0944:                                // either undefined or predefined; nothing to write
0945:                                continue;
0946:                            }
0947:                        }
0948:                        Attribute.Layout def = (Attribute.Layout) attrDefs[i]
0949:                                .get(j);
0950:                        defList.add(new Object[] { new Integer(header), def });
0951:                        assert (new Integer(j).equals(attrIndexTable.get(def)));
0952:                    }
0953:                }
0954:                // Sort the new attr defs into some "natural" order.
0955:                int numAttrDefs = defList.size();
0956:                Object[][] defs = new Object[numAttrDefs][];
0957:                defList.toArray(defs);
0958:                Arrays.sort(defs, new Comparator() {
0959:                    public int compare(Object o0, Object o1) {
0960:                        Object[] a0 = (Object[]) o0;
0961:                        Object[] a1 = (Object[]) o1;
0962:                        // Primary sort key is attr def header.
0963:                        int r = ((Comparable) a0[0]).compareTo(a1[0]);
0964:                        if (r != 0)
0965:                            return r;
0966:                        Object ind0 = attrIndexTable.get(a0[1]);
0967:                        Object ind1 = attrIndexTable.get(a1[1]);
0968:                        // Secondary sort key is attribute index.
0969:                        // (This must be so, in order to keep overflow attr order.)
0970:                        assert (ind0 != null);
0971:                        assert (ind1 != null);
0972:                        return ((Comparable) ind0).compareTo(ind1);
0973:                    }
0974:                });
0975:                attrDefsWritten = new Attribute.Layout[numAttrDefs];
0976:                PrintStream dump = !optDumpBands ? null : new PrintStream(
0977:                        getDumpStream(attr_definition_headers, ".def"));
0978:                int[] indexForDebug = new int[ATTR_CONTEXT_LIMIT];
0979:                for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
0980:                    indexForDebug[i] = attrIndexLimit[i];
0981:                }
0982:                for (int i = 0; i < defs.length; i++) {
0983:                    int header = ((Integer) defs[i][0]).intValue();
0984:                    Attribute.Layout def = (Attribute.Layout) defs[i][1];
0985:                    attrDefsWritten[i] = def;
0986:                    assert ((header & ADH_CONTEXT_MASK) == def.ctype());
0987:                    attr_definition_headers.putByte(header);
0988:                    attr_definition_name.putRef(ConstantPool.getUtf8Entry(def
0989:                            .name()));
0990:                    String layout = def
0991:                            .layoutForPackageMajver(getPackageMajver());
0992:                    attr_definition_layout.putRef(ConstantPool
0993:                            .getUtf8Entry(layout));
0994:                    // Check that we are transmitting that correct attribute index:
0995:                    boolean debug = false;
0996:                    assert (debug = true);
0997:                    if (debug) {
0998:                        int hdrIndex = (header >> ADH_BIT_SHIFT)
0999:                                - ADH_BIT_IS_LSB;
1000:                        if (hdrIndex < 0)
1001:                            hdrIndex = indexForDebug[def.ctype()]++;
1002:                        int realIndex = ((Integer) attrIndexTable.get(def))
1003:                                .intValue();
1004:                        assert (hdrIndex == realIndex);
1005:                    }
1006:                    if (dump != null) {
1007:                        int index = (header >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB;
1008:                        dump.println(index + " " + def);
1009:                    }
1010:                }
1011:                if (dump != null)
1012:                    dump.close();
1013:            }
1014:
1015:            void writeAttrCounts() throws IOException {
1016:                // Write the four xxx_attr_calls bands.
1017:                for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) {
1018:                    MultiBand xxx_attr_bands = attrBands[ctype];
1019:                    IntBand xxx_attr_calls = getAttrBand(xxx_attr_bands,
1020:                            AB_ATTR_CALLS);
1021:                    Attribute.Layout[] defs = new Attribute.Layout[attrDefs[ctype]
1022:                            .size()];
1023:                    attrDefs[ctype].toArray(defs);
1024:                    for (boolean predef = true;; predef = false) {
1025:                        for (int ai = 0; ai < defs.length; ai++) {
1026:                            Attribute.Layout def = defs[ai];
1027:                            if (def == null)
1028:                                continue; // unused index
1029:                            if (predef != isPredefinedAttr(ctype, ai))
1030:                                continue; // wrong pass
1031:                            int totalCount = attrCounts[ctype][ai];
1032:                            if (totalCount == 0)
1033:                                continue; // irrelevant
1034:                            int[] bc = (int[]) backCountTable.get(def);
1035:                            for (int j = 0; j < bc.length; j++) {
1036:                                if (bc[j] >= 0) {
1037:                                    int backCount = bc[j];
1038:                                    bc[j] = -1; // close out; do not collect further counts
1039:                                    xxx_attr_calls.putInt(backCount);
1040:                                    assert (def.getCallables()[j]
1041:                                            .flagTest(Attribute.EF_BACK));
1042:                                } else {
1043:                                    assert (!def.getCallables()[j]
1044:                                            .flagTest(Attribute.EF_BACK));
1045:                                }
1046:                            }
1047:                        }
1048:                        if (!predef)
1049:                            break;
1050:                    }
1051:                }
1052:            }
1053:
1054:            void trimClassAttributes() {
1055:                for (Iterator i = pkg.classes.iterator(); i.hasNext();) {
1056:                    Class cls = (Class) i.next();
1057:                    // Replace "obvious" SourceFile attrs by null.
1058:                    cls.minimizeSourceFile();
1059:                }
1060:            }
1061:
1062:            void collectInnerClasses() {
1063:                // Capture inner classes, removing them from individual classes.
1064:                // Irregular inner classes must stay local, though.
1065:                HashMap allICMap = new HashMap();
1066:                // First, collect a consistent global set.
1067:                for (Iterator i = pkg.classes.iterator(); i.hasNext();) {
1068:                    Class cls = (Class) i.next();
1069:                    if (!cls.hasInnerClasses())
1070:                        continue;
1071:                    for (Iterator j = cls.getInnerClasses().iterator(); j
1072:                            .hasNext();) {
1073:                        InnerClass ic = (InnerClass) j.next();
1074:                        InnerClass pic = (InnerClass) allICMap.put(
1075:                                ic.this Class, ic);
1076:                        if (pic != null && !pic.equals(ic) && pic.predictable) {
1077:                            // Different ICs.  Choose the better to make global.
1078:                            allICMap.put(pic.this Class, pic);
1079:                        }
1080:                    }
1081:                }
1082:
1083:                InnerClass[] allICs = new InnerClass[allICMap.size()];
1084:                allICMap.values().toArray(allICs);
1085:                allICMap = null; // done with it
1086:
1087:                // Note: The InnerClasses attribute must be in a valid order,
1088:                // so that A$B always occurs earlier than A$B$C.  This is an
1089:                // important side-effect of sorting lexically by class name.
1090:                Arrays.sort(allICs); // put in canonical order
1091:                pkg.setAllInnerClasses(Arrays.asList(allICs));
1092:
1093:                // Next, empty out of every local set the consistent entries.
1094:                // Calculate whether there is any remaining need to have a local
1095:                // set, and whether it needs to be locked.
1096:                for (Iterator i = pkg.classes.iterator(); i.hasNext();) {
1097:                    Class cls = (Class) i.next();
1098:                    cls.minimizeLocalICs();
1099:                }
1100:            }
1101:
1102:            void writeInnerClasses() throws IOException {
1103:                for (Iterator i = pkg.getAllInnerClasses().iterator(); i
1104:                        .hasNext();) {
1105:                    InnerClass ic = (InnerClass) i.next();
1106:                    int flags = ic.flags;
1107:                    assert ((flags & ACC_IC_LONG_FORM) == 0);
1108:                    if (!ic.predictable) {
1109:                        flags |= ACC_IC_LONG_FORM;
1110:                    }
1111:                    ic_this _class.putRef(ic.this Class);
1112:                    ic_flags.putInt(flags);
1113:                    if (!ic.predictable) {
1114:                        ic_outer_class.putRef(ic.outerClass);
1115:                        ic_name.putRef(ic.name);
1116:                    }
1117:                }
1118:            }
1119:
1120:            /** If there are any extra InnerClasses entries to write which are
1121:             *  not already implied by the global table, put them into a
1122:             *  local attribute.  This is expected to be rare.
1123:             */
1124:            void writeLocalInnerClasses(Class cls) throws IOException {
1125:                List localICs = cls.getInnerClasses();
1126:                class_InnerClasses_N.putInt(localICs.size());
1127:                for (Iterator i = localICs.iterator(); i.hasNext();) {
1128:                    InnerClass ic = (InnerClass) i.next();
1129:                    class_InnerClasses_RC.putRef(ic.this Class);
1130:                    // Is it redundant with the global version?
1131:                    if (ic.equals(pkg.getGlobalInnerClass(ic.this Class))) {
1132:                        // A zero flag means copy a global IC here.
1133:                        class_InnerClasses_F.putInt(0);
1134:                    } else {
1135:                        int flags = ic.flags;
1136:                        if (flags == 0)
1137:                            flags = ACC_IC_LONG_FORM; // force it to be non-zero
1138:                        class_InnerClasses_F.putInt(flags);
1139:                        class_InnerClasses_outer_RCN.putRef(ic.outerClass);
1140:                        class_InnerClasses_name_RUN.putRef(ic.name);
1141:                    }
1142:                }
1143:            }
1144:
1145:            void writeClassesAndByteCodes() throws IOException {
1146:                Class[] classes = new Class[pkg.classes.size()];
1147:                pkg.classes.toArray(classes);
1148:                // Note:  This code respects the order in which caller put classes.
1149:                if (verbose > 0)
1150:                    Utils.log.info("  ...scanning " + classes.length
1151:                            + " classes...");
1152:
1153:                int nwritten = 0;
1154:                for (int i = 0; i < classes.length; i++) {
1155:                    // Collect the class body, sans bytecodes.
1156:                    Class cls = classes[i];
1157:                    if (verbose > 1)
1158:                        Utils.log.fine("Scanning " + cls);
1159:
1160:                    ClassEntry this Class = cls.this Class;
1161:                    ClassEntry super Class = cls.super Class;
1162:                    ClassEntry[] interfaces = cls.interfaces;
1163:                    // Encode rare case of null superClass as thisClass:
1164:                    assert (super Class != this Class); // bad class file!?
1165:                    if (super Class == null)
1166:                        super Class = this Class;
1167:                    class_this .putRef(this Class);
1168:                    class_super .putRef(super Class);
1169:                    class_interface_count.putInt(cls.interfaces.length);
1170:                    for (int j = 0; j < interfaces.length; j++) {
1171:                        class_interface.putRef(interfaces[j]);
1172:                    }
1173:
1174:                    writeMembers(cls);
1175:                    writeAttrs(ATTR_CONTEXT_CLASS, cls, cls);
1176:
1177:                    nwritten++;
1178:                    if (verbose > 0 && (nwritten % 1000) == 0)
1179:                        Utils.log.info("Have scanned " + nwritten
1180:                                + " classes...");
1181:                }
1182:            }
1183:
1184:            void writeMembers(Class cls) throws IOException {
1185:                List fields = cls.getFields();
1186:                class_field_count.putInt(fields.size());
1187:                for (Iterator i = fields.iterator(); i.hasNext();) {
1188:                    Class.Field f = (Class.Field) i.next();
1189:                    field_descr.putRef(f.getDescriptor());
1190:                    writeAttrs(ATTR_CONTEXT_FIELD, f, cls);
1191:                }
1192:
1193:                List methods = cls.getMethods();
1194:                class_method_count.putInt(methods.size());
1195:                for (Iterator i = methods.iterator(); i.hasNext();) {
1196:                    Class.Method m = (Class.Method) i.next();
1197:                    method_descr.putRef(m.getDescriptor());
1198:                    writeAttrs(ATTR_CONTEXT_METHOD, m, cls);
1199:                    assert ((m.code != null) == (m.getAttribute(attrCodeEmpty) != null));
1200:                    if (m.code != null) {
1201:                        writeCodeHeader(m.code);
1202:                        writeByteCodes(m.code);
1203:                    }
1204:                }
1205:            }
1206:
1207:            void writeCodeHeader(Code c) throws IOException {
1208:                boolean attrsOK = testBit(archiveOptions,
1209:                        AO_HAVE_ALL_CODE_FLAGS);
1210:                int na = c.attributeSize();
1211:                int sc = shortCodeHeader(c);
1212:                if (!attrsOK && na > 0)
1213:                    // We must write flags, and can only do so for long headers.
1214:                    sc = LONG_CODE_HEADER;
1215:                if (verbose > 2) {
1216:                    int siglen = c.getMethod().getArgumentSize();
1217:                    Utils.log.fine("Code sizes info " + c.max_stack + " "
1218:                            + c.max_locals + " " + c.getHandlerCount() + " "
1219:                            + siglen + " " + na
1220:                            + (sc > 0 ? " SHORT=" + sc : ""));
1221:                }
1222:                code_headers.putByte(sc);
1223:                if (sc == LONG_CODE_HEADER) {
1224:                    code_max_stack.putInt(c.getMaxStack());
1225:                    code_max_na_locals.putInt(c.getMaxNALocals());
1226:                    code_handler_count.putInt(c.getHandlerCount());
1227:                } else {
1228:                    assert (attrsOK || na == 0);
1229:                    assert (c.getHandlerCount() < shortCodeHeader_h_limit);
1230:                }
1231:                writeCodeHandlers(c);
1232:                if (sc == LONG_CODE_HEADER || attrsOK)
1233:                    writeAttrs(ATTR_CONTEXT_CODE, c, c.this Class());
1234:            }
1235:
1236:            void writeCodeHandlers(Code c) throws IOException {
1237:                int sum, del;
1238:                for (int j = 0, jmax = c.getHandlerCount(); j < jmax; j++) {
1239:                    code_handler_class_RCN.putRef(c.handler_class[j]); // null OK
1240:                    // Encode end as offset from start, and catch as offset from end,
1241:                    // because they are strongly correlated.
1242:                    sum = c.encodeBCI(c.handler_start[j]);
1243:                    code_handler_start_P.putInt(sum);
1244:                    del = c.encodeBCI(c.handler_end[j]) - sum;
1245:                    code_handler_end_PO.putInt(del);
1246:                    sum += del;
1247:                    del = c.encodeBCI(c.handler_catch[j]) - sum;
1248:                    code_handler_catch_PO.putInt(del);
1249:                }
1250:            }
1251:
1252:            // Generic routines for writing attributes and flags of
1253:            // classes, fields, methods, and codes.
1254:            void writeAttrs(int ctype, final Attribute.Holder h, Class cls)
1255:                    throws IOException {
1256:                MultiBand xxx_attr_bands = attrBands[ctype];
1257:                IntBand xxx_flags_hi = getAttrBand(xxx_attr_bands, AB_FLAGS_HI);
1258:                IntBand xxx_flags_lo = getAttrBand(xxx_attr_bands, AB_FLAGS_LO);
1259:                boolean haveLongFlags = haveFlagsHi(ctype);
1260:                assert (attrIndexLimit[ctype] == (haveLongFlags ? 63 : 32));
1261:                if (h.attributes == null) {
1262:                    xxx_flags_lo.putInt(h.flags); // no extra bits to set here
1263:                    if (haveLongFlags)
1264:                        xxx_flags_hi.putInt(0);
1265:                    return;
1266:                }
1267:                if (verbose > 3)
1268:                    Utils.log.fine("Transmitting attrs for " + h + " flags="
1269:                            + Integer.toHexString(h.flags));
1270:
1271:                long flagMask = attrFlagMask[ctype]; // which flags are attr bits?
1272:                long flagsToAdd = 0;
1273:                int overflowCount = 0;
1274:                for (ListIterator j = h.attributes.listIterator(); j.hasNext();) {
1275:                    Attribute a = (Attribute) j.next();
1276:                    Attribute.Layout def = a.layout();
1277:                    int index = ((Integer) attrIndexTable.get(def)).intValue();
1278:                    assert (attrDefs[ctype].get(index) == def);
1279:                    if (verbose > 3)
1280:                        Utils.log.fine("add attr @" + index + " " + a + " in "
1281:                                + h);
1282:                    if (index < attrIndexLimit[ctype]
1283:                            && testBit(flagMask, 1L << index)) {
1284:                        if (verbose > 3)
1285:                            Utils.log.fine("Adding flag bit 1<<" + index
1286:                                    + " in " + Long.toHexString(flagMask));
1287:                        assert (!testBit(h.flags, 1L << index));
1288:                        flagsToAdd |= (1L << index);
1289:                        flagMask -= (1L << index); // do not use this bit twice here
1290:                    } else {
1291:                        // an overflow attr.
1292:                        flagsToAdd |= (1L << X_ATTR_OVERFLOW);
1293:                        overflowCount += 1;
1294:                        if (verbose > 3)
1295:                            Utils.log.fine("Adding overflow attr #"
1296:                                    + overflowCount);
1297:                        IntBand xxx_attr_indexes = getAttrBand(xxx_attr_bands,
1298:                                AB_ATTR_INDEXES);
1299:                        xxx_attr_indexes.putInt(index);
1300:                        // System.out.println("overflow @"+index);
1301:                    }
1302:                    if (def.bandCount == 0) {
1303:                        if (def == attrInnerClassesEmpty) {
1304:                            // Special logic to write this attr.
1305:                            writeLocalInnerClasses((Class) h);
1306:                            continue;
1307:                        }
1308:                        // Empty attr; nothing more to write here.
1309:                        continue;
1310:                    }
1311:                    assert (a.fixups == null);
1312:                    final Band[] ab = (Band[]) attrBandTable.get(def);
1313:                    assert (ab != null);
1314:                    assert (ab.length == def.bandCount);
1315:                    final int[] bc = (int[]) backCountTable.get(def);
1316:                    assert (bc != null);
1317:                    assert (bc.length == def.getCallables().length);
1318:                    // Write one attribute of type def into ab.
1319:                    if (verbose > 2)
1320:                        Utils.log.fine("writing " + a + " in " + h);
1321:                    boolean isCV = (ctype == ATTR_CONTEXT_FIELD && def == attrConstantValue);
1322:                    if (isCV)
1323:                        setConstantValueIndex((Class.Field) h);
1324:                    a.parse(cls, a.bytes(), 0, a.size(),
1325:                            new Attribute.ValueStream() {
1326:                                public void putInt(int bandIndex, int value) {
1327:                                    ((IntBand) ab[bandIndex]).putInt(value);
1328:                                }
1329:
1330:                                public void putRef(int bandIndex, Entry ref) {
1331:                                    ((CPRefBand) ab[bandIndex]).putRef(ref);
1332:                                }
1333:
1334:                                public int encodeBCI(int bci) {
1335:                                    Code code = (Code) h;
1336:                                    return code.encodeBCI(bci);
1337:                                }
1338:
1339:                                public void noteBackCall(int whichCallable) {
1340:                                    assert (bc[whichCallable] >= 0);
1341:                                    bc[whichCallable] += 1;
1342:                                }
1343:                            });
1344:                    if (isCV)
1345:                        setConstantValueIndex(null); // clean up
1346:                }
1347:
1348:                if (overflowCount > 0) {
1349:                    IntBand xxx_attr_count = getAttrBand(xxx_attr_bands,
1350:                            AB_ATTR_COUNT);
1351:                    xxx_attr_count.putInt(overflowCount);
1352:                }
1353:
1354:                xxx_flags_lo.putInt(h.flags | (int) flagsToAdd);
1355:                if (haveLongFlags)
1356:                    xxx_flags_hi.putInt((int) (flagsToAdd >>> 32));
1357:                else
1358:                    assert ((flagsToAdd >>> 32) == 0);
1359:                assert ((h.flags & flagsToAdd) == 0) : (h + ".flags="
1360:                        + Integer.toHexString(h.flags) + "^" + Long
1361:                        .toHexString(flagsToAdd));
1362:            }
1363:
1364:            // temporary scratch variables for processing code blocks
1365:            private Code curCode;
1366:            private Class curClass;
1367:            private Entry[] curCPMap;
1368:
1369:            private void beginCode(Code c) {
1370:                assert (curCode == null);
1371:                curCode = c;
1372:                curClass = c.m.this Class();
1373:                curCPMap = c.getCPMap();
1374:            }
1375:
1376:            private void endCode() {
1377:                curCode = null;
1378:                curClass = null;
1379:                curCPMap = null;
1380:            }
1381:
1382:            // Return an _invokeinit_op variant, if the instruction matches one,
1383:            // else -1.
1384:            private int initOpVariant(Instruction i, Entry newClass) {
1385:                if (i.getBC() != _invokespecial)
1386:                    return -1;
1387:                MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
1388:                if (ref.descRef.nameRef.stringValue() != "<init>")
1389:                    return -1;
1390:                ClassEntry refClass = ref.classRef;
1391:                if (refClass == curClass.this Class)
1392:                    return _invokeinit_op + _invokeinit_self_option;
1393:                if (refClass == curClass.super Class)
1394:                    return _invokeinit_op + _invokeinit_super _option;
1395:                if (refClass == newClass)
1396:                    return _invokeinit_op + _invokeinit_new_option;
1397:                return -1;
1398:            }
1399:
1400:            // Return a _self_linker_op variant, if the instruction matches one,
1401:            // else -1.
1402:            private int selfOpVariant(Instruction i) {
1403:                int bc = i.getBC();
1404:                if (!(bc >= _first_linker_op && bc <= _last_linker_op))
1405:                    return -1;
1406:                MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
1407:                ClassEntry refClass = ref.classRef;
1408:                int self_bc = _self_linker_op + (bc - _first_linker_op);
1409:                if (refClass == curClass.this Class)
1410:                    return self_bc;
1411:                if (refClass == curClass.super Class)
1412:                    return self_bc + _self_linker_super _flag;
1413:                return -1;
1414:            }
1415:
1416:            void writeByteCodes(Code code) throws IOException {
1417:                beginCode(code);
1418:                IndexGroup cp = pkg.cp;
1419:
1420:                // true if the previous instruction is an aload to absorb
1421:                boolean prevAload = false;
1422:
1423:                // class of most recent new; helps compress <init> calls
1424:                Entry newClass = null;
1425:
1426:                for (Instruction i = code.instructionAt(0); i != null; i = i
1427:                        .next()) {
1428:                    // %%% Add a stress mode which issues _ref/_byte_escape.
1429:                    if (verbose > 3)
1430:                        Utils.log.fine(i.toString());
1431:
1432:                    if (i.isNonstandard()
1433:                            && (!p200.getBoolean(Utils.COM_PREFIX
1434:                                    + "invokedynamic") || i.getBC() != _xxxunusedxxx)) {
1435:                        // Crash and burn with a complaint if there are funny
1436:                        // bytecodes in this class file.
1437:                        String complaint = code.getMethod()
1438:                                + " contains an unrecognized bytecode "
1439:                                + i
1440:                                + "; please use the pass-file option on this class.";
1441:                        Utils.log.warning(complaint);
1442:                        throw new IOException(complaint);
1443:                    }
1444:
1445:                    if (i.isWide()) {
1446:                        if (verbose > 1) {
1447:                            Utils.log.fine("_wide opcode in " + code);
1448:                            Utils.log.fine(i.toString());
1449:                        }
1450:                        bc_codes.putByte(_wide);
1451:                        codeHist[_wide]++;
1452:                    }
1453:
1454:                    int bc = i.getBC();
1455:
1456:                    // Begin "bc_linker" compression.
1457:                    if (bc == _aload_0) {
1458:                        // Try to group aload_0 with a following operation.
1459:                        Instruction ni = code.instructionAt(i.getNextPC());
1460:                        if (selfOpVariant(ni) >= 0) {
1461:                            prevAload = true;
1462:                            continue;
1463:                        }
1464:                    }
1465:
1466:                    // Test for <init> invocations:
1467:                    int init_bc = initOpVariant(i, newClass);
1468:                    if (init_bc >= 0) {
1469:                        if (prevAload) {
1470:                            // get rid of it
1471:                            bc_codes.putByte(_aload_0);
1472:                            codeHist[_aload_0]++;
1473:                            prevAload = false; //used up
1474:                        }
1475:                        // Write special bytecode.
1476:                        bc_codes.putByte(init_bc);
1477:                        codeHist[init_bc]++;
1478:                        MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
1479:                        // Write operand to a separate band.
1480:                        int coding = cp.getOverloadingIndex(ref);
1481:                        bc_initref.putInt(coding);
1482:                        continue;
1483:                    }
1484:
1485:                    int self_bc = selfOpVariant(i);
1486:                    if (self_bc >= 0) {
1487:                        boolean isField = Instruction.isFieldOp(bc);
1488:                        boolean isSuper = (self_bc >= _self_linker_op
1489:                                + _self_linker_super _flag);
1490:                        boolean isAload = prevAload;
1491:                        prevAload = false; //used up
1492:                        if (isAload)
1493:                            self_bc += _self_linker_aload_flag;
1494:                        // Write special bytecode.
1495:                        bc_codes.putByte(self_bc);
1496:                        codeHist[self_bc]++;
1497:                        // Write field or method ref to a separate band.
1498:                        MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
1499:                        CPRefBand bc_which = selfOpRefBand(self_bc);
1500:                        Index which_ix = cp.getMemberIndex(ref.tag,
1501:                                ref.classRef);
1502:                        bc_which.putRef(ref, which_ix);
1503:                        continue;
1504:                    }
1505:                    assert (!prevAload);
1506:                    // End "bc_linker" compression.
1507:
1508:                    // Normal bytecode.
1509:                    codeHist[bc]++;
1510:                    switch (bc) {
1511:                    case _tableswitch: // apc:  (df, lo, hi, (hi-lo+1)*(label))
1512:                    case _lookupswitch: // apc:  (df, nc, nc*(case, label))
1513:                        bc_codes.putByte(bc);
1514:                        Instruction.Switch isw = (Instruction.Switch) i;
1515:                        // Note that we do not write the alignment bytes.
1516:                        int apc = isw.getAlignedPC();
1517:                        int npc = isw.getNextPC();
1518:                        // write a length specification into the bytecode stream
1519:                        int caseCount = isw.getCaseCount();
1520:                        bc_case_count.putInt(caseCount);
1521:                        putLabel(bc_label, code, i.getPC(), isw
1522:                                .getDefaultLabel());
1523:                        for (int j = 0; j < caseCount; j++) {
1524:                            putLabel(bc_label, code, i.getPC(), isw
1525:                                    .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:                    switch (bc) {
1540:                    case _xxxunusedxxx: // %%% pretend this is invokedynamic
1541:                    {
1542:                        i.setNonstandardLength(3);
1543:                        int refx = i.getShortAt(1);
1544:                        Entry ref = (refx == 0) ? null : curCPMap[refx];
1545:                        // transmit the opcode, carefully:
1546:                        bc_codes.putByte(_byte_escape);
1547:                        bc_escsize.putInt(1); // one byte of opcode
1548:                        bc_escbyte.putByte(bc); // the opcode
1549:                        // transmit the CP reference, carefully:
1550:                        bc_codes.putByte(_ref_escape);
1551:                        bc_escrefsize.putInt(2); // two bytes of ref
1552:                        bc_escref.putRef(ref); // the ref
1553:                        continue;
1554:                    }
1555:                    }
1556:
1557:                    int branch = i.getBranchLabel();
1558:                    if (branch >= 0) {
1559:                        bc_codes.putByte(bc);
1560:                        putLabel(bc_label, code, i.getPC(), branch);
1561:                        continue;
1562:                    }
1563:                    Entry ref = i.getCPRef(curCPMap);
1564:                    if (ref != null) {
1565:                        if (bc == _new)
1566:                            newClass = ref;
1567:                        if (bc == _ldc)
1568:                            ldcHist[ref.tag]++;
1569:                        CPRefBand bc_which;
1570:                        int vbc = bc;
1571:                        switch (i.getCPTag()) {
1572:                        case CONSTANT_Literal:
1573:                            switch (ref.tag) {
1574:                            case CONSTANT_Integer:
1575:                                bc_which = bc_intref;
1576:                                switch (bc) {
1577:                                case _ldc:
1578:                                    vbc = _ildc;
1579:                                    break;
1580:                                case _ldc_w:
1581:                                    vbc = _ildc_w;
1582:                                    break;
1583:                                default:
1584:                                    assert (false);
1585:                                }
1586:                                break;
1587:                            case CONSTANT_Float:
1588:                                bc_which = bc_floatref;
1589:                                switch (bc) {
1590:                                case _ldc:
1591:                                    vbc = _fldc;
1592:                                    break;
1593:                                case _ldc_w:
1594:                                    vbc = _fldc_w;
1595:                                    break;
1596:                                default:
1597:                                    assert (false);
1598:                                }
1599:                                break;
1600:                            case CONSTANT_Long:
1601:                                bc_which = bc_longref;
1602:                                assert (bc == _ldc2_w);
1603:                                vbc = _lldc2_w;
1604:                                break;
1605:                            case CONSTANT_Double:
1606:                                bc_which = bc_doubleref;
1607:                                assert (bc == _ldc2_w);
1608:                                vbc = _dldc2_w;
1609:                                break;
1610:                            case CONSTANT_String:
1611:                                bc_which = bc_stringref;
1612:                                switch (bc) {
1613:                                case _ldc:
1614:                                    vbc = _aldc;
1615:                                    break;
1616:                                case _ldc_w:
1617:                                    vbc = _aldc_w;
1618:                                    break;
1619:                                default:
1620:                                    assert (false);
1621:                                }
1622:                                break;
1623:                            case CONSTANT_Class:
1624:                                bc_which = bc_classref;
1625:                                switch (bc) {
1626:                                case _ldc:
1627:                                    vbc = _cldc;
1628:                                    break;
1629:                                case _ldc_w:
1630:                                    vbc = _cldc_w;
1631:                                    break;
1632:                                default:
1633:                                    assert (false);
1634:                                }
1635:                                break;
1636:                            default:
1637:                                bc_which = null;
1638:                                assert (false);
1639:                            }
1640:                            break;
1641:                        case CONSTANT_Class:
1642:                            // Use a special shorthand for the current class:
1643:                            if (ref == curClass.this Class)
1644:                                ref = null;
1645:                            bc_which = bc_classref;
1646:                            break;
1647:                        case CONSTANT_Fieldref:
1648:                            bc_which = bc_fieldref;
1649:                            break;
1650:                        case CONSTANT_Methodref:
1651:                            bc_which = bc_methodref;
1652:                            break;
1653:                        case CONSTANT_InterfaceMethodref:
1654:                            bc_which = bc_imethodref;
1655:                            break;
1656:                        default:
1657:                            bc_which = null;
1658:                            assert (false);
1659:                        }
1660:                        bc_codes.putByte(vbc);
1661:                        bc_which.putRef(ref);
1662:                        // handle trailing junk
1663:                        if (bc == _multianewarray) {
1664:                            assert (i.getConstant() == code
1665:                                    .getByte(i.getPC() + 3));
1666:                            // Just dump the byte into the bipush pile
1667:                            bc_byte.putByte(0xFF & i.getConstant());
1668:                        } else if (bc == _invokeinterface) {
1669:                            assert (i.getLength() == 5);
1670:                            // Make sure the discarded bytes are sane:
1671:                            assert (i.getConstant() == (1 + ((MemberEntry) ref).descRef.typeRef
1672:                                    .computeSize(true)) << 8);
1673:                        } else {
1674:                            // Make sure there is nothing else to write.
1675:                            assert (i.getLength() == ((bc == _ldc) ? 2 : 3));
1676:                        }
1677:                        continue;
1678:                    }
1679:                    int slot = i.getLocalSlot();
1680:                    if (slot >= 0) {
1681:                        bc_codes.putByte(bc);
1682:                        bc_local.putInt(slot);
1683:                        int con = i.getConstant();
1684:                        if (bc == _iinc) {
1685:                            if (!i.isWide()) {
1686:                                bc_byte.putByte(0xFF & con);
1687:                            } else {
1688:                                bc_short.putInt(0xFFFF & con);
1689:                            }
1690:                        } else {
1691:                            assert (con == 0);
1692:                        }
1693:                        continue;
1694:                    }
1695:                    // Generic instruction.  Copy the body.
1696:                    bc_codes.putByte(bc);
1697:                    int pc = i.getPC() + 1;
1698:                    int npc = i.getNextPC();
1699:                    if (pc < npc) {
1700:                        // Do a few remaining multi-byte instructions.
1701:                        switch (bc) {
1702:                        case _sipush:
1703:                            bc_short.putInt(0xFFFF & i.getConstant());
1704:                            break;
1705:                        case _bipush:
1706:                            bc_byte.putByte(0xFF & i.getConstant());
1707:                            break;
1708:                        case _newarray:
1709:                            bc_byte.putByte(0xFF & i.getConstant());
1710:                            break;
1711:                        default:
1712:                            assert (false); // that's it
1713:                        }
1714:                    }
1715:                }
1716:                bc_codes.putByte(_end_marker);
1717:                bc_codes.elementCountForDebug++;
1718:                codeHist[_end_marker]++;
1719:                endCode();
1720:            }
1721:
1722:            int[] codeHist = new int[1 << 8];
1723:            int[] ldcHist = new int[20];
1724:
1725:            void printCodeHist() {
1726:                assert (verbose > 0);
1727:                String[] hist = new String[codeHist.length];
1728:                int totalBytes = 0;
1729:                for (int bc = 0; bc < codeHist.length; bc++) {
1730:                    totalBytes += codeHist[bc];
1731:                }
1732:                for (int bc = 0; bc < codeHist.length; bc++) {
1733:                    if (codeHist[bc] == 0) {
1734:                        hist[bc] = "";
1735:                        continue;
1736:                    }
1737:                    String iname = Instruction.byteName(bc);
1738:                    String count = "" + codeHist[bc];
1739:                    count = "         ".substring(count.length()) + count;
1740:                    String pct = "" + (codeHist[bc] * 10000 / totalBytes);
1741:                    while (pct.length() < 4)
1742:                        pct = "0" + pct;
1743:                    pct = pct.substring(0, pct.length() - 2) + "."
1744:                            + pct.substring(pct.length() - 2);
1745:                    hist[bc] = count + "  " + pct + "%  " + iname;
1746:                }
1747:                Arrays.sort(hist);
1748:                System.out.println("Bytecode histogram [" + totalBytes + "]");
1749:                for (int i = hist.length; --i >= 0;) {
1750:                    if (hist[i] == "")
1751:                        continue;
1752:                    System.out.println(hist[i]);
1753:                }
1754:                for (int tag = 0; tag < ldcHist.length; tag++) {
1755:                    int count = ldcHist[tag];
1756:                    if (count == 0)
1757:                        continue;
1758:                    System.out.println("ldc " + ConstantPool.tagName(tag) + " "
1759:                            + count);
1760:                }
1761:            }
1762:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.