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