1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.bcel.internal.generic;
  23 
  24 
  25 import com.sun.org.apache.bcel.internal.Constants;
  26 import com.sun.org.apache.bcel.internal.classfile.*;
  27 import java.util.HashMap;
  28 
  29 /**
  30  * This class is used to build up a constant pool. The user adds
  31  * constants via `addXXX' methods, `addString', `addClass',
  32  * etc.. These methods return an index into the constant
  33  * pool. Finally, `getFinalConstantPool()' returns the constant pool
  34  * built up. Intermediate versions of the constant pool can be
  35  * obtained with `getConstantPool()'. A constant pool has capacity for
  36  * Constants.MAX_SHORT entries. Note that the first (0) is used by the
  37  * JVM and that Double and Long constants need two slots.
  38  *
  39  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  40  * @see Constant
  41  */
  42 public class ConstantPoolGen implements java.io.Serializable {
  43   protected int        size      = 1024; // Inital size, sufficient in most cases
  44   protected Constant[] constants = new Constant[size];
  45   protected int        index     = 1; // First entry (0) used by JVM
  46 
  47   private static final String METHODREF_DELIM  = ":";
  48   private static final String IMETHODREF_DELIM = "#";
  49   private static final String FIELDREF_DELIM   = "&";
  50   private static final String NAT_DELIM        = "%";
  51 
  52   private static class Index implements java.io.Serializable {
  53     int index;
  54     Index(int i) { index = i; }
  55   }
  56 
  57   /**
  58    * Initialize with given array of constants.
  59    *
  60    * @param c array of given constants, new ones will be appended
  61    */
  62   public ConstantPoolGen(Constant[] cs) {
  63     if(cs.length > size) {
  64       size      = cs.length;
  65       constants = new Constant[size];
  66     }
  67 
  68     System.arraycopy(cs, 0, constants, 0, cs.length);
  69 
  70     if(cs.length > 0)
  71       index = cs.length;
  72 
  73     for(int i=1; i < index; i++) {
  74       Constant c = constants[i];
  75 
  76       if(c instanceof ConstantString) {
  77         ConstantString s  = (ConstantString)c;
  78         ConstantUtf8   u8 = (ConstantUtf8)constants[s.getStringIndex()];
  79 
  80         string_table.put(u8.getBytes(), new Index(i));
  81       } else if(c instanceof ConstantClass) {
  82         ConstantClass s  = (ConstantClass)c;
  83         ConstantUtf8  u8 = (ConstantUtf8)constants[s.getNameIndex()];
  84 
  85         class_table.put(u8.getBytes(), new Index(i));
  86       } else if(c instanceof ConstantNameAndType) {
  87         ConstantNameAndType n    = (ConstantNameAndType)c;
  88         ConstantUtf8        u8   = (ConstantUtf8)constants[n.getNameIndex()];
  89         ConstantUtf8        u8_2 = (ConstantUtf8)constants[n.getSignatureIndex()];
  90 
  91         n_a_t_table.put(u8.getBytes() + NAT_DELIM + u8_2.getBytes(), new Index(i));
  92        } else if(c instanceof ConstantUtf8) {
  93          ConstantUtf8 u = (ConstantUtf8)c;
  94 
  95          utf8_table.put(u.getBytes(), new Index(i));
  96       } else if(c instanceof ConstantCP) {
  97         ConstantCP          m     = (ConstantCP)c;
  98         ConstantClass       clazz = (ConstantClass)constants[m.getClassIndex()];
  99         ConstantNameAndType n     = (ConstantNameAndType)constants[m.getNameAndTypeIndex()];
 100 
 101         ConstantUtf8 u8         = (ConstantUtf8)constants[clazz.getNameIndex()];
 102         String       class_name = u8.getBytes().replace('/', '.');
 103 
 104         u8 = (ConstantUtf8)constants[n.getNameIndex()];
 105         String method_name = u8.getBytes();
 106 
 107         u8 = (ConstantUtf8)constants[n.getSignatureIndex()];
 108         String signature = u8.getBytes();
 109 
 110         String delim = METHODREF_DELIM;
 111 
 112         if(c instanceof ConstantInterfaceMethodref)
 113           delim = IMETHODREF_DELIM;
 114         else if(c instanceof ConstantFieldref)
 115           delim = FIELDREF_DELIM;
 116 
 117         cp_table.put(class_name + delim + method_name + delim + signature, new Index(i));
 118       }
 119     }
 120   }
 121 
 122   /**
 123    * Initialize with given constant pool.
 124    */
 125   public ConstantPoolGen(ConstantPool cp) {
 126     this(cp.getConstantPool());
 127   }
 128 
 129   /**
 130    * Create empty constant pool.
 131    */
 132   public ConstantPoolGen() {}
 133 
 134   /** Resize internal array of constants.
 135    */
 136   protected void adjustSize() {
 137     if(index + 3 >= size) {
 138       Constant[] cs = constants;
 139 
 140       size      *= 2;
 141       constants  = new Constant[size];
 142       System.arraycopy(cs, 0, constants, 0, index);
 143     }
 144   }
 145 
 146   private HashMap string_table = new HashMap();
 147 
 148   /**
 149    * Look for ConstantString in ConstantPool containing String `str'.
 150    *
 151    * @param str String to search for
 152    * @return index on success, -1 otherwise
 153    */
 154   public int lookupString(String str) {
 155     Index index = (Index)string_table.get(str);
 156     return (index != null)? index.index : -1;
 157   }
 158 
 159   /**
 160    * Add a new String constant to the ConstantPool, if it is not already in there.
 161    *
 162    * @param str String to add
 163    * @return index of entry
 164    */
 165   public int addString(String str) {
 166     int ret;
 167 
 168     if((ret = lookupString(str)) != -1)
 169       return ret; // Already in CP
 170 
 171     int utf8 = addUtf8(str);
 172 
 173     adjustSize();
 174 
 175     ConstantString s  = new ConstantString(utf8);
 176 
 177     ret = index;
 178     constants[index++] = s;
 179 
 180     string_table.put(str, new Index(ret));
 181 
 182     return ret;
 183   }
 184 
 185   private HashMap class_table = new HashMap();
 186 
 187   /**
 188    * Look for ConstantClass in ConstantPool named `str'.
 189    *
 190    * @param str String to search for
 191    * @return index on success, -1 otherwise
 192    */
 193   public int lookupClass(String str) {
 194     Index index = (Index)class_table.get(str.replace('.', '/'));
 195     return (index != null)? index.index : -1;
 196   }
 197 
 198   private int addClass_(String clazz) {
 199     int    ret;
 200 
 201     if((ret = lookupClass(clazz)) != -1)
 202       return ret; // Already in CP
 203 
 204     adjustSize();
 205 
 206     ConstantClass c = new ConstantClass(addUtf8(clazz));
 207 
 208     ret = index;
 209     constants[index++] = c;
 210 
 211     class_table.put(clazz, new Index(ret));
 212 
 213     return ret;
 214   }
 215 
 216   /**
 217    * Add a new Class reference to the ConstantPool, if it is not already in there.
 218    *
 219    * @param str Class to add
 220    * @return index of entry
 221    */
 222   public int addClass(String str) {
 223     return addClass_(str.replace('.', '/'));
 224   }
 225 
 226   /**
 227    * Add a new Class reference to the ConstantPool for a given type.
 228    *
 229    * @param str Class to add
 230    * @return index of entry
 231    */
 232   public int addClass(ObjectType type) {
 233     return addClass(type.getClassName());
 234   }
 235 
 236   /**
 237    * Add a reference to an array class (e.g. String[][]) as needed by MULTIANEWARRAY
 238    * instruction, e.g. to the ConstantPool.
 239    *
 240    * @param type type of array class
 241    * @return index of entry
 242    */
 243   public int addArrayClass(ArrayType type) {
 244     return addClass_(type.getSignature());
 245   }
 246 
 247   /**
 248    * Look for ConstantInteger in ConstantPool.
 249    *
 250    * @param n integer number to look for
 251    * @return index on success, -1 otherwise
 252    */
 253   public int lookupInteger(int n) {
 254     for(int i=1; i < index; i++) {
 255       if(constants[i] instanceof ConstantInteger) {
 256         ConstantInteger c = (ConstantInteger)constants[i];
 257 
 258         if(c.getBytes() == n)
 259           return i;
 260       }
 261     }
 262 
 263     return -1;
 264   }
 265 
 266   /**
 267    * Add a new Integer constant to the ConstantPool, if it is not already in there.
 268    *
 269    * @param n integer number to add
 270    * @return index of entry
 271    */
 272   public int addInteger(int n) {
 273     int  ret;
 274 
 275     if((ret = lookupInteger(n)) != -1)
 276       return ret; // Already in CP
 277 
 278     adjustSize();
 279 
 280     ret = index;
 281     constants[index++] = new ConstantInteger(n);
 282 
 283     return ret;
 284   }
 285 
 286   /**
 287    * Look for ConstantFloat in ConstantPool.
 288    *
 289    * @param n Float number to look for
 290    * @return index on success, -1 otherwise
 291    */
 292   public int lookupFloat(float n) {
 293     int bits = Float.floatToIntBits(n);
 294 
 295     for(int i=1; i < index; i++) {
 296       if(constants[i] instanceof ConstantFloat) {
 297         ConstantFloat c = (ConstantFloat)constants[i];
 298 
 299         if(Float.floatToIntBits(c.getBytes()) == bits)
 300           return i;
 301       }
 302     }
 303 
 304     return -1;
 305   }
 306 
 307   /**
 308    * Add a new Float constant to the ConstantPool, if it is not already in there.
 309    *
 310    * @param n Float number to add
 311    * @return index of entry
 312    */
 313   public int addFloat(float n) {
 314     int  ret;
 315 
 316     if((ret = lookupFloat(n)) != -1)
 317       return ret; // Already in CP
 318 
 319     adjustSize();
 320 
 321     ret = index;
 322     constants[index++] = new ConstantFloat(n);
 323 
 324     return ret;
 325   }
 326 
 327   private HashMap utf8_table = new HashMap();
 328 
 329   /**
 330    * Look for ConstantUtf8 in ConstantPool.
 331    *
 332    * @param n Utf8 string to look for
 333    * @return index on success, -1 otherwise
 334    */
 335   public int lookupUtf8(String n) {
 336     Index index = (Index)utf8_table.get(n);
 337 
 338     return (index != null)? index.index : -1;
 339   }
 340 
 341   /**
 342    * Add a new Utf8 constant to the ConstantPool, if it is not already in there.
 343    *
 344    * @param n Utf8 string to add
 345    * @return index of entry
 346    */
 347   public int addUtf8(String n) {
 348     int  ret;
 349 
 350     if((ret = lookupUtf8(n)) != -1)
 351       return ret; // Already in CP
 352 
 353     adjustSize();
 354 
 355     ret = index;
 356     constants[index++] = new ConstantUtf8(n);
 357 
 358     utf8_table.put(n, new Index(ret));
 359 
 360     return ret;
 361   }
 362 
 363   /**
 364    * Look for ConstantLong in ConstantPool.
 365    *
 366    * @param n Long number to look for
 367    * @return index on success, -1 otherwise
 368    */
 369   public int lookupLong(long n) {
 370     for(int i=1; i < index; i++) {
 371       if(constants[i] instanceof ConstantLong) {
 372         ConstantLong c = (ConstantLong)constants[i];
 373 
 374         if(c.getBytes() == n)
 375           return i;
 376       }
 377     }
 378 
 379     return -1;
 380   }
 381 
 382   /**
 383    * Add a new long constant to the ConstantPool, if it is not already in there.
 384    *
 385    * @param n Long number to add
 386    * @return index of entry
 387    */
 388   public int addLong(long n) {
 389     int  ret;
 390 
 391     if((ret = lookupLong(n)) != -1)
 392       return ret; // Already in CP
 393 
 394     adjustSize();
 395 
 396     ret = index;
 397     constants[index] = new ConstantLong(n);
 398     index += 2;   // Wastes one entry according to spec
 399 
 400     return ret;
 401   }
 402 
 403   /**
 404    * Look for ConstantDouble in ConstantPool.
 405    *
 406    * @param n Double number to look for
 407    * @return index on success, -1 otherwise
 408    */
 409   public int lookupDouble(double n) {
 410     long bits = Double.doubleToLongBits(n);
 411 
 412     for(int i=1; i < index; i++) {
 413       if(constants[i] instanceof ConstantDouble) {
 414         ConstantDouble c = (ConstantDouble)constants[i];
 415 
 416         if(Double.doubleToLongBits(c.getBytes()) == bits)
 417           return i;
 418       }
 419     }
 420 
 421     return -1;
 422   }
 423 
 424   /**
 425    * Add a new double constant to the ConstantPool, if it is not already in there.
 426    *
 427    * @param n Double number to add
 428    * @return index of entry
 429    */
 430   public int addDouble(double n) {
 431     int  ret;
 432 
 433     if((ret = lookupDouble(n)) != -1)
 434       return ret; // Already in CP
 435 
 436     adjustSize();
 437 
 438     ret = index;
 439     constants[index] = new ConstantDouble(n);
 440     index += 2;   // Wastes one entry according to spec
 441 
 442     return ret;
 443   }
 444 
 445   private HashMap n_a_t_table = new HashMap();
 446 
 447   /**
 448    * Look for ConstantNameAndType in ConstantPool.
 449    *
 450    * @param name of variable/method
 451    * @param signature of variable/method
 452    * @return index on success, -1 otherwise
 453    */
 454   public int lookupNameAndType(String name, String signature) {
 455     Index index = (Index)n_a_t_table.get(name + NAT_DELIM + signature);
 456     return (index != null)? index.index : -1;
 457   }
 458 
 459   /**
 460    * Add a new NameAndType constant to the ConstantPool if it is not already
 461    * in there.
 462    *
 463    * @param n NameAndType string to add
 464    * @return index of entry
 465    */
 466   public int addNameAndType(String name, String signature) {
 467     int  ret;
 468     int  name_index, signature_index;
 469 
 470     if((ret = lookupNameAndType(name, signature)) != -1)
 471       return ret; // Already in CP
 472 
 473     adjustSize();
 474 
 475     name_index      = addUtf8(name);
 476     signature_index = addUtf8(signature);
 477     ret = index;
 478     constants[index++] = new ConstantNameAndType(name_index, signature_index);
 479 
 480     n_a_t_table.put(name + NAT_DELIM + signature, new Index(ret));
 481     return ret;
 482   }
 483 
 484   private HashMap cp_table = new HashMap();
 485 
 486   /**
 487    * Look for ConstantMethodref in ConstantPool.
 488    *
 489    * @param class_name Where to find method
 490    * @param method_name Guess what
 491    * @param signature return and argument types
 492    * @return index on success, -1 otherwise
 493    */
 494   public int lookupMethodref(String class_name, String method_name, String signature) {
 495     Index index = (Index)cp_table.get(class_name + METHODREF_DELIM + method_name +
 496                                       METHODREF_DELIM + signature);
 497     return (index != null)? index.index : -1;
 498   }
 499 
 500   public int lookupMethodref(MethodGen method) {
 501     return lookupMethodref(method.getClassName(), method.getName(),
 502                           method.getSignature());
 503   }
 504 
 505   /**
 506    * Add a new Methodref constant to the ConstantPool, if it is not already
 507    * in there.
 508    *
 509    * @param n Methodref string to add
 510    * @return index of entry
 511    */
 512   public int addMethodref(String class_name, String method_name, String signature) {
 513     int  ret, class_index, name_and_type_index;
 514 
 515     if((ret = lookupMethodref(class_name, method_name, signature)) != -1)
 516       return ret; // Already in CP
 517 
 518     adjustSize();
 519 
 520     name_and_type_index = addNameAndType(method_name, signature);
 521     class_index         = addClass(class_name);
 522     ret = index;
 523     constants[index++] = new ConstantMethodref(class_index, name_and_type_index);
 524 
 525     cp_table.put(class_name + METHODREF_DELIM + method_name +
 526                  METHODREF_DELIM + signature, new Index(ret));
 527 
 528     return ret;
 529   }
 530 
 531   public int addMethodref(MethodGen method) {
 532     return addMethodref(method.getClassName(), method.getName(),
 533                         method.getSignature());
 534   }
 535 
 536   /**
 537    * Look for ConstantInterfaceMethodref in ConstantPool.
 538    *
 539    * @param class_name Where to find method
 540    * @param method_name Guess what
 541    * @param signature return and argument types
 542    * @return index on success, -1 otherwise
 543    */
 544   public int lookupInterfaceMethodref(String class_name, String method_name, String signature) {
 545     Index index = (Index)cp_table.get(class_name + IMETHODREF_DELIM + method_name +
 546                                       IMETHODREF_DELIM + signature);
 547     return (index != null)? index.index : -1;
 548   }
 549 
 550   public int lookupInterfaceMethodref(MethodGen method) {
 551     return lookupInterfaceMethodref(method.getClassName(), method.getName(),
 552                                     method.getSignature());
 553   }
 554 
 555   /**
 556    * Add a new InterfaceMethodref constant to the ConstantPool, if it is not already
 557    * in there.
 558    *
 559    * @param n InterfaceMethodref string to add
 560    * @return index of entry
 561    */
 562   public int addInterfaceMethodref(String class_name, String method_name, String signature) {
 563     int ret, class_index, name_and_type_index;
 564 
 565     if((ret = lookupInterfaceMethodref(class_name, method_name, signature)) != -1)
 566       return ret; // Already in CP
 567 
 568     adjustSize();
 569 
 570     class_index         = addClass(class_name);
 571     name_and_type_index = addNameAndType(method_name, signature);
 572     ret = index;
 573     constants[index++] = new ConstantInterfaceMethodref(class_index, name_and_type_index);
 574 
 575     cp_table.put(class_name + IMETHODREF_DELIM + method_name +
 576                  IMETHODREF_DELIM + signature, new Index(ret));
 577 
 578     return ret;
 579   }
 580 
 581   public int addInterfaceMethodref(MethodGen method) {
 582     return addInterfaceMethodref(method.getClassName(), method.getName(),
 583                                  method.getSignature());
 584   }
 585 
 586   /**
 587    * Look for ConstantFieldref in ConstantPool.
 588    *
 589    * @param class_name Where to find method
 590    * @param field_name Guess what
 591    * @param signature return and argument types
 592    * @return index on success, -1 otherwise
 593    */
 594   public int lookupFieldref(String class_name, String field_name, String signature) {
 595     Index index = (Index)cp_table.get(class_name + FIELDREF_DELIM + field_name +
 596                                       FIELDREF_DELIM + signature);
 597     return (index != null)? index.index : -1;
 598   }
 599 
 600   /**
 601    * Add a new Fieldref constant to the ConstantPool, if it is not already
 602    * in there.
 603    *
 604    * @param n Fieldref string to add
 605    * @return index of entry
 606    */
 607   public int addFieldref(String class_name, String field_name, String signature) {
 608     int  ret;
 609     int  class_index, name_and_type_index;
 610 
 611     if((ret = lookupFieldref(class_name, field_name, signature)) != -1)
 612       return ret; // Already in CP
 613 
 614     adjustSize();
 615 
 616     class_index         = addClass(class_name);
 617     name_and_type_index = addNameAndType(field_name, signature);
 618     ret = index;
 619     constants[index++] = new ConstantFieldref(class_index, name_and_type_index);
 620 
 621     cp_table.put(class_name + FIELDREF_DELIM + field_name + FIELDREF_DELIM + signature, new Index(ret));
 622 
 623     return ret;
 624   }
 625 
 626   /**
 627    * @param i index in constant pool
 628    * @return constant pool entry at index i
 629    */
 630   public Constant getConstant(int i) { return constants[i]; }
 631 
 632   /**
 633    * Use with care!
 634    *
 635    * @param i index in constant pool
 636    * @param c new constant pool entry at index i
 637    */
 638   public void setConstant(int i, Constant c) { constants[i] = c; }
 639 
 640   /**
 641    * @return intermediate constant pool
 642    */
 643   public ConstantPool getConstantPool() {
 644     return new ConstantPool(constants);
 645   }
 646 
 647   /**
 648    * @return current size of constant pool
 649    */
 650   public int getSize() {
 651     return index;
 652   }
 653 
 654   /**
 655    * @return constant pool with proper length
 656    */
 657   public ConstantPool getFinalConstantPool() {
 658     Constant[] cs = new Constant[index];
 659 
 660     System.arraycopy(constants, 0, cs, 0, index);
 661 
 662     return new ConstantPool(cs);
 663   }
 664 
 665   /**
 666    * @return String representation.
 667    */
 668   public String toString() {
 669     StringBuffer buf = new StringBuffer();
 670 
 671     for(int i=1; i < index; i++)
 672       buf.append(i + ")" + constants[i] + "\n");
 673 
 674     return buf.toString();
 675   }
 676 
 677   /** Import constant from another ConstantPool and return new index.
 678    */
 679   public int addConstant(Constant c, ConstantPoolGen cp) {
 680     Constant[] constants = cp.getConstantPool().getConstantPool();
 681 
 682     switch(c.getTag()) {
 683     case Constants.CONSTANT_String: {
 684       ConstantString s  = (ConstantString)c;
 685       ConstantUtf8   u8 = (ConstantUtf8)constants[s.getStringIndex()];
 686 
 687       return addString(u8.getBytes());
 688     }
 689 
 690     case Constants.CONSTANT_Class: {
 691       ConstantClass s  = (ConstantClass)c;
 692       ConstantUtf8  u8 = (ConstantUtf8)constants[s.getNameIndex()];
 693 
 694       return addClass(u8.getBytes());
 695     }
 696 
 697     case Constants.CONSTANT_NameAndType: {
 698       ConstantNameAndType n    = (ConstantNameAndType)c;
 699       ConstantUtf8        u8   = (ConstantUtf8)constants[n.getNameIndex()];
 700       ConstantUtf8        u8_2 = (ConstantUtf8)constants[n.getSignatureIndex()];
 701 
 702       return addNameAndType(u8.getBytes(), u8_2.getBytes());
 703     }
 704 
 705     case Constants.CONSTANT_Utf8:
 706       return addUtf8(((ConstantUtf8)c).getBytes());
 707 
 708     case Constants.CONSTANT_Double:
 709       return addDouble(((ConstantDouble)c).getBytes());
 710 
 711     case Constants.CONSTANT_Float:
 712       return addFloat(((ConstantFloat)c).getBytes());
 713 
 714     case Constants.CONSTANT_Long:
 715       return addLong(((ConstantLong)c).getBytes());
 716 
 717     case Constants.CONSTANT_Integer:
 718       return addInteger(((ConstantInteger)c).getBytes());
 719 
 720     case Constants.CONSTANT_InterfaceMethodref: case Constants.CONSTANT_Methodref:
 721     case Constants.CONSTANT_Fieldref: {
 722       ConstantCP          m     = (ConstantCP)c;
 723       ConstantClass       clazz = (ConstantClass)constants[m.getClassIndex()];
 724       ConstantNameAndType n     = (ConstantNameAndType)constants[m.getNameAndTypeIndex()];
 725       ConstantUtf8 u8           = (ConstantUtf8)constants[clazz.getNameIndex()];
 726       String       class_name   = u8.getBytes().replace('/', '.');
 727 
 728       u8 = (ConstantUtf8)constants[n.getNameIndex()];
 729       String name = u8.getBytes();
 730 
 731       u8 = (ConstantUtf8)constants[n.getSignatureIndex()];
 732       String signature = u8.getBytes();
 733 
 734       switch(c.getTag()) {
 735       case Constants.CONSTANT_InterfaceMethodref:
 736         return addInterfaceMethodref(class_name, name, signature);
 737 
 738       case Constants.CONSTANT_Methodref:
 739         return addMethodref(class_name, name, signature);
 740 
 741       case Constants.CONSTANT_Fieldref:
 742         return addFieldref(class_name, name, signature);
 743 
 744       default: // Never reached
 745         throw new RuntimeException("Unknown constant type " + c);
 746       }
 747     }
 748 
 749     default: // Never reached
 750       throw new RuntimeException("Unknown constant type " + c);
 751     }
 752   }
 753 }