gt:         if (ldcRefs != null) {
context: /*
   * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  
  package com.sun.java.util.jar.pack;
  
  import com.sun.java.util.jar.pack.ConstantPool.*;
  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.*;
  
  /**
   * Reader for a package file.
   *
   * @see PackageWriter
   * @author John Rose
   */
  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);
      }
  
      /** A buffered input stream which is careful not to
       *  read its underlying stream ahead of a given mark,
       *  called the 'readLimit'.  This property declares
       *  the maximum number of characters that future reads
       *  can consume from the underlying stream.
       */
      static
      class LimitedBuffer extends BufferedInputStream {
          long served;     // total number of charburgers served
          int  servedPos;  // ...as of this value of super.pos
          long limit;      // current declared 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) {
                  // fast path
                  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;
              //assert(served <= limit || limit == -1);
              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
              //        file_bands
              readFileHeader();
              readBandHeaders();
              readConstantPool();  // cp_bands
              readAttrDefs();
              readInnerClasses();
              Class[] classes = readClasses();
              readByteCodes();
              readFiles();     // file_bands
              assert(archiveSize1 == 0 || in.atLimit());
              assert(archiveSize1 == 0 ||
                     in.getBytesServed() == archiveSize0+archiveSize1);
              all_bands.doneDisbursing();
  
              // As a post-pass, build constant pools and inner classes.
              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 (verbose > 0)  ee.printStackTrace();
              if (ee instanceof IOException)  throw (IOException)ee;
              if (ee instanceof RuntimeException)  throw (RuntimeException)ee;
              throw new Error("error unpacking", ee);
          }
      }
  
      // Temporary count values, until band decoding gets rolling.
      int[] tagCount = new int[CONSTANT_Limit];
      int numFiles;
      int numAttrDefs;
      int numInnerClasses;
      int numClasses;
  
      void readFileHeader() throws IOException {
          //  file_header:
          //        archive_magic archive_header
          readArchiveMagic();
          readArchiveHeader();
      }
  
      // Local routine used to parse fixed-format scalars
      // in the file_header:
      private int getMagicInt32() throws IOException {
          int res = 0;
          for (int i = 0; i < 4; i++) {
              res <<= 8;
              res |= (archive_magic.getByte() & 0xFF);
          }
          return res;
      }
  
      static final int MAGIC_BYTES = 4;
  
      void readArchiveMagic() throws IOException {
          // Read a minimum of bytes in the first gulp.
          in.setReadLimit(MAGIC_BYTES + AH_LENGTH_MIN);
  
          //  archive_magic:
          //        #archive_magic_word :BYTE1[4]
          archive_magic.expectLength(MAGIC_BYTES);
          archive_magic.readFrom(in);
  
          // read and check magic numbers:
          int magic = getMagicInt32();
          if (pkg.magic != magic) {
              throw new IOException("Unexpected package magic number: got "
                      + magic + "; expected " + pkg.magic);
          }
          archive_magic.doneDisbursing();
      }
  
       // Fixed 6211177, converted to throw IOException
      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();
  
          // detect archive optional fields in archive header
          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();
  
          // now we are ready to use the data:
          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);  // for debug only
          } else {
              archiveSize1 = 0;
              in.setReadLimit(-1);  // remove limitation
          }
          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();
  
          // set some derived archive bits
          if (testBit(archiveOptions, AO_DEFLATE_HINT)) {
              pkg.default_options |= FO_DEFLATE_HINT;
          }
      }
  
      void readBandHeaders() throws IOException {
          band_headers.readFrom(in);
          bandHeaderBytePos = 1;  // Leave room to pushback the initial XB byte.
          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 {
          // size the constant pools:
          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) {
                  // These four counts are optional.
                  switch (tag) {
                  case CONSTANT_Integer:
                  case CONSTANT_Float:
                  case CONSTANT_Long:
                  case CONSTANT_Double:
                      continue;
                  }
              }
              if (!haveCPExtra) {
                  // These four counts are optional.
                  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();  // coding handles signs OK
                      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_lo :DELTA5
                  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_lo :DELTA5
                  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 :UDELTA5  (cp_Utf8)
                  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)
          //          ** length(cp_Utf8_big_suffix)
          int len = cpMap.length;
          if (len == 0)
              return;  // nothing to read
  
          // Bands have implicit leading zeroes, for the empty string:
          final int SUFFIX_SKIP_1 = 1;
          final int PREFIX_SKIP_2 = 2;
  
          // First band:  Read lengths of shared prefixes.
          cp_Utf8_prefix.expectLength(Math.max(0, len - PREFIX_SKIP_2));
          cp_Utf8_prefix.readFrom(in);
  
          // Second band:  Read lengths of unshared suffixes:
          cp_Utf8_suffix.expectLength(Math.max(0, len - SUFFIX_SKIP_1));
          cp_Utf8_suffix.readFrom(in);
  
          char[][] suffixChars = new char[len][];
          int bigSuffixCount = 0;
  
          // Third band:  Read the char values in the unshared suffixes:
          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) {
                  // chars are packed in cp_Utf8_big_chars
                  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();
  
          // Fourth band:  Go back and size the specially packed strings.
          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];
  
          // Fifth band(s):  Get the specially packed characters.
          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;  // already input
              suffix = cp_Utf8_big_suffix.getInt();
              suffixChars[i] = new char[suffix];
              if (suffix == 0) {
                  // Do not bother to add an empty "(Utf8_big_0)" band.
                  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();
  
          // Finally, sew together all the prefixes and suffixes.
          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();
  
              // by induction, the buffer is already filled with the prefix
              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_classes :UDELTA5  (cp_Class)
          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_Imethod_desc :UDELTA5  (cp_Descr)
          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
          //        *file_bits :BYTE1
          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();
  
          // Compute file lengths before reading any file bits.
          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++) {
              // %%% Use a big temp file for file bits?
              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);
              }
          }
  
          // Do the rest of the classes.
          while (nextClass.hasNext()) {
              Class cls = nextClass.next();
              cls.initFile(null);  // implicitly initialize to a trivial one
              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_layout :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());
                  // Check layout string for Java 6 extensions.
                  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.
          // Create them now, all at once.
          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_name :DELTA5  (null or cp_Utf8)
          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 number = parse[1];
                  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) {
                  // A zero flag means copy a global IC here.
                  InnerClass ic = pkg.getGlobalInnerClass(thisClass);
                  assert(ic != null);  // must be a valid global IC reference
                  localICs.add(ic);
              } else {
                  if (flags == ACC_IC_LONG_FORM)
                      flags = 0;  // clear the marker bit
                  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;  // placeholder for later flag read-in
  
      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
          //        code_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();
              }
              // Packer encoded rare case of null superClass as thisClass:
              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
          //class_bands.doneDisbursing(); // still need to read code attrs
          return classes;
      }
  
      private int getOutputIndex(Entry e) {
          // Output CPs do not contain signatures.
          assert(e.tag != CONSTANT_Signature);
          int k = pkg.cp.untypedIndexOf(e);
          // In the output ordering, input signatures can serve
          // in place of Utf8s.
          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<>() {
          public int compare(Entry e0, Entry e1) {
              int k0 = getOutputIndex(e0);
              int k1 = getOutputIndex(e1);
              if (k0 >= 0 && k1 >= 0)
                  // If both have keys, use the keys.
                  return k0 - k1;
              if (k0 == k1)
                  // If neither have keys, use their native tags & spellings.
                  return e0.compareTo(e1);
              // Otherwise, the guy with the key comes first.
              return (k0 >= 0)? 0-1: 1-0;
          }
      };
  
      void reconstructClass(Class cls) {
          if (verbose > 1)  Utils.log.fine("reconstruct "+cls);
  
          // check for local .ClassFile.version
          Attribute retroVersion = cls.getAttribute(attrClassFileVersion);
          if (retroVersion != null) {
              cls.removeAttribute(retroVersion);
              cls.version = parseClassFileVersionAttr(retroVersion);
          } else {
              cls.version = pkg.defaultClassVersion;
          }
  
          // Replace null SourceFile by "obvious" string.
          cls.expandSourceFile();
  
          // record the local cp:
          cls.setCPMap(reconstructLocalCPMap(cls));
      }
  
      Entry[] reconstructLocalCPMap(Class cls) {
          Set<Entry> ldcRefs = ldcRefMap.get(cls);
          Set<Entry> cpRefs = new HashSet<>();
  
          // look for constant pool entries:
          cls.visitRefs(VRM_CLASSIC, cpRefs);
  
          ArrayList<BootstrapMethodEntry> bsms = new ArrayList<>();
          // flesh out the local constant pool
          ConstantPool.completeReferencesIn(cpRefs, true, bsms);
  
          // add the bsm and references as required
          if (!bsms.isEmpty()) {
              cls.addAttribute(Package.attrBootstrapMethodsEmpty.canonicalInstance());
              cpRefs.add(Package.getRefString("BootstrapMethods"));
              Collections.sort(bsms);
              cls.setBootstrapMethods(bsms);
          }
  
          // Now that we know all our local class references,
          // compute the InnerClasses attribute.
          // An InnerClasses attribute usually gets added here,
          // although it might already have been present.
          int changed = cls.expandLocalICs();
  
          if (changed != 0) {
              if (changed > 0) {
                  // Just visit the expanded InnerClasses attr.
                  cls.visitInnerClassRefs(VRM_CLASSIC, cpRefs);
              } else {
                  // Have to recompute from scratch, because of deletions.
                  cpRefs.clear();
                  cls.visitRefs(VRM_CLASSIC, cpRefs);
              }
  
              // flesh out the local constant pool, again
              ConstantPool.completeReferencesIn(cpRefs, true, bsms);
          }
  
          // construct a local constant pool
          int numDoubles = 0;
          for (Entry e : cpRefs) {
              if (e.isDoubleWord())  numDoubles++;
          }
          Entry[] cpMap = new Entry[1+numDoubles+cpRefs.size()];
          int fillp = 1;
  
          // Add all ldc operands first.
  