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