| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package com.sun.java.util.jar.pack;  | 
 | 
 | 
 | 
import com.sun.java.util.jar.pack.ConstantPool.*;  | 
 | 
import com.sun.java.util.jar.pack.Package.Class;  | 
 | 
import com.sun.java.util.jar.pack.Package.File;  | 
 | 
import com.sun.java.util.jar.pack.Package.InnerClass;  | 
 | 
import java.io.ByteArrayOutputStream;  | 
 | 
import java.io.EOFException;  | 
 | 
import java.io.PrintStream;  | 
 | 
import java.io.FilterInputStream;  | 
 | 
import java.io.BufferedInputStream;  | 
 | 
import java.io.InputStream;  | 
 | 
import java.io.IOException;  | 
 | 
import java.util.ArrayList;  | 
 | 
import java.util.Map;  | 
 | 
import java.util.Arrays;  | 
 | 
import java.util.Collection;  | 
 | 
import java.util.Collections;  | 
 | 
import java.util.Comparator;  | 
 | 
import java.util.HashSet;  | 
 | 
import java.util.HashMap;  | 
 | 
import java.util.Iterator;  | 
 | 
import java.util.List;  | 
 | 
import java.util.ListIterator;  | 
 | 
import java.util.Set;  | 
 | 
import static com.sun.java.util.jar.pack.Constants.*;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
class PackageReader extends BandStructure { | 
 | 
    Package pkg;  | 
 | 
    byte[] bytes;  | 
 | 
    LimitedBuffer in;  | 
 | 
    Package.Version packageVersion;  | 
 | 
 | 
 | 
    PackageReader(Package pkg, InputStream in) throws IOException { | 
 | 
        this.pkg = pkg;  | 
 | 
        this.in = new LimitedBuffer(in);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    static  | 
 | 
    class LimitedBuffer extends BufferedInputStream { | 
 | 
        long served;       | 
 | 
        int  servedPos;    | 
 | 
        long limit;        | 
 | 
        long buffered;  | 
 | 
        public boolean atLimit() { | 
 | 
            boolean z = (getBytesServed() == limit);  | 
 | 
            assert(!z || limit == buffered);  | 
 | 
            return z;  | 
 | 
        }  | 
 | 
        public long getBytesServed() { | 
 | 
            return served + (pos - servedPos);  | 
 | 
        }  | 
 | 
        public void setReadLimit(long newLimit) { | 
 | 
            if (newLimit == -1)  | 
 | 
                limit = -1;  | 
 | 
            else  | 
 | 
                limit = getBytesServed() + newLimit;  | 
 | 
        }  | 
 | 
        public long getReadLimit() { | 
 | 
            if (limit == -1)  | 
 | 
                return limit;  | 
 | 
            else  | 
 | 
                return limit - getBytesServed();  | 
 | 
        }  | 
 | 
        public int read() throws IOException { | 
 | 
            if (pos < count) { | 
 | 
                  | 
 | 
                return buf[pos++] & 0xFF;  | 
 | 
            }  | 
 | 
            served += (pos - servedPos);  | 
 | 
            int ch = super.read();  | 
 | 
            servedPos = pos;  | 
 | 
            if (ch >= 0)  served += 1;  | 
 | 
            assert(served <= limit || limit == -1);  | 
 | 
            return ch;  | 
 | 
        }  | 
 | 
        public int read(byte b[], int off, int len) throws IOException { | 
 | 
            served += (pos - servedPos);  | 
 | 
            int nr = super.read(b, off, len);  | 
 | 
            servedPos = pos;  | 
 | 
            if (nr >= 0)  served += nr;  | 
 | 
              | 
 | 
            return nr;  | 
 | 
        }  | 
 | 
        public long skip(long n) throws IOException { | 
 | 
            throw new RuntimeException("no skipping"); | 
 | 
        }  | 
 | 
        LimitedBuffer(InputStream originalIn) { | 
 | 
            super(null, 1<<14);  | 
 | 
            servedPos = pos;  | 
 | 
            super.in = new FilterInputStream(originalIn) { | 
 | 
                public int read() throws IOException { | 
 | 
                    if (buffered == limit)  | 
 | 
                        return -1;  | 
 | 
                    ++buffered;  | 
 | 
                    return super.read();  | 
 | 
                }  | 
 | 
                public int read(byte b[], int off, int len) throws IOException { | 
 | 
                    if (buffered == limit)  | 
 | 
                        return -1;  | 
 | 
                    if (limit != -1) { | 
 | 
                        long remaining = limit - buffered;  | 
 | 
                        if (len > remaining)  | 
 | 
                            len = (int)remaining;  | 
 | 
                    }  | 
 | 
                    int nr = super.read(b, off, len);  | 
 | 
                    if (nr >= 0)  buffered += nr;  | 
 | 
                    return nr;  | 
 | 
                }  | 
 | 
            };  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    void read() throws IOException { | 
 | 
        boolean ok = false;  | 
 | 
        try { | 
 | 
            //  pack200_archive:  | 
 | 
            //        file_header  | 
 | 
            //        *band_headers :BYTE1  | 
 | 
            //        cp_bands  | 
 | 
            //        attr_definition_bands  | 
 | 
            //        ic_bands  | 
 | 
            //        class_bands  | 
 | 
            //        bc_bands  | 
 | 
              | 
 | 
            readFileHeader();  | 
 | 
            readBandHeaders();  | 
 | 
            readConstantPool();    | 
 | 
            readAttrDefs();  | 
 | 
            readInnerClasses();  | 
 | 
            Class[] classes = readClasses();  | 
 | 
            readByteCodes();  | 
 | 
            readFiles();       | 
 | 
            assert(archiveSize1 == 0 || in.atLimit());  | 
 | 
            assert(archiveSize1 == 0 ||  | 
 | 
                   in.getBytesServed() == archiveSize0+archiveSize1);  | 
 | 
            all_bands.doneDisbursing();  | 
 | 
 | 
 | 
              | 
 | 
            for (int i = 0; i < classes.length; i++) { | 
 | 
                reconstructClass(classes[i]);  | 
 | 
            }  | 
 | 
 | 
 | 
            ok = true;  | 
 | 
        } catch (Exception ee) { | 
 | 
            Utils.log.warning("Error on input: "+ee, ee); | 
 | 
            if (verbose > 0)  | 
 | 
                Utils.log.info("Stream offsets:"+ | 
 | 
                                 " served="+in.getBytesServed()+  | 
 | 
                                 " buffered="+in.buffered+  | 
 | 
                                 " limit="+in.limit);  | 
 | 
              | 
 | 
            if (ee instanceof IOException)  throw (IOException)ee;  | 
 | 
            if (ee instanceof RuntimeException)  throw (RuntimeException)ee;  | 
 | 
            throw new Error("error unpacking", ee); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    int[] tagCount = new int[CONSTANT_Limit];  | 
 | 
    int numFiles;  | 
 | 
    int numAttrDefs;  | 
 | 
    int numInnerClasses;  | 
 | 
    int numClasses;  | 
 | 
 | 
 | 
    void readFileHeader() throws IOException { | 
 | 
        //  file_header:  | 
 | 
          | 
 | 
        readArchiveMagic();  | 
 | 
        readArchiveHeader();  | 
 | 
    }  | 
 | 
 | 
 | 
    // Local routine used to parse fixed-format scalars  | 
 | 
      | 
 | 
    private int getMagicInt32() throws IOException { | 
 | 
        int res = 0;  | 
 | 
        for (int i = 0; i < 4; i++) { | 
 | 
            res <<= 8;  | 
 | 
            res |= (archive_magic.getByte() & 0xFF);  | 
 | 
        }  | 
 | 
        return res;  | 
 | 
    }  | 
 | 
 | 
 | 
    final static int MAGIC_BYTES = 4;  | 
 | 
 | 
 | 
    void readArchiveMagic() throws IOException { | 
 | 
          | 
 | 
        in.setReadLimit(MAGIC_BYTES + AH_LENGTH_MIN);  | 
 | 
 | 
 | 
        //  archive_magic:  | 
 | 
          | 
 | 
        archive_magic.expectLength(MAGIC_BYTES);  | 
 | 
        archive_magic.readFrom(in);  | 
 | 
 | 
 | 
          | 
 | 
        int magic = getMagicInt32();  | 
 | 
        if (pkg.magic != magic) { | 
 | 
            throw new IOException("Unexpected package magic number: got " | 
 | 
                    + magic + "; expected " + pkg.magic);  | 
 | 
        }  | 
 | 
        archive_magic.doneDisbursing();  | 
 | 
    }  | 
 | 
 | 
 | 
       | 
 | 
    void checkArchiveVersion() throws IOException { | 
 | 
        Package.Version versionFound = null;  | 
 | 
        for (Package.Version v : new Package.Version[] { | 
 | 
                JAVA8_PACKAGE_VERSION,  | 
 | 
                JAVA7_PACKAGE_VERSION,  | 
 | 
                JAVA6_PACKAGE_VERSION,  | 
 | 
                JAVA5_PACKAGE_VERSION  | 
 | 
            }) { | 
 | 
            if (packageVersion.equals(v)) { | 
 | 
                versionFound = v;  | 
 | 
                break;  | 
 | 
            }  | 
 | 
        }  | 
 | 
        if (versionFound == null) { | 
 | 
            String expVer =   JAVA8_PACKAGE_VERSION.toString()  | 
 | 
                            + "OR"  | 
 | 
                            + JAVA7_PACKAGE_VERSION.toString()  | 
 | 
                            + " OR "  | 
 | 
                            + JAVA6_PACKAGE_VERSION.toString()  | 
 | 
                            + " OR "  | 
 | 
                            + JAVA5_PACKAGE_VERSION.toString();  | 
 | 
            throw new IOException("Unexpected package minor version: got " | 
 | 
                    +  packageVersion.toString() + "; expected " + expVer);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    void readArchiveHeader() throws IOException { | 
 | 
        //  archive_header:  | 
 | 
        //        #archive_minver :UNSIGNED5[1]  | 
 | 
        //        #archive_majver :UNSIGNED5[1]  | 
 | 
        //        #archive_options :UNSIGNED5[1]  | 
 | 
        //        (archive_file_counts) ** (#have_file_headers)  | 
 | 
        //        (archive_special_counts) ** (#have_special_formats)  | 
 | 
        //        cp_counts  | 
 | 
        //        class_counts  | 
 | 
        //  | 
 | 
        //  archive_file_counts:  | 
 | 
        //        #archive_size_hi :UNSIGNED5[1]  | 
 | 
        //        #archive_size_lo :UNSIGNED5[1]  | 
 | 
        //        #archive_next_count :UNSIGNED5[1]  | 
 | 
        //        #archive_modtime :UNSIGNED5[1]  | 
 | 
        //        #file_count :UNSIGNED5[1]  | 
 | 
        //  | 
 | 
        //  class_counts:  | 
 | 
        //        #ic_count :UNSIGNED5[1]  | 
 | 
        //        #default_class_minver :UNSIGNED5[1]  | 
 | 
        //        #default_class_majver :UNSIGNED5[1]  | 
 | 
        //        #class_count :UNSIGNED5[1]  | 
 | 
        //  | 
 | 
        //  archive_special_counts:  | 
 | 
        //        #band_headers_size :UNSIGNED5[1]  | 
 | 
        //        #attr_definition_count :UNSIGNED5[1]  | 
 | 
          | 
 | 
        archive_header_0.expectLength(AH_LENGTH_0);  | 
 | 
        archive_header_0.readFrom(in);  | 
 | 
 | 
 | 
        int minver = archive_header_0.getInt();  | 
 | 
        int majver = archive_header_0.getInt();  | 
 | 
        packageVersion = Package.Version.of(majver, minver);  | 
 | 
        checkArchiveVersion();  | 
 | 
        this.initHighestClassVersion(JAVA7_MAX_CLASS_VERSION);  | 
 | 
 | 
 | 
        archiveOptions = archive_header_0.getInt();  | 
 | 
        archive_header_0.doneDisbursing();  | 
 | 
 | 
 | 
          | 
 | 
        boolean haveSpecial = testBit(archiveOptions, AO_HAVE_SPECIAL_FORMATS);  | 
 | 
        boolean haveFiles   = testBit(archiveOptions, AO_HAVE_FILE_HEADERS);  | 
 | 
        boolean haveNumbers = testBit(archiveOptions, AO_HAVE_CP_NUMBERS);  | 
 | 
        boolean haveCPExtra = testBit(archiveOptions, AO_HAVE_CP_EXTRAS);  | 
 | 
        initAttrIndexLimit();  | 
 | 
 | 
 | 
          | 
 | 
        archive_header_S.expectLength(haveFiles? AH_LENGTH_S: 0);  | 
 | 
        archive_header_S.readFrom(in);  | 
 | 
        if (haveFiles) { | 
 | 
            long sizeHi = archive_header_S.getInt();  | 
 | 
            long sizeLo = archive_header_S.getInt();  | 
 | 
            archiveSize1 = (sizeHi << 32) + ((sizeLo << 32) >>> 32);  | 
 | 
            // Set the limit, now, up to the file_bits.  | 
 | 
            in.setReadLimit(archiveSize1);    | 
 | 
        } else { | 
 | 
            archiveSize1 = 0;  | 
 | 
            in.setReadLimit(-1);    | 
 | 
        }  | 
 | 
        archive_header_S.doneDisbursing();  | 
 | 
        archiveSize0 = in.getBytesServed();  | 
 | 
 | 
 | 
        int remainingHeaders = AH_LENGTH_MIN - AH_LENGTH_0 - AH_LENGTH_S;  | 
 | 
        if (haveFiles)    remainingHeaders += AH_FILE_HEADER_LEN;  | 
 | 
        if (haveSpecial)  remainingHeaders += AH_SPECIAL_FORMAT_LEN;  | 
 | 
        if (haveNumbers)  remainingHeaders += AH_CP_NUMBER_LEN;  | 
 | 
        if (haveCPExtra)  remainingHeaders += AH_CP_EXTRA_LEN;  | 
 | 
        archive_header_1.expectLength(remainingHeaders);  | 
 | 
        archive_header_1.readFrom(in);  | 
 | 
 | 
 | 
        if (haveFiles) { | 
 | 
            archiveNextCount = archive_header_1.getInt();  | 
 | 
            pkg.default_modtime = archive_header_1.getInt();  | 
 | 
            numFiles = archive_header_1.getInt();  | 
 | 
        } else { | 
 | 
            archiveNextCount = 0;  | 
 | 
            numFiles = 0;  | 
 | 
        }  | 
 | 
 | 
 | 
        if (haveSpecial) { | 
 | 
            band_headers.expectLength(archive_header_1.getInt());  | 
 | 
            numAttrDefs = archive_header_1.getInt();  | 
 | 
        } else { | 
 | 
            band_headers.expectLength(0);  | 
 | 
            numAttrDefs = 0;  | 
 | 
        }  | 
 | 
 | 
 | 
        readConstantPoolCounts(haveNumbers, haveCPExtra);  | 
 | 
 | 
 | 
        numInnerClasses = archive_header_1.getInt();  | 
 | 
 | 
 | 
        minver = (short) archive_header_1.getInt();  | 
 | 
        majver = (short) archive_header_1.getInt();  | 
 | 
        pkg.defaultClassVersion = Package.Version.of(majver, minver);  | 
 | 
        numClasses = archive_header_1.getInt();  | 
 | 
 | 
 | 
        archive_header_1.doneDisbursing();  | 
 | 
 | 
 | 
          | 
 | 
        if (testBit(archiveOptions, AO_DEFLATE_HINT)) { | 
 | 
            pkg.default_options |= FO_DEFLATE_HINT;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    void readBandHeaders() throws IOException { | 
 | 
        band_headers.readFrom(in);  | 
 | 
        bandHeaderBytePos = 1;    | 
 | 
        bandHeaderBytes = new byte[bandHeaderBytePos + band_headers.length()];  | 
 | 
        for (int i = bandHeaderBytePos; i < bandHeaderBytes.length; i++) { | 
 | 
            bandHeaderBytes[i] = (byte) band_headers.getByte();  | 
 | 
        }  | 
 | 
        band_headers.doneDisbursing();  | 
 | 
    }  | 
 | 
 | 
 | 
    void readConstantPoolCounts(boolean haveNumbers, boolean haveCPExtra) throws IOException { | 
 | 
          | 
 | 
        for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) { | 
 | 
            //  cp_counts:  | 
 | 
            //        #cp_Utf8_count :UNSIGNED5[1]  | 
 | 
            //        (cp_number_counts) ** (#have_cp_numbers)  | 
 | 
            //        #cp_String_count :UNSIGNED5[1]  | 
 | 
            //        #cp_Class_count :UNSIGNED5[1]  | 
 | 
            //        #cp_Signature_count :UNSIGNED5[1]  | 
 | 
            //        #cp_Descr_count :UNSIGNED5[1]  | 
 | 
            //        #cp_Field_count :UNSIGNED5[1]  | 
 | 
            //        #cp_Method_count :UNSIGNED5[1]  | 
 | 
            //        #cp_Imethod_count :UNSIGNED5[1]  | 
 | 
            //        (cp_attr_counts) ** (#have_cp_attr_counts)  | 
 | 
            //  | 
 | 
            //  cp_number_counts:  | 
 | 
            //        #cp_Int_count :UNSIGNED5[1]  | 
 | 
            //        #cp_Float_count :UNSIGNED5[1]  | 
 | 
            //        #cp_Long_count :UNSIGNED5[1]  | 
 | 
            //        #cp_Double_count :UNSIGNED5[1]  | 
 | 
            //  | 
 | 
            //  cp_extra_counts:  | 
 | 
            //        #cp_MethodHandle_count :UNSIGNED5[1]  | 
 | 
            //        #cp_MethodType_count :UNSIGNED5[1]  | 
 | 
            //        #cp_InvokeDynamic_count :UNSIGNED5[1]  | 
 | 
            //        #cp_BootstrapMethod_count :UNSIGNED5[1]  | 
 | 
              | 
 | 
            byte tag = ConstantPool.TAGS_IN_ORDER[k];  | 
 | 
            if (!haveNumbers) { | 
 | 
                  | 
 | 
                switch (tag) { | 
 | 
                case CONSTANT_Integer:  | 
 | 
                case CONSTANT_Float:  | 
 | 
                case CONSTANT_Long:  | 
 | 
                case CONSTANT_Double:  | 
 | 
                    continue;  | 
 | 
                }  | 
 | 
            }  | 
 | 
            if (!haveCPExtra) { | 
 | 
                  | 
 | 
                switch (tag) { | 
 | 
                case CONSTANT_MethodHandle:  | 
 | 
                case CONSTANT_MethodType:  | 
 | 
                case CONSTANT_InvokeDynamic:  | 
 | 
                case CONSTANT_BootstrapMethod:  | 
 | 
                    continue;  | 
 | 
                }  | 
 | 
            }  | 
 | 
            tagCount[tag] = archive_header_1.getInt();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    protected Index getCPIndex(byte tag) { | 
 | 
        return pkg.cp.getIndexByTag(tag);  | 
 | 
    }  | 
 | 
    Index initCPIndex(byte tag, Entry[] cpMap) { | 
 | 
        if (verbose > 3) { | 
 | 
            for (int i = 0; i < cpMap.length; i++) { | 
 | 
                Utils.log.fine("cp.add "+cpMap[i]); | 
 | 
            }  | 
 | 
        }  | 
 | 
        Index index = ConstantPool.makeIndex(ConstantPool.tagName(tag), cpMap);  | 
 | 
        if (verbose > 1)  Utils.log.fine("Read "+index); | 
 | 
        pkg.cp.initIndexByTag(tag, index);  | 
 | 
        return index;  | 
 | 
    }  | 
 | 
 | 
 | 
    void checkLegacy(String bandname) { | 
 | 
        if (packageVersion.lessThan(JAVA7_PACKAGE_VERSION)) { | 
 | 
            throw new RuntimeException("unexpected band " + bandname); | 
 | 
        }  | 
 | 
    }  | 
 | 
    void readConstantPool() throws IOException { | 
 | 
        //  cp_bands:  | 
 | 
        //        cp_Utf8  | 
 | 
        //        *cp_Int :UDELTA5  | 
 | 
        //        *cp_Float :UDELTA5  | 
 | 
        //        cp_Long  | 
 | 
        //        cp_Double  | 
 | 
        //        *cp_String :UDELTA5  (cp_Utf8)  | 
 | 
        //        *cp_Class :UDELTA5  (cp_Utf8)  | 
 | 
        //        cp_Signature  | 
 | 
        //        cp_Descr  | 
 | 
        //        cp_Field  | 
 | 
        //        cp_Method  | 
 | 
        //        cp_Imethod  | 
 | 
 | 
 | 
        if (verbose > 0)  Utils.log.info("Reading CP"); | 
 | 
 | 
 | 
        for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) { | 
 | 
            byte tag = ConstantPool.TAGS_IN_ORDER[k];  | 
 | 
            int  len = tagCount[tag];  | 
 | 
 | 
 | 
            Entry[] cpMap = new Entry[len];  | 
 | 
            if (verbose > 0)  | 
 | 
                Utils.log.info("Reading "+cpMap.length+" "+ConstantPool.tagName(tag)+" entries..."); | 
 | 
 | 
 | 
            switch (tag) { | 
 | 
            case CONSTANT_Utf8:  | 
 | 
                readUtf8Bands(cpMap);  | 
 | 
                break;  | 
 | 
            case CONSTANT_Integer:  | 
 | 
                cp_Int.expectLength(cpMap.length);  | 
 | 
                cp_Int.readFrom(in);  | 
 | 
                for (int i = 0; i < cpMap.length; i++) { | 
 | 
                    int x = cp_Int.getInt();    | 
 | 
                    cpMap[i] = ConstantPool.getLiteralEntry(x);  | 
 | 
                }  | 
 | 
                cp_Int.doneDisbursing();  | 
 | 
                break;  | 
 | 
            case CONSTANT_Float:  | 
 | 
                cp_Float.expectLength(cpMap.length);  | 
 | 
                cp_Float.readFrom(in);  | 
 | 
                for (int i = 0; i < cpMap.length; i++) { | 
 | 
                    int x = cp_Float.getInt();  | 
 | 
                    float fx = Float.intBitsToFloat(x);  | 
 | 
                    cpMap[i] = ConstantPool.getLiteralEntry(fx);  | 
 | 
                }  | 
 | 
                cp_Float.doneDisbursing();  | 
 | 
                break;  | 
 | 
            case CONSTANT_Long:  | 
 | 
                //  cp_Long:  | 
 | 
                //        *cp_Long_hi :UDELTA5  | 
 | 
                  | 
 | 
                cp_Long_hi.expectLength(cpMap.length);  | 
 | 
                cp_Long_hi.readFrom(in);  | 
 | 
                cp_Long_lo.expectLength(cpMap.length);  | 
 | 
                cp_Long_lo.readFrom(in);  | 
 | 
                for (int i = 0; i < cpMap.length; i++) { | 
 | 
                    long hi = cp_Long_hi.getInt();  | 
 | 
                    long lo = cp_Long_lo.getInt();  | 
 | 
                    long x = (hi << 32) + ((lo << 32) >>> 32);  | 
 | 
                    cpMap[i] = ConstantPool.getLiteralEntry(x);  | 
 | 
                }  | 
 | 
                cp_Long_hi.doneDisbursing();  | 
 | 
                cp_Long_lo.doneDisbursing();  | 
 | 
                break;  | 
 | 
            case CONSTANT_Double:  | 
 | 
                //  cp_Double:  | 
 | 
                //        *cp_Double_hi :UDELTA5  | 
 | 
                  | 
 | 
                cp_Double_hi.expectLength(cpMap.length);  | 
 | 
                cp_Double_hi.readFrom(in);  | 
 | 
                cp_Double_lo.expectLength(cpMap.length);  | 
 | 
                cp_Double_lo.readFrom(in);  | 
 | 
                for (int i = 0; i < cpMap.length; i++) { | 
 | 
                    long hi = cp_Double_hi.getInt();  | 
 | 
                    long lo = cp_Double_lo.getInt();  | 
 | 
                    long x = (hi << 32) + ((lo << 32) >>> 32);  | 
 | 
                    double dx = Double.longBitsToDouble(x);  | 
 | 
                    cpMap[i] = ConstantPool.getLiteralEntry(dx);  | 
 | 
                }  | 
 | 
                cp_Double_hi.doneDisbursing();  | 
 | 
                cp_Double_lo.doneDisbursing();  | 
 | 
                break;  | 
 | 
            case CONSTANT_String:  | 
 | 
                cp_String.expectLength(cpMap.length);  | 
 | 
                cp_String.readFrom(in);  | 
 | 
                cp_String.setIndex(getCPIndex(CONSTANT_Utf8));  | 
 | 
                for (int i = 0; i < cpMap.length; i++) { | 
 | 
                    cpMap[i] = ConstantPool.getLiteralEntry(cp_String.getRef().stringValue());  | 
 | 
                }  | 
 | 
                cp_String.doneDisbursing();  | 
 | 
                break;  | 
 | 
            case CONSTANT_Class:  | 
 | 
                cp_Class.expectLength(cpMap.length);  | 
 | 
                cp_Class.readFrom(in);  | 
 | 
                cp_Class.setIndex(getCPIndex(CONSTANT_Utf8));  | 
 | 
                for (int i = 0; i < cpMap.length; i++) { | 
 | 
                    cpMap[i] = ConstantPool.getClassEntry(cp_Class.getRef().stringValue());  | 
 | 
                }  | 
 | 
                cp_Class.doneDisbursing();  | 
 | 
                break;  | 
 | 
            case CONSTANT_Signature:  | 
 | 
                readSignatureBands(cpMap);  | 
 | 
                break;  | 
 | 
            case CONSTANT_NameandType:  | 
 | 
                //  cp_Descr:  | 
 | 
                //        *cp_Descr_type :DELTA5  (cp_Signature)  | 
 | 
                  | 
 | 
                cp_Descr_name.expectLength(cpMap.length);  | 
 | 
                cp_Descr_name.readFrom(in);  | 
 | 
                cp_Descr_name.setIndex(getCPIndex(CONSTANT_Utf8));  | 
 | 
                cp_Descr_type.expectLength(cpMap.length);  | 
 | 
                cp_Descr_type.readFrom(in);  | 
 | 
                cp_Descr_type.setIndex(getCPIndex(CONSTANT_Signature));  | 
 | 
                for (int i = 0; i < cpMap.length; i++) { | 
 | 
                    Entry ref  = cp_Descr_name.getRef();  | 
 | 
                    Entry ref2 = cp_Descr_type.getRef();  | 
 | 
                    cpMap[i] = ConstantPool.getDescriptorEntry((Utf8Entry)ref,  | 
 | 
                                                        (SignatureEntry)ref2);  | 
 | 
                }  | 
 | 
                cp_Descr_name.doneDisbursing();  | 
 | 
                cp_Descr_type.doneDisbursing();  | 
 | 
                break;  | 
 | 
            case CONSTANT_Fieldref:  | 
 | 
                readMemberRefs(tag, cpMap, cp_Field_class, cp_Field_desc);  | 
 | 
                break;  | 
 | 
            case CONSTANT_Methodref:  | 
 | 
                readMemberRefs(tag, cpMap, cp_Method_class, cp_Method_desc);  | 
 | 
                break;  | 
 | 
            case CONSTANT_InterfaceMethodref:  | 
 | 
                readMemberRefs(tag, cpMap, cp_Imethod_class, cp_Imethod_desc);  | 
 | 
                break;  | 
 | 
            case CONSTANT_MethodHandle:  | 
 | 
                if (cpMap.length > 0) { | 
 | 
                    checkLegacy(cp_MethodHandle_refkind.name());  | 
 | 
                }  | 
 | 
                cp_MethodHandle_refkind.expectLength(cpMap.length);  | 
 | 
                cp_MethodHandle_refkind.readFrom(in);  | 
 | 
                cp_MethodHandle_member.expectLength(cpMap.length);  | 
 | 
                cp_MethodHandle_member.readFrom(in);  | 
 | 
                cp_MethodHandle_member.setIndex(getCPIndex(CONSTANT_AnyMember));  | 
 | 
                for (int i = 0; i < cpMap.length; i++) { | 
 | 
                    byte        refKind = (byte)        cp_MethodHandle_refkind.getInt();  | 
 | 
                    MemberEntry memRef  = (MemberEntry) cp_MethodHandle_member.getRef();  | 
 | 
                    cpMap[i] = ConstantPool.getMethodHandleEntry(refKind, memRef);  | 
 | 
                }  | 
 | 
                cp_MethodHandle_refkind.doneDisbursing();  | 
 | 
                cp_MethodHandle_member.doneDisbursing();  | 
 | 
                break;  | 
 | 
            case CONSTANT_MethodType:  | 
 | 
                if (cpMap.length > 0) { | 
 | 
                    checkLegacy(cp_MethodType.name());  | 
 | 
                }  | 
 | 
                cp_MethodType.expectLength(cpMap.length);  | 
 | 
                cp_MethodType.readFrom(in);  | 
 | 
                cp_MethodType.setIndex(getCPIndex(CONSTANT_Signature));  | 
 | 
                for (int i = 0; i < cpMap.length; i++) { | 
 | 
                    SignatureEntry typeRef  = (SignatureEntry) cp_MethodType.getRef();  | 
 | 
                    cpMap[i] = ConstantPool.getMethodTypeEntry(typeRef);  | 
 | 
                }  | 
 | 
                cp_MethodType.doneDisbursing();  | 
 | 
                break;  | 
 | 
            case CONSTANT_InvokeDynamic:  | 
 | 
                if (cpMap.length > 0) { | 
 | 
                    checkLegacy(cp_InvokeDynamic_spec.name());  | 
 | 
                }  | 
 | 
                cp_InvokeDynamic_spec.expectLength(cpMap.length);  | 
 | 
                cp_InvokeDynamic_spec.readFrom(in);  | 
 | 
                cp_InvokeDynamic_spec.setIndex(getCPIndex(CONSTANT_BootstrapMethod));  | 
 | 
                cp_InvokeDynamic_desc.expectLength(cpMap.length);  | 
 | 
                cp_InvokeDynamic_desc.readFrom(in);  | 
 | 
                cp_InvokeDynamic_desc.setIndex(getCPIndex(CONSTANT_NameandType));  | 
 | 
                for (int i = 0; i < cpMap.length; i++) { | 
 | 
                    BootstrapMethodEntry bss   = (BootstrapMethodEntry) cp_InvokeDynamic_spec.getRef();  | 
 | 
                    DescriptorEntry      descr = (DescriptorEntry)      cp_InvokeDynamic_desc.getRef();  | 
 | 
                    cpMap[i] = ConstantPool.getInvokeDynamicEntry(bss, descr);  | 
 | 
                }  | 
 | 
                cp_InvokeDynamic_spec.doneDisbursing();  | 
 | 
                cp_InvokeDynamic_desc.doneDisbursing();  | 
 | 
                break;  | 
 | 
            case CONSTANT_BootstrapMethod:  | 
 | 
                if (cpMap.length > 0) { | 
 | 
                    checkLegacy(cp_BootstrapMethod_ref.name());  | 
 | 
                }  | 
 | 
                cp_BootstrapMethod_ref.expectLength(cpMap.length);  | 
 | 
                cp_BootstrapMethod_ref.readFrom(in);  | 
 | 
                cp_BootstrapMethod_ref.setIndex(getCPIndex(CONSTANT_MethodHandle));  | 
 | 
                cp_BootstrapMethod_arg_count.expectLength(cpMap.length);  | 
 | 
                cp_BootstrapMethod_arg_count.readFrom(in);  | 
 | 
                int totalArgCount = cp_BootstrapMethod_arg_count.getIntTotal();  | 
 | 
                cp_BootstrapMethod_arg.expectLength(totalArgCount);  | 
 | 
                cp_BootstrapMethod_arg.readFrom(in);  | 
 | 
                cp_BootstrapMethod_arg.setIndex(getCPIndex(CONSTANT_LoadableValue));  | 
 | 
                for (int i = 0; i < cpMap.length; i++) { | 
 | 
                    MethodHandleEntry bsm = (MethodHandleEntry) cp_BootstrapMethod_ref.getRef();  | 
 | 
                    int argc = cp_BootstrapMethod_arg_count.getInt();  | 
 | 
                    Entry[] argRefs = new Entry[argc];  | 
 | 
                    for (int j = 0; j < argc; j++) { | 
 | 
                        argRefs[j] = cp_BootstrapMethod_arg.getRef();  | 
 | 
                    }  | 
 | 
                    cpMap[i] = ConstantPool.getBootstrapMethodEntry(bsm, argRefs);  | 
 | 
                }  | 
 | 
                cp_BootstrapMethod_ref.doneDisbursing();  | 
 | 
                cp_BootstrapMethod_arg_count.doneDisbursing();  | 
 | 
                cp_BootstrapMethod_arg.doneDisbursing();  | 
 | 
                break;  | 
 | 
            default:  | 
 | 
                throw new AssertionError("unexpected CP tag in package"); | 
 | 
            }  | 
 | 
 | 
 | 
            Index index = initCPIndex(tag, cpMap);  | 
 | 
 | 
 | 
            if (optDumpBands) { | 
 | 
                try (PrintStream ps = new PrintStream(getDumpStream(index, ".idx"))) { | 
 | 
                    printArrayTo(ps, index.cpMap, 0, index.cpMap.length);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        cp_bands.doneDisbursing();  | 
 | 
 | 
 | 
        if (optDumpBands || verbose > 1) { | 
 | 
            for (byte tag = CONSTANT_GroupFirst; tag < CONSTANT_GroupLimit; tag++) { | 
 | 
                Index index = pkg.cp.getIndexByTag(tag);  | 
 | 
                if (index == null || index.isEmpty())  continue;  | 
 | 
                Entry[] cpMap = index.cpMap;  | 
 | 
                if (verbose > 1)  | 
 | 
                    Utils.log.info("Index group "+ConstantPool.tagName(tag)+" contains "+cpMap.length+" entries."); | 
 | 
                if (optDumpBands) { | 
 | 
                    try (PrintStream ps = new PrintStream(getDumpStream(index.debugName, tag, ".gidx", index))) { | 
 | 
                        printArrayTo(ps, cpMap, 0, cpMap.length, true);  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        setBandIndexes();  | 
 | 
    }  | 
 | 
 | 
 | 
    void readUtf8Bands(Entry[] cpMap) throws IOException { | 
 | 
        //  cp_Utf8:  | 
 | 
        //        *cp_Utf8_prefix :DELTA5  | 
 | 
        //        *cp_Utf8_suffix :UNSIGNED5  | 
 | 
        //        *cp_Utf8_chars :CHAR3  | 
 | 
        //        *cp_Utf8_big_suffix :DELTA5  | 
 | 
        //        (*cp_Utf8_big_chars :DELTA5)  | 
 | 
          | 
 | 
        int len = cpMap.length;  | 
 | 
        if (len == 0)  | 
 | 
            return;    | 
 | 
 | 
 | 
          | 
 | 
        final int SUFFIX_SKIP_1 = 1;  | 
 | 
        final int PREFIX_SKIP_2 = 2;  | 
 | 
 | 
 | 
          | 
 | 
        cp_Utf8_prefix.expectLength(Math.max(0, len - PREFIX_SKIP_2));  | 
 | 
        cp_Utf8_prefix.readFrom(in);  | 
 | 
 | 
 | 
          | 
 | 
        cp_Utf8_suffix.expectLength(Math.max(0, len - SUFFIX_SKIP_1));  | 
 | 
        cp_Utf8_suffix.readFrom(in);  | 
 | 
 | 
 | 
        char[][] suffixChars = new char[len][];  | 
 | 
        int bigSuffixCount = 0;  | 
 | 
 | 
 | 
          | 
 | 
        cp_Utf8_chars.expectLength(cp_Utf8_suffix.getIntTotal());  | 
 | 
        cp_Utf8_chars.readFrom(in);  | 
 | 
        for (int i = 0; i < len; i++) { | 
 | 
            int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt();  | 
 | 
            if (suffix == 0 && i >= SUFFIX_SKIP_1) { | 
 | 
                  | 
 | 
                bigSuffixCount += 1;  | 
 | 
                continue;  | 
 | 
            }  | 
 | 
            suffixChars[i] = new char[suffix];  | 
 | 
            for (int j = 0; j < suffix; j++) { | 
 | 
                int ch = cp_Utf8_chars.getInt();  | 
 | 
                assert(ch == (char)ch);  | 
 | 
                suffixChars[i][j] = (char)ch;  | 
 | 
            }  | 
 | 
        }  | 
 | 
        cp_Utf8_chars.doneDisbursing();  | 
 | 
 | 
 | 
          | 
 | 
        int maxChars = 0;  | 
 | 
        cp_Utf8_big_suffix.expectLength(bigSuffixCount);  | 
 | 
        cp_Utf8_big_suffix.readFrom(in);  | 
 | 
        cp_Utf8_suffix.resetForSecondPass();  | 
 | 
        for (int i = 0; i < len; i++) { | 
 | 
            int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt();  | 
 | 
            int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt();  | 
 | 
            if (suffix == 0 && i >= SUFFIX_SKIP_1) { | 
 | 
                assert(suffixChars[i] == null);  | 
 | 
                suffix = cp_Utf8_big_suffix.getInt();  | 
 | 
            } else { | 
 | 
                assert(suffixChars[i] != null);  | 
 | 
            }  | 
 | 
            if (maxChars < prefix + suffix)  | 
 | 
                maxChars = prefix + suffix;  | 
 | 
        }  | 
 | 
        char[] buf = new char[maxChars];  | 
 | 
 | 
 | 
          | 
 | 
        cp_Utf8_suffix.resetForSecondPass();  | 
 | 
        cp_Utf8_big_suffix.resetForSecondPass();  | 
 | 
        for (int i = 0; i < len; i++) { | 
 | 
            if (i < SUFFIX_SKIP_1)  continue;  | 
 | 
            int suffix = cp_Utf8_suffix.getInt();  | 
 | 
            if (suffix != 0)  continue;    | 
 | 
            suffix = cp_Utf8_big_suffix.getInt();  | 
 | 
            suffixChars[i] = new char[suffix];  | 
 | 
            if (suffix == 0) { | 
 | 
                  | 
 | 
                continue;  | 
 | 
            }  | 
 | 
            IntBand packed = cp_Utf8_big_chars.newIntBand("(Utf8_big_"+i+")"); | 
 | 
            packed.expectLength(suffix);  | 
 | 
            packed.readFrom(in);  | 
 | 
            for (int j = 0; j < suffix; j++) { | 
 | 
                int ch = packed.getInt();  | 
 | 
                assert(ch == (char)ch);  | 
 | 
                suffixChars[i][j] = (char)ch;  | 
 | 
            }  | 
 | 
            packed.doneDisbursing();  | 
 | 
        }  | 
 | 
        cp_Utf8_big_chars.doneDisbursing();  | 
 | 
 | 
 | 
          | 
 | 
        cp_Utf8_prefix.resetForSecondPass();  | 
 | 
        cp_Utf8_suffix.resetForSecondPass();  | 
 | 
        cp_Utf8_big_suffix.resetForSecondPass();  | 
 | 
        for (int i = 0; i < len; i++) { | 
 | 
            int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt();  | 
 | 
            int suffix = (i < SUFFIX_SKIP_1)? 0: cp_Utf8_suffix.getInt();  | 
 | 
            if (suffix == 0 && i >= SUFFIX_SKIP_1)  | 
 | 
                suffix = cp_Utf8_big_suffix.getInt();  | 
 | 
 | 
 | 
              | 
 | 
            System.arraycopy(suffixChars[i], 0, buf, prefix, suffix);  | 
 | 
 | 
 | 
            cpMap[i] = ConstantPool.getUtf8Entry(new String(buf, 0, prefix+suffix));  | 
 | 
        }  | 
 | 
 | 
 | 
        cp_Utf8_prefix.doneDisbursing();  | 
 | 
        cp_Utf8_suffix.doneDisbursing();  | 
 | 
        cp_Utf8_big_suffix.doneDisbursing();  | 
 | 
    }  | 
 | 
 | 
 | 
    Map<Utf8Entry, SignatureEntry> utf8Signatures;  | 
 | 
 | 
 | 
    void readSignatureBands(Entry[] cpMap) throws IOException { | 
 | 
        //  cp_Signature:  | 
 | 
        //        *cp_Signature_form :DELTA5  (cp_Utf8)  | 
 | 
          | 
 | 
        cp_Signature_form.expectLength(cpMap.length);  | 
 | 
        cp_Signature_form.readFrom(in);  | 
 | 
        cp_Signature_form.setIndex(getCPIndex(CONSTANT_Utf8));  | 
 | 
        int[] numSigClasses = new int[cpMap.length];  | 
 | 
        for (int i = 0; i < cpMap.length; i++) { | 
 | 
            Utf8Entry formRef = (Utf8Entry) cp_Signature_form.getRef();  | 
 | 
            numSigClasses[i] = ConstantPool.countClassParts(formRef);  | 
 | 
        }  | 
 | 
        cp_Signature_form.resetForSecondPass();  | 
 | 
        cp_Signature_classes.expectLength(getIntTotal(numSigClasses));  | 
 | 
        cp_Signature_classes.readFrom(in);  | 
 | 
        cp_Signature_classes.setIndex(getCPIndex(CONSTANT_Class));  | 
 | 
        utf8Signatures = new HashMap<>();  | 
 | 
        for (int i = 0; i < cpMap.length; i++) { | 
 | 
            Utf8Entry formRef = (Utf8Entry) cp_Signature_form.getRef();  | 
 | 
            ClassEntry[] classRefs = new ClassEntry[numSigClasses[i]];  | 
 | 
            for (int j = 0; j < classRefs.length; j++) { | 
 | 
                classRefs[j] = (ClassEntry) cp_Signature_classes.getRef();  | 
 | 
            }  | 
 | 
            SignatureEntry se = ConstantPool.getSignatureEntry(formRef, classRefs);  | 
 | 
            cpMap[i] = se;  | 
 | 
            utf8Signatures.put(se.asUtf8Entry(), se);  | 
 | 
        }  | 
 | 
        cp_Signature_form.doneDisbursing();  | 
 | 
        cp_Signature_classes.doneDisbursing();  | 
 | 
    }  | 
 | 
 | 
 | 
    void readMemberRefs(byte tag, Entry[] cpMap, CPRefBand cp_class, CPRefBand cp_desc) throws IOException { | 
 | 
        //  cp_Field:  | 
 | 
        //        *cp_Field_class :DELTA5  (cp_Class)  | 
 | 
        //        *cp_Field_desc :UDELTA5  (cp_Descr)  | 
 | 
        //  cp_Method:  | 
 | 
        //        *cp_Method_class :DELTA5  (cp_Class)  | 
 | 
        //        *cp_Method_desc :UDELTA5  (cp_Descr)  | 
 | 
        //  cp_Imethod:  | 
 | 
        //        *cp_Imethod_class :DELTA5  (cp_Class)  | 
 | 
          | 
 | 
        cp_class.expectLength(cpMap.length);  | 
 | 
        cp_class.readFrom(in);  | 
 | 
        cp_class.setIndex(getCPIndex(CONSTANT_Class));  | 
 | 
        cp_desc.expectLength(cpMap.length);  | 
 | 
        cp_desc.readFrom(in);  | 
 | 
        cp_desc.setIndex(getCPIndex(CONSTANT_NameandType));  | 
 | 
        for (int i = 0; i < cpMap.length; i++) { | 
 | 
            ClassEntry      mclass = (ClassEntry     ) cp_class.getRef();  | 
 | 
            DescriptorEntry mdescr = (DescriptorEntry) cp_desc.getRef();  | 
 | 
            cpMap[i] = ConstantPool.getMemberEntry(tag, mclass, mdescr);  | 
 | 
        }  | 
 | 
        cp_class.doneDisbursing();  | 
 | 
        cp_desc.doneDisbursing();  | 
 | 
    }  | 
 | 
 | 
 | 
    void readFiles() throws IOException { | 
 | 
        //  file_bands:  | 
 | 
        //        *file_name :UNSIGNED5  (cp_Utf8)  | 
 | 
        //        *file_size_hi :UNSIGNED5  | 
 | 
        //        *file_size_lo :UNSIGNED5  | 
 | 
        //        *file_modtime :DELTA5  | 
 | 
        //        *file_options :UNSIGNED5  | 
 | 
          | 
 | 
        if (verbose > 0)  | 
 | 
            Utils.log.info("  ...building "+numFiles+" files..."); | 
 | 
        file_name.expectLength(numFiles);  | 
 | 
        file_size_lo.expectLength(numFiles);  | 
 | 
        int options = archiveOptions;  | 
 | 
        boolean haveSizeHi  = testBit(options, AO_HAVE_FILE_SIZE_HI);  | 
 | 
        boolean haveModtime = testBit(options, AO_HAVE_FILE_MODTIME);  | 
 | 
        boolean haveOptions = testBit(options, AO_HAVE_FILE_OPTIONS);  | 
 | 
        if (haveSizeHi)  | 
 | 
            file_size_hi.expectLength(numFiles);  | 
 | 
        if (haveModtime)  | 
 | 
            file_modtime.expectLength(numFiles);  | 
 | 
        if (haveOptions)  | 
 | 
            file_options.expectLength(numFiles);  | 
 | 
 | 
 | 
        file_name.readFrom(in);  | 
 | 
        file_size_hi.readFrom(in);  | 
 | 
        file_size_lo.readFrom(in);  | 
 | 
        file_modtime.readFrom(in);  | 
 | 
        file_options.readFrom(in);  | 
 | 
        file_bits.setInputStreamFrom(in);  | 
 | 
 | 
 | 
        Iterator<Class> nextClass = pkg.getClasses().iterator();  | 
 | 
 | 
 | 
          | 
 | 
        long totalFileLength = 0;  | 
 | 
        long[] fileLengths = new long[numFiles];  | 
 | 
        for (int i = 0; i < numFiles; i++) { | 
 | 
            long size = ((long)file_size_lo.getInt() << 32) >>> 32;  | 
 | 
            if (haveSizeHi)  | 
 | 
                size += (long)file_size_hi.getInt() << 32;  | 
 | 
            fileLengths[i] = size;  | 
 | 
            totalFileLength += size;  | 
 | 
        }  | 
 | 
        assert(in.getReadLimit() == -1 || in.getReadLimit() == totalFileLength);  | 
 | 
 | 
 | 
        byte[] buf = new byte[1<<16];  | 
 | 
        for (int i = 0; i < numFiles; i++) { | 
 | 
              | 
 | 
            Utf8Entry name = (Utf8Entry) file_name.getRef();  | 
 | 
            long size = fileLengths[i];  | 
 | 
            File file = pkg.new File(name);  | 
 | 
            file.modtime = pkg.default_modtime;  | 
 | 
            file.options = pkg.default_options;  | 
 | 
            if (haveModtime)  | 
 | 
                file.modtime += file_modtime.getInt();  | 
 | 
            if (haveOptions)  | 
 | 
                file.options |= file_options.getInt();  | 
 | 
            if (verbose > 1)  | 
 | 
                Utils.log.fine("Reading "+size+" bytes of "+name.stringValue()); | 
 | 
            long toRead = size;  | 
 | 
            while (toRead > 0) { | 
 | 
                int nr = buf.length;  | 
 | 
                if (nr > toRead)  nr = (int) toRead;  | 
 | 
                nr = file_bits.getInputStream().read(buf, 0, nr);  | 
 | 
                if (nr < 0)  throw new EOFException();  | 
 | 
                file.addBytes(buf, 0, nr);  | 
 | 
                toRead -= nr;  | 
 | 
            }  | 
 | 
            pkg.addFile(file);  | 
 | 
            if (file.isClassStub()) { | 
 | 
                assert(file.getFileLength() == 0);  | 
 | 
                Class cls = nextClass.next();  | 
 | 
                cls.initFile(file);  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        while (nextClass.hasNext()) { | 
 | 
            Class cls = nextClass.next();  | 
 | 
            cls.initFile(null);    | 
 | 
            cls.file.modtime = pkg.default_modtime;  | 
 | 
        }  | 
 | 
 | 
 | 
        file_name.doneDisbursing();  | 
 | 
        file_size_hi.doneDisbursing();  | 
 | 
        file_size_lo.doneDisbursing();  | 
 | 
        file_modtime.doneDisbursing();  | 
 | 
        file_options.doneDisbursing();  | 
 | 
        file_bits.doneDisbursing();  | 
 | 
        file_bands.doneDisbursing();  | 
 | 
 | 
 | 
        if (archiveSize1 != 0 && !in.atLimit()) { | 
 | 
            throw new RuntimeException("Predicted archive_size "+ | 
 | 
                                       archiveSize1+" != "+  | 
 | 
                                       (in.getBytesServed()-archiveSize0));  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    void readAttrDefs() throws IOException { | 
 | 
        //  attr_definition_bands:  | 
 | 
        //        *attr_definition_headers :BYTE1  | 
 | 
        //        *attr_definition_name :UNSIGNED5  (cp_Utf8)  | 
 | 
          | 
 | 
        attr_definition_headers.expectLength(numAttrDefs);  | 
 | 
        attr_definition_name.expectLength(numAttrDefs);  | 
 | 
        attr_definition_layout.expectLength(numAttrDefs);  | 
 | 
        attr_definition_headers.readFrom(in);  | 
 | 
        attr_definition_name.readFrom(in);  | 
 | 
        attr_definition_layout.readFrom(in);  | 
 | 
        try (PrintStream dump = !optDumpBands ? null  | 
 | 
                 : new PrintStream(getDumpStream(attr_definition_headers, ".def")))  | 
 | 
        { | 
 | 
            for (int i = 0; i < numAttrDefs; i++) { | 
 | 
                int       header = attr_definition_headers.getByte();  | 
 | 
                Utf8Entry name   = (Utf8Entry) attr_definition_name.getRef();  | 
 | 
                Utf8Entry layout = (Utf8Entry) attr_definition_layout.getRef();  | 
 | 
                int       ctype  = (header &  ADH_CONTEXT_MASK);  | 
 | 
                int       index  = (header >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB;  | 
 | 
                Attribute.Layout def = new Attribute.Layout(ctype,  | 
 | 
                                                            name.stringValue(),  | 
 | 
                                                            layout.stringValue());  | 
 | 
                  | 
 | 
                String pvLayout = def.layoutForClassVersion(getHighestClassVersion());  | 
 | 
                if (!pvLayout.equals(def.layout())) { | 
 | 
                    throw new IOException("Bad attribute layout in archive: "+def.layout()); | 
 | 
                }  | 
 | 
                this.setAttributeLayoutIndex(def, index);  | 
 | 
                if (dump != null)  dump.println(index+" "+def);  | 
 | 
            }  | 
 | 
        }  | 
 | 
        attr_definition_headers.doneDisbursing();  | 
 | 
        attr_definition_name.doneDisbursing();  | 
 | 
        attr_definition_layout.doneDisbursing();  | 
 | 
        // Attribute layouts define bands, one per layout element.  | 
 | 
          | 
 | 
        makeNewAttributeBands();  | 
 | 
        attr_definition_bands.doneDisbursing();  | 
 | 
    }  | 
 | 
 | 
 | 
    void readInnerClasses() throws IOException { | 
 | 
        //  ic_bands:  | 
 | 
        //        *ic_this_class :UDELTA5  (cp_Class)  | 
 | 
        //        *ic_flags :UNSIGNED5  | 
 | 
        //        *ic_outer_class :DELTA5  (null or cp_Class)  | 
 | 
          | 
 | 
        ic_this_class.expectLength(numInnerClasses);  | 
 | 
        ic_this_class.readFrom(in);  | 
 | 
        ic_flags.expectLength(numInnerClasses);  | 
 | 
        ic_flags.readFrom(in);  | 
 | 
        int longICCount = 0;  | 
 | 
        for (int i = 0; i < numInnerClasses; i++) { | 
 | 
            int flags = ic_flags.getInt();  | 
 | 
            boolean longForm = (flags & ACC_IC_LONG_FORM) != 0;  | 
 | 
            if (longForm) { | 
 | 
                longICCount += 1;  | 
 | 
            }  | 
 | 
        }  | 
 | 
        ic_outer_class.expectLength(longICCount);  | 
 | 
        ic_outer_class.readFrom(in);  | 
 | 
        ic_name.expectLength(longICCount);  | 
 | 
        ic_name.readFrom(in);  | 
 | 
        ic_flags.resetForSecondPass();  | 
 | 
        List<InnerClass> icList = new ArrayList<>(numInnerClasses);  | 
 | 
        for (int i = 0; i < numInnerClasses; i++) { | 
 | 
            int flags = ic_flags.getInt();  | 
 | 
            boolean longForm = (flags & ACC_IC_LONG_FORM) != 0;  | 
 | 
            flags &= ~ACC_IC_LONG_FORM;  | 
 | 
            ClassEntry thisClass = (ClassEntry) ic_this_class.getRef();  | 
 | 
            ClassEntry outerClass;  | 
 | 
            Utf8Entry  thisName;  | 
 | 
            if (longForm) { | 
 | 
                outerClass = (ClassEntry) ic_outer_class.getRef();  | 
 | 
                thisName   = (Utf8Entry)  ic_name.getRef();  | 
 | 
            } else { | 
 | 
                String n = thisClass.stringValue();  | 
 | 
                String[] parse = Package.parseInnerClassName(n);  | 
 | 
                assert(parse != null);  | 
 | 
                String pkgOuter = parse[0];  | 
 | 
                  | 
 | 
                String name     = parse[2];  | 
 | 
                if (pkgOuter == null)  | 
 | 
                    outerClass = null;  | 
 | 
                else  | 
 | 
                    outerClass = ConstantPool.getClassEntry(pkgOuter);  | 
 | 
                if (name == null)  | 
 | 
                    thisName   = null;  | 
 | 
                else  | 
 | 
                    thisName   = ConstantPool.getUtf8Entry(name);  | 
 | 
            }  | 
 | 
            InnerClass ic =  | 
 | 
                new InnerClass(thisClass, outerClass, thisName, flags);  | 
 | 
            assert(longForm || ic.predictable);  | 
 | 
            icList.add(ic);  | 
 | 
        }  | 
 | 
        ic_flags.doneDisbursing();  | 
 | 
        ic_this_class.doneDisbursing();  | 
 | 
        ic_outer_class.doneDisbursing();  | 
 | 
        ic_name.doneDisbursing();  | 
 | 
        pkg.setAllInnerClasses(icList);  | 
 | 
        ic_bands.doneDisbursing();  | 
 | 
    }  | 
 | 
 | 
 | 
    void readLocalInnerClasses(Class cls) throws IOException { | 
 | 
        int nc = class_InnerClasses_N.getInt();  | 
 | 
        List<InnerClass> localICs = new ArrayList<>(nc);  | 
 | 
        for (int i = 0; i < nc; i++) { | 
 | 
            ClassEntry thisClass = (ClassEntry) class_InnerClasses_RC.getRef();  | 
 | 
            int        flags     =              class_InnerClasses_F.getInt();  | 
 | 
            if (flags == 0) { | 
 | 
                  | 
 | 
                InnerClass ic = pkg.getGlobalInnerClass(thisClass);  | 
 | 
                assert(ic != null);    | 
 | 
                localICs.add(ic);  | 
 | 
            } else { | 
 | 
                if (flags == ACC_IC_LONG_FORM)  | 
 | 
                    flags = 0;    | 
 | 
                ClassEntry outer = (ClassEntry) class_InnerClasses_outer_RCN.getRef();  | 
 | 
                Utf8Entry name   = (Utf8Entry)  class_InnerClasses_name_RUN.getRef();  | 
 | 
                localICs.add(new InnerClass(thisClass, outer, name, flags));  | 
 | 
            }  | 
 | 
        }  | 
 | 
        cls.setInnerClasses(localICs);  | 
 | 
        // cls.expandLocalICs may add more tuples to ics also,  | 
 | 
        // or may even delete tuples.  | 
 | 
        // We cannot do that now, because we do not know the  | 
 | 
        // full contents of the local constant pool yet.  | 
 | 
    }  | 
 | 
 | 
 | 
    static final int NO_FLAGS_YET = 0;    | 
 | 
 | 
 | 
    Class[] readClasses() throws IOException { | 
 | 
        //  class_bands:  | 
 | 
        //        *class_this :DELTA5  (cp_Class)  | 
 | 
        //        *class_super :DELTA5  (cp_Class)  | 
 | 
        //        *class_interface_count :DELTA5  | 
 | 
        //        *class_interface :DELTA5  (cp_Class)  | 
 | 
        //        ...(member bands)...  | 
 | 
        //        class_attr_bands  | 
 | 
          | 
 | 
        Class[] classes = new Class[numClasses];  | 
 | 
        if (verbose > 0)  | 
 | 
            Utils.log.info("  ...building "+classes.length+" classes..."); | 
 | 
 | 
 | 
        class_this.expectLength(numClasses);  | 
 | 
        class_super.expectLength(numClasses);  | 
 | 
        class_interface_count.expectLength(numClasses);  | 
 | 
 | 
 | 
        class_this.readFrom(in);  | 
 | 
        class_super.readFrom(in);  | 
 | 
        class_interface_count.readFrom(in);  | 
 | 
        class_interface.expectLength(class_interface_count.getIntTotal());  | 
 | 
        class_interface.readFrom(in);  | 
 | 
        for (int i = 0; i < classes.length; i++) { | 
 | 
            ClassEntry   thisClass  = (ClassEntry) class_this.getRef();  | 
 | 
            ClassEntry   superClass = (ClassEntry) class_super.getRef();  | 
 | 
            ClassEntry[] interfaces = new ClassEntry[class_interface_count.getInt()];  | 
 | 
            for (int j = 0; j < interfaces.length; j++) { | 
 | 
                interfaces[j] = (ClassEntry) class_interface.getRef();  | 
 | 
            }  | 
 | 
              | 
 | 
            if (superClass == thisClass)  superClass = null;  | 
 | 
            Class cls = pkg.new Class(NO_FLAGS_YET,  | 
 | 
                                      thisClass, superClass, interfaces);  | 
 | 
            classes[i] = cls;  | 
 | 
        }  | 
 | 
        class_this.doneDisbursing();  | 
 | 
        class_super.doneDisbursing();  | 
 | 
        class_interface_count.doneDisbursing();  | 
 | 
        class_interface.doneDisbursing();  | 
 | 
        readMembers(classes);  | 
 | 
        countAndReadAttrs(ATTR_CONTEXT_CLASS, Arrays.asList(classes));  | 
 | 
        pkg.trimToSize();  | 
 | 
        readCodeHeaders();  | 
 | 
        //code_bands.doneDisbursing(); // still need to read code attrs  | 
 | 
          | 
 | 
        return classes;  | 
 | 
    }  | 
 | 
 | 
 | 
    private int getOutputIndex(Entry e) { | 
 | 
          | 
 | 
        assert(e.tag != CONSTANT_Signature);  | 
 | 
        int k = pkg.cp.untypedIndexOf(e);  | 
 | 
        // In the output ordering, input signatures can serve  | 
 | 
          | 
 | 
        if (k >= 0)  | 
 | 
            return k;  | 
 | 
        if (e.tag == CONSTANT_Utf8) { | 
 | 
            Entry se = utf8Signatures.get(e);  | 
 | 
            return pkg.cp.untypedIndexOf(se);  | 
 | 
        }  | 
 | 
        return -1;  | 
 | 
    }  | 
 | 
 | 
 | 
    Comparator<Entry> entryOutputOrder = new Comparator<Entry>() { | 
 | 
        public int compare(Entry e0, Entry e1) { | 
 | 
            int k0 = getOutputIndex(e0);  | 
 | 
            int k1 = getOutputIndex(e1);  | 
 | 
            if (k0 >= 0 && k1 >= 0)  | 
 | 
                  | 
 | 
                return k0 - k1;  | 
 | 
            if (k0 == k1)  | 
 | 
                  | 
 | 
                return e0.compareTo(e1);  | 
 | 
              | 
 | 
            return (k0 >= 0)? 0-1: 1-0;  | 
 | 
        }  | 
 | 
    };  | 
 | 
 | 
 | 
    void reconstructClass(Class cls) { | 
 | 
        if (verbose > 1)  Utils.log.fine("reconstruct "+cls); | 
 | 
 | 
 | 
          | 
 | 
        Attribute retroVersion = cls.getAttribute(attrClassFileVersion);  | 
 | 
        if (retroVersion != null) { | 
 | 
            cls.removeAttribute(retroVersion);  | 
 | 
            cls.version = parseClassFileVersionAttr(retroVersion);  | 
 | 
        } else { | 
 | 
            cls.version = pkg.defaultClassVersion;  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        cls.expandSourceFile();  | 
 | 
 | 
 | 
          | 
 | 
        cls.setCPMap(reconstructLocalCPMap(cls));  | 
 | 
    }  | 
 | 
 | 
 | 
    Entry[] reconstructLocalCPMap(Class cls) { | 
 | 
        Set<Entry> ldcRefs = ldcRefMap.get(cls);  | 
 | 
        Set<Entry> cpRefs = new HashSet<>();  | 
 | 
 | 
 | 
          | 
 | 
        cls.visitRefs(VRM_CLASSIC, cpRefs);  | 
 | 
 | 
 | 
        ArrayList<BootstrapMethodEntry> bsms = new ArrayList<>();  | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        cls.addAttribute(Package.attrBootstrapMethodsEmpty.canonicalInstance());  | 
 | 
 | 
 | 
          | 
 | 
        ConstantPool.completeReferencesIn(cpRefs, true, bsms);  | 
 | 
 | 
 | 
        // Now that we know all our local class references,  | 
 | 
          | 
 | 
        int changed = cls.expandLocalICs();  | 
 | 
 | 
 | 
        if (changed != 0) { | 
 | 
            if (changed > 0) { | 
 | 
                  | 
 | 
                cls.visitInnerClassRefs(VRM_CLASSIC, cpRefs);  | 
 | 
            } else { | 
 | 
                  | 
 | 
                cpRefs.clear();  | 
 | 
                cls.visitRefs(VRM_CLASSIC, cpRefs);  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            ConstantPool.completeReferencesIn(cpRefs, true, bsms);  | 
 | 
        }  | 
 | 
 | 
 | 
        // remove the attr previously set, otherwise add the bsm and  | 
 | 
          | 
 | 
        if (bsms.isEmpty()) { | 
 | 
            cls.attributes.remove(Package.attrBootstrapMethodsEmpty.canonicalInstance());  | 
 | 
        } else { | 
 | 
            cpRefs.add(Package.getRefString("BootstrapMethods")); | 
 | 
            Collections.sort(bsms);  | 
 | 
            cls.setBootstrapMethods(bsms);  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        int numDoubles = 0;  | 
 | 
        for (Entry e : cpRefs) { | 
 | 
            if (e.isDoubleWord())  numDoubles++;  | 
 | 
        }  | 
 | 
        Entry[] cpMap = new Entry[1+numDoubles+cpRefs.size()];  | 
 | 
        int fillp = 1;  | 
 | 
 | 
 | 
          | 
 | 
        if (ldcRefs != null) { | 
 | 
            assert(cpRefs.containsAll(ldcRefs));  | 
 | 
            for (Entry e : ldcRefs) { | 
 | 
                cpMap[fillp++] = e;  | 
 | 
            }  | 
 | 
            assert(fillp == 1+ldcRefs.size());  | 
 | 
            cpRefs.removeAll(ldcRefs);  | 
 | 
            ldcRefs = null;    | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        Set<Entry> wideRefs = cpRefs;  | 
 | 
        cpRefs = null;    | 
 | 
        int narrowLimit = fillp;  | 
 | 
        for (Entry e : wideRefs) { | 
 | 
            cpMap[fillp++] = e;  | 
 | 
        }  | 
 | 
        assert(fillp == narrowLimit+wideRefs.size());  | 
 | 
        Arrays.sort(cpMap, 1, narrowLimit, entryOutputOrder);  | 
 | 
        Arrays.sort(cpMap, narrowLimit, fillp, entryOutputOrder);  | 
 | 
 | 
 | 
        if (verbose > 3) { | 
 | 
            Utils.log.fine("CP of "+this+" {"); | 
 | 
            for (int i = 0; i < fillp; i++) { | 
 | 
                Entry e = cpMap[i];  | 
 | 
                Utils.log.fine("  "+((e==null)?-1:getOutputIndex(e)) | 
 | 
                                   +" : "+e);  | 
 | 
            }  | 
 | 
            Utils.log.fine("}"); | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        int revp = cpMap.length;  | 
 | 
        for (int i = fillp; --i >= 1; ) { | 
 | 
            Entry e = cpMap[i];  | 
 | 
            if (e.isDoubleWord())  | 
 | 
                cpMap[--revp] = null;  | 
 | 
            cpMap[--revp] = e;  | 
 | 
        }  | 
 | 
        assert(revp == 1);    | 
 | 
 | 
 | 
        return cpMap;  | 
 | 
    }  | 
 | 
 | 
 | 
    void readMembers(Class[] classes) throws IOException { | 
 | 
        //  class_bands:  | 
 | 
        //        ...  | 
 | 
        //        *class_field_count :DELTA5  | 
 | 
        //        *class_method_count :DELTA5  | 
 | 
        //  | 
 | 
        //        *field_descr :DELTA5  (cp_Descr)  | 
 | 
        //        field_attr_bands  | 
 | 
        //  | 
 | 
        //        *method_descr :MDELTA5  (cp_Descr)  | 
 | 
        //        method_attr_bands  | 
 | 
          | 
 | 
        assert(classes.length == numClasses);  | 
 | 
        class_field_count.expectLength(numClasses);  | 
 | 
        class_method_count.expectLength(numClasses);  | 
 | 
        class_field_count.readFrom(in);  | 
 | 
        class_method_count.readFrom(in);  | 
 | 
 | 
 | 
          | 
 | 
        int totalNF = class_field_count.getIntTotal();  | 
 | 
        int totalNM = class_method_count.getIntTotal();  | 
 | 
        field_descr.expectLength(totalNF);  | 
 | 
        method_descr.expectLength(totalNM);  | 
 | 
        if (verbose > 1)  Utils.log.fine("expecting #fields="+totalNF+ | 
 | 
                " and #methods="+totalNM+" in #classes="+numClasses);  | 
 | 
 | 
 | 
        List<Class.Field> fields = new ArrayList<>(totalNF);  | 
 | 
        field_descr.readFrom(in);  | 
 | 
        for (int i = 0; i < classes.length; i++) { | 
 | 
            Class c = classes[i];  | 
 | 
            int nf = class_field_count.getInt();  | 
 | 
            for (int j = 0; j < nf; j++) { | 
 | 
                Class.Field f = c.new Field(NO_FLAGS_YET, (DescriptorEntry)  | 
 | 
                                            field_descr.getRef());  | 
 | 
                fields.add(f);  | 
 | 
            }  | 
 | 
        }  | 
 | 
        class_field_count.doneDisbursing();  | 
 | 
        field_descr.doneDisbursing();  | 
 | 
        countAndReadAttrs(ATTR_CONTEXT_FIELD, fields);  | 
 | 
        fields = null;    | 
 | 
 | 
 | 
        List<Class.Method> methods = new ArrayList<>(totalNM);  | 
 | 
        method_descr.readFrom(in);  | 
 | 
        for (int i = 0; i < classes.length; i++) { | 
 | 
            Class c = classes[i];  | 
 | 
            int nm = class_method_count.getInt();  | 
 | 
            for (int j = 0; j < nm; j++) { | 
 | 
                Class.Method m = c.new Method(NO_FLAGS_YET, (DescriptorEntry)  | 
 | 
                                              method_descr.getRef());  | 
 | 
                methods.add(m);  | 
 | 
            }  | 
 | 
        }  | 
 | 
        class_method_count.doneDisbursing();  | 
 | 
        method_descr.doneDisbursing();  | 
 | 
        countAndReadAttrs(ATTR_CONTEXT_METHOD, methods);  | 
 | 
 | 
 | 
        // Up to this point, Code attributes look like empty attributes.  | 
 | 
        // Now we start to special-case them.  The empty canonical Code  | 
 | 
          | 
 | 
        allCodes = buildCodeAttrs(methods);  | 
 | 
    }  | 
 | 
 | 
 | 
    Code[] allCodes;  | 
 | 
    List<Code> codesWithFlags;  | 
 | 
    Map<Class, Set<Entry>> ldcRefMap = new HashMap<>();  | 
 | 
 | 
 | 
    Code[] buildCodeAttrs(List<Class.Method> methods) { | 
 | 
        List<Code> codes = new ArrayList<>(methods.size());  | 
 | 
        for (Class.Method m : methods) { | 
 | 
            if (m.getAttribute(attrCodeEmpty) != null) { | 
 | 
                m.code = new Code(m);  | 
 | 
                codes.add(m.code);  | 
 | 
            }  | 
 | 
        }  | 
 | 
        Code[] a = new Code[codes.size()];  | 
 | 
        codes.toArray(a);  | 
 | 
        return a;  | 
 | 
    }  | 
 | 
 | 
 | 
    void readCodeHeaders() throws IOException { | 
 | 
        //  code_bands:  | 
 | 
        //        *code_headers :BYTE1  | 
 | 
        //  | 
 | 
        //        *code_max_stack :UNSIGNED5  | 
 | 
        //        *code_max_na_locals :UNSIGNED5  | 
 | 
        //        *code_handler_count :UNSIGNED5  | 
 | 
        //        ...  | 
 | 
          | 
 | 
        boolean attrsOK = testBit(archiveOptions, AO_HAVE_ALL_CODE_FLAGS);  | 
 | 
        code_headers.expectLength(allCodes.length);  | 
 | 
        code_headers.readFrom(in);  | 
 | 
        List<Code> longCodes = new ArrayList<>(allCodes.length / 10);  | 
 | 
        for (int i = 0; i < allCodes.length; i++) { | 
 | 
            Code c = allCodes[i];  | 
 | 
            int sc = code_headers.getByte();  | 
 | 
            assert(sc == (sc & 0xFF));  | 
 | 
            if (verbose > 2)  | 
 | 
                Utils.log.fine("codeHeader "+c+" = "+sc); | 
 | 
            if (sc == LONG_CODE_HEADER) { | 
 | 
                  | 
 | 
                longCodes.add(c);  | 
 | 
                continue;  | 
 | 
            }  | 
 | 
              | 
 | 
            c.setMaxStack(     shortCodeHeader_max_stack(sc) );  | 
 | 
            c.setMaxNALocals(  shortCodeHeader_max_na_locals(sc) );  | 
 | 
            c.setHandlerCount( shortCodeHeader_handler_count(sc) );  | 
 | 
            assert(shortCodeHeader(c) == sc);  | 
 | 
        }  | 
 | 
        code_headers.doneDisbursing();  | 
 | 
        code_max_stack.expectLength(longCodes.size());  | 
 | 
        code_max_na_locals.expectLength(longCodes.size());  | 
 | 
        code_handler_count.expectLength(longCodes.size());  | 
 | 
 | 
 | 
          | 
 | 
        code_max_stack.readFrom(in);  | 
 | 
        code_max_na_locals.readFrom(in);  | 
 | 
        code_handler_count.readFrom(in);  | 
 | 
        for (Code c : longCodes) { | 
 | 
            c.setMaxStack(     code_max_stack.getInt() );  | 
 | 
            c.setMaxNALocals(  code_max_na_locals.getInt() );  | 
 | 
            c.setHandlerCount( code_handler_count.getInt() );  | 
 | 
        }  | 
 | 
        code_max_stack.doneDisbursing();  | 
 | 
        code_max_na_locals.doneDisbursing();  | 
 | 
        code_handler_count.doneDisbursing();  | 
 | 
 | 
 | 
        readCodeHandlers();  | 
 | 
 | 
 | 
        if (attrsOK) { | 
 | 
              | 
 | 
            codesWithFlags = Arrays.asList(allCodes);  | 
 | 
        } else { | 
 | 
              | 
 | 
            codesWithFlags = longCodes;  | 
 | 
        }  | 
 | 
        countAttrs(ATTR_CONTEXT_CODE, codesWithFlags);  | 
 | 
        // do readAttrs later, after BCs are scanned  | 
 | 
    }  | 
 | 
 | 
 | 
    void readCodeHandlers() throws IOException { | 
 | 
        //  code_bands:  | 
 | 
        //        ...  | 
 | 
        //        *code_handler_start_P :BCI5  | 
 | 
        //        *code_handler_end_PO :BRANCH5  | 
 | 
        //        *code_handler_catch_PO :BRANCH5  | 
 | 
        //        *code_handler_class_RCN :UNSIGNED5  (null or cp_Class)  | 
 | 
          | 
 | 
        int nh = 0;  | 
 | 
        for (int i = 0; i < allCodes.length; i++) { | 
 | 
            Code c = allCodes[i];  | 
 | 
            nh += c.getHandlerCount();  | 
 | 
        }  | 
 | 
 | 
 | 
        ValueBand[] code_handler_bands = { | 
 | 
            code_handler_start_P,  | 
 | 
            code_handler_end_PO,  | 
 | 
            code_handler_catch_PO,  | 
 | 
            code_handler_class_RCN  | 
 | 
        };  | 
 | 
 | 
 | 
        for (int i = 0; i < code_handler_bands.length; i++) { | 
 | 
            code_handler_bands[i].expectLength(nh);  | 
 | 
            code_handler_bands[i].readFrom(in);  | 
 | 
        }  | 
 | 
 | 
 | 
        for (int i = 0; i < allCodes.length; i++) { | 
 | 
            Code c = allCodes[i];  | 
 | 
            for (int j = 0, jmax = c.getHandlerCount(); j < jmax; j++) { | 
 | 
                c.handler_class[j] = code_handler_class_RCN.getRef();  | 
 | 
                // For now, just record the raw BCI codes.  | 
 | 
                  | 
 | 
                c.handler_start[j] = code_handler_start_P.getInt();  | 
 | 
                c.handler_end[j]   = code_handler_end_PO.getInt();  | 
 | 
                c.handler_catch[j] = code_handler_catch_PO.getInt();  | 
 | 
            }  | 
 | 
        }  | 
 | 
        for (int i = 0; i < code_handler_bands.length; i++) { | 
 | 
            code_handler_bands[i].doneDisbursing();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    void fixupCodeHandlers() { | 
 | 
          | 
 | 
        for (int i = 0; i < allCodes.length; i++) { | 
 | 
            Code c = allCodes[i];  | 
 | 
            for (int j = 0, jmax = c.getHandlerCount(); j < jmax; j++) { | 
 | 
                int sum = c.handler_start[j];  | 
 | 
                c.handler_start[j] = c.decodeBCI(sum);  | 
 | 
                sum += c.handler_end[j];  | 
 | 
                c.handler_end[j]   = c.decodeBCI(sum);  | 
 | 
                sum += c.handler_catch[j];  | 
 | 
                c.handler_catch[j] = c.decodeBCI(sum);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Generic routines for reading attributes of  | 
 | 
    // classes, fields, methods, and codes.  | 
 | 
    // The holders is a global list, already collected,  | 
 | 
      | 
 | 
    void countAndReadAttrs(int ctype, Collection<? extends Attribute.Holder> holders)  | 
 | 
            throws IOException { | 
 | 
        //  class_attr_bands:  | 
 | 
        //        *class_flags :UNSIGNED5  | 
 | 
        //        *class_attr_count :UNSIGNED5  | 
 | 
        //        *class_attr_indexes :UNSIGNED5  | 
 | 
        //        *class_attr_calls :UNSIGNED5  | 
 | 
        //        *class_Signature_RS :UNSIGNED5 (cp_Signature)  | 
 | 
        //        class_metadata_bands  | 
 | 
        //        *class_SourceFile_RU :UNSIGNED5 (cp_Utf8)  | 
 | 
        //        *class_EnclosingMethod_RM :UNSIGNED5 (cp_Method)  | 
 | 
        //        ic_local_bands  | 
 | 
        //        *class_ClassFile_version_minor_H :UNSIGNED5  | 
 | 
        //        *class_ClassFile_version_major_H :UNSIGNED5  | 
 | 
        //        class_type_metadata_bands  | 
 | 
        //  | 
 | 
        //  field_attr_bands:  | 
 | 
        //        *field_flags :UNSIGNED5  | 
 | 
        //        *field_attr_count :UNSIGNED5  | 
 | 
        //        *field_attr_indexes :UNSIGNED5  | 
 | 
        //        *field_attr_calls :UNSIGNED5  | 
 | 
        //        *field_Signature_RS :UNSIGNED5 (cp_Signature)  | 
 | 
        //        field_metadata_bands  | 
 | 
        //        *field_ConstantValue_KQ :UNSIGNED5 (cp_Int, etc.; see note)  | 
 | 
        //        field_type_metadata_bands  | 
 | 
        //  | 
 | 
        //  method_attr_bands:  | 
 | 
        //        *method_flags :UNSIGNED5  | 
 | 
        //        *method_attr_count :UNSIGNED5  | 
 | 
        //        *method_attr_indexes :UNSIGNED5  | 
 | 
        //        *method_attr_calls :UNSIGNED5  | 
 | 
        //        *method_Signature_RS :UNSIGNED5 (cp_Signature)  | 
 | 
        //        method_metadata_bands  | 
 | 
        //        *method_Exceptions_N :UNSIGNED5  | 
 | 
        //        *method_Exceptions_RC :UNSIGNED5  (cp_Class)  | 
 | 
        //        *method_MethodParameters_NB: BYTE1  | 
 | 
        //        *method_MethodParameters_RUN: UNSIGNED5 (cp_Utf8)  | 
 | 
        //        *method_MethodParameters_FH:  UNSIGNED5 (flag)  | 
 | 
        //        method_type_metadata_bands  | 
 | 
        //  | 
 | 
        //  code_attr_bands:  | 
 | 
        //        *code_flags :UNSIGNED5  | 
 | 
        //        *code_attr_count :UNSIGNED5  | 
 | 
        //        *code_attr_indexes :UNSIGNED5  | 
 | 
        //        *code_attr_calls :UNSIGNED5  | 
 | 
        //        *code_LineNumberTable_N :UNSIGNED5  | 
 | 
        //        *code_LineNumberTable_bci_P :BCI5  | 
 | 
        //        *code_LineNumberTable_line :UNSIGNED5  | 
 | 
        //        *code_LocalVariableTable_N :UNSIGNED5  | 
 | 
        //        *code_LocalVariableTable_bci_P :BCI5  | 
 | 
        //        *code_LocalVariableTable_span_O :BRANCH5  | 
 | 
        //        *code_LocalVariableTable_name_RU :UNSIGNED5 (cp_Utf8)  | 
 | 
        //        *code_LocalVariableTable_type_RS :UNSIGNED5 (cp_Signature)  | 
 | 
        //        *code_LocalVariableTable_slot :UNSIGNED5  | 
 | 
        //        code_type_metadata_bands  | 
 | 
 | 
 | 
        countAttrs(ctype, holders);  | 
 | 
        readAttrs(ctype, holders);  | 
 | 
    }  | 
 | 
 | 
 | 
    // Read flags and count the attributes that are to be placed  | 
 | 
      | 
 | 
    void countAttrs(int ctype, Collection<? extends Attribute.Holder> holders)  | 
 | 
            throws IOException { | 
 | 
          | 
 | 
        MultiBand xxx_attr_bands = attrBands[ctype];  | 
 | 
        long flagMask = attrFlagMask[ctype];  | 
 | 
        if (verbose > 1) { | 
 | 
            Utils.log.fine("scanning flags and attrs for "+ | 
 | 
                    Attribute.contextName(ctype)+"["+holders.size()+"]");  | 
 | 
        }  | 
 | 
 | 
 | 
        // Fetch the attribute layout definitions which govern the bands  | 
 | 
          | 
 | 
        List<Attribute.Layout> defList = attrDefs.get(ctype);  | 
 | 
        Attribute.Layout[] defs = new Attribute.Layout[defList.size()];  | 
 | 
        defList.toArray(defs);  | 
 | 
        IntBand xxx_flags_hi = getAttrBand(xxx_attr_bands, AB_FLAGS_HI);  | 
 | 
        IntBand xxx_flags_lo = getAttrBand(xxx_attr_bands, AB_FLAGS_LO);  | 
 | 
        IntBand xxx_attr_count = getAttrBand(xxx_attr_bands, AB_ATTR_COUNT);  | 
 | 
        IntBand xxx_attr_indexes = getAttrBand(xxx_attr_bands, AB_ATTR_INDEXES);  | 
 | 
        IntBand xxx_attr_calls = getAttrBand(xxx_attr_bands, AB_ATTR_CALLS);  | 
 | 
 | 
 | 
          | 
 | 
        int overflowMask = attrOverflowMask[ctype];  | 
 | 
        int overflowHolderCount = 0;  | 
 | 
        boolean haveLongFlags = haveFlagsHi(ctype);  | 
 | 
        xxx_flags_hi.expectLength(haveLongFlags? holders.size(): 0);  | 
 | 
        xxx_flags_hi.readFrom(in);  | 
 | 
        xxx_flags_lo.expectLength(holders.size());  | 
 | 
        xxx_flags_lo.readFrom(in);  | 
 | 
        assert((flagMask & overflowMask) == overflowMask);  | 
 | 
        for (Attribute.Holder h : holders) { | 
 | 
            int flags = xxx_flags_lo.getInt();  | 
 | 
            h.flags = flags;  | 
 | 
            if ((flags & overflowMask) != 0)  | 
 | 
                overflowHolderCount += 1;  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        xxx_attr_count.expectLength(overflowHolderCount);  | 
 | 
        xxx_attr_count.readFrom(in);  | 
 | 
        xxx_attr_indexes.expectLength(xxx_attr_count.getIntTotal());  | 
 | 
        xxx_attr_indexes.readFrom(in);  | 
 | 
 | 
 | 
        // Now it's time to check flag bits that indicate attributes.  | 
 | 
        // We accumulate (a) a list of attribute types for each holder  | 
 | 
        // (class/field/method/code), and also we accumulate (b) a total  | 
 | 
          | 
 | 
        int[] totalCounts = new int[defs.length];  | 
 | 
        for (Attribute.Holder h : holders) { | 
 | 
            assert(h.attributes == null);  | 
 | 
              | 
 | 
            long attrBits = ((h.flags & flagMask) << 32) >>> 32;  | 
 | 
            // Clean up the flags now.  | 
 | 
            h.flags -= (int)attrBits;     | 
 | 
            assert(h.flags == (char)h.flags);    | 
 | 
            assert((ctype != ATTR_CONTEXT_CODE) || h.flags == 0);  | 
 | 
            if (haveLongFlags)  | 
 | 
                attrBits += (long)xxx_flags_hi.getInt() << 32;  | 
 | 
            if (attrBits == 0)  continue;    | 
 | 
 | 
 | 
            int noa = 0;    | 
 | 
            long overflowBit = (attrBits & overflowMask);  | 
 | 
            assert(overflowBit >= 0);  | 
 | 
            attrBits -= overflowBit;  | 
 | 
            if (overflowBit != 0) { | 
 | 
                noa = xxx_attr_count.getInt();  | 
 | 
            }  | 
 | 
 | 
 | 
            int nfa = 0;    | 
 | 
            long bits = attrBits;  | 
 | 
            for (int ai = 0; bits != 0; ai++) { | 
 | 
                if ((bits & (1L<<ai)) == 0)  continue;  | 
 | 
                bits -= (1L<<ai);  | 
 | 
                nfa += 1;  | 
 | 
            }  | 
 | 
            List<Attribute> ha = new ArrayList<>(nfa + noa);  | 
 | 
            h.attributes = ha;  | 
 | 
            bits = attrBits;    | 
 | 
            for (int ai = 0; bits != 0; ai++) { | 
 | 
                if ((bits & (1L<<ai)) == 0)  continue;  | 
 | 
                bits -= (1L<<ai);  | 
 | 
                totalCounts[ai] += 1;  | 
 | 
                  | 
 | 
                if (defs[ai] == null)  badAttrIndex(ai, ctype);  | 
 | 
                Attribute canonical = defs[ai].canonicalInstance();  | 
 | 
                ha.add(canonical);  | 
 | 
                nfa -= 1;  | 
 | 
            }  | 
 | 
            assert(nfa == 0);  | 
 | 
            for (; noa > 0; noa--) { | 
 | 
                int ai = xxx_attr_indexes.getInt();  | 
 | 
                totalCounts[ai] += 1;  | 
 | 
                  | 
 | 
                if (defs[ai] == null)  badAttrIndex(ai, ctype);  | 
 | 
                Attribute canonical = defs[ai].canonicalInstance();  | 
 | 
                ha.add(canonical);  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        xxx_flags_hi.doneDisbursing();  | 
 | 
        xxx_flags_lo.doneDisbursing();  | 
 | 
        xxx_attr_count.doneDisbursing();  | 
 | 
        xxx_attr_indexes.doneDisbursing();  | 
 | 
 | 
 | 
        // Now each holder has a list of canonical attribute instances.  | 
 | 
        // For layouts with no elements, we are done.  However, for  | 
 | 
        // layouts with bands, we must replace each canonical (empty)  | 
 | 
        // instance with a value-bearing one, initialized from the  | 
 | 
        // appropriate bands.  | 
 | 
 | 
 | 
          | 
 | 
        int callCounts = 0;  | 
 | 
        for (boolean predef = true; ; predef = false) { | 
 | 
            for (int ai = 0; ai < defs.length; ai++) { | 
 | 
                Attribute.Layout def = defs[ai];  | 
 | 
                if (def == null)  continue;    | 
 | 
                if (predef != isPredefinedAttr(ctype, ai))  | 
 | 
                    continue;    | 
 | 
                int totalCount = totalCounts[ai];  | 
 | 
                if (totalCount == 0)  | 
 | 
                    continue;    | 
 | 
                Attribute.Layout.Element[] cbles = def.getCallables();  | 
 | 
                for (int j = 0; j < cbles.length; j++) { | 
 | 
                    assert(cbles[j].kind == Attribute.EK_CBLE);  | 
 | 
                    if (cbles[j].flagTest(Attribute.EF_BACK))  | 
 | 
                        callCounts += 1;  | 
 | 
                }  | 
 | 
            }  | 
 | 
            if (!predef)  break;  | 
 | 
        }  | 
 | 
        xxx_attr_calls.expectLength(callCounts);  | 
 | 
        xxx_attr_calls.readFrom(in);  | 
 | 
 | 
 | 
          | 
 | 
        for (boolean predef = true; ; predef = false) { | 
 | 
            for (int ai = 0; ai < defs.length; ai++) { | 
 | 
                Attribute.Layout def = defs[ai];  | 
 | 
                if (def == null)  continue;    | 
 | 
                if (predef != isPredefinedAttr(ctype, ai))  | 
 | 
                    continue;    | 
 | 
                int totalCount = totalCounts[ai];  | 
 | 
                Band[] ab = attrBandTable.get(def);  | 
 | 
                if (def == attrInnerClassesEmpty) { | 
 | 
                    // Special case.  | 
 | 
                    // Size the bands as if using the following layout:  | 
 | 
                      | 
 | 
                    class_InnerClasses_N.expectLength(totalCount);  | 
 | 
                    class_InnerClasses_N.readFrom(in);  | 
 | 
                    int tupleCount = class_InnerClasses_N.getIntTotal();  | 
 | 
                    class_InnerClasses_RC.expectLength(tupleCount);  | 
 | 
                    class_InnerClasses_RC.readFrom(in);  | 
 | 
                    class_InnerClasses_F.expectLength(tupleCount);  | 
 | 
                    class_InnerClasses_F.readFrom(in);  | 
 | 
                      | 
 | 
                    tupleCount -= class_InnerClasses_F.getIntCount(0);  | 
 | 
                    class_InnerClasses_outer_RCN.expectLength(tupleCount);  | 
 | 
                    class_InnerClasses_outer_RCN.readFrom(in);  | 
 | 
                    class_InnerClasses_name_RUN.expectLength(tupleCount);  | 
 | 
                    class_InnerClasses_name_RUN.readFrom(in);  | 
 | 
                } else if (!optDebugBands && totalCount == 0) { | 
 | 
                    // Expect no elements at all.  Skip quickly. however if we  | 
 | 
                      | 
 | 
                    for (int j = 0; j < ab.length; j++) { | 
 | 
                        ab[j].doneWithUnusedBand();  | 
 | 
                    }  | 
 | 
                } else { | 
 | 
                      | 
 | 
                    boolean hasCallables = def.hasCallables();  | 
 | 
                    if (!hasCallables) { | 
 | 
                        readAttrBands(def.elems, totalCount, new int[0], ab);  | 
 | 
                    } else { | 
 | 
                        Attribute.Layout.Element[] cbles = def.getCallables();  | 
 | 
                        // At first, record initial calls.  | 
 | 
                          | 
 | 
                        int[] forwardCounts = new int[cbles.length];  | 
 | 
                        forwardCounts[0] = totalCount;  | 
 | 
                        for (int j = 0; j < cbles.length; j++) { | 
 | 
                            assert(cbles[j].kind == Attribute.EK_CBLE);  | 
 | 
                            int entryCount = forwardCounts[j];  | 
 | 
                            forwardCounts[j] = -1;    | 
 | 
                            if (totalCount > 0 && cbles[j].flagTest(Attribute.EF_BACK))  | 
 | 
                                entryCount += xxx_attr_calls.getInt();  | 
 | 
                            readAttrBands(cbles[j].body, entryCount, forwardCounts, ab);  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                      | 
 | 
                    if (optDebugBands && totalCount == 0) { | 
 | 
                        for (int j = 0; j < ab.length; j++) { | 
 | 
                            ab[j].doneDisbursing();  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
            if (!predef)  break;  | 
 | 
        }  | 
 | 
        xxx_attr_calls.doneDisbursing();  | 
 | 
    }  | 
 | 
 | 
 | 
    void badAttrIndex(int ai, int ctype) throws IOException { | 
 | 
        throw new IOException("Unknown attribute index "+ai+" for "+ | 
 | 
                                   ATTR_CONTEXT_NAME[ctype]+" attribute");  | 
 | 
    }  | 
 | 
 | 
 | 
    void readAttrs(int ctype, Collection<? extends Attribute.Holder> holders)  | 
 | 
            throws IOException { | 
 | 
          | 
 | 
        Set<Attribute.Layout> sawDefs = new HashSet<>();  | 
 | 
        ByteArrayOutputStream buf = new ByteArrayOutputStream();  | 
 | 
        for (final Attribute.Holder h : holders) { | 
 | 
            if (h.attributes == null)  continue;  | 
 | 
            for (ListIterator<Attribute> j = h.attributes.listIterator(); j.hasNext(); ) { | 
 | 
                Attribute a = j.next();  | 
 | 
                Attribute.Layout def = a.layout();  | 
 | 
                if (def.bandCount == 0) { | 
 | 
                    if (def == attrInnerClassesEmpty) { | 
 | 
                          | 
 | 
                        readLocalInnerClasses((Class) h);  | 
 | 
                        continue;  | 
 | 
                    }  | 
 | 
                      | 
 | 
                    continue;  | 
 | 
                }  | 
 | 
                sawDefs.add(def);  | 
 | 
                boolean isCV = (ctype == ATTR_CONTEXT_FIELD && def == attrConstantValue);  | 
 | 
                if (isCV)  setConstantValueIndex((Class.Field)h);  | 
 | 
                if (verbose > 2)  | 
 | 
                    Utils.log.fine("read "+a+" in "+h); | 
 | 
                final Band[] ab = attrBandTable.get(def);  | 
 | 
                  | 
 | 
                buf.reset();  | 
 | 
                Object fixups = a.unparse(new Attribute.ValueStream() { | 
 | 
                    public int getInt(int bandIndex) { | 
 | 
                        return ((IntBand) ab[bandIndex]).getInt();  | 
 | 
                    }  | 
 | 
                    public Entry getRef(int bandIndex) { | 
 | 
                        return ((CPRefBand) ab[bandIndex]).getRef();  | 
 | 
                    }  | 
 | 
                    public int decodeBCI(int bciCode) { | 
 | 
                        Code code = (Code) h;  | 
 | 
                        return code.decodeBCI(bciCode);  | 
 | 
                    }  | 
 | 
                }, buf);  | 
 | 
                  | 
 | 
                j.set(a.addContent(buf.toByteArray(), fixups));  | 
 | 
                if (isCV)  setConstantValueIndex(null);    | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        for (Attribute.Layout def : sawDefs) { | 
 | 
            if (def == null)  continue;    | 
 | 
            Band[] ab = attrBandTable.get(def);  | 
 | 
            for (int j = 0; j < ab.length; j++) { | 
 | 
                ab[j].doneDisbursing();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        if (ctype == ATTR_CONTEXT_CLASS) { | 
 | 
            class_InnerClasses_N.doneDisbursing();  | 
 | 
            class_InnerClasses_RC.doneDisbursing();  | 
 | 
            class_InnerClasses_F.doneDisbursing();  | 
 | 
            class_InnerClasses_outer_RCN.doneDisbursing();  | 
 | 
            class_InnerClasses_name_RUN.doneDisbursing();  | 
 | 
        }  | 
 | 
 | 
 | 
        MultiBand xxx_attr_bands = attrBands[ctype];  | 
 | 
        for (int i = 0; i < xxx_attr_bands.size(); i++) { | 
 | 
            Band b = xxx_attr_bands.get(i);  | 
 | 
            if (b instanceof MultiBand)  | 
 | 
                b.doneDisbursing();  | 
 | 
        }  | 
 | 
        xxx_attr_bands.doneDisbursing();  | 
 | 
    }  | 
 | 
 | 
 | 
    private  | 
 | 
    void readAttrBands(Attribute.Layout.Element[] elems,  | 
 | 
                       int count, int[] forwardCounts,  | 
 | 
                       Band[] ab)  | 
 | 
            throws IOException { | 
 | 
        for (int i = 0; i < elems.length; i++) { | 
 | 
            Attribute.Layout.Element e = elems[i];  | 
 | 
            Band eBand = null;  | 
 | 
            if (e.hasBand()) { | 
 | 
                eBand = ab[e.bandIndex];  | 
 | 
                eBand.expectLength(count);  | 
 | 
                eBand.readFrom(in);  | 
 | 
            }  | 
 | 
            switch (e.kind) { | 
 | 
            case Attribute.EK_REPL:  | 
 | 
                  | 
 | 
                int repCount = ((IntBand)eBand).getIntTotal();  | 
 | 
                  | 
 | 
                readAttrBands(e.body, repCount, forwardCounts, ab);  | 
 | 
                break;  | 
 | 
            case Attribute.EK_UN:  | 
 | 
                int remainingCount = count;  | 
 | 
                for (int j = 0; j < e.body.length; j++) { | 
 | 
                    int caseCount;  | 
 | 
                    if (j == e.body.length-1) { | 
 | 
                        caseCount = remainingCount;  | 
 | 
                    } else { | 
 | 
                        caseCount = 0;  | 
 | 
                        for (int j0 = j;  | 
 | 
                             (j == j0)  | 
 | 
                             || (j < e.body.length  | 
 | 
                                 && e.body[j].flagTest(Attribute.EF_BACK));  | 
 | 
                             j++) { | 
 | 
                            caseCount += ((IntBand)eBand).getIntCount(e.body[j].value);  | 
 | 
                        }  | 
 | 
                        --j;    | 
 | 
                    }  | 
 | 
                    remainingCount -= caseCount;  | 
 | 
                    readAttrBands(e.body[j].body, caseCount, forwardCounts, ab);  | 
 | 
                }  | 
 | 
                assert(remainingCount == 0);  | 
 | 
                break;  | 
 | 
            case Attribute.EK_CALL:  | 
 | 
                assert(e.body.length == 1);  | 
 | 
                assert(e.body[0].kind == Attribute.EK_CBLE);  | 
 | 
                if (!e.flagTest(Attribute.EF_BACK)) { | 
 | 
                    // Backward calls are pre-counted, but forwards are not.  | 
 | 
                      | 
 | 
                    assert(forwardCounts[e.value] >= 0);  | 
 | 
                    forwardCounts[e.value] += count;  | 
 | 
                }  | 
 | 
                break;  | 
 | 
            case Attribute.EK_CBLE:  | 
 | 
                assert(false);  | 
 | 
                break;  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    void readByteCodes() throws IOException { | 
 | 
        //  bc_bands:  | 
 | 
        //        *bc_codes :BYTE1  | 
 | 
        //        *bc_case_count :UNSIGNED5  | 
 | 
        //        *bc_case_value :DELTA5  | 
 | 
        //        *bc_byte :BYTE1  | 
 | 
        //        *bc_short :DELTA5  | 
 | 
        //        *bc_local :UNSIGNED5  | 
 | 
        //        *bc_label :BRANCH5  | 
 | 
        //        *bc_intref :DELTA5  (cp_Int)  | 
 | 
        //        *bc_floatref :DELTA5  (cp_Float)  | 
 | 
        //        *bc_longref :DELTA5  (cp_Long)  | 
 | 
        //        *bc_doubleref :DELTA5  (cp_Double)  | 
 | 
        //        *bc_stringref :DELTA5  (cp_String)  | 
 | 
        //        *bc_classref :UNSIGNED5  (current class or cp_Class)  | 
 | 
        //        *bc_fieldref :DELTA5  (cp_Field)  | 
 | 
        //        *bc_methodref :UNSIGNED5  (cp_Method)  | 
 | 
        //        *bc_imethodref :DELTA5  (cp_Imethod)  | 
 | 
        //        *bc_thisfield :UNSIGNED5 (cp_Field, only for current class)  | 
 | 
        //        *bc_superfield :UNSIGNED5 (cp_Field, only for current super)  | 
 | 
        //        *bc_thismethod :UNSIGNED5 (cp_Method, only for current class)  | 
 | 
        //        *bc_supermethod :UNSIGNED5 (cp_Method, only for current super)  | 
 | 
        //        *bc_initref :UNSIGNED5 (cp_Field, only for most recent new)  | 
 | 
        //        *bc_escref :UNSIGNED5 (cp_All)  | 
 | 
        //        *bc_escrefsize :UNSIGNED5  | 
 | 
        //        *bc_escsize :UNSIGNED5  | 
 | 
          | 
 | 
        bc_codes.elementCountForDebug = allCodes.length;  | 
 | 
        bc_codes.setInputStreamFrom(in);  | 
 | 
        readByteCodeOps();    | 
 | 
        bc_codes.doneDisbursing();  | 
 | 
 | 
 | 
          | 
 | 
        Band[] operand_bands = { | 
 | 
            bc_case_value,  | 
 | 
            bc_byte, bc_short,  | 
 | 
            bc_local, bc_label,  | 
 | 
            bc_intref, bc_floatref,  | 
 | 
            bc_longref, bc_doubleref, bc_stringref,  | 
 | 
            bc_loadablevalueref,  | 
 | 
            bc_classref, bc_fieldref,  | 
 | 
            bc_methodref, bc_imethodref,  | 
 | 
            bc_indyref,  | 
 | 
            bc_thisfield, bc_superfield,  | 
 | 
            bc_thismethod, bc_supermethod,  | 
 | 
            bc_initref,  | 
 | 
            bc_escref, bc_escrefsize, bc_escsize  | 
 | 
        };  | 
 | 
        for (int i = 0; i < operand_bands.length; i++) { | 
 | 
            operand_bands[i].readFrom(in);  | 
 | 
        }  | 
 | 
        bc_escbyte.expectLength(bc_escsize.getIntTotal());  | 
 | 
        bc_escbyte.readFrom(in);  | 
 | 
 | 
 | 
        expandByteCodeOps();  | 
 | 
 | 
 | 
          | 
 | 
        bc_case_count.doneDisbursing();  | 
 | 
        for (int i = 0; i < operand_bands.length; i++) { | 
 | 
            operand_bands[i].doneDisbursing();  | 
 | 
        }  | 
 | 
        bc_escbyte.doneDisbursing();  | 
 | 
        bc_bands.doneDisbursing();  | 
 | 
 | 
 | 
        // We must delay the parsing of Code attributes until we  | 
 | 
          | 
 | 
        readAttrs(ATTR_CONTEXT_CODE, codesWithFlags);  | 
 | 
          | 
 | 
        fixupCodeHandlers();  | 
 | 
          | 
 | 
        code_bands.doneDisbursing();  | 
 | 
        class_bands.doneDisbursing();  | 
 | 
    }  | 
 | 
 | 
 | 
    private void readByteCodeOps() throws IOException { | 
 | 
          | 
 | 
        byte[] buf = new byte[1<<12];  | 
 | 
          | 
 | 
        List<Integer> allSwitchOps = new ArrayList<>();  | 
 | 
        for (int k = 0; k < allCodes.length; k++) { | 
 | 
            Code c = allCodes[k];  | 
 | 
        scanOneMethod:  | 
 | 
            for (int i = 0; ; i++) { | 
 | 
                int bc = bc_codes.getByte();  | 
 | 
                if (i + 10 > buf.length)  buf = realloc(buf);  | 
 | 
                buf[i] = (byte)bc;  | 
 | 
                boolean isWide = false;  | 
 | 
                if (bc == _wide) { | 
 | 
                    bc = bc_codes.getByte();  | 
 | 
                    buf[++i] = (byte)bc;  | 
 | 
                    isWide = true;  | 
 | 
                }  | 
 | 
                assert(bc == (0xFF & bc));  | 
 | 
                  | 
 | 
                switch (bc) { | 
 | 
                case _tableswitch:  | 
 | 
                case _lookupswitch:  | 
 | 
                    bc_case_count.expectMoreLength(1);  | 
 | 
                    allSwitchOps.add(bc);  | 
 | 
                    break;  | 
 | 
                case _iinc:  | 
 | 
                    bc_local.expectMoreLength(1);  | 
 | 
                    if (isWide)  | 
 | 
                        bc_short.expectMoreLength(1);  | 
 | 
                    else  | 
 | 
                        bc_byte.expectMoreLength(1);  | 
 | 
                    break;  | 
 | 
                case _sipush:  | 
 | 
                    bc_short.expectMoreLength(1);  | 
 | 
                    break;  | 
 | 
                case _bipush:  | 
 | 
                    bc_byte.expectMoreLength(1);  | 
 | 
                    break;  | 
 | 
                case _newarray:  | 
 | 
                    bc_byte.expectMoreLength(1);  | 
 | 
                    break;  | 
 | 
                case _multianewarray:  | 
 | 
                    assert(getCPRefOpBand(bc) == bc_classref);  | 
 | 
                    bc_classref.expectMoreLength(1);  | 
 | 
                    bc_byte.expectMoreLength(1);  | 
 | 
                    break;  | 
 | 
                case _ref_escape:  | 
 | 
                    bc_escrefsize.expectMoreLength(1);  | 
 | 
                    bc_escref.expectMoreLength(1);  | 
 | 
                    break;  | 
 | 
                case _byte_escape:  | 
 | 
                    bc_escsize.expectMoreLength(1);  | 
 | 
                      | 
 | 
                    break;  | 
 | 
                default:  | 
 | 
                    if (Instruction.isInvokeInitOp(bc)) { | 
 | 
                        bc_initref.expectMoreLength(1);  | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    if (Instruction.isSelfLinkerOp(bc)) { | 
 | 
                        CPRefBand bc_which = selfOpRefBand(bc);  | 
 | 
                        bc_which.expectMoreLength(1);  | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    if (Instruction.isBranchOp(bc)) { | 
 | 
                        bc_label.expectMoreLength(1);  | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    if (Instruction.isCPRefOp(bc)) { | 
 | 
                        CPRefBand bc_which = getCPRefOpBand(bc);  | 
 | 
                        bc_which.expectMoreLength(1);  | 
 | 
                        assert(bc != _multianewarray);    | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    if (Instruction.isLocalSlotOp(bc)) { | 
 | 
                        bc_local.expectMoreLength(1);  | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    break;  | 
 | 
                case _end_marker:  | 
 | 
                    { | 
 | 
                          | 
 | 
                        c.bytes = realloc(buf, i);  | 
 | 
                        break scanOneMethod;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        bc_case_count.readFrom(in);  | 
 | 
        for (Integer i : allSwitchOps) { | 
 | 
            int bc = i.intValue();  | 
 | 
            int caseCount = bc_case_count.getInt();  | 
 | 
            bc_label.expectMoreLength(1+caseCount);   | 
 | 
            bc_case_value.expectMoreLength(bc == _tableswitch ? 1 : caseCount);  | 
 | 
        }  | 
 | 
        bc_case_count.resetForSecondPass();  | 
 | 
    }  | 
 | 
 | 
 | 
    private void expandByteCodeOps() throws IOException { | 
 | 
          | 
 | 
        byte[] buf = new byte[1<<12];  | 
 | 
          | 
 | 
        int[] insnMap = new int[1<<12];  | 
 | 
          | 
 | 
        int[] labels = new int[1<<10];  | 
 | 
          | 
 | 
        Fixups fixupBuf = new Fixups();  | 
 | 
 | 
 | 
        for (int k = 0; k < allCodes.length; k++) { | 
 | 
            Code code = allCodes[k];  | 
 | 
            byte[] codeOps = code.bytes;  | 
 | 
            code.bytes = null;    | 
 | 
 | 
 | 
            Class curClass = code.thisClass();  | 
 | 
 | 
 | 
            Set<Entry> ldcRefSet = ldcRefMap.get(curClass);  | 
 | 
            if (ldcRefSet == null)  | 
 | 
                ldcRefMap.put(curClass, ldcRefSet = new HashSet<>());  | 
 | 
 | 
 | 
            ClassEntry thisClass  = curClass.thisClass;  | 
 | 
            ClassEntry superClass = curClass.superClass;  | 
 | 
            ClassEntry newClass   = null;    | 
 | 
 | 
 | 
            int pc = 0;    | 
 | 
            int numInsns = 0;  | 
 | 
            int numLabels = 0;  | 
 | 
            boolean hasEscs = false;  | 
 | 
            fixupBuf.clear();  | 
 | 
            for (int i = 0; i < codeOps.length; i++) { | 
 | 
                int bc = Instruction.getByte(codeOps, i);  | 
 | 
                int curPC = pc;  | 
 | 
                insnMap[numInsns++] = curPC;  | 
 | 
                if (pc + 10 > buf.length)  buf = realloc(buf);  | 
 | 
                if (numInsns+10 > insnMap.length)  insnMap = realloc(insnMap);  | 
 | 
                if (numLabels+10 > labels.length)  labels = realloc(labels);  | 
 | 
                boolean isWide = false;  | 
 | 
                if (bc == _wide) { | 
 | 
                    buf[pc++] = (byte) bc;  | 
 | 
                    bc = Instruction.getByte(codeOps, ++i);  | 
 | 
                    isWide = true;  | 
 | 
                }  | 
 | 
                switch (bc) { | 
 | 
                case _tableswitch:   | 
 | 
                case _lookupswitch:   | 
 | 
                    { | 
 | 
                        int caseCount = bc_case_count.getInt();  | 
 | 
                        while ((pc + 30 + caseCount*8) > buf.length)  | 
 | 
                            buf = realloc(buf);  | 
 | 
                        buf[pc++] = (byte) bc;  | 
 | 
                          | 
 | 
                        Arrays.fill(buf, pc, pc+30, (byte)0);  | 
 | 
                        Instruction.Switch isw = (Instruction.Switch)  | 
 | 
                            Instruction.at(buf, curPC);  | 
 | 
                          | 
 | 
                        isw.setCaseCount(caseCount);  | 
 | 
                        if (bc == _tableswitch) { | 
 | 
                            isw.setCaseValue(0, bc_case_value.getInt());  | 
 | 
                        } else { | 
 | 
                            for (int j = 0; j < caseCount; j++) { | 
 | 
                                isw.setCaseValue(j, bc_case_value.getInt());  | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                          | 
 | 
                        labels[numLabels++] = curPC;  | 
 | 
                        pc = isw.getNextPC();  | 
 | 
                        continue;  | 
 | 
                    }  | 
 | 
                case _iinc:  | 
 | 
                    { | 
 | 
                        buf[pc++] = (byte) bc;  | 
 | 
                        int local = bc_local.getInt();  | 
 | 
                        int delta;  | 
 | 
                        if (isWide) { | 
 | 
                            delta = bc_short.getInt();  | 
 | 
                            Instruction.setShort(buf, pc, local); pc += 2;  | 
 | 
                            Instruction.setShort(buf, pc, delta); pc += 2;  | 
 | 
                        } else { | 
 | 
                            delta = (byte) bc_byte.getByte();  | 
 | 
                            buf[pc++] = (byte)local;  | 
 | 
                            buf[pc++] = (byte)delta;  | 
 | 
                        }  | 
 | 
                        continue;  | 
 | 
                    }  | 
 | 
                case _sipush:  | 
 | 
                    { | 
 | 
                        int val = bc_short.getInt();  | 
 | 
                        buf[pc++] = (byte) bc;  | 
 | 
                        Instruction.setShort(buf, pc, val); pc += 2;  | 
 | 
                        continue;  | 
 | 
                    }  | 
 | 
                case _bipush:  | 
 | 
                case _newarray:  | 
 | 
                    { | 
 | 
                        int val = bc_byte.getByte();  | 
 | 
                        buf[pc++] = (byte) bc;  | 
 | 
                        buf[pc++] = (byte) val;  | 
 | 
                        continue;  | 
 | 
                    }  | 
 | 
                case _ref_escape:  | 
 | 
                    { | 
 | 
                          | 
 | 
                        hasEscs = true;  | 
 | 
                        int size = bc_escrefsize.getInt();  | 
 | 
                        Entry ref = bc_escref.getRef();  | 
 | 
                        if (size == 1)  ldcRefSet.add(ref);  | 
 | 
                        int fmt;  | 
 | 
                        switch (size) { | 
 | 
                        case 1: fixupBuf.addU1(pc, ref); break;  | 
 | 
                        case 2: fixupBuf.addU2(pc, ref); break;  | 
 | 
                        default: assert(false); fmt = 0;  | 
 | 
                        }  | 
 | 
                        buf[pc+0] = buf[pc+1] = 0;  | 
 | 
                        pc += size;  | 
 | 
                    }  | 
 | 
                    continue;  | 
 | 
                case _byte_escape:  | 
 | 
                    { | 
 | 
                          | 
 | 
                        hasEscs = true;  | 
 | 
                        int size = bc_escsize.getInt();  | 
 | 
                        while ((pc + size) > buf.length)  | 
 | 
                            buf = realloc(buf);  | 
 | 
                        while (size-- > 0) { | 
 | 
                            buf[pc++] = (byte) bc_escbyte.getByte();  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    continue;  | 
 | 
                default:  | 
 | 
                    if (Instruction.isInvokeInitOp(bc)) { | 
 | 
                        int idx = (bc - _invokeinit_op);  | 
 | 
                        int origBC = _invokespecial;  | 
 | 
                        ClassEntry classRef;  | 
 | 
                        switch (idx) { | 
 | 
                        case _invokeinit_self_option:  | 
 | 
                            classRef = thisClass; break;  | 
 | 
                        case _invokeinit_super_option:  | 
 | 
                            classRef = superClass; break;  | 
 | 
                        default:  | 
 | 
                            assert(idx == _invokeinit_new_option);  | 
 | 
                            classRef = newClass; break;  | 
 | 
                        }  | 
 | 
                        buf[pc++] = (byte) origBC;  | 
 | 
                        int coding = bc_initref.getInt();  | 
 | 
                          | 
 | 
                        MemberEntry ref = pkg.cp.getOverloadingForIndex(CONSTANT_Methodref, classRef, "<init>", coding);  | 
 | 
                        fixupBuf.addU2(pc, ref);  | 
 | 
                        buf[pc+0] = buf[pc+1] = 0;  | 
 | 
                        pc += 2;  | 
 | 
                        assert(Instruction.opLength(origBC) == (pc - curPC));  | 
 | 
                        continue;  | 
 | 
                    }  | 
 | 
                    if (Instruction.isSelfLinkerOp(bc)) { | 
 | 
                        int idx = (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);  | 
 | 
                        CPRefBand bc_which;  | 
 | 
                        ClassEntry which_cls  = isSuper ? superClass : thisClass;  | 
 | 
                        Index which_ix;  | 
 | 
                        if (isField) { | 
 | 
                            bc_which = isSuper ? bc_superfield  : bc_thisfield;  | 
 | 
                            which_ix = pkg.cp.getMemberIndex(CONSTANT_Fieldref, which_cls);  | 
 | 
                        } else { | 
 | 
                            bc_which = isSuper ? bc_supermethod : bc_thismethod;  | 
 | 
                            which_ix = pkg.cp.getMemberIndex(CONSTANT_Methodref, which_cls);  | 
 | 
                        }  | 
 | 
                        assert(bc_which == selfOpRefBand(bc));  | 
 | 
                        MemberEntry ref = (MemberEntry) bc_which.getRef(which_ix);  | 
 | 
                        if (isAload) { | 
 | 
                            buf[pc++] = (byte) _aload_0;  | 
 | 
                            curPC = pc;  | 
 | 
                              | 
 | 
                            insnMap[numInsns++] = curPC;  | 
 | 
                        }  | 
 | 
                        buf[pc++] = (byte) origBC;  | 
 | 
                        fixupBuf.addU2(pc, ref);  | 
 | 
                        buf[pc+0] = buf[pc+1] = 0;  | 
 | 
                        pc += 2;  | 
 | 
                        assert(Instruction.opLength(origBC) == (pc - curPC));  | 
 | 
                        continue;  | 
 | 
                    }  | 
 | 
                    if (Instruction.isBranchOp(bc)) { | 
 | 
                        buf[pc++] = (byte) bc;  | 
 | 
                        assert(!isWide);    | 
 | 
                        int nextPC = curPC + Instruction.opLength(bc);  | 
 | 
                          | 
 | 
                        labels[numLabels++] = curPC;  | 
 | 
                          | 
 | 
                        while (pc < nextPC)  buf[pc++] = 0;  | 
 | 
                        continue;  | 
 | 
                    }  | 
 | 
                    if (Instruction.isCPRefOp(bc)) { | 
 | 
                        CPRefBand bc_which = getCPRefOpBand(bc);  | 
 | 
                        Entry ref = bc_which.getRef();  | 
 | 
                        if (ref == null) { | 
 | 
                            if (bc_which == bc_classref) { | 
 | 
                                  | 
 | 
                                ref = thisClass;  | 
 | 
                            } else { | 
 | 
                                assert(false);  | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                        int origBC = bc;  | 
 | 
                        int size = 2;  | 
 | 
                        switch (bc) { | 
 | 
                        case _invokestatic_int:  | 
 | 
                            origBC = _invokestatic;  | 
 | 
                            break;  | 
 | 
                        case _invokespecial_int:  | 
 | 
                            origBC = _invokespecial;  | 
 | 
                            break;  | 
 | 
                        case _ildc:  | 
 | 
                        case _cldc:  | 
 | 
                        case _fldc:  | 
 | 
                        case _sldc:  | 
 | 
                        case _qldc:  | 
 | 
                            origBC = _ldc;  | 
 | 
                            size = 1;  | 
 | 
                            ldcRefSet.add(ref);  | 
 | 
                            break;  | 
 | 
                        case _ildc_w:  | 
 | 
                        case _cldc_w:  | 
 | 
                        case _fldc_w:  | 
 | 
                        case _sldc_w:  | 
 | 
                        case _qldc_w:  | 
 | 
                            origBC = _ldc_w;  | 
 | 
                            break;  | 
 | 
                        case _lldc2_w:  | 
 | 
                        case _dldc2_w:  | 
 | 
                            origBC = _ldc2_w;  | 
 | 
                            break;  | 
 | 
                        case _new:  | 
 | 
                            newClass = (ClassEntry) ref;  | 
 | 
                            break;  | 
 | 
                        }  | 
 | 
                        buf[pc++] = (byte) origBC;  | 
 | 
                        int fmt;  | 
 | 
                        switch (size) { | 
 | 
                        case 1: fixupBuf.addU1(pc, ref); break;  | 
 | 
                        case 2: fixupBuf.addU2(pc, ref); break;  | 
 | 
                        default: assert(false); fmt = 0;  | 
 | 
                        }  | 
 | 
                        buf[pc+0] = buf[pc+1] = 0;  | 
 | 
                        pc += size;  | 
 | 
                        if (origBC == _multianewarray) { | 
 | 
                              | 
 | 
                            int val = bc_byte.getByte();  | 
 | 
                            buf[pc++] = (byte) val;  | 
 | 
                        } else if (origBC == _invokeinterface) { | 
 | 
                            int argSize = ((MemberEntry)ref).descRef.typeRef.computeSize(true);  | 
 | 
                            buf[pc++] = (byte)( 1 + argSize );  | 
 | 
                            buf[pc++] = 0;  | 
 | 
                        } else if (origBC == _invokedynamic) { | 
 | 
                            buf[pc++] = 0;  | 
 | 
                            buf[pc++] = 0;  | 
 | 
                        }  | 
 | 
                        assert(Instruction.opLength(origBC) == (pc - curPC));  | 
 | 
                        continue;  | 
 | 
                    }  | 
 | 
                    if (Instruction.isLocalSlotOp(bc)) { | 
 | 
                        buf[pc++] = (byte) bc;  | 
 | 
                        int local = bc_local.getInt();  | 
 | 
                        if (isWide) { | 
 | 
                            Instruction.setShort(buf, pc, local);  | 
 | 
                            pc += 2;  | 
 | 
                            if (bc == _iinc) { | 
 | 
                                int iVal = bc_short.getInt();  | 
 | 
                                Instruction.setShort(buf, pc, iVal);  | 
 | 
                                pc += 2;  | 
 | 
                            }  | 
 | 
                        } else { | 
 | 
                            Instruction.setByte(buf, pc, local);  | 
 | 
                            pc += 1;  | 
 | 
                            if (bc == _iinc) { | 
 | 
                                int iVal = bc_byte.getByte();  | 
 | 
                                Instruction.setByte(buf, pc, iVal);  | 
 | 
                                pc += 1;  | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                        assert(Instruction.opLength(bc) == (pc - curPC));  | 
 | 
                        continue;  | 
 | 
                    }  | 
 | 
                      | 
 | 
                    if (bc >= _bytecode_limit)  | 
 | 
                        Utils.log.warning("unrecognized bytescode "+bc | 
 | 
                                            +" "+Instruction.byteName(bc));  | 
 | 
                    assert(bc < _bytecode_limit);  | 
 | 
                    buf[pc++] = (byte) bc;  | 
 | 
                    assert(Instruction.opLength(bc) == (pc - curPC));  | 
 | 
                    continue;  | 
 | 
                }  | 
 | 
            }  | 
 | 
              | 
 | 
            code.setBytes(realloc(buf, pc));  | 
 | 
            code.setInstructionMap(insnMap, numInsns);  | 
 | 
            // fix up labels, now that code has its insnMap  | 
 | 
            Instruction ibr = null;    | 
 | 
            for (int i = 0; i < numLabels; i++) { | 
 | 
                int curPC = labels[i];  | 
 | 
                  | 
 | 
                ibr = Instruction.at(code.bytes, curPC, ibr);  | 
 | 
                if (ibr instanceof Instruction.Switch) { | 
 | 
                    Instruction.Switch isw = (Instruction.Switch) ibr;  | 
 | 
                    isw.setDefaultLabel(getLabel(bc_label, code, curPC));  | 
 | 
                    int caseCount = isw.getCaseCount();  | 
 | 
                    for (int j = 0; j < caseCount; j++) { | 
 | 
                        isw.setCaseLabel(j, getLabel(bc_label, code, curPC));  | 
 | 
                    }  | 
 | 
                } else { | 
 | 
                    ibr.setBranchLabel(getLabel(bc_label, code, curPC));  | 
 | 
                }  | 
 | 
            }  | 
 | 
            if (fixupBuf.size() > 0) { | 
 | 
                if (verbose > 2)  | 
 | 
                    Utils.log.fine("Fixups in code: "+fixupBuf); | 
 | 
                code.addFixups(fixupBuf);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |