alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (BandStructure.java)

This example Java source code file (BandStructure.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

band, byte1, coding, constant_class, cprefband, delta5, intband, ioexception, jar, multiband, override, string, udelta5, unsigned5, util

The BandStructure.java Java example source code

/*
 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.java.util.jar.pack;

import com.sun.java.util.jar.pack.ConstantPool.Entry;
import com.sun.java.util.jar.pack.ConstantPool.Index;
import com.sun.java.util.jar.pack.Package.Class.Field;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.Pack200;
import static com.sun.java.util.jar.pack.Constants.*;
import java.util.LinkedList;

/**
 * Define the structure and ordering of "bands" in a packed file.
 * @author John Rose
 */
abstract
class BandStructure {
    static final int MAX_EFFORT = 9;
    static final int MIN_EFFORT = 1;
    static final int DEFAULT_EFFORT = 5;

    // Inherit options from Pack200:
    PropMap p200 = Utils.currentPropMap();

    int verbose = p200.getInteger(Utils.DEBUG_VERBOSE);
    int effort = p200.getInteger(Pack200.Packer.EFFORT);
    { if (effort == 0)  effort = DEFAULT_EFFORT; }
    boolean optDumpBands = p200.getBoolean(Utils.COM_PREFIX+"dump.bands");
    boolean optDebugBands = p200.getBoolean(Utils.COM_PREFIX+"debug.bands");

    // Various heuristic options.
    boolean optVaryCodings = !p200.getBoolean(Utils.COM_PREFIX+"no.vary.codings");
    boolean optBigStrings = !p200.getBoolean(Utils.COM_PREFIX+"no.big.strings");

    abstract protected Index getCPIndex(byte tag);

    // Local copy of highest class version.
    private Package.Version highestClassVersion = null;

    /** Call this exactly once, early, to specify the archive major version. */
    public void initHighestClassVersion(Package.Version highestClassVersion) throws IOException {
        if (this.highestClassVersion != null) {
            throw new IOException(
                "Highest class major version is already initialized to " +
                this.highestClassVersion + "; new setting is " + highestClassVersion);
        }
        this.highestClassVersion = highestClassVersion;
        adjustToClassVersion();
    }

    public Package.Version getHighestClassVersion() {
        return highestClassVersion;
    }

    private final boolean isReader = this instanceof PackageReader;

    protected BandStructure() {}

    final static Coding BYTE1 = Coding.of(1,256);

    final static Coding CHAR3 = Coding.of(3,128);
    // Note:  Tried sharper (3,16) with no post-zip benefit.

    // This is best used with BCI values:
    final static Coding BCI5 = Coding.of(5,4);  // mostly 1-byte offsets
    final static Coding BRANCH5 = Coding.of(5,4,2); // mostly forward branches

    final static Coding UNSIGNED5 = Coding.of(5,64);
    final static Coding UDELTA5 = UNSIGNED5.getDeltaCoding();
    // "sharp" (5,64) zips 0.4% better than "medium" (5,128)
    // It zips 1.1% better than "flat" (5,192)

    final static Coding SIGNED5 = Coding.of(5,64,1);  //sharp
    final static Coding DELTA5 = SIGNED5.getDeltaCoding();
    // Note:  Tried (5,128,2) and (5,192,2) with no benefit.

    final static Coding MDELTA5 = Coding.of(5,64,2).getDeltaCoding();

    final private static Coding[] basicCodings = {
        // Table of "Canonical BHSD Codings" from Pack200 spec.
        null,  // _meta_default

        // Fixed-length codings:
        Coding.of(1,256,0),
        Coding.of(1,256,1),
        Coding.of(1,256,0).getDeltaCoding(),
        Coding.of(1,256,1).getDeltaCoding(),
        Coding.of(2,256,0),
        Coding.of(2,256,1),
        Coding.of(2,256,0).getDeltaCoding(),
        Coding.of(2,256,1).getDeltaCoding(),
        Coding.of(3,256,0),
        Coding.of(3,256,1),
        Coding.of(3,256,0).getDeltaCoding(),
        Coding.of(3,256,1).getDeltaCoding(),
        Coding.of(4,256,0),
        Coding.of(4,256,1),
        Coding.of(4,256,0).getDeltaCoding(),
        Coding.of(4,256,1).getDeltaCoding(),

        // Full-range variable-length codings:
        Coding.of(5,  4,0),
        Coding.of(5,  4,1),
        Coding.of(5,  4,2),
        Coding.of(5, 16,0),
        Coding.of(5, 16,1),
        Coding.of(5, 16,2),
        Coding.of(5, 32,0),
        Coding.of(5, 32,1),
        Coding.of(5, 32,2),
        Coding.of(5, 64,0),
        Coding.of(5, 64,1),
        Coding.of(5, 64,2),
        Coding.of(5,128,0),
        Coding.of(5,128,1),
        Coding.of(5,128,2),

        Coding.of(5,  4,0).getDeltaCoding(),
        Coding.of(5,  4,1).getDeltaCoding(),
        Coding.of(5,  4,2).getDeltaCoding(),
        Coding.of(5, 16,0).getDeltaCoding(),
        Coding.of(5, 16,1).getDeltaCoding(),
        Coding.of(5, 16,2).getDeltaCoding(),
        Coding.of(5, 32,0).getDeltaCoding(),
        Coding.of(5, 32,1).getDeltaCoding(),
        Coding.of(5, 32,2).getDeltaCoding(),
        Coding.of(5, 64,0).getDeltaCoding(),
        Coding.of(5, 64,1).getDeltaCoding(),
        Coding.of(5, 64,2).getDeltaCoding(),
        Coding.of(5,128,0).getDeltaCoding(),
        Coding.of(5,128,1).getDeltaCoding(),
        Coding.of(5,128,2).getDeltaCoding(),

        // Variable length subrange codings:
        Coding.of(2,192,0),
        Coding.of(2,224,0),
        Coding.of(2,240,0),
        Coding.of(2,248,0),
        Coding.of(2,252,0),

        Coding.of(2,  8,0).getDeltaCoding(),
        Coding.of(2,  8,1).getDeltaCoding(),
        Coding.of(2, 16,0).getDeltaCoding(),
        Coding.of(2, 16,1).getDeltaCoding(),
        Coding.of(2, 32,0).getDeltaCoding(),
        Coding.of(2, 32,1).getDeltaCoding(),
        Coding.of(2, 64,0).getDeltaCoding(),
        Coding.of(2, 64,1).getDeltaCoding(),
        Coding.of(2,128,0).getDeltaCoding(),
        Coding.of(2,128,1).getDeltaCoding(),
        Coding.of(2,192,0).getDeltaCoding(),
        Coding.of(2,192,1).getDeltaCoding(),
        Coding.of(2,224,0).getDeltaCoding(),
        Coding.of(2,224,1).getDeltaCoding(),
        Coding.of(2,240,0).getDeltaCoding(),
        Coding.of(2,240,1).getDeltaCoding(),
        Coding.of(2,248,0).getDeltaCoding(),
        Coding.of(2,248,1).getDeltaCoding(),

        Coding.of(3,192,0),
        Coding.of(3,224,0),
        Coding.of(3,240,0),
        Coding.of(3,248,0),
        Coding.of(3,252,0),

        Coding.of(3,  8,0).getDeltaCoding(),
        Coding.of(3,  8,1).getDeltaCoding(),
        Coding.of(3, 16,0).getDeltaCoding(),
        Coding.of(3, 16,1).getDeltaCoding(),
        Coding.of(3, 32,0).getDeltaCoding(),
        Coding.of(3, 32,1).getDeltaCoding(),
        Coding.of(3, 64,0).getDeltaCoding(),
        Coding.of(3, 64,1).getDeltaCoding(),
        Coding.of(3,128,0).getDeltaCoding(),
        Coding.of(3,128,1).getDeltaCoding(),
        Coding.of(3,192,0).getDeltaCoding(),
        Coding.of(3,192,1).getDeltaCoding(),
        Coding.of(3,224,0).getDeltaCoding(),
        Coding.of(3,224,1).getDeltaCoding(),
        Coding.of(3,240,0).getDeltaCoding(),
        Coding.of(3,240,1).getDeltaCoding(),
        Coding.of(3,248,0).getDeltaCoding(),
        Coding.of(3,248,1).getDeltaCoding(),

        Coding.of(4,192,0),
        Coding.of(4,224,0),
        Coding.of(4,240,0),
        Coding.of(4,248,0),
        Coding.of(4,252,0),

        Coding.of(4,  8,0).getDeltaCoding(),
        Coding.of(4,  8,1).getDeltaCoding(),
        Coding.of(4, 16,0).getDeltaCoding(),
        Coding.of(4, 16,1).getDeltaCoding(),
        Coding.of(4, 32,0).getDeltaCoding(),
        Coding.of(4, 32,1).getDeltaCoding(),
        Coding.of(4, 64,0).getDeltaCoding(),
        Coding.of(4, 64,1).getDeltaCoding(),
        Coding.of(4,128,0).getDeltaCoding(),
        Coding.of(4,128,1).getDeltaCoding(),
        Coding.of(4,192,0).getDeltaCoding(),
        Coding.of(4,192,1).getDeltaCoding(),
        Coding.of(4,224,0).getDeltaCoding(),
        Coding.of(4,224,1).getDeltaCoding(),
        Coding.of(4,240,0).getDeltaCoding(),
        Coding.of(4,240,1).getDeltaCoding(),
        Coding.of(4,248,0).getDeltaCoding(),
        Coding.of(4,248,1).getDeltaCoding(),

        null
    };
    final private static Map<Coding, Integer> basicCodingIndexes;
    static {
        assert(basicCodings[_meta_default] == null);
        assert(basicCodings[_meta_canon_min] != null);
        assert(basicCodings[_meta_canon_max] != null);
        Map<Coding, Integer> map = new HashMap<>();
        for (int i = 0; i < basicCodings.length; i++) {
            Coding c = basicCodings[i];
            if (c == null)  continue;
            assert(i >= _meta_canon_min);
            assert(i <= _meta_canon_max);
            map.put(c, i);
        }
        basicCodingIndexes = map;
    }
    public static Coding codingForIndex(int i) {
        return i < basicCodings.length ? basicCodings[i] : null;
    }
    public static int indexOf(Coding c) {
        Integer i = basicCodingIndexes.get(c);
        if (i == null)  return 0;
        return i.intValue();
    }
    public static Coding[] getBasicCodings() {
        return basicCodings.clone();
    }

    protected byte[] bandHeaderBytes;    // used for input only
    protected int    bandHeaderBytePos;  // BHB read pointer, for input only
    protected int    bandHeaderBytePos0; // for debug

    protected CodingMethod getBandHeader(int XB, Coding regularCoding) {
        CodingMethod[] res = {null};
        // push back XB onto the band header bytes
        bandHeaderBytes[--bandHeaderBytePos] = (byte) XB;
        bandHeaderBytePos0 = bandHeaderBytePos;
        // scan forward through XB and any additional band header bytes
        bandHeaderBytePos = parseMetaCoding(bandHeaderBytes,
                                            bandHeaderBytePos,
                                            regularCoding,
                                            res);
        return res[0];
    }

    public static int parseMetaCoding(byte[] bytes, int pos, Coding dflt, CodingMethod[] res) {
        if ((bytes[pos] & 0xFF) == _meta_default) {
            res[0] = dflt;
            return pos+1;
        }
        int pos2;
        pos2 = Coding.parseMetaCoding(bytes, pos, dflt, res);
        if (pos2 > pos)  return pos2;
        pos2 = PopulationCoding.parseMetaCoding(bytes, pos, dflt, res);
        if (pos2 > pos)  return pos2;
        pos2 = AdaptiveCoding.parseMetaCoding(bytes, pos, dflt, res);
        if (pos2 > pos)  return pos2;
        throw new RuntimeException("Bad meta-coding op "+(bytes[pos]&0xFF));
    }

    static final int SHORT_BAND_HEURISTIC = 100;

    public static final int NO_PHASE        = 0;

    // package writing phases:
    public static final int COLLECT_PHASE   = 1; // collect data before write
    public static final int FROZEN_PHASE    = 3; // no longer collecting
    public static final int WRITE_PHASE     = 5; // ready to write bytes

    // package reading phases:
    public static final int EXPECT_PHASE    = 2; // gather expected counts
    public static final int READ_PHASE      = 4; // ready to read bytes
    public static final int DISBURSE_PHASE  = 6; // pass out data after read

    public static final int DONE_PHASE      = 8; // done writing or reading

    static boolean phaseIsRead(int p) {
        return (p % 2) == 0;
    }
    static int phaseCmp(int p0, int p1) {
        assert((p0 % 2) == (p1 % 2) || (p0 % 8) == 0 || (p1 % 8) == 0);
        return p0 - p1;
    }

    /** The packed file is divided up into a number of segments.
     *  Most segments are typed as ValueBand, strongly-typed sequences
     *  of integer values, all interpreted in a single way.
     *  A few segments are ByteBands, which hetergeneous sequences
     *  of bytes.
     *
     *  The two phases for writing a packed file are COLLECT and WRITE.
     *  1. When writing a packed file, each band collects
     *  data in an ad-hoc order.
     *  2. At the end, each band is assigned a coding scheme,
     *  and then all the bands are written in their global order.
     *
     *  The three phases for reading a packed file are EXPECT, READ,
     *  and DISBURSE.
     *  1. For each band, the expected number of integers  is determined.
     *  2. The data is actually read from the file into the band.
     *  3. The band pays out its values as requested, in an ad hoc order.
     *
     *  When the last phase of a band is done, it is marked so (DONE).
     *  Clearly, these phases must be properly ordered WRT each other.
     */
    abstract class Band {
        private int    phase = NO_PHASE;
        private final  String name;

        private int    valuesExpected;

        protected long outputSize = -1;  // cache

        final public Coding regularCoding;

        final public int seqForDebug;
        public int       elementCountForDebug;


        protected Band(String name, Coding regularCoding) {
            this.name = name;
            this.regularCoding = regularCoding;
            this.seqForDebug = ++nextSeqForDebug;
            if (verbose > 2)
                Utils.log.fine("Band "+seqForDebug+" is "+name);
            // caller must call init
        }

        public Band init() {
            // Cannot due this from the constructor, because constructor
            // may wish to initialize some subclass variables.
            // Set initial phase for reading or writing:
            if (isReader)
                readyToExpect();
            else
                readyToCollect();
            return this;
        }

        // common operations
        boolean isReader() { return isReader; }
        int phase() { return phase; }
        String name() { return name; }

        /** Return -1 if data buffer not allocated, else max length. */
        public abstract int capacity();

        /** Allocate data buffer to specified length. */
        protected abstract void setCapacity(int cap);

        /** Return current number of values in buffer, which must exist. */
        public abstract int length();

        protected abstract int valuesRemainingForDebug();

        public final int valuesExpected() {
            return valuesExpected;
        }

        /** Write out bytes, encoding the values. */
        public final void writeTo(OutputStream out) throws IOException {
            assert(assertReadyToWriteTo(this, out));
            setPhase(WRITE_PHASE);
            // subclasses continue by writing their contents to output
            writeDataTo(out);
            doneWriting();
        }

        abstract void chooseBandCodings() throws IOException;

        public final long outputSize() {
            if (outputSize >= 0) {
                long size = outputSize;
                assert(size == computeOutputSize());
                return size;
            }
            return computeOutputSize();
        }

        protected abstract long computeOutputSize();

        abstract protected void writeDataTo(OutputStream out) throws IOException;

        /** Expect a certain number of values. */
        void expectLength(int l) {
            assert(assertPhase(this, EXPECT_PHASE));
            assert(valuesExpected == 0);  // all at once
            assert(l >= 0);
            valuesExpected = l;
        }
        /** Expect more values.  (Multiple calls accumulate.) */
        void expectMoreLength(int l) {
            assert(assertPhase(this, EXPECT_PHASE));
            valuesExpected += l;
        }


        /// Phase change markers.

        private void readyToCollect() { // called implicitly by constructor
            setCapacity(1);
            setPhase(COLLECT_PHASE);
        }
        protected void doneWriting() {
            assert(assertPhase(this, WRITE_PHASE));
            setPhase(DONE_PHASE);
        }
        private void readyToExpect() { // called implicitly by constructor
            setPhase(EXPECT_PHASE);
        }
        /** Read in bytes, decoding the values. */
        public final void readFrom(InputStream in) throws IOException {
            assert(assertReadyToReadFrom(this, in));
            setCapacity(valuesExpected());
            setPhase(READ_PHASE);
            // subclasses continue by reading their contents from input:
            readDataFrom(in);
            readyToDisburse();
        }
        abstract protected void readDataFrom(InputStream in) throws IOException;
        protected void readyToDisburse() {
            if (verbose > 1)  Utils.log.fine("readyToDisburse "+this);
            setPhase(DISBURSE_PHASE);
        }
        public void doneDisbursing() {
            assert(assertPhase(this, DISBURSE_PHASE));
            setPhase(DONE_PHASE);
        }
        public final void doneWithUnusedBand() {
            if (isReader) {
                assert(assertPhase(this, EXPECT_PHASE));
                assert(valuesExpected() == 0);
                // Fast forward:
                setPhase(READ_PHASE);
                setPhase(DISBURSE_PHASE);
                setPhase(DONE_PHASE);
            } else {
                setPhase(FROZEN_PHASE);
            }
        }

        protected void setPhase(int newPhase) {
            assert(assertPhaseChangeOK(this, phase, newPhase));
            this.phase = newPhase;
        }

        protected int lengthForDebug = -1;  // DEBUG ONLY
        @Override
        public String toString() {  // DEBUG ONLY
            int length = (lengthForDebug != -1 ? lengthForDebug : length());
            String str = name;
            if (length != 0)
                str += "[" + length + "]";
            if (elementCountForDebug != 0)
                str += "(" + elementCountForDebug + ")";
            return str;
        }
    }

    class ValueBand extends Band {
        private int[]  values;   // must be null in EXPECT phase
        private int    length;
        private int    valuesDisbursed;

        private CodingMethod bandCoding;
        private byte[] metaCoding;

        protected ValueBand(String name, Coding regularCoding) {
            super(name, regularCoding);
        }

        @Override
        public int capacity() {
            return values == null ? -1 : values.length;
        }

        /** Declare predicted or needed capacity. */
        @Override
        protected void setCapacity(int cap) {
            assert(length <= cap);
            if (cap == -1) { values = null; return; }
            values = realloc(values, cap);
        }

        @Override
        public int length() {
            return length;
        }
        @Override
        protected int valuesRemainingForDebug() {
            return length - valuesDisbursed;
        }
        protected int valueAtForDebug(int i) {
            return values[i];
        }

        void patchValue(int i, int value) {
            // Only one use for this.
            assert(this == archive_header_S);
            assert(i == AH_ARCHIVE_SIZE_HI || i == AH_ARCHIVE_SIZE_LO);
            assert(i < length);  // must have already output a dummy
            values[i] = value;
            outputSize = -1;  // decache
        }

        protected void initializeValues(int[] values) {
            assert(assertCanChangeLength(this));
            assert(length == 0);
            this.values = values;
            this.length = values.length;
        }

        /** Collect one value, or store one decoded value. */
        protected void addValue(int x) {
            assert(assertCanChangeLength(this));
            if (length == values.length)
                setCapacity(length < 1000 ? length * 10 : length * 2);
            values[length++] = x;
        }

        private boolean canVaryCoding() {
            if (!optVaryCodings)           return false;
            if (length == 0)               return false;
            // Can't read band_headers w/o the archive header:
            if (this == archive_header_0)  return false;
            if (this == archive_header_S)  return false;
            if (this == archive_header_1)  return false;
            // BYTE1 bands can't vary codings, but the others can.
            // All that's needed for the initial escape is at least
            // 256 negative values or more than 256 non-negative values
            return (regularCoding.min() <= -256 || regularCoding.max() >= 256);
        }

        private boolean shouldVaryCoding() {
            assert(canVaryCoding());
            if (effort < MAX_EFFORT && length < SHORT_BAND_HEURISTIC)
                return false;
            return true;
        }

        @Override
        protected void chooseBandCodings() throws IOException {
            boolean canVary = canVaryCoding();
            if (!canVary || !shouldVaryCoding()) {
                if (regularCoding.canRepresent(values, 0, length)) {
                    bandCoding = regularCoding;
                } else {
                    assert(canVary);
                    if (verbose > 1)
                        Utils.log.fine("regular coding fails in band "+name());
                    bandCoding = UNSIGNED5;
                }
                outputSize = -1;
            } else {
                int[] sizes = {0,0};
                bandCoding = chooseCoding(values, 0, length,
                                          regularCoding, name(),
                                          sizes);
                outputSize = sizes[CodingChooser.BYTE_SIZE];
                if (outputSize == 0)  // CodingChooser failed to size it.
                    outputSize = -1;
            }

            // Compute and save the meta-coding bytes also.
            if (bandCoding != regularCoding) {
                metaCoding = bandCoding.getMetaCoding(regularCoding);
                if (verbose > 1) {
                    Utils.log.fine("alternate coding "+this+" "+bandCoding);
                }
            } else if (canVary &&
                       decodeEscapeValue(values[0], regularCoding) >= 0) {
                // Need an explicit default.
                metaCoding = defaultMetaCoding;
            } else {
                // Common case:  Zero bytes of meta coding.
                metaCoding = noMetaCoding;
            }
            if (metaCoding.length > 0
                && (verbose > 2 || verbose > 1 && metaCoding.length > 1)) {
                StringBuffer sb = new StringBuffer();
                for (int i = 0; i < metaCoding.length; i++) {
                    if (i == 1)  sb.append(" /");
                    sb.append(" ").append(metaCoding[i] & 0xFF);
                }
                Utils.log.fine("   meta-coding "+sb);
            }

            assert((outputSize < 0) ||
                   !(bandCoding instanceof Coding) ||
                   (outputSize == ((Coding)bandCoding)
                    .getLength(values, 0, length)))
                : (bandCoding+" : "+
                   outputSize+" != "+
                   ((Coding)bandCoding).getLength(values, 0, length)
                   +" ?= "+getCodingChooser().computeByteSize(bandCoding,values,0,length)
                   );

            // Compute outputSize of the escape value X, if any.
            if (metaCoding.length > 0) {
                // First byte XB of meta-coding is treated specially,
                // but any other bytes go into the band headers band.
                // This must be done before any other output happens.
                if (outputSize >= 0)
                    outputSize += computeEscapeSize();  // good cache
                // Other bytes go into band_headers.
                for (int i = 1; i < metaCoding.length; i++) {
                    band_headers.putByte(metaCoding[i] & 0xFF);
                }
            }
        }

        @Override
        protected long computeOutputSize() {
            outputSize = getCodingChooser().computeByteSize(bandCoding,
                                                            values, 0, length);
            assert(outputSize < Integer.MAX_VALUE);
            outputSize += computeEscapeSize();
            return outputSize;
        }

        protected int computeEscapeSize() {
            if (metaCoding.length == 0)  return 0;
            int XB = metaCoding[0] & 0xFF;
            int X = encodeEscapeValue(XB, regularCoding);
            return regularCoding.setD(0).getLength(X);
        }

        @Override
        protected void writeDataTo(OutputStream out) throws IOException {
            if (length == 0)  return;  // nothing to write
            long len0 = 0;
            if (out == outputCounter) {
                len0 = outputCounter.getCount();
            }
            if (metaCoding.length > 0) {
                int XB = metaCoding[0] & 0xFF;
                // We need an explicit band header, either because
                // there is a non-default coding method, or because
                // the first value would be parsed as an escape value.
                int X = encodeEscapeValue(XB, regularCoding);
                //System.out.println("X="+X+" XB="+XB+" in "+this);
                regularCoding.setD(0).writeTo(out, X);
            }
            bandCoding.writeArrayTo(out, values, 0, length);
            if (out == outputCounter) {
                assert(outputSize == outputCounter.getCount() - len0)
                    : (outputSize+" != "+outputCounter.getCount()+"-"+len0);
            }
            if (optDumpBands)  dumpBand();
        }

        @Override
        protected void readDataFrom(InputStream in) throws IOException {
            length = valuesExpected();
            if (length == 0)  return;  // nothing to read
            if (verbose > 1)
                Utils.log.fine("Reading band "+this);
            if (!canVaryCoding()) {
                bandCoding = regularCoding;
                metaCoding = noMetaCoding;
            } else {
                assert(in.markSupported());  // input must be buffered
                in.mark(Coding.B_MAX);
                int X = regularCoding.setD(0).readFrom(in);
                int XB = decodeEscapeValue(X, regularCoding);
                if (XB < 0) {
                    // Do not consume this value.  No alternate coding.
                    in.reset();
                    bandCoding = regularCoding;
                    metaCoding = noMetaCoding;
                } else if (XB == _meta_default) {
                    bandCoding = regularCoding;
                    metaCoding = defaultMetaCoding;
                } else {
                    if (verbose > 2)
                        Utils.log.fine("found X="+X+" => XB="+XB);
                    bandCoding = getBandHeader(XB, regularCoding);
                    // This is really used only by dumpBands.
                    int p0 = bandHeaderBytePos0;
                    int p1 = bandHeaderBytePos;
                    metaCoding = new byte[p1-p0];
                    System.arraycopy(bandHeaderBytes, p0,
                                     metaCoding, 0, metaCoding.length);
                }
            }
            if (bandCoding != regularCoding) {
                if (verbose > 1)
                    Utils.log.fine(name()+": irregular coding "+bandCoding);
            }
            bandCoding.readArrayFrom(in, values, 0, length);
            if (optDumpBands)  dumpBand();
        }

        @Override
        public void doneDisbursing() {
            super.doneDisbursing();
            values = null;  // for GC
        }

        private void dumpBand() throws IOException {
            assert(optDumpBands);
            try (PrintStream ps = new PrintStream(getDumpStream(this, ".txt"))) {
                String irr = (bandCoding == regularCoding) ? "" : " irregular";
                ps.print("# length="+length+
                         " size="+outputSize()+
                         irr+" coding="+bandCoding);
                if (metaCoding != noMetaCoding) {
                    StringBuffer sb = new StringBuffer();
                    for (int i = 0; i < metaCoding.length; i++) {
                        if (i == 1)  sb.append(" /");
                        sb.append(" ").append(metaCoding[i] & 0xFF);
                    }
                    ps.print(" //header: "+sb);
                }
                printArrayTo(ps, values, 0, length);
            }
            try (OutputStream ds = getDumpStream(this, ".bnd")) {
                bandCoding.writeArrayTo(ds, values, 0, length);
            }
        }

        /** Disburse one value. */
        protected int getValue() {
            assert(phase() == DISBURSE_PHASE);
            // when debugging return a zero if lengths are zero
            if (optDebugBands && length == 0 && valuesDisbursed == length)
                return 0;
            assert(valuesDisbursed <= length);
            return values[valuesDisbursed++];
        }

        /** Reset for another pass over the same value set. */
        public void resetForSecondPass() {
            assert(phase() == DISBURSE_PHASE);
            assert(valuesDisbursed == length());  // 1st pass is complete
            valuesDisbursed = 0;
        }
    }

    class ByteBand extends Band {
        private ByteArrayOutputStream bytes;  // input buffer
        private ByteArrayOutputStream bytesForDump;
        private InputStream in;

        public ByteBand(String name) {
            super(name, BYTE1);
        }

        @Override
        public int capacity() {
            return bytes == null ? -1 : Integer.MAX_VALUE;
        }
        @Override
        protected void setCapacity(int cap) {
            assert(bytes == null);  // do this just once
            bytes = new ByteArrayOutputStream(cap);
        }
        public void destroy() {
            lengthForDebug = length();
            bytes = null;
        }

        @Override
        public int length() {
            return bytes == null ? -1 : bytes.size();
        }
        public void reset() {
            bytes.reset();
        }
        @Override
        protected int valuesRemainingForDebug() {
            return (bytes == null) ? -1 : ((ByteArrayInputStream)in).available();
        }

        @Override
        protected void chooseBandCodings() throws IOException {
            // No-op.
            assert(decodeEscapeValue(regularCoding.min(), regularCoding) < 0);
            assert(decodeEscapeValue(regularCoding.max(), regularCoding) < 0);
        }

        @Override
        protected long computeOutputSize() {
            // do not cache
            return bytes.size();
        }

        @Override
        public void writeDataTo(OutputStream out) throws IOException {
            if (length() == 0)  return;
            bytes.writeTo(out);
            if (optDumpBands)  dumpBand();
            destroy();  // done with the bits!
        }

        private void dumpBand() throws IOException {
            assert(optDumpBands);
            try (OutputStream ds = getDumpStream(this, ".bnd")) {
                if (bytesForDump != null)
                    bytesForDump.writeTo(ds);
                else
                    bytes.writeTo(ds);
            }
        }

        @Override
        public void readDataFrom(InputStream in) throws IOException {
            int vex = valuesExpected();
            if (vex == 0)  return;
            if (verbose > 1) {
                lengthForDebug = vex;
                Utils.log.fine("Reading band "+this);
                lengthForDebug = -1;
            }
            byte[] buf = new byte[Math.min(vex, 1<<14)];
            while (vex > 0) {
                int nr = in.read(buf, 0, Math.min(vex, buf.length));
                if (nr < 0)  throw new EOFException();
                bytes.write(buf, 0, nr);
                vex -= nr;
            }
            if (optDumpBands)  dumpBand();
        }

        @Override
        public void readyToDisburse() {
            in = new ByteArrayInputStream(bytes.toByteArray());
            super.readyToDisburse();
        }

        @Override
        public void doneDisbursing() {
            super.doneDisbursing();
            if (optDumpBands
                && bytesForDump != null && bytesForDump.size() > 0) {
                try {
                    dumpBand();
                } catch (IOException ee) {
                    throw new RuntimeException(ee);
                }
            }
            in = null; // GC
            bytes = null;  // GC
            bytesForDump = null;  // GC
        }

        // alternative to readFrom:
        public void setInputStreamFrom(InputStream in) throws IOException {
            assert(bytes == null);
            assert(assertReadyToReadFrom(this, in));
            setPhase(READ_PHASE);
            this.in = in;
            if (optDumpBands) {
                // Tap the stream.
                bytesForDump = new ByteArrayOutputStream();
                this.in = new FilterInputStream(in) {
                    @Override
                    public int read() throws IOException {
                        int ch = in.read();
                        if (ch >= 0)  bytesForDump.write(ch);
                        return ch;
                    }
                    @Override
                    public int read(byte b[], int off, int len) throws IOException {
                        int nr = in.read(b, off, len);
                        if (nr >= 0)  bytesForDump.write(b, off, nr);
                        return nr;
                    }
                };
            }
            super.readyToDisburse();
        }

        public OutputStream collectorStream() {
            assert(phase() == COLLECT_PHASE);
            assert(bytes != null);
            return bytes;
        }

        public InputStream getInputStream() {
            assert(phase() == DISBURSE_PHASE);
            assert(in != null);
            return in;
        }
        public int getByte() throws IOException {
            int b = getInputStream().read();
            if (b < 0)  throw new EOFException();
            return b;
        }
        public void putByte(int b) throws IOException {
            assert(b == (b & 0xFF));
            collectorStream().write(b);
        }
        @Override
        public String toString() {
            return "byte "+super.toString();
        }
    }

    class IntBand extends ValueBand {
        // The usual coding for bands is 7bit/5byte/delta.
        public IntBand(String name, Coding regularCoding) {
            super(name, regularCoding);
        }

        public void putInt(int x) {
            assert(phase() == COLLECT_PHASE);
            addValue(x);
        }

        public int getInt() {
            return getValue();
        }
        /** Return the sum of all values in this band. */
        public int getIntTotal() {
            assert(phase() == DISBURSE_PHASE);
            // assert that this is the whole pass; no other reads allowed
            assert(valuesRemainingForDebug() == length());
            int total = 0;
            for (int k = length(); k > 0; k--) {
                total += getInt();
            }
            resetForSecondPass();
            return total;
        }
        /** Return the occurrence count of a specific value in this band. */
        public int getIntCount(int value) {
            assert(phase() == DISBURSE_PHASE);
            // assert that this is the whole pass; no other reads allowed
            assert(valuesRemainingForDebug() == length());
            int total = 0;
            for (int k = length(); k > 0; k--) {
                if (getInt() == value) {
                    total += 1;
                }
            }
            resetForSecondPass();
            return total;
        }
    }

    static int getIntTotal(int[] values) {
        int total = 0;
        for (int i = 0; i < values.length; i++) {
            total += values[i];
        }
        return total;
    }

    class CPRefBand extends ValueBand {
        Index index;
        boolean nullOK;

        public CPRefBand(String name, Coding regularCoding, byte cpTag, boolean nullOK) {
            super(name, regularCoding);
            this.nullOK = nullOK;
            if (cpTag != CONSTANT_None)
                setBandIndex(this, cpTag);
        }
        public CPRefBand(String name, Coding regularCoding, byte cpTag) {
            this(name, regularCoding, cpTag, false);
        }
        public CPRefBand(String name, Coding regularCoding, Object undef) {
            this(name, regularCoding, CONSTANT_None, false);
        }

        public void setIndex(Index index) {
            this.index = index;
        }

        protected void readDataFrom(InputStream in) throws IOException {
            super.readDataFrom(in);
            assert(assertValidCPRefs(this));
        }

        /** Write a constant pool reference. */
        public void putRef(Entry e) {
            addValue(encodeRefOrNull(e, index));
        }
        public void putRef(Entry e, Index index) {
            assert(this.index == null);
            addValue(encodeRefOrNull(e, index));
        }
        public void putRef(Entry e, byte cptag) {
            putRef(e, getCPIndex(cptag));
        }

        public Entry getRef() {
            if (index == null)  Utils.log.warning("No index for "+this);
            assert(index != null);
            return decodeRefOrNull(getValue(), index);
        }
        public Entry getRef(Index index) {
            assert(this.index == null);
            return decodeRefOrNull(getValue(), index);
        }
        public Entry getRef(byte cptag) {
            return getRef(getCPIndex(cptag));
        }

        private int encodeRefOrNull(Entry e, Index index) {
            int nonNullCode;  // NNC is the coding which assumes nulls are rare
            if (e == null) {
                nonNullCode = -1;  // negative values are rare
            } else {
                nonNullCode = encodeRef(e, index);
            }
            // If nulls are expected, increment, to make -1 code turn to 0.
            return (nullOK ? 1 : 0) + nonNullCode;
        }
        private Entry decodeRefOrNull(int code, Index index) {
            // Inverse to encodeRefOrNull...
            int nonNullCode = code - (nullOK ? 1 : 0);
            if (nonNullCode == -1) {
                return null;
            } else {
                return decodeRef(nonNullCode, index);
            }
        }
    }

    // Bootstrap support for CPRefBands.  These are needed to record
    // intended CP indexes, before the CP has been created.
    private final List<CPRefBand> allKQBands = new ArrayList<>();
    private List<Object[]> needPredefIndex = new ArrayList<>();


    int encodeRef(Entry e, Index ix) {
        if (ix == null)
            throw new RuntimeException("null index for " + e.stringValue());
        int coding = ix.indexOf(e);
        if (verbose > 2)
            Utils.log.fine("putRef "+coding+" => "+e);
        return coding;
    }

    Entry decodeRef(int n, Index ix) {
        if (n < 0 || n >= ix.size())
            Utils.log.warning("decoding bad ref "+n+" in "+ix);
        Entry e = ix.getEntry(n);
        if (verbose > 2)
            Utils.log.fine("getRef "+n+" => "+e);
        return e;
    }

    private CodingChooser codingChooser;
    protected CodingChooser getCodingChooser() {
        if (codingChooser == null) {
            codingChooser = new CodingChooser(effort, basicCodings);
            if (codingChooser.stress != null
                && this instanceof PackageWriter) {
                // Twist the random state based on my first file.
                // This sends each segment off in a different direction.
                List<Package.Class> classes = ((PackageWriter)this).pkg.classes;
                if (!classes.isEmpty()) {
                    Package.Class cls = classes.get(0);
                    codingChooser.addStressSeed(cls.getName().hashCode());
                }
            }
        }
        return codingChooser;
    }

    public CodingMethod chooseCoding(int[] values, int start, int end,
                                     Coding regular, String bandName,
                                     int[] sizes) {
        assert(optVaryCodings);
        if (effort <= MIN_EFFORT) {
            return regular;
        }
        CodingChooser cc = getCodingChooser();
        if (verbose > 1 || cc.verbose > 1) {
            Utils.log.fine("--- chooseCoding "+bandName);
        }
        return cc.choose(values, start, end, regular, sizes);
    }

    static final byte[] defaultMetaCoding = { _meta_default };
    static final byte[] noMetaCoding      = {};

    // The first value in a band is always coded with the default coding D.
    // If this first value X is an escape value, it actually represents the
    // first (and perhaps only) byte of a meta-coding.
    //
    // If D.S != 0 and D includes the range [-256..-1],
    // the escape values are in that range,
    // and the first byte XB is -1-X.
    //
    // If D.S == 0 and D includes the range [(D.L)..(D.L)+255],
    // the escape values are in that range,
    // and XB is X-(D.L).
    //
    // This representation is designed so that a band header is unlikely
    // to be confused with the initial value of a headerless band,
    // and yet so that a band header is likely to occupy only a byte or two.
    //
    // Result is in [0..255] if XB was successfully extracted, else -1.
    // See section "Coding Specifier Meta-Encoding" in the JSR 200 spec.
    protected static int decodeEscapeValue(int X, Coding regularCoding) {
        // The first value in a band is always coded with the default coding D.
        // If this first value X is an escape value, it actually represents the
        // first (and perhaps only) byte of a meta-coding.
        // Result is in [0..255] if XB was successfully extracted, else -1.
        if (regularCoding.B() == 1 || regularCoding.L() == 0)
            return -1;  // degenerate regular coding (BYTE1)
        if (regularCoding.S() != 0) {
            if (-256 <= X && X <= -1 && regularCoding.min() <= -256) {
                int XB = -1-X;
                assert(XB >= 0 && XB < 256);
                return XB;
            }
        } else {
            int L = regularCoding.L();
            if (L <= X && X <= L+255 && regularCoding.max() >= L+255) {
                int XB = X-L;
                assert(XB >= 0 && XB < 256);
                return XB;
            }
        }
        return -1;  // negative value for failure
    }
    // Inverse to decodeEscapeValue().
    protected static int encodeEscapeValue(int XB, Coding regularCoding) {
        assert(XB >= 0 && XB < 256);
        assert(regularCoding.B() > 1 && regularCoding.L() > 0);
        int X;
        if (regularCoding.S() != 0) {
            assert(regularCoding.min() <= -256);
            X = -1-XB;
        } else {
            int L = regularCoding.L();
            assert(regularCoding.max() >= L+255);
            X = XB+L;
        }
        assert(decodeEscapeValue(X, regularCoding) == XB)
            : (regularCoding+" XB="+XB+" X="+X);
        return X;
    }

    static {
        boolean checkXB = false;
        assert(checkXB = true);
        if (checkXB) {
            for (int i = 0; i < basicCodings.length; i++) {
                Coding D = basicCodings[i];
                if (D == null)   continue;
                if (D.B() == 1)  continue;
                if (D.L() == 0)  continue;
                for (int XB = 0; XB <= 255; XB++) {
                    // The following exercises decodeEscapeValue also:
                    encodeEscapeValue(XB, D);
                }
            }
        }
    }

    class MultiBand extends Band {
        MultiBand(String name, Coding regularCoding) {
            super(name, regularCoding);
        }

        @Override
        public Band init() {
            super.init();
            // This is all just to keep the asserts happy:
            setCapacity(0);
            if (phase() == EXPECT_PHASE) {
                // Fast forward:
                setPhase(READ_PHASE);
                setPhase(DISBURSE_PHASE);
            }
            return this;
        }

        Band[] bands     = new Band[10];
        int    bandCount = 0;

        int size() {
            return bandCount;
        }
        Band get(int i) {
            assert(i < bandCount);
            return bands[i];
        }
        Band[] toArray() {
            return (Band[]) realloc(bands, bandCount);
        }

        void add(Band b) {
            assert(bandCount == 0 || notePrevForAssert(b, bands[bandCount-1]));
            if (bandCount == bands.length) {
                bands = (Band[]) realloc(bands);
            }
            bands[bandCount++] = b;
        }

        ByteBand newByteBand(String name) {
            ByteBand b = new ByteBand(name);
            b.init(); add(b);
            return b;
        }
        IntBand newIntBand(String name) {
            IntBand b = new IntBand(name, regularCoding);
            b.init(); add(b);
            return b;
        }
        IntBand newIntBand(String name, Coding regularCoding) {
            IntBand b = new IntBand(name, regularCoding);
            b.init(); add(b);
            return b;
        }
        MultiBand newMultiBand(String name, Coding regularCoding) {
            MultiBand b = new MultiBand(name, regularCoding);
            b.init(); add(b);
            return b;
        }
        CPRefBand newCPRefBand(String name, byte cpTag) {
            CPRefBand b = new CPRefBand(name, regularCoding, cpTag);
            b.init(); add(b);
            return b;
        }
        CPRefBand newCPRefBand(String name, Coding regularCoding,
                               byte cpTag) {
            CPRefBand b = new CPRefBand(name, regularCoding, cpTag);
            b.init(); add(b);
            return b;
        }
        CPRefBand newCPRefBand(String name, Coding regularCoding,
                               byte cpTag, boolean nullOK) {
            CPRefBand b = new CPRefBand(name, regularCoding, cpTag, nullOK);
            b.init(); add(b);
            return b;
        }

        int bandCount() { return bandCount; }

        private int cap = -1;
        @Override
        public int capacity() { return cap; }
        @Override
        public void setCapacity(int cap) { this.cap = cap; }

        @Override
        public int length() { return 0; }
        @Override
        public int valuesRemainingForDebug() { return 0; }

        @Override
        protected void chooseBandCodings() throws IOException {
            // coding decision pass
            for (int i = 0; i < bandCount; i++) {
                Band b = bands[i];
                b.chooseBandCodings();
            }
        }

        @Override
        protected long computeOutputSize() {
            // coding decision pass
            long sum = 0;
            for (int i = 0; i < bandCount; i++) {
                Band b = bands[i];
                long bsize = b.outputSize();
                assert(bsize >= 0) : b;
                sum += bsize;
            }
            // do not cache
            return sum;
        }

        @Override
        protected void writeDataTo(OutputStream out) throws IOException {
            long preCount = 0;
            if (outputCounter != null)  preCount = outputCounter.getCount();
            for (int i = 0; i < bandCount; i++) {
                Band b = bands[i];
                b.writeTo(out);
                if (outputCounter != null) {
                    long postCount = outputCounter.getCount();
                    long len = postCount - preCount;
                    preCount = postCount;
                    if ((verbose > 0 && len > 0) || verbose > 1) {
                        Utils.log.info("  ...wrote "+len+" bytes from "+b);
                    }
                }
            }
        }

        @Override
        protected void readDataFrom(InputStream in) throws IOException {
            assert(false);  // not called?
            for (int i = 0; i < bandCount; i++) {
                Band b = bands[i];
                b.readFrom(in);
                if ((verbose > 0 && b.length() > 0) || verbose > 1) {
                    Utils.log.info("  ...read "+b);
                }
            }
        }

        @Override
        public String toString() {
            return "{"+bandCount()+" bands: "+super.toString()+"}";
        }
    }

    /**
     * An output stream which counts the number of bytes written.
     */
    private static
    class ByteCounter extends FilterOutputStream {
        // (should go public under the name CountingOutputStream?)

        private long count;

        public ByteCounter(OutputStream out) {
            super(out);
        }

        public long getCount() { return count; }
        public void setCount(long c) { count = c; }

        @Override
        public void write(int b) throws IOException {
            count++;
            if (out != null)  out.write(b);
        }
        @Override
        public void write(byte b[], int off, int len) throws IOException {
            count += len;
            if (out != null)  out.write(b, off, len);
        }
        @Override
        public String toString() {
            return String.valueOf(getCount());
        }
    }
    ByteCounter outputCounter;

    void writeAllBandsTo(OutputStream out) throws IOException {
        // Wrap a byte-counter around the output stream.
        outputCounter = new ByteCounter(out);
        out = outputCounter;
        all_bands.writeTo(out);
        if (verbose > 0) {
            long nbytes = outputCounter.getCount();
            Utils.log.info("Wrote total of "+nbytes+" bytes.");
            assert(nbytes == archiveSize0+archiveSize1);
        }
        outputCounter = null;
    }

    // random AO_XXX bits, decoded from the archive header
    protected int archiveOptions;

    // archiveSize1 sizes most of the archive [archive_options..file_bits).
    protected long archiveSize0; // size through archive_size_lo
    protected long archiveSize1; // size reported in archive_header
    protected int  archiveNextCount; // reported in archive_header

    static final int AH_LENGTH_0 = 3;     // archive_header_0 = {minver, majver, options}
    static final int AH_LENGTH_MIN = 15;  // observed in spec {header_0[3], cp_counts[8], class_counts[4]}
    // Length contributions from optional archive size fields:
    static final int AH_LENGTH_S = 2; // archive_header_S = optional {size_hi, size_lo}
    static final int AH_ARCHIVE_SIZE_HI = 0; // offset in archive_header_S
    static final int AH_ARCHIVE_SIZE_LO = 1; // offset in archive_header_S
    // Length contributions from optional header fields:
    static final int AH_FILE_HEADER_LEN = 5; // file_counts = {{size_hi, size_lo}, next, modtime, files}
    static final int AH_SPECIAL_FORMAT_LEN = 2; // special_counts = {layouts, band_headers}
    static final int AH_CP_NUMBER_LEN = 4;  // cp_number_counts = {int, float, long, double}
    static final int AH_CP_EXTRA_LEN = 4;  // cp_attr_counts = {MH, MT, InDy, BSM}

    // Common structure of attribute band groups:
    static final int AB_FLAGS_HI = 0;
    static final int AB_FLAGS_LO = 1;
    static final int AB_ATTR_COUNT = 2;
    static final int AB_ATTR_INDEXES = 3;
    static final int AB_ATTR_CALLS = 4;

    static IntBand getAttrBand(MultiBand xxx_attr_bands, int which) {
        IntBand b = (IntBand) xxx_attr_bands.get(which);
        switch (which) {
        case AB_FLAGS_HI:
            assert(b.name().endsWith("_flags_hi")); break;
        case AB_FLAGS_LO:
            assert(b.name().endsWith("_flags_lo")); break;
        case AB_ATTR_COUNT:
            assert(b.name().endsWith("_attr_count")); break;
        case AB_ATTR_INDEXES:
            assert(b.name().endsWith("_attr_indexes")); break;
        case AB_ATTR_CALLS:
            assert(b.name().endsWith("_attr_calls")); break;
        default:
            assert(false); break;
        }
        return b;
    }

    static private final boolean NULL_IS_OK = true;

    MultiBand all_bands = (MultiBand) new MultiBand("(package)", UNSIGNED5).init();

    // file header (various random bytes)
    ByteBand archive_magic = all_bands.newByteBand("archive_magic");
    IntBand  archive_header_0 = all_bands.newIntBand("archive_header_0", UNSIGNED5);
    IntBand  archive_header_S = all_bands.newIntBand("archive_header_S", UNSIGNED5);
    IntBand  archive_header_1 = all_bands.newIntBand("archive_header_1", UNSIGNED5);
    ByteBand band_headers = all_bands.newByteBand("band_headers");

    // constant pool contents
    MultiBand cp_bands = all_bands.newMultiBand("(constant_pool)", DELTA5);
    IntBand   cp_Utf8_prefix = cp_bands.newIntBand("cp_Utf8_prefix");
    IntBand   cp_Utf8_suffix = cp_bands.newIntBand("cp_Utf8_suffix", UNSIGNED5);
    IntBand   cp_Utf8_chars = cp_bands.newIntBand("cp_Utf8_chars", CHAR3);
    IntBand   cp_Utf8_big_suffix = cp_bands.newIntBand("cp_Utf8_big_suffix");
    MultiBand cp_Utf8_big_chars = cp_bands.newMultiBand("(cp_Utf8_big_chars)", DELTA5);
    IntBand   cp_Int = cp_bands.newIntBand("cp_Int", UDELTA5);
    IntBand   cp_Float = cp_bands.newIntBand("cp_Float", UDELTA5);
    IntBand   cp_Long_hi = cp_bands.newIntBand("cp_Long_hi", UDELTA5);
    IntBand   cp_Long_lo = cp_bands.newIntBand("cp_Long_lo");
    IntBand   cp_Double_hi = cp_bands.newIntBand("cp_Double_hi", UDELTA5);
    IntBand   cp_Double_lo = cp_bands.newIntBand("cp_Double_lo");
    CPRefBand cp_String = cp_bands.newCPRefBand("cp_String", UDELTA5, CONSTANT_Utf8);
    CPRefBand cp_Class = cp_bands.newCPRefBand("cp_Class", UDELTA5, CONSTANT_Utf8);
    CPRefBand cp_Signature_form = cp_bands.newCPRefBand("cp_Signature_form", CONSTANT_Utf8);
    CPRefBand cp_Signature_classes = cp_bands.newCPRefBand("cp_Signature_classes", UDELTA5, CONSTANT_Class);
    CPRefBand cp_Descr_name = cp_bands.newCPRefBand("cp_Descr_name", CONSTANT_Utf8);
    CPRefBand cp_Descr_type = cp_bands.newCPRefBand("cp_Descr_type", UDELTA5, CONSTANT_Signature);
    CPRefBand cp_Field_class = cp_bands.newCPRefBand("cp_Field_class", CONSTANT_Class);
    CPRefBand cp_Field_desc = cp_bands.newCPRefBand("cp_Field_desc", UDELTA5, CONSTANT_NameandType);
    CPRefBand cp_Method_class = cp_bands.newCPRefBand("cp_Method_class", CONSTANT_Class);
    CPRefBand cp_Method_desc = cp_bands.newCPRefBand("cp_Method_desc", UDELTA5, CONSTANT_NameandType);
    CPRefBand cp_Imethod_class = cp_bands.newCPRefBand("cp_Imethod_class", CONSTANT_Class);
    CPRefBand cp_Imethod_desc = cp_bands.newCPRefBand("cp_Imethod_desc", UDELTA5, CONSTANT_NameandType);
    IntBand   cp_MethodHandle_refkind = cp_bands.newIntBand("cp_MethodHandle_refkind", DELTA5);
    CPRefBand cp_MethodHandle_member = cp_bands.newCPRefBand("cp_MethodHandle_member", UDELTA5, CONSTANT_AnyMember);
    CPRefBand cp_MethodType = cp_bands.newCPRefBand("cp_MethodType", UDELTA5, CONSTANT_Signature);
    CPRefBand cp_BootstrapMethod_ref = cp_bands.newCPRefBand("cp_BootstrapMethod_ref", DELTA5, CONSTANT_MethodHandle);
    IntBand   cp_BootstrapMethod_arg_count = cp_bands.newIntBand("cp_BootstrapMethod_arg_count", UDELTA5);
    CPRefBand cp_BootstrapMethod_arg = cp_bands.newCPRefBand("cp_BootstrapMethod_arg", DELTA5, CONSTANT_LoadableValue);
    CPRefBand cp_InvokeDynamic_spec = cp_bands.newCPRefBand("cp_InvokeDynamic_spec", DELTA5, CONSTANT_BootstrapMethod);
    CPRefBand cp_InvokeDynamic_desc = cp_bands.newCPRefBand("cp_InvokeDynamic_desc", UDELTA5, CONSTANT_NameandType);

    // bands for carrying attribute definitions:
    MultiBand attr_definition_bands = all_bands.newMultiBand("(attr_definition_bands)", UNSIGNED5);
    ByteBand attr_definition_headers = attr_definition_bands.newByteBand("attr_definition_headers");
    CPRefBand attr_definition_name = attr_definition_bands.newCPRefBand("attr_definition_name", CONSTANT_Utf8);
    CPRefBand attr_definition_layout = attr_definition_bands.newCPRefBand("attr_definition_layout", CONSTANT_Utf8);

    // bands for hardwired InnerClasses attribute (shared across the package)
    MultiBand ic_bands = all_bands.newMultiBand("(ic_bands)", DELTA5);
    CPRefBand ic_this_class = ic_bands.newCPRefBand("ic_this_class", UDELTA5, CONSTANT_Class);
    IntBand ic_flags = ic_bands.newIntBand("ic_flags", UNSIGNED5);
    // These bands contain data only where flags sets ACC_IC_LONG_FORM:
    CPRefBand ic_outer_class = ic_bands.newCPRefBand("ic_outer_class", DELTA5, CONSTANT_Class, NULL_IS_OK);
    CPRefBand ic_name = ic_bands.newCPRefBand("ic_name", DELTA5, CONSTANT_Utf8, NULL_IS_OK);

    // bands for carrying class schema information:
    MultiBand class_bands = all_bands.newMultiBand("(class_bands)", DELTA5);
    CPRefBand class_this = class_bands.newCPRefBand("class_this", CONSTANT_Class);
    CPRefBand class_super = class_bands.newCPRefBand("class_super", CONSTANT_Class);
    IntBand   class_interface_count = class_bands.newIntBand("class_interface_count");
    CPRefBand class_interface = class_bands.newCPRefBand("class_interface", CONSTANT_Class);

    // bands for class members
    IntBand   class_field_count = class_bands.newIntBand("class_field_count");
    IntBand   class_method_count = class_bands.newIntBand("class_method_count");

    CPRefBand field_descr = class_bands.newCPRefBand("field_descr", CONSTANT_NameandType);
    MultiBand field_attr_bands = class_bands.newMultiBand("(field_attr_bands)", UNSIGNED5);
    IntBand field_flags_hi = field_attr_bands.newIntBand("field_flags_hi");
    IntBand field_flags_lo = field_attr_bands.newIntBand("field_flags_lo");
    IntBand field_attr_count = field_attr_bands.newIntBand("field_attr_count");
    IntBand field_attr_indexes = field_attr_bands.newIntBand("field_attr_indexes");
    IntBand field_attr_calls = field_attr_bands.newIntBand("field_attr_calls");

    // bands for predefined field attributes
    CPRefBand field_ConstantValue_KQ = field_attr_bands.newCPRefBand("field_ConstantValue_KQ", CONSTANT_FieldSpecific);
    CPRefBand field_Signature_RS = field_attr_bands.newCPRefBand("field_Signature_RS", CONSTANT_Signature);
    MultiBand field_metadata_bands = field_attr_bands.newMultiBand("(field_metadata_bands)", UNSIGNED5);
    MultiBand field_type_metadata_bands = field_attr_bands.newMultiBand("(field_type_metadata_bands)", UNSIGNED5);

    CPRefBand method_descr = class_bands.newCPRefBand("method_descr", MDELTA5, CONSTANT_NameandType);
    MultiBand method_attr_bands = class_bands.newMultiBand("(method_attr_bands)", UNSIGNED5);
    IntBand  method_flags_hi = method_attr_bands.newIntBand("method_flags_hi");
    IntBand  method_flags_lo = method_attr_bands.newIntBand("method_flags_lo");
    IntBand  method_attr_count = method_attr_bands.newIntBand("method_attr_count");
    IntBand  method_attr_indexes = method_attr_bands.newIntBand("method_attr_indexes");
    IntBand  method_attr_calls = method_attr_bands.newIntBand("method_attr_calls");
    // band for predefined method attributes
    IntBand  method_Exceptions_N = method_attr_bands.newIntBand("method_Exceptions_N");
    CPRefBand method_Exceptions_RC = method_attr_bands.newCPRefBand("method_Exceptions_RC", CONSTANT_Class);
    CPRefBand method_Signature_RS = method_attr_bands.newCPRefBand("method_Signature_RS", CONSTANT_Signature);
    MultiBand method_metadata_bands = method_attr_bands.newMultiBand("(method_metadata_bands)", UNSIGNED5);
    // band for predefine method parameters
    IntBand  method_MethodParameters_NB = method_attr_bands.newIntBand("method_MethodParameters_NB", BYTE1);
    CPRefBand method_MethodParameters_name_RUN = method_attr_bands.newCPRefBand("method_MethodParameters_name_RUN", UNSIGNED5, CONSTANT_Utf8, NULL_IS_OK);
    IntBand   method_MethodParameters_flag_FH = method_attr_bands.newIntBand("method_MethodParameters_flag_FH");
    MultiBand method_type_metadata_bands = method_attr_bands.newMultiBand("(method_type_metadata_bands)", UNSIGNED5);

    MultiBand class_attr_bands = class_bands.newMultiBand("(class_attr_bands)", UNSIGNED5);
    IntBand class_flags_hi = class_attr_bands.newIntBand("class_flags_hi");
    IntBand class_flags_lo = class_attr_bands.newIntBand("class_flags_lo");
    IntBand class_attr_count = class_attr_bands.newIntBand("class_attr_count");
    IntBand class_attr_indexes = class_attr_bands.newIntBand("class_attr_indexes");
    IntBand class_attr_calls = class_attr_bands.newIntBand("class_attr_calls");
    // band for predefined SourceFile and other class attributes
    CPRefBand class_SourceFile_RUN = class_attr_bands.newCPRefBand("class_SourceFile_RUN", UNSIGNED5, CONSTANT_Utf8, NULL_IS_OK);
    CPRefBand class_EnclosingMethod_RC = class_attr_bands.newCPRefBand("class_EnclosingMethod_RC", CONSTANT_Class);
    CPRefBand class_EnclosingMethod_RDN = class_attr_bands.newCPRefBand("class_EnclosingMethod_RDN", UNSIGNED5, CONSTANT_NameandType, NULL_IS_OK);
    CPRefBand class_Signature_RS = class_attr_bands.newCPRefBand("class_Signature_RS", CONSTANT_Signature);
    MultiBand class_metadata_bands = class_attr_bands.newMultiBand("(class_metadata_bands)", UNSIGNED5);
    IntBand   class_InnerClasses_N = class_attr_bands.newIntBand("class_InnerClasses_N");
    CPRefBand class_InnerClasses_RC = class_attr_bands.newCPRefBand("class_InnerClasses_RC", CONSTANT_Class);
    IntBand   class_InnerClasses_F = class_attr_bands.newIntBand("class_InnerClasses_F");
    CPRefBand class_InnerClasses_outer_RCN = class_attr_bands.newCPRefBand("class_InnerClasses_outer_RCN", UNSIGNED5, CONSTANT_Class, NULL_IS_OK);
    CPRefBand class_InnerClasses_name_RUN = class_attr_bands.newCPRefBand("class_InnerClasses_name_RUN", UNSIGNED5, CONSTANT_Utf8, NULL_IS_OK);
    IntBand class_ClassFile_version_minor_H = class_attr_bands.newIntBand("class_ClassFile_version_minor_H");
    IntBand class_ClassFile_version_major_H = class_attr_bands.newIntBand("class_ClassFile_version_major_H");
    MultiBand class_type_metadata_bands = class_attr_bands.newMultiBand("(class_type_metadata_bands)", UNSIGNED5);

    MultiBand code_bands = class_bands.newMultiBand("(code_bands)", UNSIGNED5);
    ByteBand  code_headers = code_bands.newByteBand("code_headers"); //BYTE1
    IntBand   code_max_stack = code_bands.newIntBand("code_max_stack", UNSIGNED5);
    IntBand   code_max_na_locals = code_bands.newIntBand("code_max_na_locals", UNSIGNED5);
    IntBand   code_handler_count = code_bands.newIntBand("code_handler_count", UNSIGNED5);
    IntBand   code_handler_start_P = code_bands.newIntBand("code_handler_start_P", BCI5);
    IntBand   code_handler_end_PO = code_bands.newIntBand("code_handler_end_PO", BRANCH5);
    IntBand   code_handler_catch_PO = code_bands.newIntBand("code_handler_catch_PO", BRANCH5);
    CPRefBand code_handler_class_RCN = code_bands.newCPRefBand("code_handler_class_RCN", UNSIGNED5, CONSTANT_Class, NULL_IS_OK);

    MultiBand code_attr_bands = class_bands.newMultiBand("(code_attr_bands)", UNSIGNED5);
    IntBand   code_flags_hi = code_attr_bands.newIntBand("code_flags_hi");
    IntBand   code_flags_lo = code_attr_bands.newIntBand("code_flags_lo");
    IntBand   code_attr_count = code_attr_bands.newIntBand("code_attr_count");
    IntBand   code_attr_indexes = code_attr_bands.newIntBand("code_attr_indexes");
    IntBand   code_attr_calls = code_attr_bands.newIntBand("code_attr_calls");

    MultiBand stackmap_bands = code_attr_bands.newMultiBand("(StackMapTable_bands)", UNSIGNED5);
    IntBand   code_StackMapTable_N = stackmap_bands.newIntBand("code_StackMapTable_N");
    IntBand   code_StackMapTable_frame_T = stackmap_bands.newIntBand("code_StackMapTable_frame_T",BYTE1);
    IntBand   code_StackMapTable_local_N = stackmap_bands.newIntBand("code_StackMapTable_local_N");
    IntBand   code_StackMapTable_stack_N = stackmap_bands.newIntBand("code_StackMapTable_stack_N");
    IntBand   code_StackMapTable_offset = stackmap_bands.newIntBand("code_StackMapTable_offset", UNSIGNED5);
    IntBand   code_StackMapTable_T = stackmap_bands.newIntBand("code_StackMapTable_T", BYTE1);
    CPRefBand code_StackMapTable_RC = stackmap_bands.newCPRefBand("code_StackMapTable_RC", CONSTANT_Class);
    IntBand   code_StackMapTable_P = stackmap_bands.newIntBand("code_StackMapTable_P", BCI5);

    // bands for predefined LineNumberTable attribute
    IntBand   code_LineNumberTable_N = code_attr_bands.newIntBand("code_LineNumberTable_N");
    IntBand   code_LineNumberTable_bci_P = code_attr_bands.newIntBand("code_LineNumberTable_bci_P", BCI5);
    IntBand   code_LineNumberTable_line = code_attr_bands.newIntBand("code_LineNumberTable_line");

    // bands for predefined LocalVariable{Type}Table attributes
    IntBand   code_LocalVariableTable_N = code_attr_bands.newIntBand("code_LocalVariableTable_N");
    IntBand   code_LocalVariableTable_bci_P = code_attr_bands.newIntBand("code_LocalVariableTable_bci_P", BCI5);
    IntBand   code_LocalVariableTable_span_O = code_attr_bands.newIntBand("code_LocalVariableTable_span_O", BRANCH5);
    CPRefBand code_LocalVariableTable_name_RU = code_attr_bands.newCPRefBand("code_LocalVariableTable_name_RU", CONSTANT_Utf8);
    CPRefBand code_LocalVariableTable_type_RS = code_attr_bands.newCPRefBand("code_LocalVariableTable_type_RS", CONSTANT_Signature);
    IntBand   code_LocalVariableTable_slot = code_attr_bands.newIntBand("code_LocalVariableTable_slot");
    IntBand   code_LocalVariableTypeTable_N = code_attr_bands.newIntBand("code_LocalVariableTypeTable_N");
    IntBand   code_LocalVariableTypeTable_bci_P = code_attr_bands.newIntBand("code_LocalVariableTypeTable_bci_P", BCI5);
    IntBand   code_LocalVariableTypeTable_span_O = code_attr_bands.newIntBand("code_LocalVariableTypeTable_span_O", BRANCH5);
    CPRefBand code_LocalVariableTypeTable_name_RU = code_attr_bands.newCPRefBand("code_LocalVariableTypeTable_name_RU", CONSTANT_Utf8);
    CPRefBand code_LocalVariableTypeTable_type_RS = code_attr_bands.newCPRefBand("code_LocalVariableTypeTable_type_RS", CONSTANT_Signature);
    IntBand   code_LocalVariableTypeTable_slot = code_attr_bands.newIntBand("code_LocalVariableTypeTable_slot");
    MultiBand code_type_metadata_bands = code_attr_bands.newMultiBand("(code_type_metadata_bands)", UNSIGNED5);

    // bands for bytecodes
    MultiBand bc_bands = all_bands.newMultiBand("(byte_codes)", UNSIGNED5);
    ByteBand  bc_codes = bc_bands.newByteBand("bc_codes"); //BYTE1
    // remaining bands provide typed opcode fields required by the bc_codes

    IntBand   bc_case_count = bc_bands.newIntBand("bc_case_count");  // *switch
    IntBand   bc_case_value = bc_bands.newIntBand("bc_case_value", DELTA5);  // *switch
    ByteBand  bc_byte = bc_bands.newByteBand("bc_byte"); //BYTE1   // bipush, iinc, *newarray
    IntBand   bc_short = bc_bands.newIntBand("bc_short", DELTA5);  // sipush, wide iinc
    IntBand   bc_local = bc_bands.newIntBand("bc_local");    // *load, *store, iinc, ret
    IntBand   bc_label = bc_bands.newIntBand("bc_label", BRANCH5);    // if*, goto*, jsr*, *switch

    // Most CP refs exhibit some correlation, and benefit from delta coding.
    // The notable exceptions are class and method references.

    // ldc* operands:
    CPRefBand bc_intref = bc_bands.newCPRefBand("bc_intref", DELTA5, CONSTANT_Integer);
    CPRefBand bc_floatref = bc_bands.newCPRefBand("bc_floatref", DELTA5, CONSTANT_Float);
    CPRefBand bc_longref = bc_bands.newCPRefBand("bc_longref", DELTA5, CONSTANT_Long);
    CPRefBand bc_doubleref = bc_bands.newCPRefBand("bc_doubleref", DELTA5, CONSTANT_Double);
    CPRefBand bc_stringref = bc_bands.newCPRefBand("bc_stringref", DELTA5, CONSTANT_String);
    CPRefBand bc_loadablevalueref = bc_bands.newCPRefBand("bc_loadablevalueref", DELTA5, CONSTANT_LoadableValue);

    // nulls produced by bc_classref are taken to mean the current class
    CPRefBand bc_classref = bc_bands.newCPRefBand("bc_classref", UNSIGNED5, CONSTANT_Class, NULL_IS_OK);   // new, *anew*, c*cast, i*of, ldc
    CPRefBand bc_fieldref = bc_bands.newCPRefBand("bc_fieldref", DELTA5, CONSTANT_Fieldref);   // get*, put*
    CPRefBand bc_methodref = bc_bands.newCPRefBand("bc_methodref", CONSTANT_Methodref); // invoke[vs]*
    CPRefBand bc_imethodref = bc_bands.newCPRefBand("bc_imethodref", DELTA5, CONSTANT_InterfaceMethodref); // invokeinterface
    CPRefBand bc_indyref = bc_bands.newCPRefBand("bc_indyref", DELTA5, CONSTANT_InvokeDynamic); // invokedynamic

    // _self_linker_op family
    CPRefBand bc_thisfield = bc_bands.newCPRefBand("bc_thisfield", CONSTANT_None);     // any field within cur. class
    CPRefBand bc_superfield = bc_bands.newCPRefBand("bc_superfield", CONSTANT_None);   // any field within superclass
    CPRefBand bc_thismethod = bc_bands.newCPRefBand("bc_thismethod", CONSTANT_None);   // any method within cur. class
    CPRefBand bc_supermethod = bc_bands.newCPRefBand("bc_supermethod", CONSTANT_None); // any method within superclass
    // bc_invokeinit family:
    IntBand   bc_initref = bc_bands.newIntBand("bc_initref");
    // escapes
    CPRefBand bc_escref = bc_bands.newCPRefBand("bc_escref", CONSTANT_All);
    IntBand   bc_escrefsize = bc_bands.newIntBand("bc_escrefsize");
    IntBand   bc_escsize = bc_bands.newIntBand("bc_escsize");
    ByteBand  bc_escbyte = bc_bands.newByteBand("bc_escbyte");

    // bands for carrying resource files and file attributes:
    MultiBand file_bands = all_bands.newMultiBand("(file_bands)", UNSIGNED5);
    CPRefBand file_name = file_bands.newCPRefBand("file_name", CONSTANT_Utf8);
    IntBand file_size_hi = file_bands.newIntBand("file_size_hi");
    IntBand file_size_lo = file_bands.newIntBand("file_size_lo");
    IntBand file_modtime = file_bands.newIntBand("file_modtime", DELTA5);
    IntBand file_options = file_bands.newIntBand("file_options");
    ByteBand file_bits = file_bands.newByteBand("file_bits");

    // End of band definitions!

    /** Given CP indexes, distribute tag-specific indexes to bands. */
    protected void setBandIndexes() {
        // Handle prior calls to setBandIndex:
        for (Object[] need : needPredefIndex) {
            CPRefBand b     = (CPRefBand) need[0];
            Byte      which = (Byte)      need[1];
            b.setIndex(getCPIndex(which.byteValue()));
        }
        needPredefIndex = null;  // no more predefs

        if (verbose > 3) {
            printCDecl(all_bands);
        }
    }

    protected void setBandIndex(CPRefBand b, byte which) {
        Object[] need = { b, Byte.valueOf(which) };
        if (which == CONSTANT_FieldSpecific) {
            // I.e., attribute layouts KQ (no null) or KQN (null ok).
            allKQBands.add(b);
        } else if (needPredefIndex != null) {
            needPredefIndex.add(need);
        } else {
            // Not in predefinition mode; getCPIndex now works.
            b.setIndex(getCPIndex(which));
        }
    }

    protected void setConstantValueIndex(Field f) {
        Index ix = null;
        if (f != null) {
            byte tag = f.getLiteralTag();
            ix = getCPIndex(tag);
            if (verbose > 2)
                Utils.log.fine("setConstantValueIndex "+f+" "+ConstantPool.tagName(tag)+" => "+ix);
            assert(ix != null);
        }
        // Typically, allKQBands is the singleton of field_ConstantValue_KQ.
        for (CPRefBand xxx_KQ : allKQBands) {
            xxx_KQ.setIndex(ix);
        }
    }

    // Table of bands which contain metadata.
    protected MultiBand[] metadataBands = new MultiBand[ATTR_CONTEXT_LIMIT];
    {
        metadataBands[ATTR_CONTEXT_CLASS] = class_metadata_bands;
        metadataBands[ATTR_CONTEXT_FIELD] = field_metadata_bands;
        metadataBands[ATTR_CONTEXT_METHOD] = method_metadata_bands;
    }
    // Table of bands which contains type_metadata (TypeAnnotations)
    protected MultiBand[] typeMetadataBands = new MultiBand[ATTR_CONTEXT_LIMIT];
    {
        typeMetadataBands[ATTR_CONTEXT_CLASS] = class_type_metadata_bands;
        typeMetadataBands[ATTR_CONTEXT_FIELD] = field_type_metadata_bands;
        typeMetadataBands[ATTR_CONTEXT_METHOD] = method_type_metadata_bands;
        typeMetadataBands[ATTR_CONTEXT_CODE]   = code_type_metadata_bands;
    }

    // Attribute layouts.
    public static final int ADH_CONTEXT_MASK   = 0x3;  // (ad_hdr & ADH_CONTEXT_MASK)
    public static final int ADH_BIT_SHIFT      = 0x2;  // (ad_hdr >> ADH_BIT_SHIFT)
    public static final int ADH_BIT_IS_LSB     = 1;
    public static final int ATTR_INDEX_OVERFLOW  = -1;

    public int[] attrIndexLimit = new int[ATTR_CONTEXT_LIMIT];
    // Each index limit is either 32 or 63, depending on AO_HAVE_XXX_FLAGS_HI.

    // Which flag bits are taken over by attributes?
    protected long[] attrFlagMask = new long[ATTR_CONTEXT_LIMIT];
    // Which flag bits have been taken over explicitly?
    protected long[] attrDefSeen = new long[ATTR_CONTEXT_LIMIT];

    // What pseudo-attribute bits are there to watch for?
    protected int[] attrOverflowMask = new int[ATTR_CONTEXT_LIMIT];
    protected int attrClassFileVersionMask;

    // Mapping from Attribute.Layout to Band[] (layout element bands).
    protected Map<Attribute.Layout, Band[]> attrBandTable = new HashMap<>();

    // Well-known attributes:
    protected final Attribute.Layout attrCodeEmpty;
    protected final Attribute.Layout attrInnerClassesEmpty;
    protected final Attribute.Layout attrClassFileVersion;
    protected final Attribute.Layout attrConstantValue;

    // Mapping from Attribute.Layout to Integer (inverse of attrDefs)
    Map<Attribute.Layout, Integer> attrIndexTable = new HashMap<>();

    // Mapping from attribute index (<32 are flag bits) to attributes.
    protected List<List attrDefs =
            new FixedList<>(ATTR_CONTEXT_LIMIT);
    {
        for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
            assert(attrIndexLimit[i] == 0);
            attrIndexLimit[i] = 32;  // just for the sake of predefs.
            attrDefs.set(i, new ArrayList<>(Collections.nCopies(
                    attrIndexLimit[i], (Attribute.Layout)null)));

        }

        // Add predefined attribute definitions:
        attrInnerClassesEmpty =
        predefineAttribute(CLASS_ATTR_InnerClasses, ATTR_CONTEXT_CLASS, null,
                           "InnerClasses", "");
        assert(attrInnerClassesEmpty == Package.attrInnerClassesEmpty);
        predefineAttribute(CLASS_ATTR_SourceFile, ATTR_CONTEXT_CLASS,
                           new Band[] { class_SourceFile_RUN },
                           "SourceFile", "RUNH");
        predefineAttribute(CLASS_ATTR_EnclosingMethod, ATTR_CONTEXT_CLASS,
                           new Band[] {
                               class_EnclosingMethod_RC,
                               class_EnclosingMethod_RDN
                           },
                           "EnclosingMethod", "RCHRDNH");
        attrClassFileVersion =
        predefineAttribute(CLASS_ATTR_ClassFile_version, ATTR_CONTEXT_CLASS,
                           new Band[] {
                               class_ClassFile_version_minor_H,
                               class_ClassFile_version_major_H
                           },
                           ".ClassFile.version", "HH");
        predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_CLASS,
                           new Band[] { class_Signature_RS },
                           "Signature", "RSH");
        predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_CLASS, null,
                           "Deprecated", "");
        //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_CLASS, null,
        //                 "Synthetic", "");
        predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_CLASS, null,
                           ".Overflow", "");
        attrConstantValue =
        predefineAttribute(FIELD_ATTR_ConstantValue, ATTR_CONTEXT_FIELD,
                           new Band[] { field_ConstantValue_KQ },
                           "ConstantValue", "KQH");
        predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_FIELD,
                           new Band[] { field_Signature_RS },
                           "Signature", "RSH");
        predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_FIELD, null,
                           "Deprecated", "");
        //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_FIELD, null,
        //                 "Synthetic", "");
        predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_FIELD, null,
                           ".Overflow", "");
        attrCodeEmpty =
        predefineAttribute(METHOD_ATTR_Code, ATTR_CONTEXT_METHOD, null,
                           "Code", "");
        predefineAttribute(METHOD_ATTR_Exceptions, ATTR_CONTEXT_METHOD,
                           new Band[] {
                               method_Exceptions_N,
                               method_Exceptions_RC
                           },
                           "Exceptions", "NH[RCH]");
        predefineAttribute(METHOD_ATTR_MethodParameters, ATTR_CONTEXT_METHOD,
                           new Band[]{
                                method_MethodParameters_NB,
                                method_MethodParameters_name_RUN,
                                method_MethodParameters_flag_FH
                           },
                           "MethodParameters", "NB[RUNHFH]");
        assert(attrCodeEmpty == Package.attrCodeEmpty);
        predefineAttribute(X_ATTR_Signature, ATTR_CONTEXT_METHOD,
                           new Band[] { method_Signature_RS },
                           "Signature", "RSH");
        predefineAttribute(X_ATTR_Deprecated, ATTR_CONTEXT_METHOD, null,
                           "Deprecated", "");
        //predefineAttribute(X_ATTR_Synthetic, ATTR_CONTEXT_METHOD, null,
        //                 "Synthetic", "");
        predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_METHOD, null,
                           ".Overflow", "");

        for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) {
            MultiBand xxx_metadata_bands = metadataBands[ctype];
            if (ctype != ATTR_CONTEXT_CODE) {
                // These arguments cause the bands to be built
                // automatically for this complicated layout:
                predefineAttribute(X_ATTR_RuntimeVisibleAnnotations,
                                   ATTR_CONTEXT_NAME[ctype]+"_RVA_",
                                   xxx_metadata_bands,
                                   Attribute.lookup(null, ctype,
                                                    "RuntimeVisibleAnnotations"));
                predefineAttribute(X_ATTR_RuntimeInvisibleAnnotations,
                                   ATTR_CONTEXT_NAME[ctype]+"_RIA_",
                                   xxx_metadata_bands,
                                   Attribute.lookup(null, ctype,
                                                    "RuntimeInvisibleAnnotations"));

                if (ctype == ATTR_CONTEXT_METHOD) {
                    predefineAttribute(METHOD_ATTR_RuntimeVisibleParameterAnnotations,
                                       "method_RVPA_", xxx_metadata_bands,
                                       Attribute.lookup(null, ctype,
                                       "RuntimeVisibleParameterAnnotations"));
                    predefineAttribute(METHOD_ATTR_RuntimeInvisibleParameterAnnotations,
                                       "method_RIPA_", xxx_metadata_bands,
                                       Attribute.lookup(null, ctype,
                                       "RuntimeInvisibleParameterAnnotations"));
                    predefineAttribute(METHOD_ATTR_AnnotationDefault,
                                       "method_AD_", xxx_metadata_bands,
                                       Attribute.lookup(null, ctype,
                                       "AnnotationDefault"));
                }
            }
            // All contexts have these
            MultiBand xxx_type_metadata_bands = typeMetadataBands[ctype];
            predefineAttribute(X_ATTR_RuntimeVisibleTypeAnnotations,
                    ATTR_CONTEXT_NAME[ctype] + "_RVTA_",
                    xxx_type_metadata_bands,
                    Attribute.lookup(null, ctype,
                    "RuntimeVisibleTypeAnnotations"));
            predefineAttribute(X_ATTR_RuntimeInvisibleTypeAnnotations,
                    ATTR_CONTEXT_NAME[ctype] + "_RITA_",
                    xxx_type_metadata_bands,
                    Attribute.lookup(null, ctype,
                    "RuntimeInvisibleTypeAnnotations"));
        }


        Attribute.Layout stackMapDef = Attribute.lookup(null, ATTR_CONTEXT_CODE, "StackMapTable").layout();
        predefineAttribute(CODE_ATTR_StackMapTable, ATTR_CONTEXT_CODE,
                           stackmap_bands.toArray(),
                           stackMapDef.name(), stackMapDef.layout());

        predefineAttribute(CODE_ATTR_LineNumberTable, ATTR_CONTEXT_CODE,
                           new Band[] {
                               code_LineNumberTable_N,
                               code_LineNumberTable_bci_P,
                               code_LineNumberTable_line
                           },
                           "LineNumberTable", "NH[PHH]");
        predefineAttribute(CODE_ATTR_LocalVariableTable, ATTR_CONTEXT_CODE,
                           new Band[] {
                               code_LocalVariableTable_N,
                               code_LocalVariableTable_bci_P,
                               code_LocalVariableTable_span_O,
                               code_LocalVariableTable_name_RU,
                               code_LocalVariableTable_type_RS,
                               code_LocalVariableTable_slot
                           },
                           "LocalVariableTable", "NH[PHOHRUHRSHH]");
        predefineAttribute(CODE_ATTR_LocalVariableTypeTable, ATTR_CONTEXT_CODE,
                           new Band[] {
                               code_LocalVariableTypeTable_N,
                               code_LocalVariableTypeTable_bci_P,
                               code_LocalVariableTypeTable_span_O,
                               code_LocalVariableTypeTable_name_RU,
                               code_LocalVariableTypeTable_type_RS,
                               code_LocalVariableTypeTable_slot
                           },
                           "LocalVariableTypeTable", "NH[PHOHRUHRSHH]");
        predefineAttribute(X_ATTR_OVERFLOW, ATTR_CONTEXT_CODE, null,
                           ".Overflow", "");

        // Clear the record of having seen these definitions,
        // so they may be redefined without error.
        for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
            attrDefSeen[i] = 0;
        }

        // Set up the special masks:
        for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
            attrOverflowMask[i] = (1<(attrIndexLimit[ctype]);
        // Remove nulls and non-predefs.
        for (int ai = 0; ai < attrIndexLimit[ctype]; ai++) {
            if (testBit(attrDefSeen[ctype], 1L<= liml)  return LONG_CODE_HEADER;
        int sc = shortCodeHeader_h_base(h);
        sc += s + lims*l1;
        if (sc > 255)  return LONG_CODE_HEADER;
        assert(shortCodeHeader_max_stack(sc) == s);
        assert(shortCodeHeader_max_na_locals(sc) == l1);
        assert(shortCodeHeader_handler_count(sc) == h);
        return sc;
    }

    static final int LONG_CODE_HEADER = 0;
    static int shortCodeHeader_handler_count(int sc) {
        assert(sc > 0 && sc <= 255);
        for (int h = 0; ; h++) {
            if (sc < shortCodeHeader_h_base(h+1))
                return h;
        }
    }
    static int shortCodeHeader_max_stack(int sc) {
        int h = shortCodeHeader_handler_count(sc);
        int lims = shortCodeLimits[h][0];
        return (sc - shortCodeHeader_h_base(h)) % lims;
    }
    static int shortCodeHeader_max_na_locals(int sc) {
        int h = shortCodeHeader_handler_count(sc);
        int lims = shortCodeLimits[h][0];
        return (sc - shortCodeHeader_h_base(h)) / lims;
    }

    private static int shortCodeHeader_h_base(int h) {
        assert(h <= shortCodeLimits.length);
        int sc = 1;
        for (int h0 = 0; h0 < h; h0++) {
            int lims = shortCodeLimits[h0][0];
            int liml = shortCodeLimits[h0][1];
            sc += lims * liml;
        }
        return sc;
    }

    // utilities for accessing the bc_label band:
    protected void putLabel(IntBand bc_label, Code c, int pc, int targetPC) {
        bc_label.putInt(c.encodeBCI(targetPC) - c.encodeBCI(pc));
    }
    protected int getLabel(IntBand bc_label, Code c, int pc) {
        return c.decodeBCI(bc_label.getInt() + c.encodeBCI(pc));
    }

    protected CPRefBand getCPRefOpBand(int bc) {
        switch (Instruction.getCPRefOpTag(bc)) {
        case CONSTANT_Class:
            return bc_classref;
        case CONSTANT_Fieldref:
            return bc_fieldref;
        case CONSTANT_Methodref:
            return bc_methodref;
        case CONSTANT_InterfaceMethodref:
            return bc_imethodref;
        case CONSTANT_InvokeDynamic:
            return bc_indyref;
        case CONSTANT_LoadableValue:
            switch (bc) {
            case _ildc: case _ildc_w:
                return bc_intref;
            case _fldc: case _fldc_w:
                return bc_floatref;
            case _lldc2_w:
                return bc_longref;
            case _dldc2_w:
                return bc_doubleref;
            case _sldc: case _sldc_w:
                return bc_stringref;
            case _cldc: case _cldc_w:
                return bc_classref;
            case _qldc: case _qldc_w:
                return bc_loadablevalueref;
            }
            break;
        }
        assert(false);
        return null;
    }

    protected CPRefBand selfOpRefBand(int self_bc) {
        assert(Instruction.isSelfLinkerOp(self_bc));
        int idx = (self_bc - _self_linker_op);
        boolean isSuper = (idx >= _self_linker_super_flag);
        if (isSuper)  idx -= _self_linker_super_flag;
        boolean isAload = (idx >= _self_linker_aload_flag);
        if (isAload)  idx -= _self_linker_aload_flag;
        int origBC = _first_linker_op + idx;
        boolean isField = Instruction.isFieldOp(origBC);
        if (!isSuper)
            return isField? bc_thisfield: bc_thismethod;
        else
            return isField? bc_superfield: bc_supermethod;
    }

    ////////////////////////////////////////////////////////////////////

    static int nextSeqForDebug;
    static File dumpDir = null;
    static OutputStream getDumpStream(Band b, String ext) throws IOException {
        return getDumpStream(b.name, b.seqForDebug, ext, b);
    }
    static OutputStream getDumpStream(Index ix, String ext) throws IOException {
        if (ix.size() == 0)  return new ByteArrayOutputStream();
        int seq = ConstantPool.TAG_ORDER[ix.cpMap[0].tag];
        return getDumpStream(ix.debugName, seq, ext, ix);
    }
    static OutputStream getDumpStream(String name, int seq, String ext, Object b) throws IOException {
        if (dumpDir == null) {
            dumpDir = File.createTempFile("BD_", "", new File("."));
            dumpDir.delete();
            if (dumpDir.mkdir())
                Utils.log.info("Dumping bands to "+dumpDir);
        }
        name = name.replace('(', ' ').replace(')', ' ');
        name = name.replace('/', ' ');
        name = name.replace('*', ' ');
        name = name.trim().replace(' ','_');
        name = ((10000+seq) + "_" + name).substring(1);
        File dumpFile = new File(dumpDir, name+ext);
        Utils.log.info("Dumping "+b+" to "+dumpFile);
        return new BufferedOutputStream(new FileOutputStream(dumpFile));
    }

    // DEBUG ONLY:  Validate me at each length change.
    static boolean assertCanChangeLength(Band b) {
        switch (b.phase) {
        case COLLECT_PHASE:
        case READ_PHASE:
            return true;
        }
        return false;
    }

    // DEBUG ONLY:  Validate a phase.
    static boolean assertPhase(Band b, int phaseExpected) {
        if (b.phase() != phaseExpected) {
            Utils.log.warning("phase expected "+phaseExpected+" was "+b.phase()+" in "+b);
            return false;
        }
        return true;
    }


    // DEBUG ONLY:  Tells whether verbosity is turned on.
    static int verbose() {
        return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE);
    }


    // DEBUG ONLY:  Validate me at each phase change.
    static boolean assertPhaseChangeOK(Band b, int p0, int p1) {
        switch (p0*10+p1) {
        /// Writing phases:
        case NO_PHASE*10+COLLECT_PHASE:
            // Ready to collect data from the input classes.
            assert(!b.isReader());
            assert(b.capacity() >= 0);
            assert(b.length() == 0);
            return true;
        case COLLECT_PHASE*10+FROZEN_PHASE:
        case FROZEN_PHASE*10+FROZEN_PHASE:
            assert(b.length() == 0);
            return true;
        case COLLECT_PHASE*10+WRITE_PHASE:
        case FROZEN_PHASE*10+WRITE_PHASE:
            // Data is all collected.  Ready to write bytes to disk.
            return true;
        case WRITE_PHASE*10+DONE_PHASE:
            // Done writing to disk.  Ready to reset, in principle.
            return true;

        /// Reading phases:
        case NO_PHASE*10+EXPECT_PHASE:
            assert(b.isReader());
            assert(b.capacity() < 0);
            return true;
        case EXPECT_PHASE*10+READ_PHASE:
            // Ready to read values from disk.
            assert(Math.max(0,b.capacity()) >= b.valuesExpected());
            assert(b.length() <= 0);
            return true;
        case READ_PHASE*10+DISBURSE_PHASE:
            // Ready to disburse values.
            assert(b.valuesRemainingForDebug() == b.length());
            return true;
        case DISBURSE_PHASE*10+DONE_PHASE:
            // Done disbursing values.  Ready to reset, in principle.
            assert(assertDoneDisbursing(b));
            return true;
        }
        if (p0 == p1)
            Utils.log.warning("Already in phase "+p0);
        else
            Utils.log.warning("Unexpected phase "+p0+" -> "+p1);
        return false;
    }

    static private boolean assertDoneDisbursing(Band b) {
        if (b.phase != DISBURSE_PHASE) {
            Utils.log.warning("assertDoneDisbursing: still in phase "+b.phase+": "+b);
            if (verbose() <= 1)  return false;  // fail now
        }
        int left = b.valuesRemainingForDebug();
        if (left > 0) {
            Utils.log.warning("assertDoneDisbursing: "+left+" values left in "+b);
            if (verbose() <= 1)  return false;  // fail now
        }
        if (b instanceof MultiBand) {
            MultiBand mb = (MultiBand) b;
            for (int i = 0; i < mb.bandCount; i++) {
                Band sub = mb.bands[i];
                if (sub.phase != DONE_PHASE) {
                    Utils.log.warning("assertDoneDisbursing: sub-band still in phase "+sub.phase+": "+sub);
                    if (verbose() <= 1)  return false;  // fail now
                }
            }
        }
        return true;
    }

    static private void printCDecl(Band b) {
        if (b instanceof MultiBand) {
            MultiBand mb = (MultiBand) b;
            for (int i = 0; i < mb.bandCount; i++) {
                printCDecl(mb.bands[i]);
            }
            return;
        }
        String ixS = "NULL";
        if (b instanceof CPRefBand) {
            Index ix = ((CPRefBand)b).index;
            if (ix != null)  ixS = "INDEX("+ix.debugName+")";
        }
        Coding[] knownc = { BYTE1, CHAR3, BCI5, BRANCH5, UNSIGNED5,
                            UDELTA5, SIGNED5, DELTA5, MDELTA5 };
        String[] knowns = { "BYTE1", "CHAR3", "BCI5", "BRANCH5", "UNSIGNED5",
                            "UDELTA5", "SIGNED5", "DELTA5", "MDELTA5" };
        Coding rc = b.regularCoding;
        int rci = Arrays.asList(knownc).indexOf(rc);
        String cstr;
        if (rci >= 0)
            cstr = knowns[rci];
        else
            cstr = "CODING"+rc.keyString();
        System.out.println("  BAND_INIT(\""+b.name()+"\""
                           +", "+cstr+", "+ixS+"),");
    }

    private Map<Band, Band> prevForAssertMap;

    // DEBUG ONLY:  Record something about the band order.
    boolean notePrevForAssert(Band b, Band p) {
        if (prevForAssertMap == null)
            prevForAssertMap = new HashMap<>();
        prevForAssertMap.put(b, p);
        return true;
    }

    // DEBUG ONLY:  Validate next input band, ensure bands are read in sequence
    private boolean assertReadyToReadFrom(Band b, InputStream in) throws IOException {
        Band p = prevForAssertMap.get(b);
        // Any previous band must be done reading before this one starts.
        if (p != null && phaseCmp(p.phase(), DISBURSE_PHASE) < 0) {
            Utils.log.warning("Previous band not done reading.");
            Utils.log.info("    Previous band: "+p);
            Utils.log.info("        Next band: "+b);
            assert(verbose > 0);  // die unless verbose is true
        }
        String name = b.name;
        if (optDebugBands && !name.startsWith("(")) {
            assert(bandSequenceList != null);
            // Verify synchronization between reader & writer:
            String inName = bandSequenceList.removeFirst();
            // System.out.println("Reading: " + name);
            if (!inName.equals(name)) {
                Utils.log.warning("Expected " + name + " but read: " + inName);
                return false;
            }
            Utils.log.info("Read band in sequence: " + name);
        }
        return true;
    }

    // DEBUG ONLY:  Make sure a bunch of cprefs are correct.
    private boolean assertValidCPRefs(CPRefBand b) {
        if (b.index == null)  return true;
        int limit = b.index.size()+1;
        for (int i = 0; i < b.length(); i++) {
            int v = b.valueAtForDebug(i);
            if (v < 0 || v >= limit) {
                Utils.log.warning("CP ref out of range "+
                                   "["+i+"] = "+v+" in "+b);
                return false;
            }
        }
        return true;
    }

    /*
     * DEBUG ONLY:  write the bands to a list and read back the list in order,
     * this works perfectly if we use the java packer and unpacker, typically
     * this will work with --repack or if they are in the same jvm instance.
     */
    static LinkedList<String> bandSequenceList = null;
    private boolean assertReadyToWriteTo(Band b, OutputStream out) throws IOException {
        Band p = prevForAssertMap.get(b);
        // Any previous band must be done writing before this one starts.
        if (p != null && phaseCmp(p.phase(), DONE_PHASE) < 0) {
            Utils.log.warning("Previous band not done writing.");
            Utils.log.info("    Previous band: "+p);
            Utils.log.info("        Next band: "+b);
            assert(verbose > 0);  // die unless verbose is true
        }
        String name = b.name;
        if (optDebugBands && !name.startsWith("(")) {
            if (bandSequenceList == null)
                bandSequenceList = new LinkedList<>();
            // Verify synchronization between reader & writer:
            bandSequenceList.add(name);
            // System.out.println("Writing: " + b);
        }
        return true;
    }

    protected static boolean testBit(int flags, int bitMask) {
        return (flags & bitMask) != 0;
    }
    protected static int setBit(int flags, int bitMask, boolean z) {
        return z ? (flags | bitMask) : (flags &~ bitMask);
    }
    protected static boolean testBit(long flags, long bitMask) {
        return (flags & bitMask) != 0;
    }
    protected static long setBit(long flags, long bitMask, boolean z) {
        return z ? (flags | bitMask) : (flags &~ bitMask);
    }


    static void printArrayTo(PrintStream ps, int[] values, int start, int end) {
        int len = end-start;
        for (int i = 0; i < len; i++) {
            if (i % 10 == 0)
                ps.println();
            else
                ps.print(" ");
            ps.print(values[start+i]);
        }
        ps.println();
    }

    static void printArrayTo(PrintStream ps, Entry[] cpMap, int start, int end) {
        printArrayTo(ps, cpMap, start, end, false);
    }
    static void printArrayTo(PrintStream ps, Entry[] cpMap, int start, int end, boolean showTags) {
        StringBuffer buf = new StringBuffer();
        int len = end-start;
        for (int i = 0; i < len; i++) {
            Entry e = cpMap[start+i];
            ps.print(start+i); ps.print("=");
            if (showTags) { ps.print(e.tag); ps.print(":"); }
            String s = e.stringValue();
            buf.setLength(0);
            for (int j = 0; j < s.length(); j++) {
                char ch = s.charAt(j);
                if (!(ch < ' ' || ch > '~' || ch == '\\')) {
                    buf.append(ch);
                } else if (ch == '\\') {
                    buf.append("\\\\");
                } else if (ch == '\n') {
                    buf.append("\\n");
                } else if (ch == '\t') {
                    buf.append("\\t");
                } else if (ch == '\r') {
                    buf.append("\\r");
                } else {
                    String str = "000"+Integer.toHexString(ch);
                    buf.append("\\u").append(str.substring(str.length()-4));
                }
            }
            ps.println(buf);
        }
    }


    // Utilities for reallocating:
    protected static Object[] realloc(Object[] a, int len) {
        java.lang.Class<?> elt = a.getClass().getComponentType();
        Object[] na = (Object[]) java.lang.reflect.Array.newInstance(elt, len);
        System.arraycopy(a, 0, na, 0, Math.min(a.length, len));
        return na;
    }
    protected static Object[] realloc(Object[] a) {
        return realloc(a, Math.max(10, a.length*2));
    }

    protected static int[] realloc(int[] a, int len) {
        if (len == 0)  return noInts;
        if (a == null)  return new int[len];
        int[] na = new int[len];
        System.arraycopy(a, 0, na, 0, Math.min(a.length, len));
        return na;
    }
    protected static int[] realloc(int[] a) {
        return realloc(a, Math.max(10, a.length*2));
    }

    protected static byte[] realloc(byte[] a, int len) {
        if (len == 0)  return noBytes;
        if (a == null)  return new byte[len];
        byte[] na = new byte[len];
        System.arraycopy(a, 0, na, 0, Math.min(a.length, len));
        return na;
    }
    protected static byte[] realloc(byte[] a) {
        return realloc(a, Math.max(10, a.length*2));
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java BandStructure.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.