view agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java @ 6169:cfa2c82f4c04

7175133: jinfo failed to get system properties after 6924259 Summary: String offset and count fields as fix of 6924259 were removed, and become optional. SA still use offset and count fields to read String contents and failed. Fix if they exist, use them other then use value field only to read, this keeps consistent with the changes in 6924259. Reviewed-by: dholmes, mikael Contributed-by: yumin.qi@oracle.com
author minqi
date Fri, 22 Jun 2012 15:35:30 -0700
parents 38fd165da001
children da91efe96a93
line wrap: on
line source

/*
 * Copyright (c) 2000, 2011, 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.
 *
 * 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 sun.jvm.hotspot.oops;

import java.io.*;
import java.util.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;

// A ConstantPool is an oop containing class constants
// as described in the class file

public class ConstantPool extends Oop implements ClassConstants {

  public class CPSlot {
    private Address ptr;

    CPSlot(Address ptr) {
      this.ptr = ptr;
    }
    CPSlot(Symbol sym) {
      this.ptr = sym.getAddress().orWithMask(1);
    }

    public boolean isOop() {
      return (ptr.minus(null) & 1) == 0;
    }
    public boolean isMetaData() {
      return (ptr.minus(null) & 1) == 1;
    }

    public Symbol getSymbol() {
      if (isMetaData()) {
        return Symbol.create(ptr.xorWithMask(1));
      }
      throw new InternalError("not a symbol");
    }
    public Oop getOop() {
      if (isOop()) {
        return VM.getVM().getObjectHeap().newOop(ptr.addOffsetToAsOopHandle(0));
      }
      throw new InternalError("not an oop");
    }
  }

  // Used for debugging this code
  private static final boolean DEBUG = false;

  protected void debugMessage(String message) {
    System.out.println(message);
  }

  static {
    VM.registerVMInitializedObserver(new Observer() {
        public void update(Observable o, Object data) {
          initialize(VM.getVM().getTypeDataBase());
        }
      });
  }

  private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
    Type type   = db.lookupType("constantPoolOopDesc");
    tags        = new OopField(type.getOopField("_tags"), 0);
    operands    = new OopField(type.getOopField("_operands"), 0);
    cache       = new OopField(type.getOopField("_cache"), 0);
    poolHolder  = new OopField(type.getOopField("_pool_holder"), 0);
    length      = new CIntField(type.getCIntegerField("_length"), 0);
    headerSize  = type.getSize();
    elementSize = 0;
    // fetch constants:
    INDY_BSM_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_bsm_offset").intValue();
    INDY_ARGC_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_argc_offset").intValue();
    INDY_ARGV_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_argv_offset").intValue();
  }

  ConstantPool(OopHandle handle, ObjectHeap heap) {
    super(handle, heap);
  }

  public boolean isConstantPool()      { return true; }

  private static OopField tags;
  private static OopField operands;
  private static OopField cache;
  private static OopField poolHolder;
  private static CIntField length; // number of elements in oop

  private static long headerSize;
  private static long elementSize;

  private static int INDY_BSM_OFFSET;
  private static int INDY_ARGC_OFFSET;
  private static int INDY_ARGV_OFFSET;

  public TypeArray         getTags()       { return (TypeArray)         tags.getValue(this); }
  public TypeArray         getOperands()   { return (TypeArray)         operands.getValue(this); }
  public ConstantPoolCache getCache()      { return (ConstantPoolCache) cache.getValue(this); }
  public Klass             getPoolHolder() { return (Klass)             poolHolder.getValue(this); }
  public int               getLength()     { return (int)length.getValue(this); }

  private long getElementSize() {
    if (elementSize !=0 ) {
      return elementSize;
    } else {
      elementSize = VM.getVM().getOopSize();
    }
    return elementSize;
  }

  private long indexOffset(long index) {
    if (Assert.ASSERTS_ENABLED) {
      Assert.that(index > 0 && index < getLength(),  "invalid cp index " + index + " " + getLength());
    }
    return (index * getElementSize()) + headerSize;
  }

  public ConstantTag getTagAt(long index) {
    return new ConstantTag(getTags().getByteAt((int) index));
  }

  public CPSlot getSlotAt(long index) {
    return new CPSlot(getHandle().getAddressAt(indexOffset(index)));
  }

  public Oop getObjAtRaw(long index){
    return getHeap().newOop(getHandle().getOopHandleAt(indexOffset(index)));
  }

  public Symbol getSymbolAt(long index) {
    CPSlot slot = getSlotAt(index);
    return slot.getSymbol();
  }

  public int getIntAt(long index){
    return getHandle().getJIntAt(indexOffset(index));
  }

  public float getFloatAt(long index){
    return getHandle().getJFloatAt(indexOffset(index));
  }

  public long getLongAt(long index) {
    int oneHalf = getHandle().getJIntAt(indexOffset(index + 1));
    int otherHalf   = getHandle().getJIntAt(indexOffset(index));
    // buildLongFromIntsPD accepts higher address value, lower address value
    // in that order.
    return VM.getVM().buildLongFromIntsPD(oneHalf, otherHalf);
  }

  public double getDoubleAt(long index) {
    return Double.longBitsToDouble(getLongAt(index));
  }

  public int getFieldOrMethodAt(int which) {
    if (DEBUG) {
      System.err.print("ConstantPool.getFieldOrMethodAt(" + which + "): new index = ");
    }
    int i = -1;
    ConstantPoolCache cache = getCache();
    if (cache == null) {
      i = which;
    } else {
      // change byte-ordering and go via cache
      i = cache.getEntryAt(0xFFFF & VM.getVM().getBytes().swapShort((short) which)).getConstantPoolIndex();
    }
    if (Assert.ASSERTS_ENABLED) {
      Assert.that(getTagAt(i).isFieldOrMethod(), "Corrupted constant pool");
    }
    if (DEBUG) {
      System.err.println(i);
    }
    int res = getIntAt(i);
    if (DEBUG) {
      System.err.println("ConstantPool.getFieldOrMethodAt(" + i + "): result = " + res);
    }
    return res;
  }

  public int[] getNameAndTypeAt(int which) {
    if (Assert.ASSERTS_ENABLED) {
      Assert.that(getTagAt(which).isNameAndType(), "Corrupted constant pool");
    }
    int i = getIntAt(which);
    if (DEBUG) {
      System.err.println("ConstantPool.getNameAndTypeAt(" + which + "): result = " + i);
    }
    return new int[] { extractLowShortFromInt(i), extractHighShortFromInt(i) };
  }

  public Symbol getNameRefAt(int which) {
    return implGetNameRefAt(which, false);
  }

  private Symbol implGetNameRefAt(int which, boolean uncached) {
    int signatureIndex = getNameRefIndexAt(implNameAndTypeRefIndexAt(which, uncached));
    return getSymbolAt(signatureIndex);
  }

  public Symbol getSignatureRefAt(int which) {
    return implGetSignatureRefAt(which, false);
  }

  private Symbol implGetSignatureRefAt(int which, boolean uncached) {
    int signatureIndex = getSignatureRefIndexAt(implNameAndTypeRefIndexAt(which, uncached));
    return getSymbolAt(signatureIndex);
  }


  private int implNameAndTypeRefIndexAt(int which, boolean uncached) {
    int i = which;
    if (!uncached && getCache() != null) {
      if (ConstantPoolCache.isSecondaryIndex(which)) {
        // Invokedynamic index.
        int pool_index = getCache().getMainEntryAt(which).getConstantPoolIndex();
        pool_index = invokeDynamicNameAndTypeRefIndexAt(pool_index);
        // assert(tagAt(pool_index).isNameAndType(), "");
        return pool_index;
      }
      // change byte-ordering and go via cache
      i = remapInstructionOperandFromCache(which);
    } else {
      if (getTagAt(which).isInvokeDynamic()) {
        int pool_index = invokeDynamicNameAndTypeRefIndexAt(which);
        // assert(tag_at(pool_index).is_name_and_type(), "");
        return pool_index;
      }
    }
    // assert(tag_at(i).is_field_or_method(), "Corrupted constant pool");
    // assert(!tag_at(i).is_invoke_dynamic(), "Must be handled above");
    int ref_index = getIntAt(i);
    return extractHighShortFromInt(ref_index);
  }

  private int remapInstructionOperandFromCache(int operand) {
    int cpc_index = operand;
    // DEBUG_ONLY(cpc_index -= CPCACHE_INDEX_TAG);
    // assert((int)(u2)cpc_index == cpc_index, "clean u2");
    int member_index = getCache().getEntryAt(cpc_index).getConstantPoolIndex();
    return member_index;
  }

  int invokeDynamicNameAndTypeRefIndexAt(int which) {
    // assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
    return extractHighShortFromInt(getIntAt(which));
  }

  // returns null, if not resolved.
  public Klass getKlassRefAt(int which) {
    if( ! getTagAt(which).isKlass()) return null;
    return (Klass) getObjAtRaw(which);
  }

  // returns null, if not resolved.
  public InstanceKlass getFieldOrMethodKlassRefAt(int which) {
    int refIndex = getFieldOrMethodAt(which);
    int klassIndex = extractLowShortFromInt(refIndex);
    return (InstanceKlass) getKlassRefAt(klassIndex);
  }

  // returns null, if not resolved.
  public Method getMethodRefAt(int which) {
    InstanceKlass klass = getFieldOrMethodKlassRefAt(which);
    if (klass == null) return null;
    Symbol name = getNameRefAt(which);
    Symbol sig  = getSignatureRefAt(which);
    return klass.findMethod(name, sig);
  }

  // returns null, if not resolved.
  public Field getFieldRefAt(int which) {
    InstanceKlass klass = getFieldOrMethodKlassRefAt(which);
    if (klass == null) return null;
    Symbol name = getNameRefAt(which);
    Symbol sig  = getSignatureRefAt(which);
    return klass.findField(name, sig);
  }

  public int getNameAndTypeRefIndexAt(int index) {
    return implNameAndTypeRefIndexAt(index, false);
  }

  /** Lookup for entries consisting of (name_index, signature_index) */
  public int getNameRefIndexAt(int index) {
    int[] refIndex = getNameAndTypeAt(index);
    if (DEBUG) {
      System.err.println("ConstantPool.getNameRefIndexAt(" + index + "): refIndex = " + refIndex[0]+"/"+refIndex[1]);
    }
    int i = refIndex[0];
    if (DEBUG) {
      System.err.println("ConstantPool.getNameRefIndexAt(" + index + "): result = " + i);
    }
    return i;
  }

  /** Lookup for entries consisting of (name_index, signature_index) */
  public int getSignatureRefIndexAt(int index) {
    int[] refIndex = getNameAndTypeAt(index);
    if (DEBUG) {
      System.err.println("ConstantPool.getSignatureRefIndexAt(" + index + "): refIndex = " + refIndex[0]+"/"+refIndex[1]);
    }
    int i = refIndex[1];
    if (DEBUG) {
      System.err.println("ConstantPool.getSignatureRefIndexAt(" + index + "): result = " + i);
    }
    return i;
  }

  /** Lookup for MethodHandle entries. */
  public int getMethodHandleIndexAt(int i) {
    if (Assert.ASSERTS_ENABLED) {
      Assert.that(getTagAt(i).isMethodHandle(), "Corrupted constant pool");
    }
    int res = extractHighShortFromInt(getIntAt(i));
    if (DEBUG) {
      System.err.println("ConstantPool.getMethodHandleIndexAt(" + i + "): result = " + res);
    }
    return res;
  }

  /** Lookup for MethodHandle entries. */
  public int getMethodHandleRefKindAt(int i) {
    if (Assert.ASSERTS_ENABLED) {
      Assert.that(getTagAt(i).isMethodHandle(), "Corrupted constant pool");
    }
    int res = extractLowShortFromInt(getIntAt(i));
    if (DEBUG) {
      System.err.println("ConstantPool.getMethodHandleRefKindAt(" + i + "): result = " + res);
    }
    return res;
  }

  /** Lookup for MethodType entries. */
  public int getMethodTypeIndexAt(int i) {
    if (Assert.ASSERTS_ENABLED) {
      Assert.that(getTagAt(i).isMethodType(), "Corrupted constant pool");
    }
    int res = getIntAt(i);
    if (DEBUG) {
      System.err.println("ConstantPool.getMethodHandleTypeAt(" + i + "): result = " + res);
    }
    return res;
  }

  /** Lookup for multi-operand (InvokeDynamic) entries. */
  public short[] getBootstrapSpecifierAt(int i) {
    if (Assert.ASSERTS_ENABLED) {
      Assert.that(getTagAt(i).isInvokeDynamic(), "Corrupted constant pool");
    }
    int bsmSpec = extractLowShortFromInt(this.getIntAt(i));
    TypeArray operands = getOperands();
    if (operands == null)  return null;  // safety first
    int basePos = VM.getVM().buildIntFromShorts(operands.getShortAt(bsmSpec * 2 + 0),
                                                operands.getShortAt(bsmSpec * 2 + 1));
    int argv = basePos + INDY_ARGV_OFFSET;
    int argc = operands.getShortAt(basePos + INDY_ARGC_OFFSET);
    int endPos = argv + argc;
    short[] values = new short[endPos - basePos];
    for (int j = 0; j < values.length; j++) {
        values[j] = operands.getShortAt(basePos+j);
    }
    return values;
  }

  final private static String[] nameForTag = new String[] {
  };

  private String nameForTag(int tag) {
    switch (tag) {
    case JVM_CONSTANT_Utf8:               return "JVM_CONSTANT_Utf8";
    case JVM_CONSTANT_Unicode:            return "JVM_CONSTANT_Unicode";
    case JVM_CONSTANT_Integer:            return "JVM_CONSTANT_Integer";
    case JVM_CONSTANT_Float:              return "JVM_CONSTANT_Float";
    case JVM_CONSTANT_Long:               return "JVM_CONSTANT_Long";
    case JVM_CONSTANT_Double:             return "JVM_CONSTANT_Double";
    case JVM_CONSTANT_Class:              return "JVM_CONSTANT_Class";
    case JVM_CONSTANT_String:             return "JVM_CONSTANT_String";
    case JVM_CONSTANT_Fieldref:           return "JVM_CONSTANT_Fieldref";
    case JVM_CONSTANT_Methodref:          return "JVM_CONSTANT_Methodref";
    case JVM_CONSTANT_InterfaceMethodref: return "JVM_CONSTANT_InterfaceMethodref";
    case JVM_CONSTANT_NameAndType:        return "JVM_CONSTANT_NameAndType";
    case JVM_CONSTANT_MethodHandle:       return "JVM_CONSTANT_MethodHandle";
    case JVM_CONSTANT_MethodType:         return "JVM_CONSTANT_MethodType";
    case JVM_CONSTANT_InvokeDynamic:      return "JVM_CONSTANT_InvokeDynamic";
    case JVM_CONSTANT_Invalid:            return "JVM_CONSTANT_Invalid";
    case JVM_CONSTANT_UnresolvedClass:    return "JVM_CONSTANT_UnresolvedClass";
    case JVM_CONSTANT_UnresolvedClassInError:    return "JVM_CONSTANT_UnresolvedClassInError";
    case JVM_CONSTANT_ClassIndex:         return "JVM_CONSTANT_ClassIndex";
    case JVM_CONSTANT_UnresolvedString:   return "JVM_CONSTANT_UnresolvedString";
    case JVM_CONSTANT_StringIndex:        return "JVM_CONSTANT_StringIndex";
    }
    throw new InternalError("Unknown tag: " + tag);
  }

  public void iterateFields(OopVisitor visitor, boolean doVMFields) {
    super.iterateFields(visitor, doVMFields);
    if (doVMFields) {
      visitor.doOop(tags, true);
      visitor.doOop(cache, true);
      visitor.doOop(poolHolder, true);

      final int length = (int) getLength();
      // zero'th pool entry is always invalid. ignore it.
      for (int index = 1; index < length; index++) {
        int ctag = (int) getTags().getByteAt((int) index);
        switch (ctag) {
        case JVM_CONSTANT_ClassIndex:
        case JVM_CONSTANT_StringIndex:
        case JVM_CONSTANT_Integer:
          visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
          break;

        case JVM_CONSTANT_Float:
          visitor.doFloat(new FloatField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
          break;

        case JVM_CONSTANT_Long:
          visitor.doLong(new LongField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
          // long entries occupy two slots
          index++;
          break;

        case JVM_CONSTANT_Double:
          visitor.doDouble(new DoubleField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
          // double entries occupy two slots
          index++;
          break;

        case JVM_CONSTANT_UnresolvedClassInError:
        case JVM_CONSTANT_UnresolvedClass:
        case JVM_CONSTANT_Class:
        case JVM_CONSTANT_UnresolvedString:
        case JVM_CONSTANT_Utf8:
          visitor.doOop(new OopField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
          break;

        case JVM_CONSTANT_Fieldref:
        case JVM_CONSTANT_Methodref:
        case JVM_CONSTANT_InterfaceMethodref:
        case JVM_CONSTANT_NameAndType:
        case JVM_CONSTANT_MethodHandle:
        case JVM_CONSTANT_MethodType:
        case JVM_CONSTANT_InvokeDynamic:
          visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
          break;
        }
      }
    }
    /*
    int length = getLength();
    for (int index = 0; index < length; index++) {
      long offset = baseOffset + (index + typeDataBase.getOopSize());
      visitor.doOop(new IndexableField(index, offset, false), getObjAt(index));
    }
    */
  }

  public void writeBytes(OutputStream os) throws IOException {
          // Map between any modified UTF-8 and it's constant pool index.
          Map utf8ToIndex = new HashMap();
      DataOutputStream dos = new DataOutputStream(os);
      TypeArray tags = getTags();
      int len = (int)getLength();
      int ci = 0; // constant pool index

      // collect all modified UTF-8 Strings from Constant Pool

      for (ci = 1; ci < len; ci++) {
          byte cpConstType = tags.getByteAt(ci);
          if(cpConstType == JVM_CONSTANT_Utf8) {
              Symbol sym = getSymbolAt(ci);
              utf8ToIndex.put(sym.asString(), new Short((short) ci));
          }
          else if(cpConstType == JVM_CONSTANT_Long ||
                  cpConstType == JVM_CONSTANT_Double) {
              ci++;
          }
      }


      for(ci = 1; ci < len; ci++) {
          int cpConstType = (int)tags.getByteAt(ci);
          // write cp_info
          // write constant type
          switch(cpConstType) {
              case JVM_CONSTANT_Utf8: {
                  dos.writeByte(cpConstType);
                  Symbol sym = getSymbolAt(ci);
                  dos.writeShort((short)sym.getLength());
                  dos.write(sym.asByteArray());
                  if (DEBUG) debugMessage("CP[" + ci + "] = modified UTF-8 " + sym.asString());
                  break;
              }

              case JVM_CONSTANT_Unicode:
                  throw new IllegalArgumentException("Unicode constant!");

              case JVM_CONSTANT_Integer:
                  dos.writeByte(cpConstType);
                  dos.writeInt(getIntAt(ci));
                  if (DEBUG) debugMessage("CP[" + ci + "] = int " + getIntAt(ci));
                  break;

              case JVM_CONSTANT_Float:
                  dos.writeByte(cpConstType);
                  dos.writeFloat(getFloatAt(ci));
                  if (DEBUG) debugMessage("CP[" + ci + "] = float " + getFloatAt(ci));
                  break;

              case JVM_CONSTANT_Long: {
                  dos.writeByte(cpConstType);
                  long l = getLongAt(ci);
                  // long entries occupy two pool entries
                  ci++;
                  dos.writeLong(l);
                  break;
              }

              case JVM_CONSTANT_Double:
                  dos.writeByte(cpConstType);
                  dos.writeDouble(getDoubleAt(ci));
                  // double entries occupy two pool entries
                  ci++;
                  break;

              case JVM_CONSTANT_Class: {
                  dos.writeByte(cpConstType);
                  // Klass already resolved. ConstantPool constains klassOop.
                  Klass refKls = (Klass) getObjAtRaw(ci);
                  String klassName = refKls.getName().asString();
                  Short s = (Short) utf8ToIndex.get(klassName);
                  dos.writeShort(s.shortValue());
                  if (DEBUG) debugMessage("CP[" + ci  + "] = class " + s);
                  break;
              }

              // case JVM_CONSTANT_ClassIndex:
              case JVM_CONSTANT_UnresolvedClassInError:
              case JVM_CONSTANT_UnresolvedClass: {
                  dos.writeByte(JVM_CONSTANT_Class);
                  String klassName = getSymbolAt(ci).asString();
                  Short s = (Short) utf8ToIndex.get(klassName);
                  dos.writeShort(s.shortValue());
                  if (DEBUG) debugMessage("CP[" + ci + "] = class " + s);
                  break;
              }

              case JVM_CONSTANT_String: {
                  dos.writeByte(cpConstType);
                  String str = OopUtilities.stringOopToString(getObjAtRaw(ci));
                  Short s = (Short) utf8ToIndex.get(str);
                  dos.writeShort(s.shortValue());
                  if (DEBUG) debugMessage("CP[" + ci + "] = string " + s);
                  break;
              }

                  // case JVM_CONSTANT_StringIndex:
              case JVM_CONSTANT_UnresolvedString: {
                  dos.writeByte(JVM_CONSTANT_String);
                  String val = getSymbolAt(ci).asString();

                  Short s = (Short) utf8ToIndex.get(val);
                  dos.writeShort(s.shortValue());
                  if (DEBUG) debugMessage("CP[" + ci + "] = string " + s);
                  break;
              }

              // all external, internal method/field references
              case JVM_CONSTANT_Fieldref:
              case JVM_CONSTANT_Methodref:
              case JVM_CONSTANT_InterfaceMethodref: {
                  dos.writeByte(cpConstType);
                  int value = getIntAt(ci);
                  short klassIndex = (short) extractLowShortFromInt(value);
                  short nameAndTypeIndex = (short) extractHighShortFromInt(value);
                  dos.writeShort(klassIndex);
                  dos.writeShort(nameAndTypeIndex);
                  if (DEBUG) debugMessage("CP[" + ci + "] = ref klass = " +
                                          klassIndex + ", N&T = " + nameAndTypeIndex);
                  break;
              }

              case JVM_CONSTANT_NameAndType: {
                  dos.writeByte(cpConstType);
                  int value = getIntAt(ci);
                  short nameIndex = (short) extractLowShortFromInt(value);
                  short signatureIndex = (short) extractHighShortFromInt(value);
                  dos.writeShort(nameIndex);
                  dos.writeShort(signatureIndex);
                  if (DEBUG) debugMessage("CP[" + ci + "] = N&T name = " + nameIndex
                                          + ", type = " + signatureIndex);
                  break;
              }

              case JVM_CONSTANT_MethodHandle: {
                  dos.writeByte(cpConstType);
                  int value = getIntAt(ci);
                  short nameIndex = (short) extractLowShortFromInt(value);
                  short signatureIndex = (short) extractHighShortFromInt(value);
                  dos.writeShort(nameIndex);
                  dos.writeShort(signatureIndex);
                  if (DEBUG) debugMessage("CP[" + ci + "] = N&T name = " + nameIndex
                                          + ", type = " + signatureIndex);
                  break;
              }

              case JVM_CONSTANT_InvokeDynamic: {
                  dos.writeByte(cpConstType);
                  int value = getIntAt(ci);
                  short bsmIndex = (short) extractLowShortFromInt(value);
                  short nameAndTypeIndex = (short) extractHighShortFromInt(value);
                  dos.writeShort(bsmIndex);
                  dos.writeShort(nameAndTypeIndex);
                  if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " + bsmIndex
                                          + ", N&T = " + nameAndTypeIndex);
                  break;
              }

              default:
                  throw new InternalError("unknown tag: " + cpConstType);
          } // switch
      }
      dos.flush();
      return;
  }

  public void printValueOn(PrintStream tty) {
    Oop holder = poolHolder.getValue(this);
    if (holder instanceof Klass) {
      tty.print("ConstantPool for " + ((Klass)holder).getName().asString());
    } else {
      tty.print("ConstantPool for partially loaded class");
    }
  }

  public long getObjectSize() {
    return alignObjectSize(headerSize + (getLength() * getElementSize()));
  }

  //----------------------------------------------------------------------
  // Internals only below this point
  //

  private static int extractHighShortFromInt(int val) {
    // must stay in sync with constantPoolOopDesc::name_and_type_at_put, method_at_put, etc.
    return (val >> 16) & 0xFFFF;
  }

  private static int extractLowShortFromInt(int val) {
    // must stay in sync with constantPoolOopDesc::name_and_type_at_put, method_at_put, etc.
    return val & 0xFFFF;
  }
}