1 /*
   2  * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot.oops;
  26 
  27 import java.io.*;
  28 import java.util.*;
  29 import sun.jvm.hotspot.debugger.*;
  30 import sun.jvm.hotspot.runtime.*;
  31 import sun.jvm.hotspot.types.*;
  32 import sun.jvm.hotspot.utilities.*;
  33 
  34 // A ConstantPool is an oop containing class constants
  35 // as described in the class file
  36 
  37 public class ConstantPool extends Metadata implements ClassConstants {
  38   public class CPSlot {
  39     private Address ptr;
  40 
  41     CPSlot(Address ptr) {
  42       this.ptr = ptr;
  43     }
  44     CPSlot(Symbol sym) {
  45       this.ptr = sym.getAddress().orWithMask(1);
  46     }
  47 
  48     public boolean isResolved() {
  49       return (ptr.minus(null) & 1) == 0;
  50     }
  51     public boolean isUnresolved() {
  52       return (ptr.minus(null) & 1) == 1;
  53     }
  54 
  55     public Symbol getSymbol() {
  56       if (!isUnresolved()) throw new InternalError("not a symbol");
  57         return Symbol.create(ptr.xorWithMask(1));
  58       }
  59     public Klass getKlass() {
  60       if (!isResolved()) throw new InternalError("not klass");
  61       return (Klass)Metadata.instantiateWrapperFor(ptr);
  62     }
  63   }
  64 
  65   // Used for debugging this code
  66   private static final boolean DEBUG = false;
  67 
  68   protected void debugMessage(String message) {
  69     System.out.println(message);
  70   }
  71 
  72   static {
  73     VM.registerVMInitializedObserver(new Observer() {
  74         public void update(Observable o, Object data) {
  75           initialize(VM.getVM().getTypeDataBase());
  76         }
  77       });
  78   }
  79 
  80   private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
  81     Type type   = db.lookupType("ConstantPool");
  82     tags        = type.getAddressField("_tags");
  83     operands    = type.getAddressField("_operands");
  84     cache       = type.getAddressField("_cache");
  85     poolHolder  = new MetadataField(type.getAddressField("_pool_holder"), 0);
  86     length      = new CIntField(type.getCIntegerField("_length"), 0);
  87     headerSize  = type.getSize();
  88     elementSize = 0;
  89     // fetch constants:
  90     INDY_BSM_OFFSET = db.lookupIntConstant("ConstantPool::_indy_bsm_offset").intValue();
  91     INDY_ARGC_OFFSET = db.lookupIntConstant("ConstantPool::_indy_argc_offset").intValue();
  92     INDY_ARGV_OFFSET = db.lookupIntConstant("ConstantPool::_indy_argv_offset").intValue();
  93   }
  94 
  95   public ConstantPool(Address addr) {
  96     super(addr);
  97   }
  98 
  99   public boolean isConstantPool()      { return true; }
 100 
 101   private static AddressField tags;
 102   private static AddressField operands;
 103   private static AddressField cache;
 104   private static MetadataField poolHolder;
 105   private static CIntField length; // number of elements in oop
 106 
 107   private static long headerSize;
 108   private static long elementSize;
 109 
 110   private static int INDY_BSM_OFFSET;
 111   private static int INDY_ARGC_OFFSET;
 112   private static int INDY_ARGV_OFFSET;
 113 
 114   public U1Array           getTags()       { return new U1Array(tags.getValue(getAddress())); }
 115   public U2Array           getOperands()   { return new U2Array(operands.getValue(getAddress())); }
 116   public ConstantPoolCache getCache()      {
 117     Address addr = cache.getValue(getAddress());
 118     return (ConstantPoolCache) VMObjectFactory.newObject(ConstantPoolCache.class, addr);
 119   }
 120   public InstanceKlass     getPoolHolder() { return (InstanceKlass)poolHolder.getValue(this); }
 121   public int               getLength()     { return (int)length.getValue(getAddress()); }
 122   public Oop               getResolvedReferences() {
 123     return getCache().getResolvedReferences();
 124   }
 125 
 126   public U2Array referenceMap() {
 127     return getCache().referenceMap();
 128   }
 129 
 130   public int objectToCPIndex(int index) {
 131     return referenceMap().at(index);
 132   }
 133 
 134   private long getElementSize() {
 135     if (elementSize !=0 ) {
 136       return elementSize;
 137     } else {
 138       elementSize = VM.getVM().getOopSize();
 139     }
 140     return elementSize;
 141   }
 142 
 143   private long indexOffset(long index) {
 144     if (Assert.ASSERTS_ENABLED) {
 145       Assert.that(index >= 0 && index < getLength(),  "invalid cp index " + index + " " + getLength());
 146     }
 147     return (index * getElementSize()) + headerSize;
 148   }
 149 
 150   public ConstantTag getTagAt(long index) {
 151     return new ConstantTag((byte)getTags().at((int) index));
 152   }
 153 
 154   public CPSlot getSlotAt(long index) {
 155     return new CPSlot(getAddressAtRaw(index));
 156   }
 157 
 158   public Address getAddressAtRaw(long index) {
 159     return getAddress().getAddressAt(indexOffset(index));
 160   }
 161 
 162   public Symbol getSymbolAt(long index) {
 163     return Symbol.create(getAddressAtRaw(index));
 164   }
 165 
 166   public int getIntAt(long index){
 167     return getAddress().getJIntAt(indexOffset(index));
 168   }
 169 
 170   public float getFloatAt(long index){
 171     return getAddress().getJFloatAt(indexOffset(index));
 172   }
 173 
 174   public long getLongAt(long index) {
 175     int oneHalf = getAddress().getJIntAt(indexOffset(index + 1));
 176     int otherHalf   = getAddress().getJIntAt(indexOffset(index));
 177     // buildLongFromIntsPD accepts higher address value, lower address value
 178     // in that order.
 179     return VM.getVM().buildLongFromIntsPD(oneHalf, otherHalf);
 180   }
 181 
 182   public double getDoubleAt(long index) {
 183     return Double.longBitsToDouble(getLongAt(index));
 184   }
 185 
 186   public int getFieldOrMethodAt(int which) {
 187     if (DEBUG) {
 188       System.err.print("ConstantPool.getFieldOrMethodAt(" + which + "): new index = ");
 189     }
 190     int i = -1;
 191     ConstantPoolCache cache = getCache();
 192     if (cache == null) {
 193       i = which;
 194     } else {
 195       // change byte-ordering and go via cache
 196       i = cache.getEntryAt(0xFFFF & which).getConstantPoolIndex();
 197     }
 198     if (Assert.ASSERTS_ENABLED) {
 199       Assert.that(getTagAt(i).isFieldOrMethod(), "Corrupted constant pool");
 200     }
 201     if (DEBUG) {
 202       System.err.println(i);
 203     }
 204     int res = getIntAt(i);
 205     if (DEBUG) {
 206       System.err.println("ConstantPool.getFieldOrMethodAt(" + i + "): result = " + res);
 207     }
 208     return res;
 209   }
 210 
 211   public int[] getNameAndTypeAt(int which) {
 212     if (Assert.ASSERTS_ENABLED) {
 213       Assert.that(getTagAt(which).isNameAndType(), "Corrupted constant pool: " + which + " " + getTagAt(which));
 214     }
 215     int i = getIntAt(which);
 216     if (DEBUG) {
 217       System.err.println("ConstantPool.getNameAndTypeAt(" + which + "): result = " + i);
 218     }
 219     return new int[] { extractLowShortFromInt(i), extractHighShortFromInt(i) };
 220   }
 221 
 222   public Symbol getNameRefAt(int which) {
 223     return implGetNameRefAt(which, false);
 224   }
 225 
 226   public Symbol uncachedGetNameRefAt(int which) {
 227     return implGetNameRefAt(which, true);
 228   }
 229 
 230   private Symbol implGetNameRefAt(int which, boolean uncached) {
 231     int signatureIndex = getNameRefIndexAt(implNameAndTypeRefIndexAt(which, uncached));
 232     return getSymbolAt(signatureIndex);
 233   }
 234 
 235   public Symbol getSignatureRefAt(int which) {
 236     return implGetSignatureRefAt(which, false);
 237   }
 238 
 239   public Symbol uncachedGetSignatureRefAt(int which) {
 240     return implGetSignatureRefAt(which, true);
 241   }
 242 
 243   private Symbol implGetSignatureRefAt(int which, boolean uncached) {
 244     int signatureIndex = getSignatureRefIndexAt(implNameAndTypeRefIndexAt(which, uncached));
 245     return getSymbolAt(signatureIndex);
 246   }
 247 
 248   public static boolean isInvokedynamicIndex(int i) { return (i < 0); }
 249 
 250   public static int  decodeInvokedynamicIndex(int i) { Assert.that(isInvokedynamicIndex(i),  ""); return ~i; }
 251 
 252   // The invokedynamic points at the object index.  The object map points at
 253   // the cpCache index and the cpCache entry points at the original constant
 254   // pool index.
 255   public int invokedynamicCPCacheIndex(int index) {
 256     Assert.that(isInvokedynamicIndex(index), "should be a invokedynamic index");
 257     int rawIndex = decodeInvokedynamicIndex(index);
 258     return referenceMap().at(rawIndex);
 259   }
 260 
 261   ConstantPoolCacheEntry invokedynamicCPCacheEntryAt(int index) {
 262     // decode index that invokedynamic points to.
 263     int cpCacheIndex = invokedynamicCPCacheIndex(index);
 264     return getCache().getEntryAt(cpCacheIndex);
 265   }
 266 
 267   private int implNameAndTypeRefIndexAt(int which, boolean uncached) {
 268     int i = which;
 269     if (!uncached && getCache() != null) {
 270       if (isInvokedynamicIndex(which)) {
 271         // Invokedynamic index is index into resolved_references
 272         int poolIndex = invokedynamicCPCacheEntryAt(which).getConstantPoolIndex();
 273         poolIndex = invokeDynamicNameAndTypeRefIndexAt(poolIndex);
 274         Assert.that(getTagAt(poolIndex).isNameAndType(), "");
 275         return poolIndex;
 276       }
 277       // change byte-ordering and go via cache
 278       i = remapInstructionOperandFromCache(which);
 279     } else {
 280       if (getTagAt(which).isInvokeDynamic()) {
 281         int poolIndex = invokeDynamicNameAndTypeRefIndexAt(which);
 282         Assert.that(getTagAt(poolIndex).isNameAndType(), "");
 283         return poolIndex;
 284       }
 285     }
 286     // assert(tag_at(i).is_field_or_method(), "Corrupted constant pool");
 287     // assert(!tag_at(i).is_invoke_dynamic(), "Must be handled above");
 288     int refIndex = getIntAt(i);
 289     return extractHighShortFromInt(refIndex);
 290   }
 291 
 292   private int remapInstructionOperandFromCache(int operand) {
 293     int cpc_index = operand;
 294     // DEBUG_ONLY(cpc_index -= CPCACHE_INDEX_TAG);
 295     // assert((int)(u2)cpc_index == cpc_index, "clean u2");
 296     int member_index = getCache().getEntryAt(cpc_index).getConstantPoolIndex();
 297     return member_index;
 298   }
 299 
 300   public int invokeDynamicNameAndTypeRefIndexAt(int which) {
 301     // assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
 302     return extractHighShortFromInt(getIntAt(which));
 303   }
 304 
 305   // returns null, if not resolved.
 306   public Klass getKlassAt(int which) {
 307     if( ! getTagAt(which).isKlass()) return null;
 308     return (Klass)Metadata.instantiateWrapperFor(getAddressAtRaw(which));
 309   }
 310 
 311   public Symbol getKlassNameAt(int which) {
 312     CPSlot entry = getSlotAt(which);
 313     if (entry.isResolved()) {
 314       return entry.getKlass().getName();
 315     } else {
 316       return entry.getSymbol();
 317     }
 318   }
 319 
 320   public Symbol getUnresolvedStringAt(int which) {
 321     return getSlotAt(which).getSymbol();
 322   }
 323 
 324   // returns null, if not resolved.
 325   public InstanceKlass getFieldOrMethodKlassRefAt(int which) {
 326     int refIndex = getFieldOrMethodAt(which);
 327     int klassIndex = extractLowShortFromInt(refIndex);
 328     return (InstanceKlass) getKlassAt(klassIndex);
 329   }
 330 
 331   // returns null, if not resolved.
 332   public Method getMethodRefAt(int which) {
 333     InstanceKlass klass = getFieldOrMethodKlassRefAt(which);
 334     if (klass == null) return null;
 335     Symbol name = getNameRefAt(which);
 336     Symbol sig  = getSignatureRefAt(which);
 337     return klass.findMethod(name, sig);
 338   }
 339 
 340   // returns null, if not resolved.
 341   public Field getFieldRefAt(int which) {
 342     InstanceKlass klass = getFieldOrMethodKlassRefAt(which);
 343     if (klass == null) return null;
 344     Symbol name = getNameRefAt(which);
 345     Symbol sig  = getSignatureRefAt(which);
 346     return klass.findField(name, sig);
 347   }
 348 
 349   public int getNameAndTypeRefIndexAt(int index) {
 350     return implNameAndTypeRefIndexAt(index, false);
 351   }
 352 
 353   /** Lookup for entries consisting of (name_index, signature_index) */
 354   public int getNameRefIndexAt(int index) {
 355     int[] refIndex = getNameAndTypeAt(index);
 356     if (DEBUG) {
 357       System.err.println("ConstantPool.getNameRefIndexAt(" + index + "): refIndex = " + refIndex[0]+"/"+refIndex[1]);
 358     }
 359     int i = refIndex[0];
 360     if (DEBUG) {
 361       System.err.println("ConstantPool.getNameRefIndexAt(" + index + "): result = " + i);
 362     }
 363     return i;
 364   }
 365 
 366   /** Lookup for entries consisting of (name_index, signature_index) */
 367   public int getSignatureRefIndexAt(int index) {
 368     int[] refIndex = getNameAndTypeAt(index);
 369     if (DEBUG) {
 370       System.err.println("ConstantPool.getSignatureRefIndexAt(" + index + "): refIndex = " + refIndex[0]+"/"+refIndex[1]);
 371     }
 372     int i = refIndex[1];
 373     if (DEBUG) {
 374       System.err.println("ConstantPool.getSignatureRefIndexAt(" + index + "): result = " + i);
 375     }
 376     return i;
 377   }
 378 
 379   /** Lookup for MethodHandle entries. */
 380   public int getMethodHandleIndexAt(int i) {
 381     if (Assert.ASSERTS_ENABLED) {
 382       Assert.that(getTagAt(i).isMethodHandle(), "Corrupted constant pool");
 383     }
 384     int res = extractHighShortFromInt(getIntAt(i));
 385     if (DEBUG) {
 386       System.err.println("ConstantPool.getMethodHandleIndexAt(" + i + "): result = " + res);
 387     }
 388     return res;
 389   }
 390 
 391   /** Lookup for MethodHandle entries. */
 392   public int getMethodHandleRefKindAt(int i) {
 393     if (Assert.ASSERTS_ENABLED) {
 394       Assert.that(getTagAt(i).isMethodHandle(), "Corrupted constant pool");
 395     }
 396     int res = extractLowShortFromInt(getIntAt(i));
 397     if (DEBUG) {
 398       System.err.println("ConstantPool.getMethodHandleRefKindAt(" + i + "): result = " + res);
 399     }
 400     return res;
 401   }
 402 
 403   /** Lookup for MethodType entries. */
 404   public int getMethodTypeIndexAt(int i) {
 405     if (Assert.ASSERTS_ENABLED) {
 406       Assert.that(getTagAt(i).isMethodType(), "Corrupted constant pool");
 407     }
 408     int res = getIntAt(i);
 409     if (DEBUG) {
 410       System.err.println("ConstantPool.getMethodHandleTypeAt(" + i + "): result = " + res);
 411     }
 412     return res;
 413   }
 414 
 415   /** Lookup for multi-operand (InvokeDynamic) entries. */
 416   public short[] getBootstrapSpecifierAt(int i) {
 417     if (Assert.ASSERTS_ENABLED) {
 418       Assert.that(getTagAt(i).isInvokeDynamic(), "Corrupted constant pool");
 419     }
 420     int bsmSpec = extractLowShortFromInt(this.getIntAt(i));
 421     U2Array operands = getOperands();
 422     if (operands == null)  return null;  // safety first
 423     int basePos = VM.getVM().buildIntFromShorts(operands.at(bsmSpec * 2 + 0),
 424                                                 operands.at(bsmSpec * 2 + 1));
 425     int argv = basePos + INDY_ARGV_OFFSET;
 426     int argc = operands.at(basePos + INDY_ARGC_OFFSET);
 427     int endPos = argv + argc;
 428     short[] values = new short[endPos - basePos];
 429     for (int j = 0; j < values.length; j++) {
 430         values[j] = operands.at(basePos+j);
 431     }
 432     return values;
 433   }
 434 
 435   final private static String[] nameForTag = new String[] {
 436   };
 437 
 438   private String nameForTag(int tag) {
 439     switch (tag) {
 440     case JVM_CONSTANT_Utf8:               return "JVM_CONSTANT_Utf8";
 441     case JVM_CONSTANT_Unicode:            return "JVM_CONSTANT_Unicode";
 442     case JVM_CONSTANT_Integer:            return "JVM_CONSTANT_Integer";
 443     case JVM_CONSTANT_Float:              return "JVM_CONSTANT_Float";
 444     case JVM_CONSTANT_Long:               return "JVM_CONSTANT_Long";
 445     case JVM_CONSTANT_Double:             return "JVM_CONSTANT_Double";
 446     case JVM_CONSTANT_Class:              return "JVM_CONSTANT_Class";
 447     case JVM_CONSTANT_String:             return "JVM_CONSTANT_String";
 448     case JVM_CONSTANT_Fieldref:           return "JVM_CONSTANT_Fieldref";
 449     case JVM_CONSTANT_Methodref:          return "JVM_CONSTANT_Methodref";
 450     case JVM_CONSTANT_InterfaceMethodref: return "JVM_CONSTANT_InterfaceMethodref";
 451     case JVM_CONSTANT_NameAndType:        return "JVM_CONSTANT_NameAndType";
 452     case JVM_CONSTANT_MethodHandle:       return "JVM_CONSTANT_MethodHandle";
 453     case JVM_CONSTANT_MethodType:         return "JVM_CONSTANT_MethodType";
 454     case JVM_CONSTANT_InvokeDynamic:      return "JVM_CONSTANT_InvokeDynamic";
 455     case JVM_CONSTANT_Invalid:            return "JVM_CONSTANT_Invalid";
 456     case JVM_CONSTANT_UnresolvedClass:    return "JVM_CONSTANT_UnresolvedClass";
 457     case JVM_CONSTANT_ClassIndex:         return "JVM_CONSTANT_ClassIndex";
 458     case JVM_CONSTANT_StringIndex:        return "JVM_CONSTANT_StringIndex";
 459     case JVM_CONSTANT_UnresolvedClassInError:    return "JVM_CONSTANT_UnresolvedClassInError";
 460     case JVM_CONSTANT_MethodHandleInError:return "JVM_CONSTANT_MethodHandleInError";
 461     case JVM_CONSTANT_MethodTypeInError:  return "JVM_CONSTANT_MethodTypeInError";
 462     }
 463     throw new InternalError("Unknown tag: " + tag);
 464   }
 465 
 466   public void iterateFields(MetadataVisitor visitor) {
 467     super.iterateFields(visitor);
 468     visitor.doMetadata(poolHolder, true);
 469 
 470       final int length = (int) getLength();
 471       // zero'th pool entry is always invalid. ignore it.
 472       for (int index = 1; index < length; index++) {
 473       int ctag = (int) getTags().at((int) index);
 474         switch (ctag) {
 475         case JVM_CONSTANT_ClassIndex:
 476         case JVM_CONSTANT_StringIndex:
 477         case JVM_CONSTANT_Integer:
 478           visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
 479           break;
 480 
 481         case JVM_CONSTANT_Float:
 482           visitor.doFloat(new FloatField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
 483           break;
 484 
 485         case JVM_CONSTANT_Long:
 486           visitor.doLong(new LongField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
 487           // long entries occupy two slots
 488           index++;
 489           break;
 490 
 491         case JVM_CONSTANT_Double:
 492           visitor.doDouble(new DoubleField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
 493           // double entries occupy two slots
 494           index++;
 495           break;
 496 
 497         case JVM_CONSTANT_UnresolvedClassInError:
 498         case JVM_CONSTANT_UnresolvedClass:
 499         case JVM_CONSTANT_Class:
 500         case JVM_CONSTANT_Utf8:
 501           visitor.doOop(new OopField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
 502           break;
 503 
 504         case JVM_CONSTANT_Fieldref:
 505         case JVM_CONSTANT_Methodref:
 506         case JVM_CONSTANT_InterfaceMethodref:
 507         case JVM_CONSTANT_NameAndType:
 508         case JVM_CONSTANT_MethodHandle:
 509         case JVM_CONSTANT_MethodType:
 510         case JVM_CONSTANT_InvokeDynamic:
 511           visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
 512           break;
 513         }
 514       }
 515     }
 516 
 517   public void writeBytes(OutputStream os) throws IOException {
 518           // Map between any modified UTF-8 and it's constant pool index.
 519           Map utf8ToIndex = new HashMap();
 520       DataOutputStream dos = new DataOutputStream(os);
 521       U1Array tags = getTags();
 522       int len = (int)getLength();
 523       int ci = 0; // constant pool index
 524 
 525       // collect all modified UTF-8 Strings from Constant Pool
 526 
 527       for (ci = 1; ci < len; ci++) {
 528           int cpConstType = tags.at(ci);
 529           if(cpConstType == JVM_CONSTANT_Utf8) {
 530               Symbol sym = getSymbolAt(ci);
 531               utf8ToIndex.put(sym.asString(), new Short((short) ci));
 532           }
 533           else if(cpConstType == JVM_CONSTANT_Long ||
 534                   cpConstType == JVM_CONSTANT_Double) {
 535               ci++;
 536           }
 537       }
 538 
 539 
 540       for(ci = 1; ci < len; ci++) {
 541           int cpConstType = tags.at(ci);
 542           // write cp_info
 543           // write constant type
 544           switch(cpConstType) {
 545               case JVM_CONSTANT_Utf8: {
 546                   dos.writeByte(cpConstType);
 547                   Symbol sym = getSymbolAt(ci);
 548                   dos.writeShort((short)sym.getLength());
 549                   dos.write(sym.asByteArray());
 550                   if (DEBUG) debugMessage("CP[" + ci + "] = modified UTF-8 " + sym.asString());
 551                   break;
 552               }
 553 
 554               case JVM_CONSTANT_Unicode:
 555                   throw new IllegalArgumentException("Unicode constant!");
 556 
 557               case JVM_CONSTANT_Integer:
 558                   dos.writeByte(cpConstType);
 559                   dos.writeInt(getIntAt(ci));
 560                   if (DEBUG) debugMessage("CP[" + ci + "] = int " + getIntAt(ci));
 561                   break;
 562 
 563               case JVM_CONSTANT_Float:
 564                   dos.writeByte(cpConstType);
 565                   dos.writeFloat(getFloatAt(ci));
 566                   if (DEBUG) debugMessage("CP[" + ci + "] = float " + getFloatAt(ci));
 567                   break;
 568 
 569               case JVM_CONSTANT_Long: {
 570                   dos.writeByte(cpConstType);
 571                   long l = getLongAt(ci);
 572                   // long entries occupy two pool entries
 573                   ci++;
 574                   dos.writeLong(l);
 575                   break;
 576               }
 577 
 578               case JVM_CONSTANT_Double:
 579                   dos.writeByte(cpConstType);
 580                   dos.writeDouble(getDoubleAt(ci));
 581                   // double entries occupy two pool entries
 582                   ci++;
 583                   break;
 584 
 585               case JVM_CONSTANT_Class: {
 586                   dos.writeByte(cpConstType);
 587                   // Klass already resolved. ConstantPool constains Klass*.
 588                   Klass refKls = (Klass)Metadata.instantiateWrapperFor(getAddressAtRaw(ci));
 589                   String klassName = refKls.getName().asString();
 590                   Short s = (Short) utf8ToIndex.get(klassName);
 591                   dos.writeShort(s.shortValue());
 592                   if (DEBUG) debugMessage("CP[" + ci  + "] = class " + s);
 593                   break;
 594               }
 595 
 596               // case JVM_CONSTANT_ClassIndex:
 597               case JVM_CONSTANT_UnresolvedClassInError:
 598               case JVM_CONSTANT_UnresolvedClass: {
 599                   dos.writeByte(JVM_CONSTANT_Class);
 600                   String klassName = getSymbolAt(ci).asString();
 601                   Short s = (Short) utf8ToIndex.get(klassName);
 602                   dos.writeShort(s.shortValue());
 603                   if (DEBUG) debugMessage("CP[" + ci + "] = class " + s);
 604                   break;
 605               }
 606 
 607               case JVM_CONSTANT_String: {
 608                   dos.writeByte(cpConstType);
 609                   String str = getUnresolvedStringAt(ci).asString();
 610                   Short s = (Short) utf8ToIndex.get(str);
 611                   dos.writeShort(s.shortValue());
 612                   if (DEBUG) debugMessage("CP[" + ci + "] = string " + s);
 613                   break;
 614               }
 615 
 616               // all external, internal method/field references
 617               case JVM_CONSTANT_Fieldref:
 618               case JVM_CONSTANT_Methodref:
 619               case JVM_CONSTANT_InterfaceMethodref: {
 620                   dos.writeByte(cpConstType);
 621                   int value = getIntAt(ci);
 622                   short klassIndex = (short) extractLowShortFromInt(value);
 623                   short nameAndTypeIndex = (short) extractHighShortFromInt(value);
 624                   dos.writeShort(klassIndex);
 625                   dos.writeShort(nameAndTypeIndex);
 626                   if (DEBUG) debugMessage("CP[" + ci + "] = ref klass = " +
 627                                           klassIndex + ", N&T = " + nameAndTypeIndex);
 628                   break;
 629               }
 630 
 631               case JVM_CONSTANT_NameAndType: {
 632                   dos.writeByte(cpConstType);
 633                   int value = getIntAt(ci);
 634                   short nameIndex = (short) extractLowShortFromInt(value);
 635                   short signatureIndex = (short) extractHighShortFromInt(value);
 636                   dos.writeShort(nameIndex);
 637                   dos.writeShort(signatureIndex);
 638                   if (DEBUG) debugMessage("CP[" + ci + "] = N&T name = " + nameIndex
 639                                           + ", type = " + signatureIndex);
 640                   break;
 641               }
 642 
 643               case JVM_CONSTANT_MethodHandle: {
 644                   dos.writeByte(cpConstType);
 645                   int value = getIntAt(ci);
 646                   byte refKind = (byte) extractLowShortFromInt(value);
 647                   short memberIndex = (short) extractHighShortFromInt(value);
 648                   dos.writeByte(refKind);
 649                   dos.writeShort(memberIndex);
 650                   if (DEBUG) debugMessage("CP[" + ci + "] = MH kind = " +
 651                                           refKind + ", mem = " + memberIndex);
 652                   break;
 653               }
 654 
 655               case JVM_CONSTANT_MethodType: {
 656                   dos.writeByte(cpConstType);
 657                   int value = getIntAt(ci);
 658                   short refIndex = (short) value;
 659                   dos.writeShort(refIndex);
 660                   if (DEBUG) debugMessage("CP[" + ci + "] = MT index = " + refIndex);
 661                   break;
 662               }
 663 
 664               case JVM_CONSTANT_InvokeDynamic: {
 665                   dos.writeByte(cpConstType);
 666                   int value = getIntAt(ci);
 667                   short bsmIndex = (short) extractLowShortFromInt(value);
 668                   short nameAndTypeIndex = (short) extractHighShortFromInt(value);
 669                   dos.writeShort(bsmIndex);
 670                   dos.writeShort(nameAndTypeIndex);
 671                   if (DEBUG) debugMessage("CP[" + ci + "] = INDY bsm = " +
 672                                           bsmIndex + ", N&T = " + nameAndTypeIndex);
 673                   break;
 674               }
 675 
 676               default:
 677                   throw new InternalError("Unknown tag: " + cpConstType);
 678           } // switch
 679       }
 680       dos.flush();
 681       return;
 682   }
 683 
 684   public void printValueOn(PrintStream tty) {
 685     tty.print("ConstantPool for " + getPoolHolder().getName().asString());
 686   }
 687 
 688   public long getSize() {
 689     return alignSize(headerSize + getLength());
 690   }
 691 
 692   //----------------------------------------------------------------------
 693   // Internals only below this point
 694   //
 695 
 696   private static int extractHighShortFromInt(int val) {
 697     // must stay in sync with ConstantPool::name_and_type_at_put, method_at_put, etc.
 698     return (val >> 16) & 0xFFFF;
 699   }
 700 
 701   private static int extractLowShortFromInt(int val) {
 702     // must stay in sync with ConstantPool::name_and_type_at_put, method_at_put, etc.
 703     return val & 0xFFFF;
 704   }
 705 }