1 /*
   2  * Copyright (c) 2002, 2012, 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.tools.jcore;
  26 
  27 import java.io.*;
  28 import java.util.*;
  29 import sun.jvm.hotspot.oops.*;
  30 import sun.jvm.hotspot.runtime.*;
  31 import sun.jvm.hotspot.utilities.*;
  32 
  33 public class ClassWriter implements /* imports */ ClassConstants
  34 {
  35     public static final boolean DEBUG = false;
  36 
  37     protected void debugMessage(String message) {
  38         System.out.println(message);
  39     }
  40 
  41     protected InstanceKlass     klass;
  42     protected DataOutputStream  dos;
  43     protected ConstantPool      cpool;
  44 
  45     // Map between class name to index of type CONSTANT_Class
  46     protected Map<String, Short> classToIndex = new HashMap<String, Short>();
  47 
  48     // Map between any modified UTF-8 and it's constant pool index.
  49     protected Map<String, Short> utf8ToIndex = new HashMap<String, Short>();
  50 
  51     // constant pool index for attribute names.
  52 
  53     protected short  _sourceFileIndex;
  54     protected short  _innerClassesIndex;
  55     protected short  _syntheticIndex;
  56     protected short  _deprecatedIndex;
  57     protected short  _constantValueIndex;
  58     protected short  _codeIndex;
  59     protected short  _exceptionsIndex;
  60     protected short  _lineNumberTableIndex;
  61     protected short  _localVariableTableIndex;
  62     protected short  _signatureIndex;
  63 
  64     protected static int extractHighShortFromInt(int val) {
  65         // must stay in sync with ConstantPool::name_and_type_at_put, method_at_put, etc.
  66         return (val >> 16) & 0xFFFF;
  67     }
  68 
  69     protected static int extractLowShortFromInt(int val) {
  70         // must stay in sync with ConstantPool::name_and_type_at_put, method_at_put, etc.
  71         return val & 0xFFFF;
  72     }
  73 
  74     public ClassWriter(InstanceKlass kls, OutputStream os) {
  75         klass = kls;
  76         dos = new DataOutputStream(os);
  77         cpool = klass.getConstants();
  78     }
  79 
  80     public void write() throws IOException {
  81         if (DEBUG) debugMessage("class name = " + klass.getName().asString());
  82 
  83         // write magic
  84         dos.writeInt(0xCAFEBABE);
  85 
  86         writeVersion();
  87         writeConstantPool();
  88         writeClassAccessFlags();
  89         writeThisClass();
  90         writeSuperClass();
  91         writeInterfaces();
  92         writeFields();
  93         writeMethods();
  94         writeClassAttributes();
  95 
  96         // flush output
  97         dos.flush();
  98     }
  99 
 100     protected void writeVersion() throws IOException {
 101         dos.writeShort((short)klass.minorVersion());
 102         dos.writeShort((short)klass.majorVersion());
 103     }
 104 
 105     protected void writeIndex(int index) throws IOException {
 106         if (index == 0) throw new InternalError();
 107         dos.writeShort(index);
 108     }
 109 
 110     protected void writeConstantPool() throws IOException {
 111         final U1Array tags = cpool.getTags();
 112         final long len = tags.length();
 113         dos.writeShort((short) len);
 114 
 115         if (DEBUG) debugMessage("constant pool length = " + len);
 116 
 117         int ci = 0; // constant pool index
 118 
 119         // collect all modified UTF-8 Strings from Constant Pool
 120 
 121         for (ci = 1; ci < len; ci++) {
 122             int cpConstType = tags.at(ci);
 123             if(cpConstType == JVM_CONSTANT_Utf8) {
 124                 Symbol sym = cpool.getSymbolAt(ci);
 125                 utf8ToIndex.put(sym.asString(), new Short((short) ci));
 126             }
 127             else if(cpConstType == JVM_CONSTANT_Long ||
 128                       cpConstType == JVM_CONSTANT_Double) {
 129                 ci++;
 130             }
 131         }
 132 
 133         // remember index of attribute name modified UTF-8 strings
 134 
 135         // class attributes
 136         Short sourceFileIndex = (Short) utf8ToIndex.get("SourceFile");
 137         _sourceFileIndex = (sourceFileIndex != null)? sourceFileIndex.shortValue() : 0;
 138         if (DEBUG) debugMessage("SourceFile index = " + _sourceFileIndex);
 139 
 140         Short innerClassesIndex = (Short) utf8ToIndex.get("InnerClasses");
 141         _innerClassesIndex = (innerClassesIndex != null)? innerClassesIndex.shortValue() : 0;
 142         if (DEBUG) debugMessage("InnerClasses index = " + _innerClassesIndex);
 143 
 144         // field attributes
 145         Short constantValueIndex = (Short) utf8ToIndex.get("ConstantValue");
 146         _constantValueIndex = (constantValueIndex != null)?
 147                                           constantValueIndex.shortValue() : 0;
 148         if (DEBUG) debugMessage("ConstantValue index = " + _constantValueIndex);
 149 
 150         Short syntheticIndex = (Short) utf8ToIndex.get("Synthetic");
 151         _syntheticIndex = (syntheticIndex != null)? syntheticIndex.shortValue() : 0;
 152         if (DEBUG) debugMessage("Synthetic index = " + _syntheticIndex);
 153 
 154         Short deprecatedIndex = (Short) utf8ToIndex.get("Deprecated");
 155         _deprecatedIndex = (deprecatedIndex != null)? deprecatedIndex.shortValue() : 0;
 156         if (DEBUG) debugMessage("Deprecated index = " + _deprecatedIndex);
 157 
 158         // method attributes
 159         Short codeIndex = (Short) utf8ToIndex.get("Code");
 160         _codeIndex = (codeIndex != null)? codeIndex.shortValue() : 0;
 161         if (DEBUG) debugMessage("Code index = " + _codeIndex);
 162 
 163         Short exceptionsIndex = (Short) utf8ToIndex.get("Exceptions");
 164         _exceptionsIndex = (exceptionsIndex != null)? exceptionsIndex.shortValue() : 0;
 165         if (DEBUG) debugMessage("Exceptions index = " + _exceptionsIndex);
 166 
 167         // Short syntheticIndex = (Short) utf8ToIndex.get("Synthetic");
 168         // Short deprecatedIndex = (Short) utf8ToIndex.get("Deprecated");
 169 
 170         // Code attributes
 171         Short lineNumberTableIndex = (Short) utf8ToIndex.get("LineNumberTable");
 172         _lineNumberTableIndex = (lineNumberTableIndex != null)?
 173                                        lineNumberTableIndex.shortValue() : 0;
 174         if (DEBUG) debugMessage("LineNumberTable index = " + _lineNumberTableIndex);
 175 
 176         Short localVariableTableIndex = (Short) utf8ToIndex.get("LocalVariableTable");
 177         _localVariableTableIndex = (localVariableTableIndex != null)?
 178                                        localVariableTableIndex.shortValue() : 0;
 179         if (DEBUG) debugMessage("LocalVariableTable index = " + _localVariableTableIndex);
 180 
 181         Short signatureIdx = (Short) utf8ToIndex.get("Signature");
 182         _signatureIndex = (signatureIdx != null)? signatureIdx.shortValue() : 0;
 183         if (DEBUG) debugMessage("Signature index = " + _signatureIndex);
 184 
 185         for(ci = 1; ci < len; ci++) {
 186             int cpConstType = tags.at(ci);
 187             // write cp_info
 188             // write constant type
 189             switch(cpConstType) {
 190                 case JVM_CONSTANT_Utf8: {
 191                      dos.writeByte(cpConstType);
 192                      Symbol sym = cpool.getSymbolAt(ci);
 193                      dos.writeShort((short)sym.getLength());
 194                      dos.write(sym.asByteArray());
 195                      if (DEBUG) debugMessage("CP[" + ci + "] = modified UTF-8 " + sym.asString());
 196                      break;
 197                 }
 198 
 199                 case JVM_CONSTANT_Unicode:
 200                      throw new IllegalArgumentException("Unicode constant!");
 201 
 202                 case JVM_CONSTANT_Integer:
 203                      dos.writeByte(cpConstType);
 204                      dos.writeInt(cpool.getIntAt(ci));
 205                      if (DEBUG) debugMessage("CP[" + ci + "] = int " + cpool.getIntAt(ci));
 206                      break;
 207 
 208                 case JVM_CONSTANT_Float:
 209                      dos.writeByte(cpConstType);
 210                      dos.writeFloat(cpool.getFloatAt(ci));
 211                      if (DEBUG) debugMessage("CP[" + ci + "] = float " + cpool.getFloatAt(ci));
 212                      break;
 213 
 214                 case JVM_CONSTANT_Long: {
 215                      dos.writeByte(cpConstType);
 216                      long l = cpool.getLongAt(ci);
 217                      // long entries occupy two pool entries
 218                      ci++;
 219                      dos.writeLong(l);
 220                      break;
 221                 }
 222 
 223                 case JVM_CONSTANT_Double:
 224                      dos.writeByte(cpConstType);
 225                      dos.writeDouble(cpool.getDoubleAt(ci));
 226                      // double entries occupy two pool entries
 227                      ci++;
 228                      break;
 229 
 230                 case JVM_CONSTANT_Class:
 231                 case JVM_CONSTANT_UnresolvedClass:
 232                 case JVM_CONSTANT_UnresolvedClassInError: {
 233                      dos.writeByte(JVM_CONSTANT_Class);
 234                      String klassName = cpool.getKlassNameAt(ci).asString();
 235                      Short s = (Short) utf8ToIndex.get(klassName);
 236                      classToIndex.put(klassName, new Short((short)ci));
 237                      dos.writeShort(s.shortValue());
 238                      if (DEBUG) debugMessage("CP[" + ci  + "] = class " + s);
 239                      break;
 240                 }
 241 
 242                 case JVM_CONSTANT_String: {
 243                      dos.writeByte(cpConstType);
 244                      String str = cpool.getUnresolvedStringAt(ci).asString();
 245                      Short s = (Short) utf8ToIndex.get(str);
 246                      dos.writeShort(s.shortValue());
 247                      if (DEBUG) debugMessage("CP[" + ci + "] = string " + s);
 248                      break;
 249                 }
 250 
 251                 // all external, internal method/field references
 252                 case JVM_CONSTANT_Fieldref:
 253                 case JVM_CONSTANT_Methodref:
 254                 case JVM_CONSTANT_InterfaceMethodref: {
 255                      dos.writeByte(cpConstType);
 256                      int value = cpool.getIntAt(ci);
 257                      short klassIndex = (short) extractLowShortFromInt(value);
 258                      short nameAndTypeIndex = (short) extractHighShortFromInt(value);
 259                      dos.writeShort(klassIndex);
 260                      dos.writeShort(nameAndTypeIndex);
 261                      if (DEBUG) debugMessage("CP[" + ci + "] = ref klass = " +
 262                            klassIndex + ", N&T = " + nameAndTypeIndex);
 263                      break;
 264                 }
 265 
 266                 case JVM_CONSTANT_NameAndType: {
 267                      dos.writeByte(cpConstType);
 268                      int value = cpool.getIntAt(ci);
 269                      short nameIndex = (short) extractLowShortFromInt(value);
 270                      short signatureIndex = (short) extractHighShortFromInt(value);
 271                      dos.writeShort(nameIndex);
 272                      dos.writeShort(signatureIndex);
 273                      if (DEBUG) debugMessage("CP[" + ci + "] = N&T name = " + nameIndex
 274                                         + ", type = " + signatureIndex);
 275                      break;
 276                 }
 277 
 278                 case JVM_CONSTANT_MethodHandle: {
 279                      dos.writeByte(cpConstType);
 280                      int value = cpool.getIntAt(ci);
 281                      byte refKind = (byte) extractLowShortFromInt(value);
 282                      short memberIndex = (short) extractHighShortFromInt(value);
 283                      dos.writeByte(refKind);
 284                      dos.writeShort(memberIndex);
 285                      if (DEBUG) debugMessage("CP[" + ci + "] = MH kind = " +
 286                            refKind + ", mem = " + memberIndex);
 287                      break;
 288                 }
 289 
 290                 case JVM_CONSTANT_MethodType: {
 291                      dos.writeByte(cpConstType);
 292                      int value = cpool.getIntAt(ci);
 293                      short refIndex = (short) value;
 294                      dos.writeShort(refIndex);
 295                      if (DEBUG) debugMessage("CP[" + ci + "] = MT index = " + refIndex);
 296                      break;
 297                 }
 298 
 299                 case JVM_CONSTANT_InvokeDynamic: {
 300                      dos.writeByte(cpConstType);
 301                      int value = cpool.getIntAt(ci);
 302                      short bsmIndex = (short) extractLowShortFromInt(value);
 303                      short nameAndTypeIndex = (short) extractHighShortFromInt(value);
 304                      dos.writeShort(bsmIndex);
 305                      dos.writeShort(nameAndTypeIndex);
 306                      if (DEBUG) debugMessage("CP[" + ci + "] = INDY bsm = " +
 307                            bsmIndex + ", N&T = " + nameAndTypeIndex);
 308                      break;
 309                 }
 310 
 311                 default:
 312                   throw new InternalError("Unknown tag: " + cpConstType);
 313             } // switch
 314         }
 315     }
 316 
 317     protected void writeClassAccessFlags() throws IOException {
 318         int flags = (int)(klass.getAccessFlags() & JVM_RECOGNIZED_CLASS_MODIFIERS);
 319         dos.writeShort((short)flags);
 320     }
 321 
 322     protected void writeThisClass() throws IOException {
 323         String klassName = klass.getName().asString();
 324         Short index = (Short) classToIndex.get(klassName);
 325         dos.writeShort(index.shortValue());
 326         if (DEBUG) debugMessage("this class = " + index);
 327     }
 328 
 329     protected void writeSuperClass() throws IOException {
 330         Klass superKlass = klass.getSuper();
 331         if (superKlass != null) { // is not java.lang.Object
 332             String superName = superKlass.getName().asString();
 333             Short index = (Short) classToIndex.get(superName);
 334             if (DEBUG) debugMessage("super class = " + index);
 335             dos.writeShort(index.shortValue());
 336         } else {
 337             dos.writeShort(0); // no super class
 338         }
 339     }
 340     protected void writeInterfaces() throws IOException {
 341         KlassArray interfaces = klass.getLocalInterfaces();
 342         final int len = interfaces.length();
 343 
 344         if (DEBUG) debugMessage("number of interfaces = " + len);
 345 
 346         // write interfaces count
 347         dos.writeShort((short) len);
 348         for (int i = 0; i < len; i++) {
 349            Klass k = interfaces.getAt(i);
 350            Short index = (Short) classToIndex.get(k.getName().asString());
 351            dos.writeShort(index.shortValue());
 352            if (DEBUG) debugMessage("\t" + index);
 353         }
 354     }
 355 
 356     protected void writeFields() throws IOException {
 357         final int javaFieldsCount = klass.getJavaFieldsCount();
 358 
 359         // write number of fields
 360         dos.writeShort((short) javaFieldsCount);
 361 
 362         if (DEBUG) debugMessage("number of fields = " + javaFieldsCount);
 363 
 364         for (int index = 0; index < javaFieldsCount; index++) {
 365             short accessFlags    = klass.getFieldAccessFlags(index);
 366             dos.writeShort(accessFlags & (short) JVM_RECOGNIZED_FIELD_MODIFIERS);
 367 
 368             short nameIndex    = klass.getFieldNameIndex(index);
 369             dos.writeShort(nameIndex);
 370 
 371             short signatureIndex = klass.getFieldSignatureIndex(index);
 372             dos.writeShort(signatureIndex);
 373             if (DEBUG) debugMessage("\tfield name = " + nameIndex + ", signature = " + signatureIndex);
 374 
 375             short fieldAttributeCount = 0;
 376             boolean hasSyn = hasSyntheticAttribute(accessFlags);
 377             if (hasSyn)
 378                 fieldAttributeCount++;
 379 
 380             short initvalIndex = klass.getFieldInitialValueIndex(index);
 381             if (initvalIndex != 0)
 382                 fieldAttributeCount++;
 383 
 384             short genSigIndex = klass.getFieldGenericSignatureIndex(index);
 385             if (genSigIndex != 0)
 386                 fieldAttributeCount++;
 387 
 388             dos.writeShort(fieldAttributeCount);
 389 
 390             // write synthetic, if applicable
 391             if (hasSyn)
 392                 writeSynthetic();
 393 
 394             if (initvalIndex != 0) {
 395                 writeIndex(_constantValueIndex);
 396                 dos.writeInt(2);
 397                 dos.writeShort(initvalIndex);
 398                 if (DEBUG) debugMessage("\tfield init value = " + initvalIndex);
 399             }
 400 
 401             if (genSigIndex != 0) {
 402                 writeIndex(_signatureIndex);
 403                 dos.writeInt(2);
 404                 dos.writeShort(genSigIndex);
 405                 if (DEBUG) debugMessage("\tfield generic signature index " + genSigIndex);
 406             }
 407         }
 408     }
 409 
 410     protected boolean isSynthetic(short accessFlags) {
 411         return (accessFlags & (short) JVM_ACC_SYNTHETIC) != 0;
 412     }
 413 
 414     protected boolean hasSyntheticAttribute(short accessFlags) {
 415         // Check if flags have the attribute and if the constant pool contains an entry for it.
 416         return isSynthetic(accessFlags) && _syntheticIndex != 0;
 417     }
 418 
 419     protected void writeSynthetic() throws IOException {
 420         writeIndex(_syntheticIndex);
 421         dos.writeInt(0);
 422     }
 423 
 424     protected void writeMethods() throws IOException {
 425         MethodArray methods = klass.getMethods();
 426         ArrayList<Method> valid_methods = new ArrayList<Method>();
 427         for (int i = 0; i < methods.length(); i++) {
 428             Method m = methods.at(i);
 429             long accessFlags = m.getAccessFlags();
 430             // overpass method
 431             if (accessFlags == (JVM_ACC_PUBLIC | JVM_ACC_SYNTHETIC | JVM_ACC_BRIDGE)) {
 432                 continue;
 433             }
 434             final boolean isNative = ((accessFlags & JVM_ACC_NATIVE) != 0);
 435             final boolean isAbstract = ((accessFlags & JVM_ACC_ABSTRACT) != 0);
 436             final boolean isCodeAvailable = (!isNative) && (!isAbstract);
 437             // If _codeIndex == 0 but code exists we're in an
 438             // interface and we're dealing with a default method. Skip
 439             // it.
 440             if (isCodeAvailable && _codeIndex == 0) {
 441                 continue;
 442             }
 443             valid_methods.add(m);
 444         }
 445         final int len = valid_methods.size();
 446         // write number of methods
 447         dos.writeShort((short) len);
 448         if (DEBUG) debugMessage("number of methods = " + len);
 449         for (int m = 0; m < len; m++) {
 450             writeMethod(valid_methods.get(m));
 451         }
 452     }
 453 
 454     protected void writeMethod(Method m) throws IOException {
 455         long accessFlags = m.getAccessFlags();
 456         dos.writeShort((short) (accessFlags & JVM_RECOGNIZED_METHOD_MODIFIERS));
 457         dos.writeShort((short) m.getNameIndex());
 458         dos.writeShort((short) m.getSignatureIndex());
 459         if (DEBUG) debugMessage("\tmethod name = " + m.getNameIndex() + ", signature = "
 460                         + m.getSignatureIndex());
 461 
 462         final boolean isNative = ((accessFlags & JVM_ACC_NATIVE) != 0);
 463         final boolean isAbstract = ((accessFlags & JVM_ACC_ABSTRACT) != 0);
 464 
 465         short methodAttributeCount = 0;
 466 
 467         final boolean hasSyn = hasSyntheticAttribute((short)accessFlags);
 468         if (hasSyn)
 469             methodAttributeCount++;
 470 
 471         final boolean hasCheckedExceptions = m.hasCheckedExceptions();
 472         if (hasCheckedExceptions)
 473             methodAttributeCount++;
 474 
 475         final boolean isCodeAvailable = (!isNative) && (!isAbstract);
 476         if (isCodeAvailable)
 477             methodAttributeCount++;
 478 
 479         final boolean isGeneric = (m.getGenericSignature() != null);
 480         if (isGeneric)
 481             methodAttributeCount++;
 482 
 483         dos.writeShort(methodAttributeCount);
 484         if (DEBUG) debugMessage("\tmethod attribute count = " + methodAttributeCount);
 485 
 486         if (hasSyn) {
 487             if (DEBUG) debugMessage("\tmethod is synthetic");
 488             writeSynthetic();
 489         }
 490 
 491         if (isCodeAvailable) {
 492             byte[] code = m.getByteCode();
 493             short codeAttrCount = 0;
 494             int codeSize  = 2           /* max_stack   */ +
 495                             2           /* max_locals  */ +
 496                             4           /* code_length */ +
 497                             code.length /* code        */ +
 498                             2           /* exp. table len.  */ +
 499                             2           /* code attr. count */;
 500 
 501             boolean hasExceptionTable = m.hasExceptionTable();
 502             ExceptionTableElement[] exceptionTable = null;
 503             int exceptionTableLen = 0;
 504             if (hasExceptionTable) {
 505                 exceptionTable = m.getExceptionTable();
 506                 exceptionTableLen = exceptionTable.length;
 507                 if (DEBUG) debugMessage("\tmethod has exception table");
 508                 codeSize += exceptionTableLen /* exception table is 4-tuple array */
 509                                          * (2 /* start_pc     */ +
 510                                             2 /* end_pc       */ +
 511                                             2 /* handler_pc   */ +
 512                                             2 /* catch_type   */);
 513             }
 514 
 515             boolean hasLineNumberTable = m.hasLineNumberTable();
 516             LineNumberTableElement[] lineNumberTable = null;
 517             int lineNumberAttrLen = 0;
 518 
 519             if (hasLineNumberTable) {
 520                 if (DEBUG) debugMessage("\tmethod has line number table");
 521                 lineNumberTable = m.getLineNumberTable();
 522                 if (DEBUG) debugMessage("\t\tline table length = " + lineNumberTable.length);
 523 
 524                 lineNumberAttrLen = 2 /* line number table length         */ +
 525                            lineNumberTable.length * (2 /* start_pc */ + 2 /* line_number */);
 526 
 527                 codeSize += 2 /* line number table attr index     */ +
 528                             4 /* line number table attr length    */ +
 529                             lineNumberAttrLen;
 530 
 531                 if (DEBUG) debugMessage("\t\tline number table attr size = " +
 532                                               lineNumberAttrLen);
 533 
 534                 codeAttrCount++;
 535             }
 536 
 537             boolean hasLocalVariableTable = m.hasLocalVariableTable();
 538             LocalVariableTableElement[] localVariableTable = null;
 539             int localVarAttrLen = 0;
 540 
 541             if (hasLocalVariableTable) {
 542                 if (DEBUG) debugMessage("\tmethod has local variable table");
 543                 localVariableTable = m.getLocalVariableTable();
 544                 if (DEBUG) debugMessage("\t\tlocal variable table length = "
 545                               + localVariableTable.length);
 546                 localVarAttrLen =
 547                                2 /* local variable table length      */ +
 548                                localVariableTable.length * ( 2 /* start_pc          */ +
 549                                                           2 /* length            */ +
 550                                                           2 /* name_index        */ +
 551                                                           2 /* signature_index   */ +
 552                                                           2 /* variable index    */ );
 553 
 554                 if (DEBUG) debugMessage("\t\tlocal variable attr size = " +
 555                                               localVarAttrLen);
 556 
 557                 codeSize += 2 /* local variable table attr index  */ +
 558                             4 /* local variable table attr length */ +
 559                             localVarAttrLen;
 560 
 561                 codeAttrCount++;
 562             }
 563 
 564             // fix ConstantPoolCache indices to ConstantPool indices.
 565             rewriteByteCode(m, code);
 566 
 567             // start writing Code
 568 
 569             writeIndex(_codeIndex);
 570 
 571             dos.writeInt(codeSize);
 572             if (DEBUG) debugMessage("\tcode attribute length = " + codeSize);
 573 
 574             dos.writeShort((short) m.getMaxStack());
 575             if (DEBUG) debugMessage("\tmax stack = " + m.getMaxStack());
 576 
 577             dos.writeShort((short) m.getMaxLocals());
 578             if (DEBUG) debugMessage("\tmax locals = " + m.getMaxLocals());
 579 
 580             dos.writeInt(code.length);
 581             if (DEBUG) debugMessage("\tcode size = " + code.length);
 582 
 583             dos.write(code);
 584 
 585             // write exception table size
 586             dos.writeShort((short) exceptionTableLen);
 587             if (DEBUG) debugMessage("\texception table length = " + exceptionTableLen);
 588 
 589             if (exceptionTableLen != 0) {
 590                 for (int e = 0; e < exceptionTableLen; e++) {
 591                      dos.writeShort((short) exceptionTable[e].getStartPC());
 592                      dos.writeShort((short) exceptionTable[e].getEndPC());
 593                      dos.writeShort((short) exceptionTable[e].getHandlerPC());
 594                      dos.writeShort((short) exceptionTable[e].getCatchTypeIndex());
 595                 }
 596             }
 597 
 598             dos.writeShort((short)codeAttrCount);
 599             if (DEBUG) debugMessage("\tcode attribute count = " + codeAttrCount);
 600 
 601             // write LineNumberTable, if available.
 602             if (hasLineNumberTable) {
 603                 writeIndex(_lineNumberTableIndex);
 604                 dos.writeInt(lineNumberAttrLen);
 605                 dos.writeShort((short) lineNumberTable.length);
 606                 for (int l = 0; l < lineNumberTable.length; l++) {
 607                      dos.writeShort((short) lineNumberTable[l].getStartBCI());
 608                      dos.writeShort((short) lineNumberTable[l].getLineNumber());
 609                 }
 610             }
 611 
 612             // write LocalVariableTable, if available.
 613             if (hasLocalVariableTable) {
 614                 writeIndex((short) _localVariableTableIndex);
 615                 dos.writeInt(localVarAttrLen);
 616                 dos.writeShort((short) localVariableTable.length);
 617                 for (int l = 0; l < localVariableTable.length; l++) {
 618                      dos.writeShort((short) localVariableTable[l].getStartBCI());
 619                      dos.writeShort((short) localVariableTable[l].getLength());
 620                      dos.writeShort((short) localVariableTable[l].getNameCPIndex());
 621                      dos.writeShort((short) localVariableTable[l].getDescriptorCPIndex());
 622                      dos.writeShort((short) localVariableTable[l].getSlot());
 623                 }
 624             }
 625         }
 626 
 627         if (hasCheckedExceptions) {
 628             CheckedExceptionElement[] exceptions = m.getCheckedExceptions();
 629             writeIndex(_exceptionsIndex);
 630 
 631             int attrSize = 2 /* number_of_exceptions */ +
 632                            exceptions.length * 2 /* exception_index */;
 633             dos.writeInt(attrSize);
 634             dos.writeShort(exceptions.length);
 635             if (DEBUG) debugMessage("\tmethod has " + exceptions.length
 636                                         +  " checked exception(s)");
 637             for (int e = 0; e < exceptions.length; e++) {
 638                  short cpIndex = (short) exceptions[e].getClassCPIndex();
 639                  dos.writeShort(cpIndex);
 640             }
 641         }
 642 
 643         if (isGeneric) {
 644            writeGenericSignature(m.getGenericSignature().asString());
 645         }
 646     }
 647 
 648     protected void rewriteByteCode(Method m, byte[] code) {
 649         ByteCodeRewriter r = new ByteCodeRewriter(m, cpool, code);
 650         r.rewrite();
 651     }
 652 
 653     protected void writeGenericSignature(String signature) throws IOException {
 654         writeIndex(_signatureIndex);
 655         if (DEBUG) debugMessage("signature attribute = " + _signatureIndex);
 656         dos.writeInt(2);
 657         Short index = (Short) utf8ToIndex.get(signature);
 658         dos.writeShort(index.shortValue());
 659         if (DEBUG) debugMessage("generic signature = " + index);
 660     }
 661 
 662     protected void writeClassAttributes() throws IOException {
 663         final long flags = klass.getAccessFlags();
 664         final boolean hasSyn = hasSyntheticAttribute((short) flags);
 665 
 666         // check for source file
 667         short classAttributeCount = 0;
 668 
 669         if (hasSyn)
 670             classAttributeCount++;
 671 
 672         Symbol sourceFileName = klass.getSourceFileName();
 673         if (sourceFileName != null)
 674             classAttributeCount++;
 675 
 676         Symbol genericSignature = klass.getGenericSignature();
 677         if (genericSignature != null)
 678             classAttributeCount++;
 679 
 680         U2Array innerClasses = klass.getInnerClasses();
 681         final int numInnerClasses = (int) (innerClasses.length() / 4);
 682         if (numInnerClasses != 0)
 683             classAttributeCount++;
 684 
 685         dos.writeShort(classAttributeCount);
 686         if (DEBUG) debugMessage("class attribute count = " + classAttributeCount);
 687 
 688         if (hasSyn)
 689             writeSynthetic();
 690 
 691         // write SourceFile, if any
 692         if (sourceFileName != null) {
 693             writeIndex(_sourceFileIndex);
 694             if (DEBUG) debugMessage("source file attribute = " + _sourceFileIndex);
 695             dos.writeInt(2);
 696             Short index = (Short) utf8ToIndex.get(sourceFileName.asString());
 697             dos.writeShort(index.shortValue());
 698             if (DEBUG) debugMessage("source file name = " + index);
 699         }
 700 
 701         // write Signature, if any
 702         if (genericSignature != null) {
 703             writeGenericSignature(genericSignature.asString());
 704         }
 705 
 706         // write inner classes, if any
 707         if (numInnerClasses != 0) {
 708             writeIndex(_innerClassesIndex);
 709             final int innerAttrLen = 2 /* number_of_inner_classes */ +
 710                                      numInnerClasses * (
 711                                                  2 /* inner_class_info_index */ +
 712                                                  2 /* outer_class_info_index */ +
 713                                                  2 /* inner_class_name_index */ +
 714                                                  2 /* inner_class_access_flags */);
 715             dos.writeInt(innerAttrLen);
 716 
 717             dos.writeShort(numInnerClasses);
 718             if (DEBUG) debugMessage("class has " + numInnerClasses + " inner class entries");
 719 
 720             for (int index = 0; index < numInnerClasses * 4; index++) {
 721                 dos.writeShort(innerClasses.at(index));
 722             }
 723         }
 724     }
 725 }