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
25package sun.jvm.hotspot.oops;
26
27import java.io.*;
28import java.util.*;
29import sun.jvm.hotspot.debugger.*;
30import sun.jvm.hotspot.runtime.*;
31import sun.jvm.hotspot.types.*;
32import sun.jvm.hotspot.utilities.*;
33
34// A ConstantPool is an oop containing class constants
35// as described in the class file
36
37public 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 the object index.  The object map points at
273  // the cpCache index and the cpCache entry points at the original constant
274  // pool index.
275  public int invokedynamicCPCacheIndex(int index) {
276    Assert.that(isInvokedynamicIndex(index), "should be a invokedynamic index");
277    int rawIndex = decodeInvokedynamicIndex(index);
278    return referenceMap().at(rawIndex);
279  }
280
281  ConstantPoolCacheEntry invokedynamicCPCacheEntryAt(int index) {
282    // decode index that invokedynamic points to.
283    int cpCacheIndex = invokedynamicCPCacheIndex(index);
284    return getCache().getEntryAt(cpCacheIndex);
285  }
286
287  private int implNameAndTypeRefIndexAt(int which, boolean uncached) {
288    int i = which;
289    if (!uncached && getCache() != null) {
290      if (isInvokedynamicIndex(which)) {
291        // Invokedynamic index is index into resolved_references
292        int poolIndex = invokedynamicCPCacheEntryAt(which).getConstantPoolIndex();
293        poolIndex = invokeDynamicNameAndTypeRefIndexAt(poolIndex);
294        Assert.that(getTagAt(poolIndex).isNameAndType(), "");
295        return poolIndex;
296      }
297      // change byte-ordering and go via cache
298      i = remapInstructionOperandFromCache(which);
299    } else {
300      if (getTagAt(which).isInvokeDynamic()) {
301        int poolIndex = invokeDynamicNameAndTypeRefIndexAt(which);
302        Assert.that(getTagAt(poolIndex).isNameAndType(), "");
303        return poolIndex;
304      }
305    }
306    // assert(tag_at(i).is_field_or_method(), "Corrupted constant pool");
307    // assert(!tag_at(i).is_invoke_dynamic(), "Must be handled above");
308    int refIndex = getIntAt(i);
309    return extractHighShortFromInt(refIndex);
310  }
311
312  private int remapInstructionOperandFromCache(int operand) {
313    int cpc_index = operand;
314    // DEBUG_ONLY(cpc_index -= CPCACHE_INDEX_TAG);
315    // assert((int)(u2)cpc_index == cpc_index, "clean u2");
316    int member_index = getCache().getEntryAt(cpc_index).getConstantPoolIndex();
317    return member_index;
318  }
319
320  public int invokeDynamicNameAndTypeRefIndexAt(int which) {
321    // assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
322    return extractHighShortFromInt(getIntAt(which));
323  }
324
325  // returns null, if not resolved.
326  public Klass getKlassAt(int which) {
327    if( ! getTagAt(which).isKlass()) return null;
328    int resolved_klass_index = getKlassSlotAt(which).getResolvedKlassIndex();
329    KlassArray resolved_klasses = getResolvedKlasses();
330    return resolved_klasses.getAt(resolved_klass_index);
331  }
332
333  public Symbol getKlassNameAt(int which) {
334    int name_index = getKlassSlotAt(which).getNameIndex();
335    return getSymbolAt(name_index);
336  }
337
338  public Symbol getUnresolvedStringAt(int which) {
339    return getSlotAt(which).getSymbol();
340  }
341
342  // returns null, if not resolved.
343  public InstanceKlass getFieldOrMethodKlassRefAt(int which) {
344    int refIndex = getFieldOrMethodAt(which);
345    int klassIndex = extractLowShortFromInt(refIndex);
346    return (InstanceKlass) getKlassAt(klassIndex);
347  }
348
349  // returns null, if not resolved.
350  public Method getMethodRefAt(int which) {
351    InstanceKlass klass = getFieldOrMethodKlassRefAt(which);
352    if (klass == null) return null;
353    Symbol name = getNameRefAt(which);
354    Symbol sig  = getSignatureRefAt(which);
355    return klass.findMethod(name, sig);
356  }
357
358  // returns null, if not resolved.
359  public Field getFieldRefAt(int which) {
360    InstanceKlass klass = getFieldOrMethodKlassRefAt(which);
361    if (klass == null) return null;
362    Symbol name = getNameRefAt(which);
363    Symbol sig  = getSignatureRefAt(which);
364    return klass.findField(name, sig);
365  }
366
367  public int getNameAndTypeRefIndexAt(int index) {
368    return implNameAndTypeRefIndexAt(index, false);
369  }
370
371  /** Lookup for entries consisting of (name_index, signature_index) */
372  public int getNameRefIndexAt(int index) {
373    int[] refIndex = getNameAndTypeAt(index);
374    if (DEBUG) {
375      System.err.println("ConstantPool.getNameRefIndexAt(" + index + "): refIndex = " + refIndex[0]+"/"+refIndex[1]);
376    }
377    int i = refIndex[0];
378    if (DEBUG) {
379      System.err.println("ConstantPool.getNameRefIndexAt(" + index + "): result = " + i);
380    }
381    return i;
382  }
383
384  /** Lookup for entries consisting of (name_index, signature_index) */
385  public int getSignatureRefIndexAt(int index) {
386    int[] refIndex = getNameAndTypeAt(index);
387    if (DEBUG) {
388      System.err.println("ConstantPool.getSignatureRefIndexAt(" + index + "): refIndex = " + refIndex[0]+"/"+refIndex[1]);
389    }
390    int i = refIndex[1];
391    if (DEBUG) {
392      System.err.println("ConstantPool.getSignatureRefIndexAt(" + index + "): result = " + i);
393    }
394    return i;
395  }
396
397  /** Lookup for MethodHandle entries. */
398  public int getMethodHandleIndexAt(int i) {
399    if (Assert.ASSERTS_ENABLED) {
400      Assert.that(getTagAt(i).isMethodHandle(), "Corrupted constant pool");
401    }
402    int res = extractHighShortFromInt(getIntAt(i));
403    if (DEBUG) {
404      System.err.println("ConstantPool.getMethodHandleIndexAt(" + i + "): result = " + res);
405    }
406    return res;
407  }
408
409  /** Lookup for MethodHandle entries. */
410  public int getMethodHandleRefKindAt(int i) {
411    if (Assert.ASSERTS_ENABLED) {
412      Assert.that(getTagAt(i).isMethodHandle(), "Corrupted constant pool");
413    }
414    int res = extractLowShortFromInt(getIntAt(i));
415    if (DEBUG) {
416      System.err.println("ConstantPool.getMethodHandleRefKindAt(" + i + "): result = " + res);
417    }
418    return res;
419  }
420
421  /** Lookup for MethodType entries. */
422  public int getMethodTypeIndexAt(int i) {
423    if (Assert.ASSERTS_ENABLED) {
424      Assert.that(getTagAt(i).isMethodType(), "Corrupted constant pool");
425    }
426    int res = getIntAt(i);
427    if (DEBUG) {
428      System.err.println("ConstantPool.getMethodHandleTypeAt(" + i + "): result = " + res);
429    }
430    return res;
431  }
432
433  /** Lookup for multi-operand (InvokeDynamic) entries. */
434  public short[] getBootstrapSpecifierAt(int i) {
435    if (Assert.ASSERTS_ENABLED) {
436      Assert.that(getTagAt(i).isInvokeDynamic(), "Corrupted constant pool");
437    }
438    int bsmSpec = extractLowShortFromInt(this.getIntAt(i));
439    U2Array operands = getOperands();
440    if (operands == null)  return null;  // safety first
441    int basePos = VM.getVM().buildIntFromShorts(operands.at(bsmSpec * 2 + 0),
442                                                operands.at(bsmSpec * 2 + 1));
443    int argv = basePos + INDY_ARGV_OFFSET;
444    int argc = operands.at(basePos + INDY_ARGC_OFFSET);
445    int endPos = argv + argc;
446    short[] values = new short[endPos - basePos];
447    for (int j = 0; j < values.length; j++) {
448        values[j] = operands.at(basePos+j);
449    }
450    return values;
451  }
452
453  final private static String[] nameForTag = new String[] {
454  };
455
456  private String nameForTag(int tag) {
457    switch (tag) {
458    case JVM_CONSTANT_Utf8:               return "JVM_CONSTANT_Utf8";
459    case JVM_CONSTANT_Unicode:            return "JVM_CONSTANT_Unicode";
460    case JVM_CONSTANT_Integer:            return "JVM_CONSTANT_Integer";
461    case JVM_CONSTANT_Float:              return "JVM_CONSTANT_Float";
462    case JVM_CONSTANT_Long:               return "JVM_CONSTANT_Long";
463    case JVM_CONSTANT_Double:             return "JVM_CONSTANT_Double";
464    case JVM_CONSTANT_Class:              return "JVM_CONSTANT_Class";
465    case JVM_CONSTANT_String:             return "JVM_CONSTANT_String";
466    case JVM_CONSTANT_Fieldref:           return "JVM_CONSTANT_Fieldref";
467    case JVM_CONSTANT_Methodref:          return "JVM_CONSTANT_Methodref";
468    case JVM_CONSTANT_InterfaceMethodref: return "JVM_CONSTANT_InterfaceMethodref";
469    case JVM_CONSTANT_NameAndType:        return "JVM_CONSTANT_NameAndType";
470    case JVM_CONSTANT_MethodHandle:       return "JVM_CONSTANT_MethodHandle";
471    case JVM_CONSTANT_MethodType:         return "JVM_CONSTANT_MethodType";
472    case JVM_CONSTANT_InvokeDynamic:      return "JVM_CONSTANT_InvokeDynamic";
473    case JVM_CONSTANT_Invalid:            return "JVM_CONSTANT_Invalid";
474    case JVM_CONSTANT_UnresolvedClass:    return "JVM_CONSTANT_UnresolvedClass";
475    case JVM_CONSTANT_ClassIndex:         return "JVM_CONSTANT_ClassIndex";
476    case JVM_CONSTANT_StringIndex:        return "JVM_CONSTANT_StringIndex";
477    case JVM_CONSTANT_UnresolvedClassInError:    return "JVM_CONSTANT_UnresolvedClassInError";
478    case JVM_CONSTANT_MethodHandleInError:return "JVM_CONSTANT_MethodHandleInError";
479    case JVM_CONSTANT_MethodTypeInError:  return "JVM_CONSTANT_MethodTypeInError";
480    }
481    throw new InternalError("Unknown tag: " + tag);
482  }
483
484  public void iterateFields(MetadataVisitor visitor) {
485    super.iterateFields(visitor);
486    visitor.doMetadata(poolHolder, true);
487
488      final int length = (int) getLength();
489      // zero'th pool entry is always invalid. ignore it.
490      for (int index = 1; index < length; index++) {
491      int ctag = (int) getTags().at((int) index);
492        switch (ctag) {
493        case JVM_CONSTANT_ClassIndex:
494        case JVM_CONSTANT_StringIndex:
495        case JVM_CONSTANT_Integer:
496          visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
497          break;
498
499        case JVM_CONSTANT_Float:
500          visitor.doFloat(new FloatField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
501          break;
502
503        case JVM_CONSTANT_Long:
504          visitor.doLong(new LongField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
505          // long entries occupy two slots
506          index++;
507          break;
508
509        case JVM_CONSTANT_Double:
510          visitor.doDouble(new DoubleField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
511          // double entries occupy two slots
512          index++;
513          break;
514
515        case JVM_CONSTANT_UnresolvedClassInError:
516        case JVM_CONSTANT_UnresolvedClass:
517        case JVM_CONSTANT_Class:
518        case JVM_CONSTANT_Utf8:
519          visitor.doOop(new OopField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
520          break;
521
522        case JVM_CONSTANT_Fieldref:
523        case JVM_CONSTANT_Methodref:
524        case JVM_CONSTANT_InterfaceMethodref:
525        case JVM_CONSTANT_NameAndType:
526        case JVM_CONSTANT_MethodHandle:
527        case JVM_CONSTANT_MethodType:
528        case JVM_CONSTANT_InvokeDynamic:
529          visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
530          break;
531        }
532      }
533    }
534
535  public void writeBytes(OutputStream os) throws IOException {
536          // Map between any modified UTF-8 and it's constant pool index.
537          Map utf8ToIndex = new HashMap();
538      DataOutputStream dos = new DataOutputStream(os);
539      U1Array tags = getTags();
540      int len = (int)getLength();
541      int ci = 0; // constant pool index
542
543      // collect all modified UTF-8 Strings from Constant Pool
544
545      for (ci = 1; ci < len; ci++) {
546          int cpConstType = tags.at(ci);
547          if(cpConstType == JVM_CONSTANT_Utf8) {
548              Symbol sym = getSymbolAt(ci);
549              utf8ToIndex.put(sym.asString(), new Short((short) ci));
550          }
551          else if(cpConstType == JVM_CONSTANT_Long ||
552                  cpConstType == JVM_CONSTANT_Double) {
553              ci++;
554          }
555      }
556
557
558      for(ci = 1; ci < len; ci++) {
559          int cpConstType = tags.at(ci);
560          // write cp_info
561          // write constant type
562          switch(cpConstType) {
563              case JVM_CONSTANT_Utf8: {
564                  dos.writeByte(cpConstType);
565                  Symbol sym = getSymbolAt(ci);
566                  dos.writeShort((short)sym.getLength());
567                  dos.write(sym.asByteArray());
568                  if (DEBUG) debugMessage("CP[" + ci + "] = modified UTF-8 " + sym.asString());
569                  break;
570              }
571
572              case JVM_CONSTANT_Unicode:
573                  throw new IllegalArgumentException("Unicode constant!");
574
575              case JVM_CONSTANT_Integer:
576                  dos.writeByte(cpConstType);
577                  dos.writeInt(getIntAt(ci));
578                  if (DEBUG) debugMessage("CP[" + ci + "] = int " + getIntAt(ci));
579                  break;
580
581              case JVM_CONSTANT_Float:
582                  dos.writeByte(cpConstType);
583                  dos.writeFloat(getFloatAt(ci));
584                  if (DEBUG) debugMessage("CP[" + ci + "] = float " + getFloatAt(ci));
585                  break;
586
587              case JVM_CONSTANT_Long: {
588                  dos.writeByte(cpConstType);
589                  long l = getLongAt(ci);
590                  // long entries occupy two pool entries
591                  ci++;
592                  dos.writeLong(l);
593                  break;
594              }
595
596              case JVM_CONSTANT_Double:
597                  dos.writeByte(cpConstType);
598                  dos.writeDouble(getDoubleAt(ci));
599                  // double entries occupy two pool entries
600                  ci++;
601                  break;
602
603              case JVM_CONSTANT_Class: {
604                  dos.writeByte(cpConstType);
605                  // Klass already resolved. ConstantPool constains Klass*.
606                  Klass refKls = (Klass)Metadata.instantiateWrapperFor(getAddressAtRaw(ci));
607                  String klassName = refKls.getName().asString();
608                  Short s = (Short) utf8ToIndex.get(klassName);
609                  dos.writeShort(s.shortValue());
610                  if (DEBUG) debugMessage("CP[" + ci  + "] = class " + s);
611                  break;
612              }
613
614              // case JVM_CONSTANT_ClassIndex:
615              case JVM_CONSTANT_UnresolvedClassInError:
616              case JVM_CONSTANT_UnresolvedClass: {
617                  dos.writeByte(JVM_CONSTANT_Class);
618                  String klassName = getSymbolAt(ci).asString();
619                  Short s = (Short) utf8ToIndex.get(klassName);
620                  dos.writeShort(s.shortValue());
621                  if (DEBUG) debugMessage("CP[" + ci + "] = class " + s);
622                  break;
623              }
624
625              case JVM_CONSTANT_String: {
626                  dos.writeByte(cpConstType);
627                  String str = getUnresolvedStringAt(ci).asString();
628                  Short s = (Short) utf8ToIndex.get(str);
629                  dos.writeShort(s.shortValue());
630                  if (DEBUG) debugMessage("CP[" + ci + "] = string " + s);
631                  break;
632              }
633
634              // all external, internal method/field references
635              case JVM_CONSTANT_Fieldref:
636              case JVM_CONSTANT_Methodref:
637              case JVM_CONSTANT_InterfaceMethodref: {
638                  dos.writeByte(cpConstType);
639                  int value = getIntAt(ci);
640                  short klassIndex = (short) extractLowShortFromInt(value);
641                  short nameAndTypeIndex = (short) extractHighShortFromInt(value);
642                  dos.writeShort(klassIndex);
643                  dos.writeShort(nameAndTypeIndex);
644                  if (DEBUG) debugMessage("CP[" + ci + "] = ref klass = " +
645                                          klassIndex + ", N&T = " + nameAndTypeIndex);
646                  break;
647              }
648
649              case JVM_CONSTANT_NameAndType: {
650                  dos.writeByte(cpConstType);
651                  int value = getIntAt(ci);
652                  short nameIndex = (short) extractLowShortFromInt(value);
653                  short signatureIndex = (short) extractHighShortFromInt(value);
654                  dos.writeShort(nameIndex);
655                  dos.writeShort(signatureIndex);
656                  if (DEBUG) debugMessage("CP[" + ci + "] = N&T name = " + nameIndex
657                                          + ", type = " + signatureIndex);
658                  break;
659              }
660
661              case JVM_CONSTANT_MethodHandle: {
662                  dos.writeByte(cpConstType);
663                  int value = getIntAt(ci);
664                  byte refKind = (byte) extractLowShortFromInt(value);
665                  short memberIndex = (short) extractHighShortFromInt(value);
666                  dos.writeByte(refKind);
667                  dos.writeShort(memberIndex);
668                  if (DEBUG) debugMessage("CP[" + ci + "] = MH kind = " +
669                                          refKind + ", mem = " + memberIndex);
670                  break;
671              }
672
673              case JVM_CONSTANT_MethodType: {
674                  dos.writeByte(cpConstType);
675                  int value = getIntAt(ci);
676                  short refIndex = (short) value;
677                  dos.writeShort(refIndex);
678                  if (DEBUG) debugMessage("CP[" + ci + "] = MT index = " + refIndex);
679                  break;
680              }
681
682              case JVM_CONSTANT_InvokeDynamic: {
683                  dos.writeByte(cpConstType);
684                  int value = getIntAt(ci);
685                  short bsmIndex = (short) extractLowShortFromInt(value);
686                  short nameAndTypeIndex = (short) extractHighShortFromInt(value);
687                  dos.writeShort(bsmIndex);
688                  dos.writeShort(nameAndTypeIndex);
689                  if (DEBUG) debugMessage("CP[" + ci + "] = INDY bsm = " +
690                                          bsmIndex + ", N&T = " + nameAndTypeIndex);
691                  break;
692              }
693
694              default:
695                  throw new InternalError("Unknown tag: " + cpConstType);
696          } // switch
697      }
698      dos.flush();
699      return;
700  }
701
702  public void printValueOn(PrintStream tty) {
703    tty.print("ConstantPool for " + getPoolHolder().getName().asString());
704  }
705
706  public long getSize() {
707    return alignSize(headerSize + getLength());
708  }
709
710  //----------------------------------------------------------------------
711  // Internals only below this point
712  //
713
714  private static int extractHighShortFromInt(int val) {
715    // must stay in sync with ConstantPool::name_and_type_at_put, method_at_put, etc.
716    return (val >> 16) & 0xFFFF;
717  }
718
719  private static int extractLowShortFromInt(int val) {
720    // must stay in sync with ConstantPool::name_and_type_at_put, method_at_put, etc.
721    return val & 0xFFFF;
722  }
723}
724