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.jar.*;
0031: import com.sun.java.util.jar.pack.Package.Class;
0032: import com.sun.java.util.jar.pack.Package.InnerClass;
0033: import com.sun.java.util.jar.pack.ConstantPool.*;
0034:
0035: /**
0036: * Define the structure and ordering of "bands" in a packed file.
0037: * @author John Rose
0038: * @version 1.36, 05/05/07
0039: */
0040: abstract class BandStructure implements Constants {
0041: static final int MAX_EFFORT = 9;
0042: static final int MIN_EFFORT = 1;
0043: static final int DEFAULT_EFFORT = 5;
0044:
0045: // Inherit options from Pack200:
0046: PropMap p200 = Utils.currentPropMap();
0047:
0048: int verbose = p200.getInteger(Utils.DEBUG_VERBOSE);
0049: int effort = p200.getInteger(Pack200.Packer.EFFORT);
0050: {
0051: if (effort == 0)
0052: effort = DEFAULT_EFFORT;
0053: }
0054: boolean optDumpBands = p200.getBoolean(Utils.COM_PREFIX
0055: + "dump.bands");
0056: boolean optDebugBands = p200.getBoolean(Utils.COM_PREFIX
0057: + "debug.bands");
0058:
0059: // Various heuristic options.
0060: boolean optVaryCodings = !p200.getBoolean(Utils.COM_PREFIX
0061: + "no.vary.codings");
0062: boolean optBigStrings = !p200.getBoolean(Utils.COM_PREFIX
0063: + "no.big.strings");
0064:
0065: abstract protected Index getCPIndex(byte tag);
0066:
0067: // Local copy of package version.
0068: private int packageMajver = -1;
0069:
0070: /** Call this exactly once, early, to specify the archive major version. */
0071: public void initPackageMajver(int packageMajver) throws IOException {
0072: assert (packageMajver > 0 && packageMajver < 0x10000);
0073: if (this .packageMajver > 0) {
0074: throw new IOException(
0075: "Package majver is already initialized to "
0076: + this .packageMajver + "; new setting is "
0077: + packageMajver);
0078: }
0079: this .packageMajver = packageMajver;
0080: adjustToMajver();
0081: }
0082:
0083: public int getPackageMajver() {
0084: if (packageMajver < 0) {
0085: throw new RuntimeException(
0086: "Package majver not yet initialized");
0087: }
0088: return packageMajver;
0089: }
0090:
0091: private final boolean isReader = this instanceof PackageReader;
0092:
0093: protected BandStructure() {
0094: }
0095:
0096: final static Coding BYTE1 = Coding.of(1, 256);
0097:
0098: final static Coding CHAR3 = Coding.of(3, 128);
0099: // Note: Tried sharper (3,16) with no post-zip benefit.
0100:
0101: // This is best used with BCI values:
0102: final static Coding BCI5 = Coding.of(5, 4); // mostly 1-byte offsets
0103: final static Coding BRANCH5 = Coding.of(5, 4, 2); // mostly forward branches
0104:
0105: final static Coding UNSIGNED5 = Coding.of(5, 64);
0106: final static Coding UDELTA5 = UNSIGNED5.getDeltaCoding();
0107: // "sharp" (5,64) zips 0.4% better than "medium" (5,128)
0108: // It zips 1.1% better than "flat" (5,192)
0109:
0110: final static Coding SIGNED5 = Coding.of(5, 64, 1); //sharp
0111: final static Coding DELTA5 = SIGNED5.getDeltaCoding();
0112: // Note: Tried (5,128,2) and (5,192,2) with no benefit.
0113:
0114: final static Coding MDELTA5 = Coding.of(5, 64, 2).getDeltaCoding();
0115:
0116: final private static Coding[] basicCodings = {
0117: // Table of "Canonical BHSD Codings" from Pack200 spec.
0118: null, // _meta_default
0119:
0120: // Fixed-length codings:
0121: Coding.of(1, 256, 0),
0122: Coding.of(1, 256, 1),
0123: Coding.of(1, 256, 0).getDeltaCoding(),
0124: Coding.of(1, 256, 1).getDeltaCoding(),
0125: Coding.of(2, 256, 0),
0126: Coding.of(2, 256, 1),
0127: Coding.of(2, 256, 0).getDeltaCoding(),
0128: Coding.of(2, 256, 1).getDeltaCoding(),
0129: Coding.of(3, 256, 0),
0130: Coding.of(3, 256, 1),
0131: Coding.of(3, 256, 0).getDeltaCoding(),
0132: Coding.of(3, 256, 1).getDeltaCoding(),
0133: Coding.of(4, 256, 0),
0134: Coding.of(4, 256, 1),
0135: Coding.of(4, 256, 0).getDeltaCoding(),
0136: Coding.of(4, 256, 1).getDeltaCoding(),
0137:
0138: // Full-range variable-length codings:
0139: Coding.of(5, 4, 0),
0140: Coding.of(5, 4, 1),
0141: Coding.of(5, 4, 2),
0142: Coding.of(5, 16, 0),
0143: Coding.of(5, 16, 1),
0144: Coding.of(5, 16, 2),
0145: Coding.of(5, 32, 0),
0146: Coding.of(5, 32, 1),
0147: Coding.of(5, 32, 2),
0148: Coding.of(5, 64, 0),
0149: Coding.of(5, 64, 1),
0150: Coding.of(5, 64, 2),
0151: Coding.of(5, 128, 0),
0152: Coding.of(5, 128, 1),
0153: Coding.of(5, 128, 2),
0154:
0155: Coding.of(5, 4, 0).getDeltaCoding(),
0156: Coding.of(5, 4, 1).getDeltaCoding(),
0157: Coding.of(5, 4, 2).getDeltaCoding(),
0158: Coding.of(5, 16, 0).getDeltaCoding(),
0159: Coding.of(5, 16, 1).getDeltaCoding(),
0160: Coding.of(5, 16, 2).getDeltaCoding(),
0161: Coding.of(5, 32, 0).getDeltaCoding(),
0162: Coding.of(5, 32, 1).getDeltaCoding(),
0163: Coding.of(5, 32, 2).getDeltaCoding(),
0164: Coding.of(5, 64, 0).getDeltaCoding(),
0165: Coding.of(5, 64, 1).getDeltaCoding(),
0166: Coding.of(5, 64, 2).getDeltaCoding(),
0167: Coding.of(5, 128, 0).getDeltaCoding(),
0168: Coding.of(5, 128, 1).getDeltaCoding(),
0169: Coding.of(5, 128, 2).getDeltaCoding(),
0170:
0171: // Variable length subrange codings:
0172: Coding.of(2, 192, 0), Coding.of(2, 224, 0),
0173: Coding.of(2, 240, 0), Coding.of(2, 248, 0),
0174: Coding.of(2, 252, 0),
0175:
0176: Coding.of(2, 8, 0).getDeltaCoding(),
0177: Coding.of(2, 8, 1).getDeltaCoding(),
0178: Coding.of(2, 16, 0).getDeltaCoding(),
0179: Coding.of(2, 16, 1).getDeltaCoding(),
0180: Coding.of(2, 32, 0).getDeltaCoding(),
0181: Coding.of(2, 32, 1).getDeltaCoding(),
0182: Coding.of(2, 64, 0).getDeltaCoding(),
0183: Coding.of(2, 64, 1).getDeltaCoding(),
0184: Coding.of(2, 128, 0).getDeltaCoding(),
0185: Coding.of(2, 128, 1).getDeltaCoding(),
0186: Coding.of(2, 192, 0).getDeltaCoding(),
0187: Coding.of(2, 192, 1).getDeltaCoding(),
0188: Coding.of(2, 224, 0).getDeltaCoding(),
0189: Coding.of(2, 224, 1).getDeltaCoding(),
0190: Coding.of(2, 240, 0).getDeltaCoding(),
0191: Coding.of(2, 240, 1).getDeltaCoding(),
0192: Coding.of(2, 248, 0).getDeltaCoding(),
0193: Coding.of(2, 248, 1).getDeltaCoding(),
0194:
0195: Coding.of(3, 192, 0), Coding.of(3, 224, 0),
0196: Coding.of(3, 240, 0), Coding.of(3, 248, 0),
0197: Coding.of(3, 252, 0),
0198:
0199: Coding.of(3, 8, 0).getDeltaCoding(),
0200: Coding.of(3, 8, 1).getDeltaCoding(),
0201: Coding.of(3, 16, 0).getDeltaCoding(),
0202: Coding.of(3, 16, 1).getDeltaCoding(),
0203: Coding.of(3, 32, 0).getDeltaCoding(),
0204: Coding.of(3, 32, 1).getDeltaCoding(),
0205: Coding.of(3, 64, 0).getDeltaCoding(),
0206: Coding.of(3, 64, 1).getDeltaCoding(),
0207: Coding.of(3, 128, 0).getDeltaCoding(),
0208: Coding.of(3, 128, 1).getDeltaCoding(),
0209: Coding.of(3, 192, 0).getDeltaCoding(),
0210: Coding.of(3, 192, 1).getDeltaCoding(),
0211: Coding.of(3, 224, 0).getDeltaCoding(),
0212: Coding.of(3, 224, 1).getDeltaCoding(),
0213: Coding.of(3, 240, 0).getDeltaCoding(),
0214: Coding.of(3, 240, 1).getDeltaCoding(),
0215: Coding.of(3, 248, 0).getDeltaCoding(),
0216: Coding.of(3, 248, 1).getDeltaCoding(),
0217:
0218: Coding.of(4, 192, 0), Coding.of(4, 224, 0),
0219: Coding.of(4, 240, 0), Coding.of(4, 248, 0),
0220: Coding.of(4, 252, 0),
0221:
0222: Coding.of(4, 8, 0).getDeltaCoding(),
0223: Coding.of(4, 8, 1).getDeltaCoding(),
0224: Coding.of(4, 16, 0).getDeltaCoding(),
0225: Coding.of(4, 16, 1).getDeltaCoding(),
0226: Coding.of(4, 32, 0).getDeltaCoding(),
0227: Coding.of(4, 32, 1).getDeltaCoding(),
0228: Coding.of(4, 64, 0).getDeltaCoding(),
0229: Coding.of(4, 64, 1).getDeltaCoding(),
0230: Coding.of(4, 128, 0).getDeltaCoding(),
0231: Coding.of(4, 128, 1).getDeltaCoding(),
0232: Coding.of(4, 192, 0).getDeltaCoding(),
0233: Coding.of(4, 192, 1).getDeltaCoding(),
0234: Coding.of(4, 224, 0).getDeltaCoding(),
0235: Coding.of(4, 224, 1).getDeltaCoding(),
0236: Coding.of(4, 240, 0).getDeltaCoding(),
0237: Coding.of(4, 240, 1).getDeltaCoding(),
0238: Coding.of(4, 248, 0).getDeltaCoding(),
0239: Coding.of(4, 248, 1).getDeltaCoding(),
0240:
0241: null };
0242: final private static HashMap basicCodingIndexes;
0243: static {
0244: assert (basicCodings[_meta_default] == null);
0245: assert (basicCodings[_meta_canon_min] != null);
0246: assert (basicCodings[_meta_canon_max] != null);
0247: HashMap map = new HashMap();
0248: for (int i = 0; i < basicCodings.length; i++) {
0249: Coding c = basicCodings[i];
0250: if (c == null)
0251: continue;
0252: assert (i >= _meta_canon_min);
0253: assert (i <= _meta_canon_max);
0254: map.put(c, new Integer(i));
0255: }
0256: basicCodingIndexes = map;
0257: }
0258:
0259: public static Coding codingForIndex(int i) {
0260: return i < basicCodings.length ? basicCodings[i] : null;
0261: }
0262:
0263: public static int indexOf(Coding c) {
0264: Integer i = (Integer) basicCodingIndexes.get(c);
0265: if (i == null)
0266: return 0;
0267: return i.intValue();
0268: }
0269:
0270: public static Coding[] getBasicCodings() {
0271: return (Coding[]) basicCodings.clone();
0272: }
0273:
0274: protected byte[] bandHeaderBytes; // used for input only
0275: protected int bandHeaderBytePos; // BHB read pointer, for input only
0276: protected int bandHeaderBytePos0; // for debug
0277:
0278: protected CodingMethod getBandHeader(int XB, Coding regularCoding) {
0279: CodingMethod[] res = { null };
0280: // push back XB onto the band header bytes
0281: bandHeaderBytes[--bandHeaderBytePos] = (byte) XB;
0282: bandHeaderBytePos0 = bandHeaderBytePos;
0283: // scan forward through XB and any additional band header bytes
0284: bandHeaderBytePos = parseMetaCoding(bandHeaderBytes,
0285: bandHeaderBytePos, regularCoding, res);
0286: return res[0];
0287: }
0288:
0289: public static int parseMetaCoding(byte[] bytes, int pos,
0290: Coding dflt, CodingMethod[] res) {
0291: if ((bytes[pos] & 0xFF) == _meta_default) {
0292: res[0] = dflt;
0293: return pos + 1;
0294: }
0295: int pos2;
0296: pos2 = Coding.parseMetaCoding(bytes, pos, dflt, res);
0297: if (pos2 > pos)
0298: return pos2;
0299: pos2 = PopulationCoding.parseMetaCoding(bytes, pos, dflt, res);
0300: if (pos2 > pos)
0301: return pos2;
0302: pos2 = AdaptiveCoding.parseMetaCoding(bytes, pos, dflt, res);
0303: if (pos2 > pos)
0304: return pos2;
0305: throw new RuntimeException("Bad meta-coding op "
0306: + (bytes[pos] & 0xFF));
0307: }
0308:
0309: static final int SHORT_BAND_HEURISTIC = 100;
0310:
0311: public static final int NO_PHASE = 0;
0312:
0313: // package writing phases:
0314: public static final int COLLECT_PHASE = 1; // collect data before write
0315: public static final int FROZEN_PHASE = 3; // no longer collecting
0316: public static final int WRITE_PHASE = 5; // ready to write bytes
0317:
0318: // package reading phases:
0319: public static final int EXPECT_PHASE = 2; // gather expected counts
0320: public static final int READ_PHASE = 4; // ready to read bytes
0321: public static final int DISBURSE_PHASE = 6; // pass out data after read
0322:
0323: public static final int DONE_PHASE = 8; // done writing or reading
0324:
0325: static boolean phaseIsRead(int p) {
0326: return (p % 2) == 0;
0327: }
0328:
0329: static int phaseCmp(int p0, int p1) {
0330: assert ((p0 % 2) == (p1 % 2) || (p0 % 8) == 0 || (p1 % 8) == 0);
0331: return p0 - p1;
0332: }
0333:
0334: /** The packed file is divided up into a number of segments.
0335: * Most segments are typed as ValueBand, strongly-typed sequences
0336: * of integer values, all interpreted in a single way.
0337: * A few segments are ByteBands, which hetergeneous sequences
0338: * of bytes.
0339: *
0340: * The two phases for writing a packed file are COLLECT and WRITE.
0341: * 1. When writing a packed file, each band collects
0342: * data in an ad-hoc order.
0343: * 2. At the end, each band is assigned a coding scheme,
0344: * and then all the bands are written in their global order.
0345: *
0346: * The three phases for reading a packed file are EXPECT, READ,
0347: * and DISBURSE.
0348: * 1. For each band, the expected number of integers is determined.
0349: * 2. The data is actually read from the file into the band.
0350: * 3. The band pays out its values as requested, in an ad hoc order.
0351: *
0352: * When the last phase of a band is done, it is marked so (DONE).
0353: * Clearly, these phases must be properly ordered WRT each other.
0354: */
0355: abstract class Band {
0356: private int phase = NO_PHASE;
0357: private final String name;
0358:
0359: private int valuesExpected;
0360:
0361: protected long outputSize = -1; // cache
0362:
0363: final public Coding regularCoding;
0364:
0365: final public int seqForDebug;
0366: public int elementCountForDebug;
0367:
0368: protected Band(String name, Coding regularCoding) {
0369: this .name = name;
0370: this .regularCoding = regularCoding;
0371: this .seqForDebug = ++nextSeqForDebug;
0372: if (verbose > 2)
0373: Utils.log.fine("Band " + seqForDebug + " is " + name);
0374: // caller must call init
0375: }
0376:
0377: public Band init() {
0378: // Cannot due this from the constructor, because constructor
0379: // may wish to initialize some subclass variables.
0380: // Set initial phase for reading or writing:
0381: if (isReader)
0382: readyToExpect();
0383: else
0384: readyToCollect();
0385: return this ;
0386: }
0387:
0388: // common operations
0389: boolean isReader() {
0390: return isReader;
0391: }
0392:
0393: int phase() {
0394: return phase;
0395: }
0396:
0397: String name() {
0398: return name;
0399: }
0400:
0401: /** Return -1 if data buffer not allocated, else max length. */
0402: public abstract int capacity();
0403:
0404: /** Allocate data buffer to specified length. */
0405: protected abstract void setCapacity(int cap);
0406:
0407: /** Return current number of values in buffer, which must exist. */
0408: public abstract int length();
0409:
0410: protected abstract int valuesRemainingForDebug();
0411:
0412: public final int valuesExpected() {
0413: return valuesExpected;
0414: }
0415:
0416: /** Write out bytes, encoding the values. */
0417: public final void writeTo(OutputStream out) throws IOException {
0418: assert (assertReadyToWriteTo(this , out));
0419: setPhase(WRITE_PHASE);
0420: // subclasses continue by writing their contents to output
0421: writeDataTo(out);
0422: doneWriting();
0423: }
0424:
0425: abstract void chooseBandCodings() throws IOException;
0426:
0427: public final long outputSize() {
0428: if (outputSize >= 0) {
0429: long size = outputSize;
0430: assert (size == computeOutputSize());
0431: return size;
0432: }
0433: return computeOutputSize();
0434: }
0435:
0436: protected abstract long computeOutputSize();
0437:
0438: abstract protected void writeDataTo(OutputStream out)
0439: throws IOException;
0440:
0441: /** Expect a certain number of values. */
0442: void expectLength(int l) {
0443: assert (assertPhase(this , EXPECT_PHASE));
0444: assert (valuesExpected == 0); // all at once
0445: assert (l >= 0);
0446: valuesExpected = l;
0447: }
0448:
0449: /** Expect more values. (Multiple calls accumulate.) */
0450: void expectMoreLength(int l) {
0451: assert (assertPhase(this , EXPECT_PHASE));
0452: valuesExpected += l;
0453: }
0454:
0455: /// Phase change markers.
0456:
0457: private void readyToCollect() { // called implicitly by constructor
0458: setCapacity(1);
0459: setPhase(COLLECT_PHASE);
0460: }
0461:
0462: protected void doneWriting() {
0463: assert (assertPhase(this , WRITE_PHASE));
0464: setPhase(DONE_PHASE);
0465: }
0466:
0467: private void readyToExpect() { // called implicitly by constructor
0468: setPhase(EXPECT_PHASE);
0469: }
0470:
0471: /** Read in bytes, decoding the values. */
0472: public final void readFrom(InputStream in) throws IOException {
0473: assert (assertReadyToReadFrom(this , in));
0474: setCapacity(valuesExpected());
0475: setPhase(READ_PHASE);
0476: // subclasses continue by reading their contents from input:
0477: readDataFrom(in);
0478: readyToDisburse();
0479: }
0480:
0481: abstract protected void readDataFrom(InputStream in)
0482: throws IOException;
0483:
0484: protected void readyToDisburse() {
0485: if (verbose > 1)
0486: Utils.log.fine("readyToDisburse " + this );
0487: setPhase(DISBURSE_PHASE);
0488: }
0489:
0490: public void doneDisbursing() {
0491: assert (assertPhase(this , DISBURSE_PHASE));
0492: setPhase(DONE_PHASE);
0493: }
0494:
0495: public final void doneWithUnusedBand() {
0496: if (isReader) {
0497: assert (assertPhase(this , EXPECT_PHASE));
0498: assert (valuesExpected() == 0);
0499: // Fast forward:
0500: setPhase(READ_PHASE);
0501: setPhase(DISBURSE_PHASE);
0502: setPhase(DONE_PHASE);
0503: } else {
0504: setPhase(FROZEN_PHASE);
0505: }
0506: }
0507:
0508: protected void setPhase(int newPhase) {
0509: assert (assertPhaseChangeOK(this , phase, newPhase));
0510: this .phase = newPhase;
0511: }
0512:
0513: protected int lengthForDebug = -1; // DEBUG ONLY
0514:
0515: public String toString() { // DEBUG ONLY
0516: int length = (lengthForDebug != -1 ? lengthForDebug
0517: : length());
0518: String str = name;
0519: if (length != 0)
0520: str += "[" + length + "]";
0521: if (elementCountForDebug != 0)
0522: str += "(" + elementCountForDebug + ")";
0523: return str;
0524: }
0525: }
0526:
0527: class ValueBand extends Band {
0528: private int[] values; // must be null in EXPECT phase
0529: private int length;
0530: private int valuesDisbursed;
0531:
0532: private CodingMethod bandCoding;
0533: private byte[] metaCoding;
0534:
0535: protected ValueBand(String name, Coding regularCoding) {
0536: super (name, regularCoding);
0537: }
0538:
0539: public int capacity() {
0540: return values == null ? -1 : values.length;
0541: }
0542:
0543: /** Declare predicted or needed capacity. */
0544: protected void setCapacity(int cap) {
0545: assert (length <= cap);
0546: if (cap == -1) {
0547: values = null;
0548: return;
0549: }
0550: values = realloc(values, cap);
0551: }
0552:
0553: public int length() {
0554: return length;
0555: }
0556:
0557: protected int valuesRemainingForDebug() {
0558: return length - valuesDisbursed;
0559: }
0560:
0561: protected int valueAtForDebug(int i) {
0562: return values[i];
0563: }
0564:
0565: void patchValue(int i, int value) {
0566: // Only one use for this.
0567: assert (this == archive_header_S);
0568: assert (i == AH_ARCHIVE_SIZE_HI || i == AH_ARCHIVE_SIZE_LO);
0569: assert (i < length); // must have already output a dummy
0570: values[i] = value;
0571: outputSize = -1; // decache
0572: }
0573:
0574: protected void initializeValues(int[] values) {
0575: assert (assertCanChangeLength(this ));
0576: assert (length == 0);
0577: this .values = values;
0578: this .length = values.length;
0579: }
0580:
0581: /** Collect one value, or store one decoded value. */
0582: protected void addValue(int x) {
0583: assert (assertCanChangeLength(this ));
0584: if (length == values.length)
0585: setCapacity(length < 1000 ? length * 10 : length * 2);
0586: values[length++] = x;
0587: }
0588:
0589: private boolean canVaryCoding() {
0590: if (!optVaryCodings)
0591: return false;
0592: if (length == 0)
0593: return false;
0594: // Can't read band_headers w/o the archive header:
0595: if (this == archive_header_0)
0596: return false;
0597: if (this == archive_header_S)
0598: return false;
0599: if (this == archive_header_1)
0600: return false;
0601: // BYTE1 bands can't vary codings, but the others can.
0602: // All that's needed for the initial escape is at least
0603: // 256 negative values or more than 256 non-negative values
0604: return (regularCoding.min() <= -256 || regularCoding.max() >= 256);
0605: }
0606:
0607: private boolean shouldVaryCoding() {
0608: assert (canVaryCoding());
0609: if (effort < MAX_EFFORT && length < SHORT_BAND_HEURISTIC)
0610: return false;
0611: return true;
0612: }
0613:
0614: protected void chooseBandCodings() throws IOException {
0615: boolean canVary = canVaryCoding();
0616: if (!canVary || !shouldVaryCoding()) {
0617: if (regularCoding.canRepresent(values, 0, length)) {
0618: bandCoding = regularCoding;
0619: } else {
0620: assert (canVary);
0621: if (verbose > 1)
0622: Utils.log.fine("regular coding fails in band "
0623: + name());
0624: bandCoding = UNSIGNED5;
0625: }
0626: outputSize = -1;
0627: } else {
0628: int[] sizes = { 0, 0 };
0629: bandCoding = chooseCoding(values, 0, length,
0630: regularCoding, name(), sizes);
0631: outputSize = sizes[CodingChooser.BYTE_SIZE];
0632: if (outputSize == 0) // CodingChooser failed to size it.
0633: outputSize = -1;
0634: }
0635:
0636: // Compute and save the meta-coding bytes also.
0637: if (bandCoding != regularCoding) {
0638: metaCoding = bandCoding.getMetaCoding(regularCoding);
0639: if (verbose > 1) {
0640: Utils.log.fine("alternate coding " + this + " "
0641: + bandCoding);
0642: }
0643: } else if (canVary
0644: && decodeEscapeValue(values[0], regularCoding) >= 0) {
0645: // Need an explicit default.
0646: metaCoding = defaultMetaCoding;
0647: } else {
0648: // Common case: Zero bytes of meta coding.
0649: metaCoding = noMetaCoding;
0650: }
0651: if (metaCoding.length > 0
0652: && (verbose > 2 || verbose > 1
0653: && metaCoding.length > 1)) {
0654: StringBuffer sb = new StringBuffer();
0655: for (int i = 0; i < metaCoding.length; i++) {
0656: if (i == 1)
0657: sb.append(" /");
0658: sb.append(" ").append(metaCoding[i] & 0xFF);
0659: }
0660: Utils.log.fine(" meta-coding " + sb);
0661: }
0662:
0663: assert ((outputSize < 0) || !(bandCoding instanceof Coding) || (outputSize == ((Coding) bandCoding)
0664: .getLength(values, 0, length))) : (bandCoding
0665: + " : "
0666: + outputSize
0667: + " != "
0668: + ((Coding) bandCoding)
0669: .getLength(values, 0, length) + " ?= " + getCodingChooser()
0670: .computeByteSize(bandCoding, values, 0, length));
0671:
0672: // Compute outputSize of the escape value X, if any.
0673: if (metaCoding.length > 0) {
0674: // First byte XB of meta-coding is treated specially,
0675: // but any other bytes go into the band headers band.
0676: // This must be done before any other output happens.
0677: if (outputSize >= 0)
0678: outputSize += computeEscapeSize(); // good cache
0679: // Other bytes go into band_headers.
0680: for (int i = 1; i < metaCoding.length; i++) {
0681: band_headers.putByte(metaCoding[i] & 0xFF);
0682: }
0683: }
0684: }
0685:
0686: protected long computeOutputSize() {
0687: outputSize = getCodingChooser().computeByteSize(bandCoding,
0688: values, 0, length);
0689: assert (outputSize < Integer.MAX_VALUE);
0690: outputSize += computeEscapeSize();
0691: return outputSize;
0692: }
0693:
0694: protected int computeEscapeSize() {
0695: if (metaCoding.length == 0)
0696: return 0;
0697: int XB = metaCoding[0] & 0xFF;
0698: int X = encodeEscapeValue(XB, regularCoding);
0699: return regularCoding.setD(0).getLength(X);
0700: }
0701:
0702: protected void writeDataTo(OutputStream out) throws IOException {
0703: if (length == 0)
0704: return; // nothing to write
0705: long len0 = 0;
0706: if (out == outputCounter) {
0707: len0 = outputCounter.getCount();
0708: }
0709: if (metaCoding.length > 0) {
0710: int XB = metaCoding[0] & 0xFF;
0711: // We need an explicit band header, either because
0712: // there is a non-default coding method, or because
0713: // the first value would be parsed as an escape value.
0714: int X = encodeEscapeValue(XB, regularCoding);
0715: //System.out.println("X="+X+" XB="+XB+" in "+this);
0716: regularCoding.setD(0).writeTo(out, X);
0717: }
0718: bandCoding.writeArrayTo(out, values, 0, length);
0719: if (out == outputCounter) {
0720: long len1 = outputCounter.getCount();
0721: assert (outputSize == outputCounter.getCount() - len0) : (outputSize
0722: + " != " + outputCounter.getCount() + "-" + len0);
0723: }
0724: if (optDumpBands)
0725: dumpBand();
0726: }
0727:
0728: protected void readDataFrom(InputStream in) throws IOException {
0729: length = valuesExpected();
0730: if (length == 0)
0731: return; // nothing to read
0732: if (verbose > 1)
0733: Utils.log.fine("Reading band " + this );
0734: if (!canVaryCoding()) {
0735: bandCoding = regularCoding;
0736: metaCoding = noMetaCoding;
0737: } else {
0738: assert (in.markSupported()); // input must be buffered
0739: in.mark(Coding.B_MAX);
0740: int X = regularCoding.setD(0).readFrom(in);
0741: int XB = decodeEscapeValue(X, regularCoding);
0742: if (XB < 0) {
0743: // Do not consume this value. No alternate coding.
0744: in.reset();
0745: XB = _meta_default;
0746: bandCoding = regularCoding;
0747: metaCoding = noMetaCoding;
0748: } else if (XB == _meta_default) {
0749: bandCoding = regularCoding;
0750: metaCoding = defaultMetaCoding;
0751: } else {
0752: if (verbose > 2)
0753: Utils.log.fine("found X=" + X + " => XB=" + XB);
0754: bandCoding = getBandHeader(XB, regularCoding);
0755: // This is really used only by dumpBands.
0756: int p0 = bandHeaderBytePos0;
0757: int p1 = bandHeaderBytePos;
0758: metaCoding = new byte[p1 - p0];
0759: System.arraycopy(bandHeaderBytes, p0, metaCoding,
0760: 0, metaCoding.length);
0761: }
0762: }
0763: if (bandCoding != regularCoding) {
0764: if (verbose > 1)
0765: Utils.log.fine(name() + ": irregular coding "
0766: + bandCoding);
0767: }
0768: bandCoding.readArrayFrom(in, values, 0, length);
0769: if (optDumpBands)
0770: dumpBand();
0771: }
0772:
0773: public void doneDisbursing() {
0774: super .doneDisbursing();
0775: values = null; // for GC
0776: }
0777:
0778: private void dumpBand() throws IOException {
0779: assert (optDumpBands);
0780: PrintStream ps = new PrintStream(
0781: getDumpStream(this , ".txt"));
0782: String irr = (bandCoding == regularCoding) ? ""
0783: : " irregular";
0784: ps.print("# length=" + length + " size=" + outputSize()
0785: + irr + " coding=" + bandCoding);
0786: if (metaCoding != noMetaCoding) {
0787: StringBuffer sb = new StringBuffer();
0788: for (int i = 0; i < metaCoding.length; i++) {
0789: if (i == 1)
0790: sb.append(" /");
0791: sb.append(" ").append(metaCoding[i] & 0xFF);
0792: }
0793: ps.print(" //header: " + sb);
0794: }
0795: printArrayTo(ps, values, 0, length);
0796: ps.close();
0797: OutputStream ds = getDumpStream(this , ".bnd");
0798: bandCoding.writeArrayTo(ds, values, 0, length);
0799: ds.close();
0800: }
0801:
0802: /** Disburse one value. */
0803: protected int getValue() {
0804: assert (phase() == DISBURSE_PHASE);
0805: assert (valuesDisbursed < length);
0806: return values[valuesDisbursed++];
0807: }
0808:
0809: /** Reset for another pass over the same value set. */
0810: public void resetForSecondPass() {
0811: assert (phase() == DISBURSE_PHASE);
0812: assert (valuesDisbursed == length()); // 1st pass is complete
0813: valuesDisbursed = 0;
0814: }
0815: }
0816:
0817: class ByteBand extends Band {
0818: private ByteArrayOutputStream bytes; // input buffer
0819: private ByteArrayOutputStream bytesForDump;
0820: private InputStream in;
0821:
0822: public ByteBand(String name) {
0823: super (name, BYTE1);
0824: }
0825:
0826: public int capacity() {
0827: return bytes == null ? -1 : Integer.MAX_VALUE;
0828: }
0829:
0830: protected void setCapacity(int cap) {
0831: assert (bytes == null); // do this just once
0832: bytes = new ByteArrayOutputStream(cap);
0833: }
0834:
0835: public void destroy() {
0836: lengthForDebug = length();
0837: bytes = null;
0838: }
0839:
0840: public int length() {
0841: return bytes == null ? -1 : bytes.size();
0842: }
0843:
0844: public void reset() {
0845: bytes.reset();
0846: }
0847:
0848: protected int valuesRemainingForDebug() {
0849: return (bytes == null) ? -1 : ((ByteArrayInputStream) in)
0850: .available();
0851: }
0852:
0853: protected void chooseBandCodings() throws IOException {
0854: // No-op.
0855: assert (decodeEscapeValue(regularCoding.min(),
0856: regularCoding) < 0);
0857: assert (decodeEscapeValue(regularCoding.max(),
0858: regularCoding) < 0);
0859: }
0860:
0861: protected long computeOutputSize() {
0862: // do not cache
0863: return bytes.size();
0864: }
0865:
0866: public void writeDataTo(OutputStream out) throws IOException {
0867: if (length() == 0)
0868: return;
0869: bytes.writeTo(out);
0870: if (optDumpBands)
0871: dumpBand();
0872: destroy(); // done with the bits!
0873: }
0874:
0875: private void dumpBand() throws IOException {
0876: assert (optDumpBands);
0877: OutputStream ds = getDumpStream(this , ".bnd");
0878: if (bytesForDump != null)
0879: bytesForDump.writeTo(ds);
0880: else
0881: bytes.writeTo(ds);
0882: ds.close();
0883: }
0884:
0885: public void readDataFrom(InputStream in) throws IOException {
0886: int vex = valuesExpected();
0887: if (vex == 0)
0888: return;
0889: if (verbose > 1) {
0890: lengthForDebug = vex;
0891: Utils.log.fine("Reading band " + this );
0892: lengthForDebug = -1;
0893: }
0894: byte[] buf = new byte[Math.min(vex, 1 << 14)];
0895: while (vex > 0) {
0896: int nr = in.read(buf, 0, Math.min(vex, buf.length));
0897: if (nr < 0)
0898: throw new EOFException();
0899: bytes.write(buf, 0, nr);
0900: vex -= nr;
0901: }
0902: if (optDumpBands)
0903: dumpBand();
0904: }
0905:
0906: public void readyToDisburse() {
0907: in = new ByteArrayInputStream(bytes.toByteArray());
0908: super .readyToDisburse();
0909: }
0910:
0911: public void doneDisbursing() {
0912: super .doneDisbursing();
0913: if (optDumpBands && bytesForDump != null
0914: && bytesForDump.size() > 0) {
0915: try {
0916: dumpBand();
0917: } catch (IOException ee) {
0918: throw new RuntimeException(ee);
0919: }
0920: }
0921: in = null; // GC
0922: bytes = null; // GC
0923: bytesForDump = null; // GC
0924: }
0925:
0926: // alternative to readFrom:
0927: public void setInputStreamFrom(InputStream in)
0928: throws IOException {
0929: assert (bytes == null);
0930: assert (assertReadyToReadFrom(this , in));
0931: setPhase(READ_PHASE);
0932: this .in = in;
0933: if (optDumpBands) {
0934: // Tap the stream.
0935: bytesForDump = new ByteArrayOutputStream();
0936: this .in = new FilterInputStream(in) {
0937: public int read() throws IOException {
0938: int ch = in.read();
0939: if (ch >= 0)
0940: bytesForDump.write(ch);
0941: return ch;
0942: }
0943:
0944: public int read(byte b[], int off, int len)
0945: throws IOException {
0946: int nr = in.read(b, off, len);
0947: if (nr >= 0)
0948: bytesForDump.write(b, off, nr);
0949: return nr;
0950: }
0951: };
0952: }
0953: super .readyToDisburse();
0954: }
0955:
0956: public OutputStream collectorStream() {
0957: assert (phase() == COLLECT_PHASE);
0958: assert (bytes != null);
0959: return bytes;
0960: }
0961:
0962: public InputStream getInputStream() {
0963: assert (phase() == DISBURSE_PHASE);
0964: assert (in != null);
0965: return in;
0966: }
0967:
0968: public int getByte() throws IOException {
0969: int b = getInputStream().read();
0970: if (b < 0)
0971: throw new EOFException();
0972: return b;
0973: }
0974:
0975: public void putByte(int b) throws IOException {
0976: assert (b == (b & 0xFF));
0977: collectorStream().write(b);
0978: }
0979:
0980: public String toString() {
0981: return "byte " + super .toString();
0982: }
0983: }
0984:
0985: class IntBand extends ValueBand {
0986: // The usual coding for bands is 7bit/5byte/delta.
0987: public IntBand(String name, Coding regularCoding) {
0988: super (name, regularCoding);
0989: }
0990:
0991: public void putInt(int x) {
0992: assert (phase() == COLLECT_PHASE);
0993: addValue(x);
0994: }
0995:
0996: public int getInt() {
0997: return getValue();
0998: }
0999:
1000: /** Return the sum of all values in this band. */
1001: public int getIntTotal() {
1002: assert (phase() == DISBURSE_PHASE);
1003: // assert that this is the whole pass; no other reads allowed
1004: assert (valuesRemainingForDebug() == length());
1005: int total = 0;
1006: for (int k = length(); k > 0; k--) {
1007: total += getInt();
1008: }
1009: resetForSecondPass();
1010: return total;
1011: }
1012:
1013: /** Return the occurrence count of a specific value in this band. */
1014: public int getIntCount(int value) {
1015: assert (phase() == DISBURSE_PHASE);
1016: // assert that this is the whole pass; no other reads allowed
1017: assert (valuesRemainingForDebug() == length());
1018: int total = 0;
1019: for (int k = length(); k > 0; k--) {
1020: if (getInt() == value) {
1021: total += 1;
1022: }
1023: }
1024: resetForSecondPass();
1025: return total;
1026: }
1027: }
1028:
1029: static int getIntTotal(int[] values) {
1030: int total = 0;
1031: for (int i = 0; i < values.length; i++) {
1032: total += values[i];
1033: }
1034: return total;
1035: }
1036:
1037: class CPRefBand extends ValueBand {
1038: Index index;
1039: boolean nullOK;
1040:
1041: public CPRefBand(String name, Coding regularCoding, byte cpTag,
1042: boolean nullOK) {
1043: super (name, regularCoding);
1044: this .nullOK = nullOK;
1045: if (cpTag != CONSTANT_None)
1046: setBandIndex(this , cpTag);
1047: }
1048:
1049: public CPRefBand(String name, Coding regularCoding, byte cpTag) {
1050: this (name, regularCoding, cpTag, false);
1051: }
1052:
1053: public CPRefBand(String name, Coding regularCoding, Object undef) {
1054: this (name, regularCoding, CONSTANT_None, false);
1055: }
1056:
1057: public void setIndex(Index index) {
1058: this .index = index;
1059: }
1060:
1061: protected void readDataFrom(InputStream in) throws IOException {
1062: super .readDataFrom(in);
1063: assert (assertValidCPRefs(this ));
1064: }
1065:
1066: /** Write a constant pool reference. */
1067: public void putRef(Entry e) {
1068: assert (index != null);
1069: addValue(encodeRefOrNull(e, index));
1070: }
1071:
1072: public void putRef(Entry e, Index index) {
1073: assert (this .index == null);
1074: addValue(encodeRefOrNull(e, index));
1075: }
1076:
1077: public void putRef(Entry e, byte cptag) {
1078: putRef(e, getCPIndex(cptag));
1079: }
1080:
1081: public Entry getRef() {
1082: if (index == null)
1083: Utils.log.warning("No index for " + this );
1084: assert (index != null);
1085: return decodeRefOrNull(getValue(), index);
1086: }
1087:
1088: public Entry getRef(Index index) {
1089: assert (this .index == null);
1090: return decodeRefOrNull(getValue(), index);
1091: }
1092:
1093: public Entry getRef(byte cptag) {
1094: return getRef(getCPIndex(cptag));
1095: }
1096:
1097: private int encodeRefOrNull(Entry e, Index index) {
1098: int nonNullCode; // NNC is the coding which assumes nulls are rare
1099: if (e == null) {
1100: nonNullCode = -1; // negative values are rare
1101: } else {
1102: nonNullCode = encodeRef(e, index);
1103: }
1104: // If nulls are expected, increment, to make -1 code turn to 0.
1105: return (nullOK ? 1 : 0) + nonNullCode;
1106: }
1107:
1108: private Entry decodeRefOrNull(int code, Index index) {
1109: // Inverse to encodeRefOrNull...
1110: int nonNullCode = code - (nullOK ? 1 : 0);
1111: if (nonNullCode == -1) {
1112: return null;
1113: } else {
1114: return decodeRef(nonNullCode, index);
1115: }
1116: }
1117: }
1118:
1119: // Bootstrap support for CPRefBands. These are needed to record
1120: // intended CP indexes, before the CP has been created.
1121: private ArrayList allKQBands = new ArrayList();
1122: private ArrayList needPredefIndex = new ArrayList();
1123:
1124: int encodeRef(Entry e, Index ix) {
1125: int coding = ix.indexOf(e);
1126: if (verbose > 2)
1127: Utils.log.fine("putRef " + coding + " => " + e);
1128: return coding;
1129: }
1130:
1131: Entry decodeRef(int n, Index ix) {
1132: if (n < 0 || n >= ix.size())
1133: Utils.log.warning("decoding bad ref " + n + " in " + ix);
1134: Entry e = ix.getEntry(n);
1135: if (verbose > 2)
1136: Utils.log.fine("getRef " + n + " => " + e);
1137: return e;
1138: }
1139:
1140: private CodingChooser codingChooser;
1141:
1142: protected CodingChooser getCodingChooser() {
1143: if (codingChooser == null) {
1144: codingChooser = new CodingChooser(effort, basicCodings);
1145: if (codingChooser.stress != null
1146: && this instanceof PackageWriter) {
1147: // Twist the random state based on my first file.
1148: // This sends each segment off in a different direction.
1149: List classes = ((PackageWriter) this ).pkg.classes;
1150: if (!classes.isEmpty()) {
1151: Package.Class cls = (Package.Class) classes.get(0);
1152: codingChooser.addStressSeed(cls.getName()
1153: .hashCode());
1154: }
1155: }
1156: }
1157: return codingChooser;
1158: }
1159:
1160: public CodingMethod chooseCoding(int[] values, int start, int end,
1161: Coding regular, String bandName, int[] sizes) {
1162: assert (optVaryCodings);
1163: if (effort <= MIN_EFFORT) {
1164: return regular;
1165: }
1166: CodingChooser cc = getCodingChooser();
1167: if (verbose > 1 || cc.verbose > 1) {
1168: Utils.log.fine("--- chooseCoding " + bandName);
1169: }
1170: return cc.choose(values, start, end, regular, sizes);
1171: }
1172:
1173: static final byte[] defaultMetaCoding = { _meta_default };
1174: static final byte[] noMetaCoding = {};
1175:
1176: // The first value in a band is always coded with the default coding D.
1177: // If this first value X is an escape value, it actually represents the
1178: // first (and perhaps only) byte of a meta-coding.
1179: //
1180: // If D.S != 0 and D includes the range [-256..-1],
1181: // the escape values are in that range,
1182: // and the first byte XB is -1-X.
1183: //
1184: // If D.S == 0 and D includes the range [(D.L)..(D.L)+255],
1185: // the escape values are in that range,
1186: // and XB is X-(D.L).
1187: //
1188: // This representation is designed so that a band header is unlikely
1189: // to be confused with the initial value of a headerless band,
1190: // and yet so that a band header is likely to occupy only a byte or two.
1191: //
1192: // Result is in [0..255] if XB was successfully extracted, else -1.
1193: // See section "Coding Specifier Meta-Encoding" in the JSR 200 spec.
1194: protected static int decodeEscapeValue(int X, Coding regularCoding) {
1195: // The first value in a band is always coded with the default coding D.
1196: // If this first value X is an escape value, it actually represents the
1197: // first (and perhaps only) byte of a meta-coding.
1198: // Result is in [0..255] if XB was successfully extracted, else -1.
1199: if (regularCoding.B() == 1 || regularCoding.L() == 0)
1200: return -1; // degenerate regular coding (BYTE1)
1201: if (regularCoding.S() != 0) {
1202: if (-256 <= X && X <= -1 && regularCoding.min() <= -256) {
1203: int XB = -1 - X;
1204: assert (XB >= 0 && XB < 256);
1205: return XB;
1206: }
1207: } else {
1208: int L = regularCoding.L();
1209: if (L <= X && X <= L + 255
1210: && regularCoding.max() >= L + 255) {
1211: int XB = X - L;
1212: assert (XB >= 0 && XB < 256);
1213: return XB;
1214: }
1215: }
1216: return -1; // negative value for failure
1217: }
1218:
1219: // Inverse to decodeEscapeValue().
1220: protected static int encodeEscapeValue(int XB, Coding regularCoding) {
1221: assert (XB >= 0 && XB < 256);
1222: assert (regularCoding.B() > 1 && regularCoding.L() > 0);
1223: int X;
1224: if (regularCoding.S() != 0) {
1225: assert (regularCoding.min() <= -256);
1226: X = -1 - XB;
1227: } else {
1228: int L = regularCoding.L();
1229: assert (regularCoding.max() >= L + 255);
1230: X = XB + L;
1231: }
1232: assert (decodeEscapeValue(X, regularCoding) == XB) : (regularCoding
1233: + " XB=" + XB + " X=" + X);
1234: return X;
1235: }
1236:
1237: static {
1238: boolean checkXB = false;
1239: assert (checkXB = true);
1240: if (checkXB) {
1241: for (int i = 0; i < basicCodings.length; i++) {
1242: Coding D = basicCodings[i];
1243: if (D == null)
1244: continue;
1245: if (D.B() == 1)
1246: continue;
1247: if (D.L() == 0)
1248: continue;
1249: for (int XB = 0; XB <= 255; XB++) {
1250: // The following exercises decodeEscapeValue also:
1251: encodeEscapeValue(XB, D);
1252: }
1253: }
1254: }
1255: }
1256:
1257: class MultiBand extends Band {
1258: MultiBand(String name, Coding regularCoding) {
1259: super (name, regularCoding);
1260: }
1261:
1262: public Band init() {
1263: super .init();
1264: // This is all just to keep the asserts happy:
1265: setCapacity(0);
1266: if (phase() == EXPECT_PHASE) {
1267: // Fast forward:
1268: setPhase(READ_PHASE);
1269: setPhase(DISBURSE_PHASE);
1270: }
1271: return this ;
1272: }
1273:
1274: Band[] bands = new Band[10];
1275: int bandCount = 0;
1276:
1277: int size() {
1278: return bandCount;
1279: }
1280:
1281: Band get(int i) {
1282: assert (i < bandCount);
1283: return bands[i];
1284: }
1285:
1286: Band[] toArray() {
1287: return (Band[]) realloc(bands, bandCount);
1288: }
1289:
1290: void add(Band b) {
1291: assert (bandCount == 0 || notePrevForAssert(b,
1292: bands[bandCount - 1]));
1293: if (bandCount == bands.length) {
1294: bands = (Band[]) realloc(bands);
1295: }
1296: bands[bandCount++] = b;
1297: }
1298:
1299: ByteBand newByteBand(String name) {
1300: ByteBand b = new ByteBand(name);
1301: b.init();
1302: add(b);
1303: return b;
1304: }
1305:
1306: IntBand newIntBand(String name) {
1307: IntBand b = new IntBand(name, regularCoding);
1308: b.init();
1309: add(b);
1310: return b;
1311: }
1312:
1313: IntBand newIntBand(String name, Coding regularCoding) {
1314: IntBand b = new IntBand(name, regularCoding);
1315: b.init();
1316: add(b);
1317: return b;
1318: }
1319:
1320: MultiBand newMultiBand(String name, Coding regularCoding) {
1321: MultiBand b = new MultiBand(name, regularCoding);
1322: b.init();
1323: add(b);
1324: return b;
1325: }
1326:
1327: CPRefBand newCPRefBand(String name, byte cpTag) {
1328: CPRefBand b = new CPRefBand(name, regularCoding, cpTag);
1329: b.init();
1330: add(b);
1331: return b;
1332: }
1333:
1334: CPRefBand newCPRefBand(String name, Coding regularCoding,
1335: byte cpTag) {
1336: CPRefBand b = new CPRefBand(name, regularCoding, cpTag);
1337: b.init();
1338: add(b);
1339: return b;
1340: }
1341:
1342: CPRefBand newCPRefBand(String name, Coding regularCoding,
1343: byte cpTag, boolean nullOK) {
1344: CPRefBand b = new CPRefBand(name, regularCoding, cpTag,
1345: nullOK);
1346: b.init();
1347: add(b);
1348: return b;
1349: }
1350:
1351: int bandCount() {
1352: return bandCount;
1353: }
1354:
1355: private int cap = -1;
1356:
1357: public int capacity() {
1358: return cap;
1359: }
1360:
1361: public void setCapacity(int cap) {
1362: this .cap = cap;
1363: }
1364:
1365: public int length() {
1366: return 0;
1367: }
1368:
1369: public int valuesRemainingForDebug() {
1370: return 0;
1371: }
1372:
1373: protected void chooseBandCodings() throws IOException {
1374: // coding decision pass
1375: for (int i = 0; i < bandCount; i++) {
1376: Band b = bands[i];
1377: b.chooseBandCodings();
1378: }
1379: }
1380:
1381: protected long computeOutputSize() {
1382: // coding decision pass
1383: long sum = 0;
1384: for (int i = 0; i < bandCount; i++) {
1385: Band b = bands[i];
1386: long bsize = b.outputSize();
1387: assert (bsize >= 0) : b;
1388: sum += bsize;
1389: }
1390: // do not cache
1391: return sum;
1392: }
1393:
1394: protected void writeDataTo(OutputStream out) throws IOException {
1395: long preCount = 0;
1396: if (outputCounter != null)
1397: preCount = outputCounter.getCount();
1398: for (int i = 0; i < bandCount; i++) {
1399: Band b = bands[i];
1400: b.writeTo(out);
1401: if (outputCounter != null) {
1402: long postCount = outputCounter.getCount();
1403: long len = postCount - preCount;
1404: preCount = postCount;
1405: if ((verbose > 0 && len > 0) || verbose > 1) {
1406: Utils.log.info(" ...wrote " + len
1407: + " bytes from " + b);
1408: }
1409: }
1410: }
1411: }
1412:
1413: protected void readDataFrom(InputStream in) throws IOException {
1414: assert (false); // not called?
1415: for (int i = 0; i < bandCount; i++) {
1416: Band b = bands[i];
1417: b.readFrom(in);
1418: if ((verbose > 0 && b.length() > 0) || verbose > 1) {
1419: Utils.log.info(" ...read " + b);
1420: }
1421: }
1422: }
1423:
1424: public String toString() {
1425: return "{" + bandCount() + " bands: " + super .toString()
1426: + "}";
1427: }
1428: }
1429:
1430: /**
1431: * An output stream which counts the number of bytes written.
1432: */
1433: private static class ByteCounter extends FilterOutputStream {
1434: // (should go public under the name CountingOutputStream?)
1435:
1436: private long count;
1437:
1438: public ByteCounter(OutputStream out) {
1439: super (out);
1440: }
1441:
1442: public long getCount() {
1443: return count;
1444: }
1445:
1446: public void setCount(long c) {
1447: count = c;
1448: }
1449:
1450: public void write(int b) throws IOException {
1451: count++;
1452: if (out != null)
1453: out.write(b);
1454: }
1455:
1456: public void write(byte b[], int off, int len)
1457: throws IOException {
1458: count += len;
1459: if (out != null)
1460: out.write(b, off, len);
1461: }
1462:
1463: public String toString() {
1464: return String.valueOf(getCount());
1465: }
1466: }
1467:
1468: ByteCounter outputCounter;
1469:
1470: void writeAllBandsTo(OutputStream out) throws IOException {
1471: // Wrap a byte-counter around the output stream.
1472: outputCounter = new ByteCounter(out);
1473: out = outputCounter;
1474: all_bands.writeTo(out);
1475: if (verbose > 0) {
1476: long nbytes = outputCounter.getCount();
1477: Utils.log.info("Wrote total of " + nbytes + " bytes.");
1478: assert (nbytes == archiveSize0 + archiveSize1);
1479: }
1480: outputCounter = null;
1481: }
1482:
1483: // random AO_XXX bits, decoded from the archive header
1484: protected int archiveOptions;
1485:
1486: // archiveSize1 sizes most of the archive [archive_options..file_bits).
1487: protected long archiveSize0; // size through archive_size_lo
1488: protected long archiveSize1; // size reported in archive_header
1489: protected int archiveNextCount; // reported in archive_header
1490:
1491: static final int AH_LENGTH_0 = 3; //minver, majver, options
1492: static final int AH_ARCHIVE_SIZE_HI = 0;
1493: static final int AH_ARCHIVE_SIZE_LO = 1;
1494: static final int AH_LENGTH_S = 2; //optional size hi/lo
1495: static final int AH_LENGTH = 26; // mentioned in spec
1496: // Length contributions from optional header fields:
1497: static final int AH_FILE_HEADER_LEN = 5; // sizehi/lo/next/modtime/files
1498: static final int AH_SPECIAL_FORMAT_LEN = 2; // layouts/band-headers
1499: static final int AH_CP_NUMBER_LEN = 4; // int/float/long/double
1500: static final int AH_LENGTH_MIN = AH_LENGTH
1501: - (AH_SPECIAL_FORMAT_LEN + AH_FILE_HEADER_LEN + AH_CP_NUMBER_LEN);
1502:
1503: // Common structure of attribute band groups:
1504: static final int AB_FLAGS_HI = 0;
1505: static final int AB_FLAGS_LO = 1;
1506: static final int AB_ATTR_COUNT = 2;
1507: static final int AB_ATTR_INDEXES = 3;
1508: static final int AB_ATTR_CALLS = 4;
1509:
1510: static IntBand getAttrBand(MultiBand xxx_attr_bands, int which) {
1511: IntBand b = (IntBand) xxx_attr_bands.get(which);
1512: switch (which) {
1513: case AB_FLAGS_HI:
1514: assert (b.name().endsWith("_flags_hi"));
1515: break;
1516: case AB_FLAGS_LO:
1517: assert (b.name().endsWith("_flags_lo"));
1518: break;
1519: case AB_ATTR_COUNT:
1520: assert (b.name().endsWith("_attr_count"));
1521: break;
1522: case AB_ATTR_INDEXES:
1523: assert (b.name().endsWith("_attr_indexes"));
1524: break;
1525: case AB_ATTR_CALLS:
1526: assert (b.name().endsWith("_attr_calls"));
1527: break;
1528: default:
1529: assert (false);
1530: break;
1531: }
1532: return b;
1533: }
1534:
1535: static private final boolean NULL_IS_OK = true;
1536:
1537: MultiBand all_bands = (MultiBand) new MultiBand("(package)",
1538: UNSIGNED5).init();
1539:
1540: // file header (various random bytes)
1541: ByteBand archive_magic = all_bands.newByteBand("archive_magic");
1542: IntBand archive_header_0 = all_bands.newIntBand("archive_header_0",
1543: UNSIGNED5);
1544: IntBand archive_header_S = all_bands.newIntBand("archive_header_S",
1545: UNSIGNED5);
1546: IntBand archive_header_1 = all_bands.newIntBand("archive_header_1",
1547: UNSIGNED5);
1548: ByteBand band_headers = all_bands.newByteBand("band_headers");
1549:
1550: // constant pool contents
1551: MultiBand cp_bands = all_bands.newMultiBand("(constant_pool)",
1552: DELTA5);
1553: IntBand cp_Utf8_prefix = cp_bands.newIntBand("cp_Utf8_prefix");
1554: IntBand cp_Utf8_suffix = cp_bands.newIntBand("cp_Utf8_suffix",
1555: UNSIGNED5);
1556: IntBand cp_Utf8_chars = cp_bands.newIntBand("cp_Utf8_chars", CHAR3);
1557: IntBand cp_Utf8_big_suffix = cp_bands
1558: .newIntBand("cp_Utf8_big_suffix");
1559: MultiBand cp_Utf8_big_chars = cp_bands.newMultiBand(
1560: "(cp_Utf8_big_chars)", DELTA5);
1561: IntBand cp_Int = cp_bands.newIntBand("cp_Int", UDELTA5);
1562: IntBand cp_Float = cp_bands.newIntBand("cp_Float", UDELTA5);
1563: IntBand cp_Long_hi = cp_bands.newIntBand("cp_Long_hi", UDELTA5);
1564: IntBand cp_Long_lo = cp_bands.newIntBand("cp_Long_lo");
1565: IntBand cp_Double_hi = cp_bands.newIntBand("cp_Double_hi", UDELTA5);
1566: IntBand cp_Double_lo = cp_bands.newIntBand("cp_Double_lo");
1567: CPRefBand cp_String = cp_bands.newCPRefBand("cp_String", UDELTA5,
1568: CONSTANT_Utf8);
1569: CPRefBand cp_Class = cp_bands.newCPRefBand("cp_Class", UDELTA5,
1570: CONSTANT_Utf8);
1571: CPRefBand cp_Signature_form = cp_bands.newCPRefBand(
1572: "cp_Signature_form", CONSTANT_Utf8);
1573: CPRefBand cp_Signature_classes = cp_bands.newCPRefBand(
1574: "cp_Signature_classes", UDELTA5, CONSTANT_Class);
1575: CPRefBand cp_Descr_name = cp_bands.newCPRefBand("cp_Descr_name",
1576: CONSTANT_Utf8);
1577: CPRefBand cp_Descr_type = cp_bands.newCPRefBand("cp_Descr_type",
1578: UDELTA5, CONSTANT_Signature);
1579: CPRefBand cp_Field_class = cp_bands.newCPRefBand("cp_Field_class",
1580: CONSTANT_Class);
1581: CPRefBand cp_Field_desc = cp_bands.newCPRefBand("cp_Field_desc",
1582: UDELTA5, CONSTANT_NameandType);
1583: CPRefBand cp_Method_class = cp_bands.newCPRefBand(
1584: "cp_Method_class", CONSTANT_Class);
1585: CPRefBand cp_Method_desc = cp_bands.newCPRefBand("cp_Method_desc",
1586: UDELTA5, CONSTANT_NameandType);
1587: CPRefBand cp_Imethod_class = cp_bands.newCPRefBand(
1588: "cp_Imethod_class", CONSTANT_Class);
1589: CPRefBand cp_Imethod_desc = cp_bands.newCPRefBand(
1590: "cp_Imethod_desc", UDELTA5, CONSTANT_NameandType);
1591:
1592: // bands for carrying attribute definitions:
1593: MultiBand attr_definition_bands = all_bands.newMultiBand(
1594: "(attr_definition_bands)", UNSIGNED5);
1595: ByteBand attr_definition_headers = attr_definition_bands
1596: .newByteBand("attr_definition_headers");
1597: CPRefBand attr_definition_name = attr_definition_bands
1598: .newCPRefBand("attr_definition_name", CONSTANT_Utf8);
1599: CPRefBand attr_definition_layout = attr_definition_bands
1600: .newCPRefBand("attr_definition_layout", CONSTANT_Utf8);
1601:
1602: // bands for hardwired InnerClasses attribute (shared across the package)
1603: MultiBand ic_bands = all_bands.newMultiBand("(ic_bands)", DELTA5);
1604: CPRefBand ic_this _class = ic_bands.newCPRefBand("ic_this_class",
1605: UDELTA5, CONSTANT_Class);
1606: IntBand ic_flags = ic_bands.newIntBand("ic_flags", UNSIGNED5);
1607: // These bands contain data only where flags sets ACC_IC_LONG_FORM:
1608: CPRefBand ic_outer_class = ic_bands.newCPRefBand("ic_outer_class",
1609: DELTA5, CONSTANT_Class, NULL_IS_OK);
1610: CPRefBand ic_name = ic_bands.newCPRefBand("ic_name", DELTA5,
1611: CONSTANT_Utf8, NULL_IS_OK);
1612:
1613: // bands for carrying class schema information:
1614: MultiBand class_bands = all_bands.newMultiBand("(class_bands)",
1615: DELTA5);
1616: CPRefBand class_this = class_bands.newCPRefBand("class_this",
1617: CONSTANT_Class);
1618: CPRefBand class_super = class_bands.newCPRefBand("class_super",
1619: CONSTANT_Class);
1620: IntBand class_interface_count = class_bands
1621: .newIntBand("class_interface_count");
1622: CPRefBand class_interface = class_bands.newCPRefBand(
1623: "class_interface", CONSTANT_Class);
1624:
1625: // bands for class members
1626: IntBand class_field_count = class_bands
1627: .newIntBand("class_field_count");
1628: IntBand class_method_count = class_bands
1629: .newIntBand("class_method_count");
1630:
1631: CPRefBand field_descr = class_bands.newCPRefBand("field_descr",
1632: CONSTANT_NameandType);
1633: MultiBand field_attr_bands = class_bands.newMultiBand(
1634: "(field_attr_bands)", UNSIGNED5);
1635: IntBand field_flags_hi = field_attr_bands
1636: .newIntBand("field_flags_hi");
1637: IntBand field_flags_lo = field_attr_bands
1638: .newIntBand("field_flags_lo");
1639: IntBand field_attr_count = field_attr_bands
1640: .newIntBand("field_attr_count");
1641: IntBand field_attr_indexes = field_attr_bands
1642: .newIntBand("field_attr_indexes");
1643: IntBand field_attr_calls = field_attr_bands
1644: .newIntBand("field_attr_calls");
1645:
1646: // bands for predefined field attributes
1647: CPRefBand field_ConstantValue_KQ = field_attr_bands.newCPRefBand(
1648: "field_ConstantValue_KQ", CONSTANT_Literal);
1649: CPRefBand field_Signature_RS = field_attr_bands.newCPRefBand(
1650: "field_Signature_RS", CONSTANT_Signature);
1651: MultiBand field_metadata_bands = field_attr_bands.newMultiBand(
1652: "(field_metadata_bands)", UNSIGNED5);
1653:
1654: CPRefBand method_descr = class_bands.newCPRefBand("method_descr",
1655: MDELTA5, CONSTANT_NameandType);
1656: MultiBand method_attr_bands = class_bands.newMultiBand(
1657: "(method_attr_bands)", UNSIGNED5);
1658: IntBand method_flags_hi = method_attr_bands
1659: .newIntBand("method_flags_hi");
1660: IntBand method_flags_lo = method_attr_bands
1661: .newIntBand("method_flags_lo");
1662: IntBand method_attr_count = method_attr_bands
1663: .newIntBand("method_attr_count");
1664: IntBand method_attr_indexes = method_attr_bands
1665: .newIntBand("method_attr_indexes");
1666: IntBand method_attr_calls = method_attr_bands
1667: .newIntBand("method_attr_calls");
1668: // band for predefined method attributes
1669: IntBand method_Exceptions_N = method_attr_bands
1670: .newIntBand("method_Exceptions_N");
1671: CPRefBand method_Exceptions_RC = method_attr_bands.newCPRefBand(
1672: "method_Exceptions_RC", CONSTANT_Class);
1673: CPRefBand method_Signature_RS = method_attr_bands.newCPRefBand(
1674: "method_Signature_RS", CONSTANT_Signature);
1675: MultiBand method_metadata_bands = method_attr_bands.newMultiBand(
1676: "(method_metadata_bands)", UNSIGNED5);
1677:
1678: MultiBand class_attr_bands = class_bands.newMultiBand(
1679: "(class_attr_bands)", UNSIGNED5);
1680: IntBand class_flags_hi = class_attr_bands
1681: .newIntBand("class_flags_hi");
1682: IntBand class_flags_lo = class_attr_bands
1683: .newIntBand("class_flags_lo");
1684: IntBand class_attr_count = class_attr_bands
1685: .newIntBand("class_attr_count");
1686: IntBand class_attr_indexes = class_attr_bands
1687: .newIntBand("class_attr_indexes");
1688: IntBand class_attr_calls = class_attr_bands
1689: .newIntBand("class_attr_calls");
1690: // band for predefined SourceFile and other class attributes
1691: CPRefBand class_SourceFile_RUN = class_attr_bands.newCPRefBand(
1692: "class_SourceFile_RUN", UNSIGNED5, CONSTANT_Utf8,
1693: NULL_IS_OK);
1694: CPRefBand class_EnclosingMethod_RC = class_attr_bands.newCPRefBand(
1695: "class_EnclosingMethod_RC", CONSTANT_Class);
1696: CPRefBand class_EnclosingMethod_RDN = class_attr_bands
1697: .newCPRefBand("class_EnclosingMethod_RDN", UNSIGNED5,
1698: CONSTANT_NameandType, NULL_IS_OK);
1699: CPRefBand class_Signature_RS = class_attr_bands.newCPRefBand(
1700: "class_Signature_RS", CONSTANT_Signature);
1701: MultiBand class_metadata_bands = class_attr_bands.newMultiBand(
1702: "(class_metadata_bands)", UNSIGNED5);
1703: IntBand class_InnerClasses_N = class_attr_bands
1704: .newIntBand("class_InnerClasses_N");
1705: CPRefBand class_InnerClasses_RC = class_attr_bands.newCPRefBand(
1706: "class_InnerClasses_RC", CONSTANT_Class);
1707: IntBand class_InnerClasses_F = class_attr_bands
1708: .newIntBand("class_InnerClasses_F");
1709: CPRefBand class_InnerClasses_outer_RCN = class_attr_bands
1710: .newCPRefBand("class_InnerClasses_outer_RCN", UNSIGNED5,
1711: CONSTANT_Class, NULL_IS_OK);
1712: CPRefBand class_InnerClasses_name_RUN = class_attr_bands
1713: .newCPRefBand("class_InnerClasses_name_RUN", UNSIGNED5,
1714: CONSTANT_Utf8, NULL_IS_OK);
1715: IntBand class_ClassFile_version_minor_H = class_attr_bands
1716: .newIntBand("class_ClassFile_version_minor_H");
1717: IntBand class_ClassFile_version_major_H = class_attr_bands
1718: .newIntBand("class_ClassFile_version_major_H");
1719:
1720: MultiBand code_bands = class_bands.newMultiBand("(code_bands)",
1721: UNSIGNED5);
1722: ByteBand code_headers = code_bands.newByteBand("code_headers"); //BYTE1
1723: IntBand code_max_stack = code_bands.newIntBand("code_max_stack",
1724: UNSIGNED5);
1725: IntBand code_max_na_locals = code_bands.newIntBand(
1726: "code_max_na_locals", UNSIGNED5);
1727: IntBand code_handler_count = code_bands.newIntBand(
1728: "code_handler_count", UNSIGNED5);
1729: IntBand code_handler_start_P = code_bands.newIntBand(
1730: "code_handler_start_P", BCI5);
1731: IntBand code_handler_end_PO = code_bands.newIntBand(
1732: "code_handler_end_PO", BRANCH5);
1733: IntBand code_handler_catch_PO = code_bands.newIntBand(
1734: "code_handler_catch_PO", BRANCH5);
1735: CPRefBand code_handler_class_RCN = code_bands.newCPRefBand(
1736: "code_handler_class_RCN", UNSIGNED5, CONSTANT_Class,
1737: NULL_IS_OK);
1738:
1739: MultiBand code_attr_bands = class_bands.newMultiBand(
1740: "(code_attr_bands)", UNSIGNED5);
1741: IntBand code_flags_hi = code_attr_bands.newIntBand("code_flags_hi");
1742: IntBand code_flags_lo = code_attr_bands.newIntBand("code_flags_lo");
1743: IntBand code_attr_count = code_attr_bands
1744: .newIntBand("code_attr_count");
1745: IntBand code_attr_indexes = code_attr_bands
1746: .newIntBand("code_attr_indexes");
1747: IntBand code_attr_calls = code_attr_bands
1748: .newIntBand("code_attr_calls");
1749:
1750: MultiBand stackmap_bands = code_attr_bands.newMultiBand(
1751: "StackMapTable_bands", UNSIGNED5);
1752: IntBand code_StackMapTable_N = stackmap_bands
1753: .newIntBand("code_StackMapTable_N");
1754: IntBand code_StackMapTable_frame_T = stackmap_bands.newIntBand(
1755: "code_StackMapTable_frame_T", BYTE1);
1756: IntBand code_StackMapTable_local_N = stackmap_bands
1757: .newIntBand("code_StackMapTable_local_N");
1758: IntBand code_StackMapTable_stack_N = stackmap_bands
1759: .newIntBand("code_StackMapTable_stack_N");
1760: IntBand code_StackMapTable_offset = stackmap_bands.newIntBand(
1761: "code_StackMapTable_offset", UNSIGNED5);
1762: IntBand code_StackMapTable_T = stackmap_bands.newIntBand(
1763: "code_StackMapTable_T", BYTE1);
1764: CPRefBand code_StackMapTable_RC = stackmap_bands.newCPRefBand(
1765: "code_StackMapTable_RC", CONSTANT_Class);
1766: IntBand code_StackMapTable_P = stackmap_bands.newIntBand(
1767: "code_StackMapTable_P", BCI5);
1768:
1769: // bands for predefined LineNumberTable attribute
1770: IntBand code_LineNumberTable_N = code_attr_bands
1771: .newIntBand("code_LineNumberTable_N");
1772: IntBand code_LineNumberTable_bci_P = code_attr_bands.newIntBand(
1773: "code_LineNumberTable_bci_P", BCI5);
1774: IntBand code_LineNumberTable_line = code_attr_bands
1775: .newIntBand("code_LineNumberTable_line");
1776:
1777: // bands for predefined LocalVariable{Type}Table attributes
1778: IntBand code_LocalVariableTable_N = code_attr_bands
1779: .newIntBand("code_LocalVariableTable_N");
1780: IntBand code_LocalVariableTable_bci_P = code_attr_bands.newIntBand(
1781: "code_LocalVariableTable_bci_P", BCI5);
1782: IntBand code_LocalVariableTable_span_O = code_attr_bands
1783: .newIntBand("code_LocalVariableTable_span_O", BRANCH5);
1784: CPRefBand code_LocalVariableTable_name_RU = code_attr_bands
1785: .newCPRefBand("code_LocalVariableTable_name_RU",
1786: CONSTANT_Utf8);
1787: CPRefBand code_LocalVariableTable_type_RS = code_attr_bands
1788: .newCPRefBand("code_LocalVariableTable_type_RS",
1789: CONSTANT_Signature);
1790: IntBand code_LocalVariableTable_slot = code_attr_bands
1791: .newIntBand("code_LocalVariableTable_slot");
1792: IntBand code_LocalVariableTypeTable_N = code_attr_bands
1793: .newIntBand("code_LocalVariableTypeTable_N");
1794: IntBand code_LocalVariableTypeTable_bci_P = code_attr_bands
1795: .newIntBand("code_LocalVariableTypeTable_bci_P", BCI5);
1796: IntBand code_LocalVariableTypeTable_span_O = code_attr_bands
1797: .newIntBand("code_LocalVariableTypeTable_span_O", BRANCH5);
1798: CPRefBand code_LocalVariableTypeTable_name_RU = code_attr_bands
1799: .newCPRefBand("code_LocalVariableTypeTable_name_RU",
1800: CONSTANT_Utf8);
1801: CPRefBand code_LocalVariableTypeTable_type_RS = code_attr_bands
1802: .newCPRefBand("code_LocalVariableTypeTable_type_RS",
1803: CONSTANT_Signature);
1804: IntBand code_LocalVariableTypeTable_slot = code_attr_bands
1805: .newIntBand("code_LocalVariableTypeTable_slot");
1806:
1807: // bands for bytecodes
1808: MultiBand bc_bands = all_bands.newMultiBand("(byte_codes)",
1809: UNSIGNED5);
1810: ByteBand bc_codes = bc_bands.newByteBand("bc_codes"); //BYTE1
1811: // remaining bands provide typed opcode fields required by the bc_codes
1812:
1813: IntBand bc_case_count = bc_bands.newIntBand("bc_case_count"); // *switch
1814: IntBand bc_case_value = bc_bands
1815: .newIntBand("bc_case_value", DELTA5); // *switch
1816: ByteBand bc_byte = bc_bands.newByteBand("bc_byte"); //BYTE1 // bipush, iinc, *newarray
1817: IntBand bc_short = bc_bands.newIntBand("bc_short", DELTA5); // sipush, wide iinc
1818: IntBand bc_local = bc_bands.newIntBand("bc_local"); // *load, *store, iinc, ret
1819: IntBand bc_label = bc_bands.newIntBand("bc_label", BRANCH5); // if*, goto*, jsr*, *switch
1820:
1821: // Most CP refs exhibit some correlation, and benefit from delta coding.
1822: // The notable exceptions are class and method references.
1823:
1824: // ldc* operands:
1825: CPRefBand bc_intref = bc_bands.newCPRefBand("bc_intref", DELTA5,
1826: CONSTANT_Integer);
1827: CPRefBand bc_floatref = bc_bands.newCPRefBand("bc_floatref",
1828: DELTA5, CONSTANT_Float);
1829: CPRefBand bc_longref = bc_bands.newCPRefBand("bc_longref", DELTA5,
1830: CONSTANT_Long);
1831: CPRefBand bc_doubleref = bc_bands.newCPRefBand("bc_doubleref",
1832: DELTA5, CONSTANT_Double);
1833: CPRefBand bc_stringref = bc_bands.newCPRefBand("bc_stringref",
1834: DELTA5, CONSTANT_String);
1835:
1836: // nulls produced by bc_classref are taken to mean the current class
1837: CPRefBand bc_classref = bc_bands.newCPRefBand("bc_classref",
1838: UNSIGNED5, CONSTANT_Class, NULL_IS_OK); // new, *anew*, c*cast, i*of, ldc
1839: CPRefBand bc_fieldref = bc_bands.newCPRefBand("bc_fieldref",
1840: DELTA5, CONSTANT_Fieldref); // get*, put*
1841: CPRefBand bc_methodref = bc_bands.newCPRefBand("bc_methodref",
1842: CONSTANT_Methodref); // invoke[vs]*
1843: CPRefBand bc_imethodref = bc_bands.newCPRefBand("bc_imethodref",
1844: DELTA5, CONSTANT_InterfaceMethodref); // invokeinterface
1845:
1846: // _self_linker_op family
1847: CPRefBand bc_this field = bc_bands.newCPRefBand("bc_thisfield",
1848: CONSTANT_None); // any field within cur. class
1849: CPRefBand bc_super field = bc_bands.newCPRefBand("bc_superfield",
1850: CONSTANT_None); // any field within superclass
1851: CPRefBand bc_this method = bc_bands.newCPRefBand("bc_thismethod",
1852: CONSTANT_None); // any method within cur. class
1853: CPRefBand bc_super method = bc_bands.newCPRefBand("bc_supermethod",
1854: CONSTANT_None); // any method within superclass
1855: // bc_invokeinit family:
1856: IntBand bc_initref = bc_bands.newIntBand("bc_initref");
1857: // escapes
1858: CPRefBand bc_escref = bc_bands.newCPRefBand("bc_escref",
1859: CONSTANT_All);
1860: IntBand bc_escrefsize = bc_bands.newIntBand("bc_escrefsize");
1861: IntBand bc_escsize = bc_bands.newIntBand("bc_escsize");
1862: ByteBand bc_escbyte = bc_bands.newByteBand("bc_escbyte");
1863:
1864: // bands for carrying resource files and file attributes:
1865: MultiBand file_bands = all_bands.newMultiBand("(file_bands)",
1866: UNSIGNED5);
1867: CPRefBand file_name = file_bands.newCPRefBand("file_name",
1868: CONSTANT_Utf8);
1869: IntBand file_size_hi = file_bands.newIntBand("file_size_hi");
1870: IntBand file_size_lo = file_bands.newIntBand("file_size_lo");
1871: IntBand file_modtime = file_bands
1872: .newIntBand("file_modtime", DELTA5);
1873: IntBand file_options = file_bands.newIntBand("file_options");
1874: ByteBand file_bits = file_bands.newByteBand("file_bits");
1875:
1876: // End of band definitions!
1877:
1878: /** Given CP indexes, distribute tag-specific indexes to bands. */
1879: protected void setBandIndexes() {
1880: // Handle prior calls to setBandIndex:
1881: for (Iterator i = needPredefIndex.iterator(); i.hasNext();) {
1882: Object[] need = (Object[]) i.next();
1883: CPRefBand b = (CPRefBand) need[0];
1884: Byte which = (Byte) need[1];
1885: b.setIndex(getCPIndex(which.byteValue()));
1886: }
1887: needPredefIndex = null; // no more predefs
1888:
1889: if (verbose > 3) {
1890: printCDecl(all_bands);
1891: }
1892: }
1893:
1894: protected void setBandIndex(CPRefBand b, byte which) {
1895: Object[] need = { b, new Byte(which) };
1896: if (which == CONSTANT_Literal) {
1897: // I.e., attribute layouts KQ (no null) or KQN (null ok).
1898: allKQBands.add(b);
1899: } else if (needPredefIndex != null) {
1900: needPredefIndex.add(need);
1901: } else {
1902: // Not in predefinition mode; getCPIndex now works.
1903: b.setIndex(getCPIndex(which));
1904: }
1905: }
1906:
1907: protected void setConstantValueIndex(Class.Field f) {
1908: Index ix = null;
1909: if (f != null) {
1910: byte tag = f.getLiteralTag();
1911: ix = getCPIndex(tag);
1912: if (verbose > 2)
1913: Utils.log.fine("setConstantValueIndex " + f + " "
1914: + ConstantPool.tagName(tag) + " => " + ix);
1915: assert (ix != null);
1916: }
1917: // Typically, allKQBands is the singleton of field_ConstantValue_KQ.
1918: for (Iterator i = allKQBands.iterator(); i.hasNext();) {
1919: CPRefBand xxx_KQ = (CPRefBand) i.next();
1920: xxx_KQ.setIndex(ix);
1921: }
1922: }
1923:
1924: // Table of bands which contain metadata.
1925: protected MultiBand[] metadataBands = new MultiBand[ATTR_CONTEXT_LIMIT];
1926: {
1927: metadataBands[ATTR_CONTEXT_CLASS] = class_metadata_bands;
1928: metadataBands[ATTR_CONTEXT_FIELD] = field_metadata_bands;
1929: metadataBands[ATTR_CONTEXT_METHOD] = method_metadata_bands;
1930: }
1931:
1932: // Attribute layouts.
1933: public static final int ADH_CONTEXT_MASK = 0x3; // (ad_hdr & ADH_CONTEXT_MASK)
1934: public static final int ADH_BIT_SHIFT = 0x2; // (ad_hdr >> ADH_BIT_SHIFT)
1935: public static final int ADH_BIT_IS_LSB = 1;
1936: public static final int ATTR_INDEX_OVERFLOW = -1;
1937:
1938: public int[] attrIndexLimit = new int[ATTR_CONTEXT_LIMIT];
1939: // Each index limit is either 32 or 63, depending on AO_HAVE_XXX_FLAGS_HI.
1940:
1941: // Which flag bits are taken over by attributes?
1942: protected long[] attrFlagMask = new long[ATTR_CONTEXT_LIMIT];
1943: // Which flag bits have been taken over explicitly?
1944: protected long[] attrDefSeen = new long[ATTR_CONTEXT_LIMIT];
1945:
1946: // What pseudo-attribute bits are there to watch for?
1947: protected int[] attrOverflowMask = new int[ATTR_CONTEXT_LIMIT];
1948: protected int attrClassFileVersionMask;
1949:
1950: // Mapping from Attribute.Layout to Band[] (layout element bands).
1951: protected HashMap attrBandTable = new HashMap();
1952:
1953: // Well-known attributes:
1954: protected final Attribute.Layout attrCodeEmpty;
1955: protected final Attribute.Layout attrInnerClassesEmpty;
1956: protected final Attribute.Layout attrClassFileVersion;
1957: protected final Attribute.Layout attrConstantValue;
1958:
1959: // Mapping from Attribute.Layout to Integer (inverse of attrDefs)
1960: HashMap attrIndexTable = new HashMap();
1961:
1962: // Mapping from attribute index (<32 are flag bits) to attributes.
1963: protected ArrayList[] attrDefs = new ArrayList[ATTR_CONTEXT_LIMIT];
1964: {
1965: for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
1966: assert (attrIndexLimit[i] == 0);
1967: attrIndexLimit[i] = 32; // just for the sake of predefs.
1968: attrDefs[i] = new ArrayList(Collections.nCopies(
1969: attrIndexLimit[i], null));
1970: }
1971:
1972: // Add predefined attribute definitions:
1973: attrInnerClassesEmpty = predefineAttribute(
1974: CLASS_ATTR_InnerClasses, ATTR_CONTEXT_CLASS, null,
1975: "InnerClasses", "");
1976: assert (attrInnerClassesEmpty == Package.attrInnerClassesEmpty);
1977: predefineAttribute(CLASS_ATTR_SourceFile, ATTR_CONTEXT_CLASS,
1978: new Band[] { class_SourceFile_RUN }, "SourceFile",
1979: "RUNH");
1980: predefineAttribute(CLASS_ATTR_EnclosingMethod,
1981: ATTR_CONTEXT_CLASS, new Band[] {
1982: class_EnclosingMethod_RC,
1983: class_EnclosingMethod_RDN }, "EnclosingMethod",
1984: "RCHRDNH");
1985: attrClassFileVersion = predefineAttribute(
1986: CLASS_ATTR_ClassFile_version, ATTR_CONTEXT_CLASS,
1987: new Band[] { class_ClassFile_version_minor_H,
1988: class_ClassFile_version_major_H },
1989: ".ClassFile.version", "HH");
1990: predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_CLASS,
1991: new Band[] { class_Signature_RS }, "Signature", "RSH");
1992: predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_CLASS, null,
1993: "Deprecated", "");
1994: //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_CLASS, null,
1995: // "Synthetic", "");
1996: predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_CLASS, null,
1997: ".Overflow", "");
1998: attrConstantValue = predefineAttribute(
1999: FIELD_ATTR_ConstantValue, ATTR_CONTEXT_FIELD,
2000: new Band[] { field_ConstantValue_KQ }, "ConstantValue",
2001: "KQH");
2002: predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_FIELD,
2003: new Band[] { field_Signature_RS }, "Signature", "RSH");
2004: predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_FIELD, null,
2005: "Deprecated", "");
2006: //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_FIELD, null,
2007: // "Synthetic", "");
2008: predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_FIELD, null,
2009: ".Overflow", "");
2010: attrCodeEmpty = predefineAttribute(METHOD_ATTR_Code,
2011: ATTR_CONTEXT_METHOD, null, "Code", "");
2012: predefineAttribute(
2013: METHOD_ATTR_Exceptions,
2014: ATTR_CONTEXT_METHOD,
2015: new Band[] { method_Exceptions_N, method_Exceptions_RC },
2016: "Exceptions", "NH[RCH]");
2017: assert (attrCodeEmpty == Package.attrCodeEmpty);
2018: predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_METHOD,
2019: new Band[] { method_Signature_RS }, "Signature", "RSH");
2020: predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_METHOD,
2021: null, "Deprecated", "");
2022: //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_METHOD, null,
2023: // "Synthetic", "");
2024: predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_METHOD, null,
2025: ".Overflow", "");
2026:
2027: for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) {
2028: MultiBand xxx_metadata_bands = metadataBands[ctype];
2029: if (xxx_metadata_bands == null)
2030: continue; // no code attrs
2031:
2032: // These arguments cause the bands to be built
2033: // automatically for this complicated layout:
2034: predefineAttribute(X_ATTR_RuntimeVisibleAnnotations,
2035: ATTR_CONTEXT_NAME[ctype] + "_RVA_",
2036: xxx_metadata_bands, Attribute.lookup(null, ctype,
2037: "RuntimeVisibleAnnotations"));
2038: predefineAttribute(X_ATTR_RuntimeInvisibleAnnotations,
2039: ATTR_CONTEXT_NAME[ctype] + "_RIA_",
2040: xxx_metadata_bands, Attribute.lookup(null, ctype,
2041: "RuntimeInvisibleAnnotations"));
2042: if (ctype != ATTR_CONTEXT_METHOD)
2043: continue;
2044:
2045: predefineAttribute(
2046: METHOD_ATTR_RuntimeVisibleParameterAnnotations,
2047: "method_RVPA_", xxx_metadata_bands,
2048: Attribute.lookup(null, ctype,
2049: "RuntimeVisibleParameterAnnotations"));
2050: predefineAttribute(
2051: METHOD_ATTR_RuntimeInvisibleParameterAnnotations,
2052: "method_RIPA_", xxx_metadata_bands,
2053: Attribute.lookup(null, ctype,
2054: "RuntimeInvisibleParameterAnnotations"));
2055: predefineAttribute(METHOD_ATTR_AnnotationDefault,
2056: "method_AD_", xxx_metadata_bands, Attribute.lookup(
2057: null, ctype, "AnnotationDefault"));
2058: }
2059:
2060: Attribute.Layout stackMapDef = Attribute.lookup(null,
2061: ATTR_CONTEXT_CODE, "StackMapTable").layout();
2062: predefineAttribute(CODE_ATTR_StackMapTable, ATTR_CONTEXT_CODE,
2063: stackmap_bands.toArray(), stackMapDef.name(),
2064: stackMapDef.layout());
2065:
2066: predefineAttribute(CODE_ATTR_LineNumberTable,
2067: ATTR_CONTEXT_CODE, new Band[] { code_LineNumberTable_N,
2068: code_LineNumberTable_bci_P,
2069: code_LineNumberTable_line }, "LineNumberTable",
2070: "NH[PHH]");
2071: predefineAttribute(CODE_ATTR_LocalVariableTable,
2072: ATTR_CONTEXT_CODE, new Band[] {
2073: code_LocalVariableTable_N,
2074: code_LocalVariableTable_bci_P,
2075: code_LocalVariableTable_span_O,
2076: code_LocalVariableTable_name_RU,
2077: code_LocalVariableTable_type_RS,
2078: code_LocalVariableTable_slot },
2079: "LocalVariableTable", "NH[PHOHRUHRSHH]");
2080: predefineAttribute(CODE_ATTR_LocalVariableTypeTable,
2081: ATTR_CONTEXT_CODE, new Band[] {
2082: code_LocalVariableTypeTable_N,
2083: code_LocalVariableTypeTable_bci_P,
2084: code_LocalVariableTypeTable_span_O,
2085: code_LocalVariableTypeTable_name_RU,
2086: code_LocalVariableTypeTable_type_RS,
2087: code_LocalVariableTypeTable_slot },
2088: "LocalVariableTypeTable", "NH[PHOHRUHRSHH]");
2089: predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_CODE, null,
2090: ".Overflow", "");
2091:
2092: // Clear the record of having seen these definitions,
2093: // so they may be redefined without error.
2094: for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
2095: attrDefSeen[i] = 0;
2096: }
2097:
2098: // Set up the special masks:
2099: for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
2100: attrOverflowMask[i] = (1 << X_ATTR_OVERFLOW);
2101: attrIndexLimit[i] = 0; // will make a final decision later
2102: }
2103: attrClassFileVersionMask = (1 << CLASS_ATTR_ClassFile_version);
2104: }
2105:
2106: private void adjustToMajver() {
2107: if (getPackageMajver() < JAVA6_PACKAGE_MAJOR_VERSION) {
2108: if (verbose > 0)
2109: Utils.log.fine("Legacy package version");
2110: // Revoke definition of pre-1.6 attribute type.
2111: undefineAttribute(CODE_ATTR_StackMapTable,
2112: ATTR_CONTEXT_CODE);
2113: }
2114: }
2115:
2116: protected void initAttrIndexLimit() {
2117: for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
2118: assert (attrIndexLimit[i] == 0); // decide on it now!
2119: attrIndexLimit[i] = (haveFlagsHi(i) ? 63 : 32);
2120: assert (attrDefs[i].size() == 32); // all predef indexes are <32
2121: int addMore = attrIndexLimit[i] - attrDefs[i].size();
2122: attrDefs[i].addAll(Collections.nCopies(addMore, null));
2123: }
2124: }
2125:
2126: protected boolean haveFlagsHi(int ctype) {
2127: int mask = 1 << (LG_AO_HAVE_XXX_FLAGS_HI + ctype);
2128: switch (ctype) {
2129: case ATTR_CONTEXT_CLASS:
2130: assert (mask == AO_HAVE_CLASS_FLAGS_HI);
2131: break;
2132: case ATTR_CONTEXT_FIELD:
2133: assert (mask == AO_HAVE_FIELD_FLAGS_HI);
2134: break;
2135: case ATTR_CONTEXT_METHOD:
2136: assert (mask == AO_HAVE_METHOD_FLAGS_HI);
2137: break;
2138: case ATTR_CONTEXT_CODE:
2139: assert (mask == AO_HAVE_CODE_FLAGS_HI);
2140: break;
2141: default:
2142: assert (false);
2143: }
2144: return testBit(archiveOptions, mask);
2145: }
2146:
2147: protected ArrayList getPredefinedAttrs(int ctype) {
2148: assert (attrIndexLimit[ctype] != 0);
2149: ArrayList res = new ArrayList(attrIndexLimit[ctype]);
2150: // Remove nulls and non-predefs.
2151: for (int ai = 0; ai < attrIndexLimit[ctype]; ai++) {
2152: if (testBit(attrDefSeen[ctype], 1L << ai))
2153: continue;
2154: Attribute.Layout def = (Attribute.Layout) attrDefs[ctype]
2155: .get(ai);
2156: if (def == null)
2157: continue; // unused flag bit
2158: assert (isPredefinedAttr(ctype, ai));
2159: res.add(def);
2160: }
2161: return res;
2162: }
2163:
2164: protected boolean isPredefinedAttr(int ctype, int ai) {
2165: assert (attrIndexLimit[ctype] != 0);
2166: // Overflow attrs are never predefined.
2167: if (ai >= attrIndexLimit[ctype])
2168: return false;
2169: // If the bit is set, it was explicitly def'd.
2170: if (testBit(attrDefSeen[ctype], 1L << ai))
2171: return false;
2172: return (attrDefs[ctype].get(ai) != null);
2173: }
2174:
2175: protected void adjustSpecialAttrMasks() {
2176: // Clear special masks if new definitions have been seen for them.
2177: attrClassFileVersionMask &= ~attrDefSeen[ATTR_CONTEXT_CLASS];
2178: // It is possible to clear the overflow mask (bit 16).
2179: for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
2180: attrOverflowMask[i] &= ~attrDefSeen[i];
2181: }
2182: }
2183:
2184: protected Attribute makeClassFileVersionAttr(int minver, int majver) {
2185: byte[] bytes = { (byte) (minver >> 8), (byte) minver,
2186: (byte) (majver >> 8), (byte) majver };
2187: return attrClassFileVersion.addContent(bytes);
2188: }
2189:
2190: protected short[] parseClassFileVersionAttr(Attribute attr) {
2191: assert (attr.layout() == attrClassFileVersion);
2192: assert (attr.size() == 4);
2193: byte[] bytes = attr.bytes();
2194: int minver = ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF);
2195: int majver = ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF);
2196: return new short[] { (short) minver, (short) majver };
2197: }
2198:
2199: private boolean assertBandOKForElems(Band[] ab,
2200: Attribute.Layout.Element[] elems) {
2201: for (int i = 0; i < elems.length; i++) {
2202: assert (assertBandOKForElem(ab, elems[i]));
2203: }
2204: return true;
2205: }
2206:
2207: private boolean assertBandOKForElem(Band[] ab,
2208: Attribute.Layout.Element e) {
2209: Band b = null;
2210: if (e.bandIndex != Attribute.NO_BAND_INDEX)
2211: b = ab[e.bandIndex];
2212: Coding rc = UNSIGNED5;
2213: boolean wantIntBand = true;
2214: switch (e.kind) {
2215: case Attribute.EK_INT:
2216: if (e.flagTest(Attribute.EF_SIGN)) {
2217: rc = SIGNED5;
2218: } else if (e.len == 1) {
2219: rc = BYTE1;
2220: }
2221: break;
2222: case Attribute.EK_BCI:
2223: if (!e.flagTest(Attribute.EF_DELTA)) {
2224: rc = BCI5;
2225: } else {
2226: rc = BRANCH5;
2227: }
2228: break;
2229: case Attribute.EK_BCO:
2230: rc = BRANCH5;
2231: break;
2232: case Attribute.EK_FLAG:
2233: if (e.len == 1)
2234: rc = BYTE1;
2235: break;
2236: case Attribute.EK_REPL:
2237: if (e.len == 1)
2238: rc = BYTE1;
2239: assertBandOKForElems(ab, e.body);
2240: break;
2241: case Attribute.EK_UN:
2242: if (e.flagTest(Attribute.EF_SIGN)) {
2243: rc = SIGNED5;
2244: } else if (e.len == 1) {
2245: rc = BYTE1;
2246: }
2247: assertBandOKForElems(ab, e.body);
2248: break;
2249: case Attribute.EK_CASE:
2250: assert (b == null);
2251: assertBandOKForElems(ab, e.body);
2252: return true; // no direct band
2253: case Attribute.EK_CALL:
2254: assert (b == null);
2255: return true; // no direct band
2256: case Attribute.EK_CBLE:
2257: assert (b == null);
2258: assertBandOKForElems(ab, e.body);
2259: return true; // no direct band
2260: case Attribute.EK_REF:
2261: wantIntBand = false;
2262: assert (b instanceof CPRefBand);
2263: assert (((CPRefBand) b).nullOK == e
2264: .flagTest(Attribute.EF_NULL));
2265: break;
2266: default:
2267: assert (false);
2268: }
2269: assert (b.regularCoding == rc) : (e + " // " + b);
2270: if (wantIntBand)
2271: assert (b instanceof IntBand);
2272: return true;
2273: }
2274:
2275: private Attribute.Layout predefineAttribute(int index, int ctype,
2276: Band[] ab, String name, String layout) {
2277: // Use Attribute.find to get uniquification of layouts.
2278: Attribute.Layout def = Attribute.find(ctype, name, layout)
2279: .layout();
2280: //def.predef = true;
2281: if (index >= 0) {
2282: setAttributeLayoutIndex(def, index);
2283: }
2284: if (ab == null) {
2285: ab = new Band[0];
2286: }
2287: assert (attrBandTable.get(def) == null); // no redef
2288: attrBandTable.put(def, ab);
2289: assert (def.bandCount == ab.length) : (def + " // " + Arrays
2290: .asList(ab));
2291: // Let's make sure the band types match:
2292: assert (assertBandOKForElems(ab, def.elems));
2293: return def;
2294: }
2295:
2296: // This version takes bandPrefix/addHere instead of prebuilt Band[] ab.
2297: private Attribute.Layout predefineAttribute(int index,
2298: String bandPrefix, MultiBand addHere, Attribute attr) {
2299: //Attribute.Layout def = Attribute.find(ctype, name, layout).layout();
2300: Attribute.Layout def = attr.layout();
2301: int ctype = def.ctype();
2302: return predefineAttribute(index, ctype, makeNewAttributeBands(
2303: bandPrefix, def, addHere), def.name(), def.layout());
2304: }
2305:
2306: private void undefineAttribute(int index, int ctype) {
2307: if (verbose > 1) {
2308: System.out.println("Removing predefined "
2309: + ATTR_CONTEXT_NAME[ctype] + " attribute on bit "
2310: + index);
2311: }
2312: List defList = attrDefs[ctype];
2313: Attribute.Layout def = (Attribute.Layout) defList.get(index);
2314: assert (def != null);
2315: defList.set(index, null);
2316: attrIndexTable.put(def, null);
2317: // Clear the def bit. (For predefs, it's already clear.)
2318: assert (index < 64);
2319: attrDefSeen[ctype] &= ~(1L << index);
2320: attrFlagMask[ctype] &= ~(1L << index);
2321: Band[] ab = (Band[]) attrBandTable.get(def);
2322: for (int j = 0; j < ab.length; j++) {
2323: ab[j].doneWithUnusedBand();
2324: }
2325: }
2326:
2327: // Bands which contain non-predefined attrs.
2328: protected MultiBand[] attrBands = new MultiBand[ATTR_CONTEXT_LIMIT];
2329: {
2330: attrBands[ATTR_CONTEXT_CLASS] = class_attr_bands;
2331: attrBands[ATTR_CONTEXT_FIELD] = field_attr_bands;
2332: attrBands[ATTR_CONTEXT_METHOD] = method_attr_bands;
2333: attrBands[ATTR_CONTEXT_CODE] = code_attr_bands;
2334: }
2335:
2336: // Create bands for all non-predefined attrs.
2337: void makeNewAttributeBands() {
2338: // Retract special flag bit bindings, if they were taken over.
2339: adjustSpecialAttrMasks();
2340:
2341: for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) {
2342: String cname = ATTR_CONTEXT_NAME[ctype];
2343: MultiBand xxx_attr_bands = attrBands[ctype];
2344: long defSeen = attrDefSeen[ctype];
2345: // Note: attrDefSeen is always a subset of attrFlagMask.
2346: assert ((defSeen & ~attrFlagMask[ctype]) == 0);
2347: for (int i = 0; i < attrDefs[ctype].size(); i++) {
2348: Attribute.Layout def = (Attribute.Layout) attrDefs[ctype]
2349: .get(i);
2350: if (def == null)
2351: continue; // unused flag bit
2352: if (def.bandCount == 0)
2353: continue; // empty attr
2354: if (i < attrIndexLimit[ctype]
2355: && !testBit(defSeen, 1L << i)) {
2356: // There are already predefined bands here.
2357: assert (attrBandTable.get(def) != null);
2358: continue;
2359: }
2360: int base = xxx_attr_bands.size();
2361: String pfx = cname + "_" + def.name() + "_"; // debug only
2362: if (verbose > 1)
2363: Utils.log.fine("Making new bands for " + def);
2364: Band[] newAB = makeNewAttributeBands(pfx, def,
2365: xxx_attr_bands);
2366: assert (newAB.length == def.bandCount);
2367: Band[] prevAB = (Band[]) attrBandTable.put(def, newAB);
2368: if (prevAB != null) {
2369: // We won't be using these predefined bands.
2370: for (int j = 0; j < prevAB.length; j++) {
2371: prevAB[j].doneWithUnusedBand();
2372: }
2373: }
2374: }
2375: }
2376: //System.out.println(prevForAssertMap);
2377: }
2378:
2379: private Band[] makeNewAttributeBands(String pfx,
2380: Attribute.Layout def, MultiBand addHere) {
2381: int base = addHere.size();
2382: makeNewAttributeBands(pfx, def.elems, addHere);
2383: int nb = addHere.size() - base;
2384: Band[] newAB = new Band[nb];
2385: for (int i = 0; i < nb; i++) {
2386: newAB[i] = addHere.get(base + i);
2387: }
2388: return newAB;
2389: }
2390:
2391: // Recursive helper, operates on a "body" or other sequence of elems:
2392: private void makeNewAttributeBands(String pfx,
2393: Attribute.Layout.Element[] elems, MultiBand ab) {
2394: for (int i = 0; i < elems.length; i++) {
2395: Attribute.Layout.Element e = elems[i];
2396: String name = pfx + ab.size() + "_" + e.layout;
2397: {
2398: int tem;
2399: if ((tem = name.indexOf('[')) > 0)
2400: name = name.substring(0, tem);
2401: if ((tem = name.indexOf('(')) > 0)
2402: name = name.substring(0, tem);
2403: if (name.endsWith("H"))
2404: name = name.substring(0, name.length() - 1);
2405: }
2406: Band nb;
2407: switch (e.kind) {
2408: case Attribute.EK_INT:
2409: nb = newElemBand(e, name, ab);
2410: break;
2411: case Attribute.EK_BCI:
2412: if (!e.flagTest(Attribute.EF_DELTA)) {
2413: // PH: transmit R(bci), store bci
2414: nb = ab.newIntBand(name, BCI5);
2415: } else {
2416: // POH: transmit D(R(bci)), store bci
2417: nb = ab.newIntBand(name, BRANCH5);
2418: }
2419: // Note: No case for BYTE1 here.
2420: break;
2421: case Attribute.EK_BCO:
2422: // OH: transmit D(R(bci)), store D(bci)
2423: nb = ab.newIntBand(name, BRANCH5);
2424: // Note: No case for BYTE1 here.
2425: break;
2426: case Attribute.EK_FLAG:
2427: assert (!e.flagTest(Attribute.EF_SIGN));
2428: nb = newElemBand(e, name, ab);
2429: break;
2430: case Attribute.EK_REPL:
2431: assert (!e.flagTest(Attribute.EF_SIGN));
2432: nb = newElemBand(e, name, ab);
2433: makeNewAttributeBands(pfx, e.body, ab);
2434: break;
2435: case Attribute.EK_UN:
2436: nb = newElemBand(e, name, ab);
2437: makeNewAttributeBands(pfx, e.body, ab);
2438: break;
2439: case Attribute.EK_CASE:
2440: if (!e.flagTest(Attribute.EF_BACK)) {
2441: // If it's not a duplicate body, make the bands.
2442: makeNewAttributeBands(pfx, e.body, ab);
2443: }
2444: continue; // no new band to make
2445: case Attribute.EK_REF:
2446: byte refKind = e.refKind;
2447: boolean nullOK = e.flagTest(Attribute.EF_NULL);
2448: nb = ab.newCPRefBand(name, UNSIGNED5, refKind, nullOK);
2449: // Note: No case for BYTE1 here.
2450: break;
2451: case Attribute.EK_CALL:
2452: continue; // no new band to make
2453: case Attribute.EK_CBLE:
2454: makeNewAttributeBands(pfx, e.body, ab);
2455: continue; // no new band to make
2456: default:
2457: assert (false);
2458: continue;
2459: }
2460: if (verbose > 1) {
2461: Utils.log.fine("New attribute band " + nb);
2462: }
2463: }
2464: }
2465:
2466: private Band newElemBand(Attribute.Layout.Element e, String name,
2467: MultiBand ab) {
2468: if (e.flagTest(Attribute.EF_SIGN)) {
2469: return ab.newIntBand(name, SIGNED5);
2470: } else if (e.len == 1) {
2471: return ab.newIntBand(name, BYTE1); // Not ByteBand, please.
2472: } else {
2473: return ab.newIntBand(name, UNSIGNED5);
2474: }
2475: }
2476:
2477: protected int setAttributeLayoutIndex(Attribute.Layout def,
2478: int index) {
2479: int ctype = def.ctype;
2480: assert (ATTR_INDEX_OVERFLOW <= index && index < attrIndexLimit[ctype]);
2481: List defList = attrDefs[ctype];
2482: if (index == ATTR_INDEX_OVERFLOW) {
2483: // Overflow attribute.
2484: index = defList.size();
2485: defList.add(def);
2486: if (verbose > 0)
2487: Utils.log.info("Adding new attribute at " + def + ": "
2488: + index);
2489: attrIndexTable.put(def, new Integer(index));
2490: return index;
2491: }
2492:
2493: // Detect redefinitions:
2494: if (testBit(attrDefSeen[ctype], 1L << index)) {
2495: throw new RuntimeException(
2496: "Multiple explicit definition at " + index + ": "
2497: + def);
2498: }
2499: attrDefSeen[ctype] |= (1L << index);
2500:
2501: // Adding a new fixed attribute.
2502: assert (0 <= index && index < attrIndexLimit[ctype]);
2503: if (verbose > (attrClassFileVersionMask == 0 ? 2 : 0))
2504: Utils.log.fine("Fixing new attribute at "
2505: + index
2506: + ": "
2507: + def
2508: + (defList.get(index) == null ? "" : "; replacing "
2509: + defList.get(index)));
2510: attrFlagMask[ctype] |= (1L << index);
2511: // Remove index binding of any previous fixed attr.
2512: attrIndexTable.put(defList.get(index), null);
2513: defList.set(index, def);
2514: attrIndexTable.put(def, new Integer(index));
2515: return index;
2516: }
2517:
2518: // encodings found in the code_headers band
2519: private static final int[][] shortCodeLimits = { { 12, 12 }, // s<12, l<12, e=0 [1..144]
2520: { 8, 8 }, // s<8, l<8, e=1 [145..208]
2521: { 7, 7 }, // s<7, l<7, e=2 [209..256]
2522: };
2523: public final int shortCodeHeader_h_limit = shortCodeLimits.length;
2524:
2525: // return 0 if it won't encode, else a number in [1..255]
2526: static int shortCodeHeader(Code code) {
2527: int s = code.max_stack;
2528: int l0 = code.max_locals;
2529: int h = code.handler_class.length;
2530: if (h >= shortCodeLimits.length)
2531: return LONG_CODE_HEADER;
2532: int siglen = code.getMethod().getArgumentSize();
2533: assert (l0 >= siglen); // enough locals for signature!
2534: if (l0 < siglen)
2535: return LONG_CODE_HEADER;
2536: int l1 = l0 - siglen; // do not count locals required by the signature
2537: int lims = shortCodeLimits[h][0];
2538: int liml = shortCodeLimits[h][1];
2539: if (s >= lims || l1 >= liml)
2540: return LONG_CODE_HEADER;
2541: int sc = shortCodeHeader_h_base(h);
2542: sc += s + lims * l1;
2543: if (sc > 255)
2544: return LONG_CODE_HEADER;
2545: assert (shortCodeHeader_max_stack(sc) == s);
2546: assert (shortCodeHeader_max_na_locals(sc) == l1);
2547: assert (shortCodeHeader_handler_count(sc) == h);
2548: return sc;
2549: }
2550:
2551: static final int LONG_CODE_HEADER = 0;
2552:
2553: static int shortCodeHeader_handler_count(int sc) {
2554: assert (sc > 0 && sc <= 255);
2555: for (int h = 0;; h++) {
2556: if (sc < shortCodeHeader_h_base(h + 1))
2557: return h;
2558: }
2559: }
2560:
2561: static int shortCodeHeader_max_stack(int sc) {
2562: int h = shortCodeHeader_handler_count(sc);
2563: int lims = shortCodeLimits[h][0];
2564: return (sc - shortCodeHeader_h_base(h)) % lims;
2565: }
2566:
2567: static int shortCodeHeader_max_na_locals(int sc) {
2568: int h = shortCodeHeader_handler_count(sc);
2569: int lims = shortCodeLimits[h][0];
2570: return (sc - shortCodeHeader_h_base(h)) / lims;
2571: }
2572:
2573: private static int shortCodeHeader_h_base(int h) {
2574: assert (h <= shortCodeLimits.length);
2575: int sc = 1;
2576: for (int h0 = 0; h0 < h; h0++) {
2577: int lims = shortCodeLimits[h0][0];
2578: int liml = shortCodeLimits[h0][1];
2579: sc += lims * liml;
2580: }
2581: return sc;
2582: }
2583:
2584: // utilities for accessing the bc_label band:
2585: protected void putLabel(IntBand bc_label, Code c, int pc,
2586: int targetPC) {
2587: bc_label.putInt(c.encodeBCI(targetPC) - c.encodeBCI(pc));
2588: }
2589:
2590: protected int getLabel(IntBand bc_label, Code c, int pc) {
2591: return c.decodeBCI(bc_label.getInt() + c.encodeBCI(pc));
2592: }
2593:
2594: protected CPRefBand getCPRefOpBand(int bc) {
2595: switch (Instruction.getCPRefOpTag(bc)) {
2596: case CONSTANT_Class:
2597: return bc_classref;
2598: case CONSTANT_Fieldref:
2599: return bc_fieldref;
2600: case CONSTANT_Methodref:
2601: return bc_methodref;
2602: case CONSTANT_InterfaceMethodref:
2603: return bc_imethodref;
2604: case CONSTANT_Literal:
2605: switch (bc) {
2606: case _ildc:
2607: case _ildc_w:
2608: return bc_intref;
2609: case _fldc:
2610: case _fldc_w:
2611: return bc_floatref;
2612: case _lldc2_w:
2613: return bc_longref;
2614: case _dldc2_w:
2615: return bc_doubleref;
2616: case _aldc:
2617: case _aldc_w:
2618: return bc_stringref;
2619: case _cldc:
2620: case _cldc_w:
2621: return bc_classref;
2622: }
2623: break;
2624: }
2625: assert (false);
2626: return null;
2627: }
2628:
2629: protected CPRefBand selfOpRefBand(int self_bc) {
2630: assert (Instruction.isSelfLinkerOp(self_bc));
2631: int idx = (self_bc - _self_linker_op);
2632: boolean isSuper = (idx >= _self_linker_super _flag);
2633: if (isSuper)
2634: idx -= _self_linker_super _flag;
2635: boolean isAload = (idx >= _self_linker_aload_flag);
2636: if (isAload)
2637: idx -= _self_linker_aload_flag;
2638: int origBC = _first_linker_op + idx;
2639: boolean isField = Instruction.isFieldOp(origBC);
2640: if (!isSuper)
2641: return isField ? bc_this field : bc_this method;
2642: else
2643: return isField ? bc_super field : bc_super method;
2644: }
2645:
2646: ////////////////////////////////////////////////////////////////////
2647:
2648: static int nextSeqForDebug;
2649: static File dumpDir;
2650:
2651: static OutputStream getDumpStream(Band b, String ext)
2652: throws IOException {
2653: return getDumpStream(b.name, b.seqForDebug, ext, b);
2654: }
2655:
2656: static OutputStream getDumpStream(Index ix, String ext)
2657: throws IOException {
2658: if (ix.size() == 0)
2659: return new ByteArrayOutputStream();
2660: int seq = ConstantPool.TAG_ORDER[ix.cpMap[0].tag];
2661: return getDumpStream(ix.debugName, seq, ext, ix);
2662: }
2663:
2664: static OutputStream getDumpStream(String name, int seq, String ext,
2665: Object b) throws IOException {
2666: if (dumpDir == null) {
2667: dumpDir = File.createTempFile("BD_", "", new File("."));
2668: dumpDir.delete();
2669: if (dumpDir.mkdir())
2670: Utils.log.info("Dumping bands to " + dumpDir);
2671: }
2672: name = name.replace('(', ' ').replace(')', ' ');
2673: name = name.replace('/', ' ');
2674: name = name.replace('*', ' ');
2675: name = name.trim().replace(' ', '_');
2676: name = ((10000 + seq) + "_" + name).substring(1);
2677: File dumpFile = new File(dumpDir, name + ext);
2678: Utils.log.info("Dumping " + b + " to " + dumpFile);
2679: return new BufferedOutputStream(new FileOutputStream(dumpFile));
2680: }
2681:
2682: // DEBUG ONLY: Validate me at each length change.
2683: static boolean assertCanChangeLength(Band b) {
2684: switch (b.phase) {
2685: case COLLECT_PHASE:
2686: case READ_PHASE:
2687: return true;
2688: }
2689: return false;
2690: }
2691:
2692: // DEBUG ONLY: Validate a phase.
2693: static boolean assertPhase(Band b, int phaseExpected) {
2694: if (b.phase() != phaseExpected) {
2695: Utils.log.warning("phase expected " + phaseExpected
2696: + " was " + b.phase() + " in " + b);
2697: return false;
2698: }
2699: return true;
2700: }
2701:
2702: // DEBUG ONLY: Tells whether verbosity is turned on.
2703: static int verbose() {
2704: return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE);
2705: }
2706:
2707: // DEBUG ONLY: Validate me at each phase change.
2708: static boolean assertPhaseChangeOK(Band b, int p0, int p1) {
2709: switch (p0 * 10 + p1) {
2710: /// Writing phases:
2711: case NO_PHASE * 10 + COLLECT_PHASE:
2712: // Ready to collect data from the input classes.
2713: assert (!b.isReader());
2714: assert (b.capacity() >= 0);
2715: assert (b.length() == 0);
2716: return true;
2717: case COLLECT_PHASE * 10 + FROZEN_PHASE:
2718: case FROZEN_PHASE * 10 + FROZEN_PHASE:
2719: assert (b.length() == 0);
2720: return true;
2721: case COLLECT_PHASE * 10 + WRITE_PHASE:
2722: case FROZEN_PHASE * 10 + WRITE_PHASE:
2723: // Data is all collected. Ready to write bytes to disk.
2724: return true;
2725: case WRITE_PHASE * 10 + DONE_PHASE:
2726: // Done writing to disk. Ready to reset, in principle.
2727: return true;
2728:
2729: /// Reading phases:
2730: case NO_PHASE * 10 + EXPECT_PHASE:
2731: assert (b.isReader());
2732: assert (b.capacity() < 0);
2733: return true;
2734: case EXPECT_PHASE * 10 + READ_PHASE:
2735: // Ready to read values from disk.
2736: assert (Math.max(0, b.capacity()) >= b.valuesExpected());
2737: assert (b.length() <= 0);
2738: return true;
2739: case READ_PHASE * 10 + DISBURSE_PHASE:
2740: // Ready to disburse values.
2741: assert (b.valuesRemainingForDebug() == b.length());
2742: return true;
2743: case DISBURSE_PHASE * 10 + DONE_PHASE:
2744: // Done disbursing values. Ready to reset, in principle.
2745: assert (assertDoneDisbursing(b));
2746: return true;
2747: }
2748: if (p0 == p1)
2749: Utils.log.warning("Already in phase " + p0);
2750: else
2751: Utils.log.warning("Unexpected phase " + p0 + " -> " + p1);
2752: return false;
2753: }
2754:
2755: static private boolean assertDoneDisbursing(Band b) {
2756: if (b.phase != DISBURSE_PHASE) {
2757: Utils.log.warning("assertDoneDisbursing: still in phase "
2758: + b.phase + ": " + b);
2759: if (verbose() <= 1)
2760: return false; // fail now
2761: }
2762: int left = b.valuesRemainingForDebug();
2763: if (left > 0) {
2764: Utils.log.warning("assertDoneDisbursing: " + left
2765: + " values left in " + b);
2766: if (verbose() <= 1)
2767: return false; // fail now
2768: }
2769: if (b instanceof MultiBand) {
2770: MultiBand mb = (MultiBand) b;
2771: for (int i = 0; i < mb.bandCount; i++) {
2772: Band sub = mb.bands[i];
2773: if (sub.phase != DONE_PHASE) {
2774: Utils.log
2775: .warning("assertDoneDisbursing: sub-band still in phase "
2776: + sub.phase + ": " + sub);
2777: if (verbose() <= 1)
2778: return false; // fail now
2779: }
2780: }
2781: }
2782: return true;
2783: }
2784:
2785: static private void printCDecl(Band b) {
2786: if (b instanceof MultiBand) {
2787: MultiBand mb = (MultiBand) b;
2788: for (int i = 0; i < mb.bandCount; i++) {
2789: printCDecl(mb.bands[i]);
2790: }
2791: return;
2792: }
2793: String ixS = "NULL";
2794: if (b instanceof CPRefBand) {
2795: Index ix = ((CPRefBand) b).index;
2796: if (ix != null)
2797: ixS = "INDEX(" + ix.debugName + ")";
2798: }
2799: Coding[] knownc = { BYTE1, CHAR3, BCI5, BRANCH5, UNSIGNED5,
2800: UDELTA5, SIGNED5, DELTA5, MDELTA5 };
2801: String[] knowns = { "BYTE1", "CHAR3", "BCI5", "BRANCH5",
2802: "UNSIGNED5", "UDELTA5", "SIGNED5", "DELTA5", "MDELTA5" };
2803: Coding rc = b.regularCoding;
2804: int rci = Arrays.asList(knownc).indexOf(rc);
2805: String cstr;
2806: if (rci >= 0)
2807: cstr = knowns[rci];
2808: else
2809: cstr = "CODING" + rc.keyString();
2810: System.out.println(" BAND_INIT(\"" + b.name() + "\"" + ", "
2811: + cstr + ", " + ixS + "),");
2812: }
2813:
2814: private HashMap prevForAssertMap;
2815:
2816: // DEBUG ONLY: Record something about the band order.
2817: boolean notePrevForAssert(Band b, Band p) {
2818: if (prevForAssertMap == null)
2819: prevForAssertMap = new HashMap();
2820: prevForAssertMap.put(b, p);
2821: return true;
2822: }
2823:
2824: // DEBUG ONLY: Validate next input band.
2825: private boolean assertReadyToReadFrom(Band b, InputStream in)
2826: throws IOException {
2827: Band p = (Band) prevForAssertMap.get(b);
2828: // Any previous band must be done reading before this one starts.
2829: if (p != null && phaseCmp(p.phase(), DISBURSE_PHASE) < 0) {
2830: Utils.log.warning("Previous band not done reading.");
2831: Utils.log.info(" Previous band: " + p);
2832: Utils.log.info(" Next band: " + b);
2833: Thread.dumpStack();
2834: assert (verbose > 0); // die unless verbose is true
2835: }
2836: String name = b.name;
2837: if (optDebugBands && !name.startsWith("(")) {
2838: // Verify synchronization between reader & writer:
2839: StringBuffer buf = new StringBuffer();
2840: int ch;
2841: while ((ch = in.read()) > 0)
2842: buf.append((char) ch);
2843: String inName = buf.toString();
2844: if (!inName.equals(name)) {
2845: StringBuffer sb = new StringBuffer();
2846: sb.append("Expected " + name + " but read: ");
2847: inName += (char) ch;
2848: while (inName.length() < 10)
2849: inName += (char) in.read();
2850: for (int i = 0; i < inName.length(); i++)
2851: sb.append(inName.charAt(i));
2852: Utils.log.warning(sb.toString());
2853: return false;
2854: }
2855: }
2856: return true;
2857: }
2858:
2859: // DEBUG ONLY: Make sure a bunch of cprefs are correct.
2860: private boolean assertValidCPRefs(CPRefBand b) {
2861: if (b.index == null)
2862: return true;
2863: int limit = b.index.size() + 1;
2864: for (int i = 0; i < b.length(); i++) {
2865: int v = b.valueAtForDebug(i);
2866: if (v < 0 || v >= limit) {
2867: Utils.log.warning("CP ref out of range " + "[" + i
2868: + "] = " + v + " in " + b);
2869: return false;
2870: }
2871: }
2872: return true;
2873: }
2874:
2875: // DEBUG ONLY: Maybe write a debugging cookie to next output band.
2876: private boolean assertReadyToWriteTo(Band b, OutputStream out)
2877: throws IOException {
2878: Band p = (Band) prevForAssertMap.get(b);
2879: // Any previous band must be done writing before this one starts.
2880: if (p != null && phaseCmp(p.phase(), DONE_PHASE) < 0) {
2881: Utils.log.warning("Previous band not done writing.");
2882: Utils.log.info(" Previous band: " + p);
2883: Utils.log.info(" Next band: " + b);
2884: Thread.dumpStack();
2885: assert (verbose > 0); // die unless verbose is true
2886: }
2887: String name = b.name;
2888: if (optDebugBands && !name.startsWith("(")) {
2889: // Verify synchronization between reader & writer:
2890: for (int j = 0; j < name.length(); j++) {
2891: out.write((byte) name.charAt(j));
2892: }
2893: out.write((byte) 0);
2894: }
2895: return true;
2896: }
2897:
2898: protected static boolean testBit(int flags, int bitMask) {
2899: return (flags & bitMask) != 0;
2900: }
2901:
2902: protected static int setBit(int flags, int bitMask, boolean z) {
2903: return z ? (flags | bitMask) : (flags & ~bitMask);
2904: }
2905:
2906: protected static boolean testBit(long flags, long bitMask) {
2907: return (flags & bitMask) != 0;
2908: }
2909:
2910: protected static long setBit(long flags, long bitMask, boolean z) {
2911: return z ? (flags | bitMask) : (flags & ~bitMask);
2912: }
2913:
2914: static void printArrayTo(PrintStream ps, int[] values, int start,
2915: int end) {
2916: int len = end - start;
2917: for (int i = 0; i < len; i++) {
2918: if (i % 10 == 0)
2919: ps.println();
2920: else
2921: ps.print(" ");
2922: ps.print(values[start + i]);
2923: }
2924: ps.println();
2925: }
2926:
2927: static void printArrayTo(PrintStream ps, Entry[] cpMap, int start,
2928: int end) {
2929: StringBuffer buf = new StringBuffer();
2930: int len = end - start;
2931: for (int i = 0; i < len; i++) {
2932: String s = cpMap[start + i].stringValue();
2933: buf.setLength(0);
2934: for (int j = 0; j < s.length(); j++) {
2935: char ch = s.charAt(j);
2936: if (!(ch < ' ' || ch > '~' || ch == '\\')) {
2937: buf.append(ch);
2938: } else if (ch == '\n') {
2939: buf.append("\\n");
2940: } else if (ch == '\t') {
2941: buf.append("\\t");
2942: } else if (ch == '\r') {
2943: buf.append("\\r");
2944: } else {
2945: buf.append("\\x" + Integer.toHexString(ch));
2946: }
2947: }
2948: ps.println(buf);
2949: }
2950: }
2951:
2952: // Utilities for reallocating:
2953: protected static Object[] realloc(Object[] a, int len) {
2954: java.lang.Class elt = a.getClass().getComponentType();
2955: Object[] na = (Object[]) java.lang.reflect.Array.newInstance(
2956: elt, len);
2957: System.arraycopy(a, 0, na, 0, Math.min(a.length, len));
2958: return na;
2959: }
2960:
2961: protected static Object[] realloc(Object[] a) {
2962: return realloc(a, Math.max(10, a.length * 2));
2963: }
2964:
2965: static private int[] noInts = {};
2966:
2967: protected static int[] realloc(int[] a, int len) {
2968: if (len == 0)
2969: return noInts;
2970: if (a == null)
2971: return new int[len];
2972: int[] na = new int[len];
2973: System.arraycopy(a, 0, na, 0, Math.min(a.length, len));
2974: return na;
2975: }
2976:
2977: protected static int[] realloc(int[] a) {
2978: return realloc(a, Math.max(10, a.length * 2));
2979: }
2980:
2981: static private byte[] noBytes = {};
2982:
2983: protected static byte[] realloc(byte[] a, int len) {
2984: if (len == 0)
2985: return noBytes;
2986: if (a == null)
2987: return new byte[len];
2988: byte[] na = new byte[len];
2989: System.arraycopy(a, 0, na, 0, Math.min(a.length, len));
2990: return na;
2991: }
2992:
2993: protected static byte[] realloc(byte[] a) {
2994: return realloc(a, Math.max(10, a.length * 2));
2995: }
2996: }
|