View Javadoc
1   /*
2    * Copyright (c) 2000, 2013, 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 getSymbolAt(which);
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 }