jdk/test/java/lang/instrument/ilib/InjectBytecodes.java
changeset 26255 af28748e6b2d
parent 26254 14591ffc0c61
parent 26233 d391c2eadc8c
child 26259 4dfb71e557b3
equal deleted inserted replaced
26254:14591ffc0c61 26255:af28748e6b2d
     1 /*
       
     2  * Copyright (c) 2005, 2010, 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  * An extension of BinaryCode that allows code to be printed.
       
    26  * Includes printing of disassembled byte codes, exception info,
       
    27  * local variable and line number info.
       
    28  *
       
    29  */
       
    30 
       
    31 package ilib;
       
    32 
       
    33 import java.io.ByteArrayInputStream;
       
    34 import java.io.CharArrayWriter;
       
    35 import java.io.DataInputStream;
       
    36 import java.io.IOException;
       
    37 import java.io.PrintWriter;
       
    38 import java.io.PrintStream;
       
    39 import java.util.Map;
       
    40 import java.util.HashMap;
       
    41 
       
    42 class InjectBytecodes implements RuntimeConstants {
       
    43 
       
    44     private final ClassReaderWriter c;
       
    45     private final PrintStream output;
       
    46     private final int length;
       
    47     private final int[] map;
       
    48     private final byte[] widening;
       
    49     private final Injector[] before = new Injector[256];
       
    50     private final Injector[] after  = new Injector[256];
       
    51     private final String className;
       
    52     private final String methodName;
       
    53     private final Map<Integer,byte[]> snippets = new HashMap<>();
       
    54 
       
    55     private int pos;
       
    56     private int newPos;
       
    57 
       
    58     private class Span {
       
    59         final int delta;
       
    60         final int target;
       
    61         final int newDelta;
       
    62         final int newTarget;
       
    63 
       
    64         Span(int delta) {
       
    65             this.delta = delta;
       
    66             this.target = pos + delta;
       
    67             this.newTarget = map[target];
       
    68             this.newDelta = newTarget - newPos;
       
    69         }
       
    70     }
       
    71 
       
    72     /**
       
    73      * Constructor
       
    74      */
       
    75     InjectBytecodes(ClassReaderWriter c, int length,
       
    76                     String className, String methodName) {
       
    77         this.c = c;
       
    78         this.output = System.out;
       
    79         this.length = length;
       
    80         this.map = new int[length + 1];
       
    81         this.widening = new byte[length + 1];
       
    82         this.className = className;
       
    83         this.methodName = methodName;
       
    84         c.markLocalPositionStart();
       
    85         for (int i = 0; i <= length; ++i) {
       
    86             map[i] = i;
       
    87         }
       
    88     }
       
    89 
       
    90     public void inject(int at, byte[] newCode) {
       
    91         snippets.put(new Integer(at), newCode);
       
    92         trace("external ");
       
    93         inject(at, newCode.length);
       
    94     }
       
    95 
       
    96     private void inject(int at, int len) {
       
    97         if (Inject.verbose) {
       
    98             traceln("Injecting " + len + " at " + at);
       
    99         }
       
   100         for (int i = at; i <= length; ++i) {
       
   101             map[i] += len;
       
   102         }
       
   103     }
       
   104 
       
   105     private void widen(int at, int len) {
       
   106         int delta = len - widening[at];
       
   107         if (Inject.verbose) {
       
   108             traceln();
       
   109             traceln("Widening to " + len + " at " + at);
       
   110         }
       
   111         inject(c.localPosition(), delta);  // inject at end of instruction
       
   112         widening[at] = (byte)len;          // mark at beginning of instruction
       
   113     }
       
   114 
       
   115     public void injectBefore(int code, Injector inj) {
       
   116         before[code] = inj;
       
   117     }
       
   118 
       
   119     public void injectAfter(int code, Injector inj) {
       
   120         after[code] = inj;
       
   121     }
       
   122 
       
   123     private void trace(String str) {
       
   124         if (Inject.verbose) {
       
   125             output.print(str);
       
   126         }
       
   127     }
       
   128 
       
   129     private void traceln(String str) {
       
   130         if (Inject.verbose) {
       
   131             output.println(str);
       
   132         }
       
   133     }
       
   134 
       
   135     private void traceln() {
       
   136         if (Inject.verbose) {
       
   137             output.println();
       
   138         }
       
   139     }
       
   140 
       
   141     private void trace(int i) {
       
   142         if (Inject.verbose) {
       
   143             output.print(i);
       
   144         }
       
   145     }
       
   146 
       
   147     /**
       
   148      * Print an integer so that it takes 'length' characters in
       
   149      * the output.  Temporary until formatting code is stable.
       
   150      */
       
   151     private void traceFixedWidthInt(int x, int length) {
       
   152         if (Inject.verbose) {
       
   153             CharArrayWriter baStream = new CharArrayWriter();
       
   154             PrintWriter pStream = new PrintWriter(baStream);
       
   155             pStream.print(x);
       
   156             String str = baStream.toString();
       
   157             for (int cnt = length - str.length(); cnt > 0; --cnt)
       
   158                 trace(" ");
       
   159             trace(str);
       
   160         }
       
   161     }
       
   162 
       
   163     void adjustOffsets() throws IOException {
       
   164         if (Inject.verbose) {
       
   165             traceln();
       
   166             traceln("Method " + methodName);
       
   167             traceln();
       
   168         }
       
   169         c.rewind();
       
   170         while (c.localPosition() < length) {
       
   171             insertAtInstruction();
       
   172         }
       
   173         trace("Searching for adjustments...");
       
   174         c.rewind();
       
   175         while (c.localPosition() < length) {
       
   176             if (!adjustInstruction()) {
       
   177                 c.rewind();
       
   178                 traceln();
       
   179                 traceln("Restarting adjustments after change...");
       
   180             }
       
   181         }
       
   182         // write the new bytecodes
       
   183         traceln();
       
   184         traceln();
       
   185         trace("Writing new code...");
       
   186         c.rewind();
       
   187         while (c.localPosition() < length) {
       
   188             writeInstruction();
       
   189         }
       
   190         if (!snippets.isEmpty()) {
       
   191             throw new Error("not all snippets written");
       
   192         }
       
   193     }
       
   194 
       
   195     /**
       
   196      * Walk one instruction inserting instrumentation at specified instructions
       
   197      */
       
   198     private void insertAtInstruction() throws IOException {
       
   199         pos = c.localPosition();
       
   200         int opcode = c.readU1();
       
   201         if (opcode == opc_wide) {
       
   202             // no support for instrumenting wide instructions
       
   203             int wopcode = c.readU1();
       
   204             int lvIndex = c.readU2();
       
   205             switch (wopcode) {
       
   206             case opc_aload: case opc_astore:
       
   207             case opc_fload: case opc_fstore:
       
   208             case opc_iload: case opc_istore:
       
   209             case opc_lload: case opc_lstore:
       
   210             case opc_dload: case opc_dstore:
       
   211             case opc_ret:
       
   212                 break;
       
   213 
       
   214             case opc_iinc:
       
   215                 c.readS2();
       
   216                 break;
       
   217             default:
       
   218                 throw new Error("Invalid wide opcode: " + wopcode);
       
   219             }
       
   220         } else {
       
   221             Injector inj;
       
   222 
       
   223             inj = before[opcode];
       
   224             if (inj != null) {
       
   225                 inject(pos, inj.bytecodes(className, methodName, pos));
       
   226             }
       
   227 
       
   228             switch (opcode) {
       
   229             case opc_tableswitch:{
       
   230                 int header = (pos+1+3) & (~3);        // 4byte boundry
       
   231                 c.skip(header - (pos+1));             // skip old padding
       
   232 
       
   233                 c.readU4();
       
   234                 int low = c.readU4();
       
   235                 int high = c.readU4();
       
   236                 c.skip((high+1-low) * 4);
       
   237                 break;
       
   238             }
       
   239 
       
   240             case opc_lookupswitch:{
       
   241                 int header = (pos+1+3) & (~3);        // 4byte boundry
       
   242                 c.skip(header - (pos+1));             // skip padding
       
   243 
       
   244                 c.readU4();
       
   245                 int npairs = c.readU4();
       
   246                 c.skip(npairs * 8);
       
   247                 break;
       
   248             }
       
   249 
       
   250             default: {
       
   251                 int instrLen = opcLengths[opcode];
       
   252                 c.skip(instrLen-1);
       
   253             }
       
   254             }
       
   255             inj = after[opcode];
       
   256             if (inj != null) {
       
   257                 pos = c.localPosition();
       
   258                 inject(pos, inj.bytecodes(className, methodName, pos));
       
   259             }
       
   260         }
       
   261     }
       
   262 
       
   263     /**
       
   264      * Walk one instruction adjusting for insertions
       
   265      */
       
   266     private boolean adjustInstruction() throws IOException {
       
   267         pos = c.localPosition();
       
   268         newPos = map[pos];
       
   269         int opcode = c.readU1();
       
   270         if (Inject.verbose) {
       
   271             traceln();
       
   272             traceFixedWidthInt(pos, 4);
       
   273             traceFixedWidthInt(newPos, 4);
       
   274             trace(" ");
       
   275         }
       
   276         if (opcode == opc_wide) {
       
   277             int wopcode = c.readU1();
       
   278             int lvIndex = c.readU2();
       
   279             if (Inject.verbose) {
       
   280                 trace(opcNames[wopcode] + "_w ");
       
   281             }
       
   282             switch (wopcode) {
       
   283             case opc_aload: case opc_astore:
       
   284             case opc_fload: case opc_fstore:
       
   285             case opc_iload: case opc_istore:
       
   286             case opc_lload: case opc_lstore:
       
   287             case opc_dload: case opc_dstore:
       
   288             case opc_ret:
       
   289                 trace(lvIndex);
       
   290                 break;
       
   291 
       
   292             case opc_iinc:
       
   293                 int constVal = c.readS2();
       
   294                 if (Inject.verbose) {
       
   295                     trace(lvIndex + " " + constVal);
       
   296                 }
       
   297                 break;
       
   298             default:
       
   299                 throw new Error("Invalid wide opcode: " + wopcode);
       
   300             }
       
   301         } else {
       
   302             if (Inject.verbose) {
       
   303                 trace(opcNames[opcode]);
       
   304             }
       
   305             switch (opcode) {
       
   306 
       
   307             case opc_tableswitch:{
       
   308                 int widened = widening[pos];
       
   309                 int header = (pos+1+3) & (~3);        // 4byte boundry
       
   310                 int newHeader = (newPos+1+3) & (~3);  // 4byte boundry
       
   311 
       
   312                 c.skip(header - (pos+1));             // skip old padding
       
   313 
       
   314                 Span defaultSkip = new Span(c.readU4());
       
   315                 int low = c.readU4();
       
   316                 int high = c.readU4();
       
   317                 if (Inject.verbose) {
       
   318                     trace(" " + low + " to " + high);
       
   319                     trace(": default= [was] " + defaultSkip.target);
       
   320                     trace(" [now] " + defaultSkip.newTarget);
       
   321                     for (int i = low; i <= high; ++i) {
       
   322                         Span jump = new Span(c.readU4());
       
   323                         traceln("");
       
   324                         trace('\t');
       
   325                         traceFixedWidthInt(i, 5);
       
   326                         trace(": " + jump.newTarget);
       
   327                     }
       
   328                 } else {
       
   329                     c.skip((high+1-low) * 4);
       
   330                 }
       
   331                 int newPadding = newHeader - newPos;
       
   332                 int oldPadding = header - pos;
       
   333                 int deltaPadding = newPadding - oldPadding;
       
   334                 if (widened != deltaPadding) {
       
   335                     widen(pos, deltaPadding);
       
   336                     return false;       // cause restart
       
   337                 }
       
   338                 break;
       
   339             }
       
   340 
       
   341             case opc_lookupswitch:{
       
   342                 int widened = widening[pos];
       
   343                 int header = (pos+1+3) & (~3);        // 4byte boundry
       
   344                 int newHeader = (newPos+1+3) & (~3);  // 4byte boundry
       
   345 
       
   346                 c.skip(header - (pos+1));             // skip old padding
       
   347 
       
   348                 Span defaultSkip = new Span(c.readU4());
       
   349                 int npairs = c.readU4();
       
   350                 if (Inject.verbose) {
       
   351                     trace(" npairs: " + npairs);
       
   352                     trace(": default= [was] " + defaultSkip.target);
       
   353                     trace(" [now] " + defaultSkip.newTarget);
       
   354                     for (int i = 0; i< npairs; ++i) {
       
   355                         int match = c.readU4();
       
   356                         Span jump = new Span(c.readU4());
       
   357                         traceln("");
       
   358                         trace('\t');
       
   359                         traceFixedWidthInt(match, 5);
       
   360                         trace(": " + jump.newTarget);
       
   361                     }
       
   362                 } else {
       
   363                     c.skip(npairs * 8);
       
   364                 }
       
   365                 int newPadding = newHeader - newPos;
       
   366                 int oldPadding = header - pos;
       
   367                 int deltaPadding = newPadding - oldPadding;
       
   368                 if (widened != deltaPadding) {
       
   369                     widen(pos, deltaPadding);
       
   370                     return false;       // cause restart
       
   371                 }
       
   372                 break;
       
   373             }
       
   374 
       
   375             case opc_jsr: case opc_goto:
       
   376             case opc_ifeq: case opc_ifge: case opc_ifgt:
       
   377             case opc_ifle: case opc_iflt: case opc_ifne:
       
   378             case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge:
       
   379             case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt:
       
   380             case opc_if_acmpeq: case opc_if_acmpne:
       
   381             case opc_ifnull: case opc_ifnonnull: {
       
   382                 int widened = widening[pos];
       
   383                 Span jump = new Span(c.readS2());
       
   384                 if (widened == 0) {  // not yet widened
       
   385                     int newDelta = jump.newDelta;
       
   386                     if ((newDelta < -32768) || (newDelta > 32767)) {
       
   387                         switch (opcode) {
       
   388                         case opc_jsr: case opc_goto:
       
   389                             widen(pos, 2); // will convert to wide
       
   390                             break;
       
   391                         default:
       
   392                             widen(pos, 5); // will inject goto_w
       
   393                             break;
       
   394                         }
       
   395                         return false;       // cause restart
       
   396                     }
       
   397                 }
       
   398                 if (Inject.verbose) {
       
   399                     trace(" [was] " + jump.target + " ==> " +
       
   400                           " [now] " + jump.newTarget);
       
   401                 }
       
   402                 break;
       
   403             }
       
   404 
       
   405             case opc_jsr_w:
       
   406             case opc_goto_w: {
       
   407                 Span jump = new Span(c.readU4());
       
   408                 if (Inject.verbose) {
       
   409                     trace(" [was] " + jump.target +
       
   410                           " [now] " + jump.newTarget);
       
   411                 }
       
   412                 break;
       
   413             }
       
   414 
       
   415             default: {
       
   416                 int instrLen = opcLengths[opcode];
       
   417                 c.skip(instrLen-1);
       
   418                 break;
       
   419             }
       
   420             }
       
   421         }
       
   422         return true;     // successful return
       
   423     }
       
   424 
       
   425 
       
   426     /**
       
   427      * Walk one instruction writing the transformed instruction.
       
   428      */
       
   429     private void writeInstruction() throws IOException {
       
   430         pos = c.localPosition();
       
   431         newPos = map[pos];
       
   432         byte[] newCode = snippets.remove(new Integer(pos));
       
   433         if (newCode != null) {
       
   434             traceln();
       
   435             traceFixedWidthInt(pos, 4);
       
   436             trace(" ... -- Inserting new code");
       
   437             c.writeBytes(newCode);
       
   438         }
       
   439         int opcode = c.readU1();
       
   440         if (Inject.verbose) {
       
   441             traceln();
       
   442             traceFixedWidthInt(pos, 4);
       
   443             traceFixedWidthInt(newPos, 4);
       
   444             trace(" ");
       
   445         }
       
   446         if (opcode == opc_wide) {
       
   447             int wopcode = c.readU1();
       
   448             int lvIndex = c.readU2();
       
   449             if (Inject.verbose) {
       
   450                 trace(opcNames[wopcode] + "_w ");
       
   451             }
       
   452             c.writeU1(opcode);
       
   453             c.writeU1(wopcode);
       
   454             c.writeU2(lvIndex);
       
   455             switch (wopcode) {
       
   456             case opc_aload: case opc_astore:
       
   457             case opc_fload: case opc_fstore:
       
   458             case opc_iload: case opc_istore:
       
   459             case opc_lload: case opc_lstore:
       
   460             case opc_dload: case opc_dstore:
       
   461             case opc_ret:
       
   462                 trace(lvIndex);
       
   463                 break;
       
   464 
       
   465             case opc_iinc:
       
   466                 int constVal = c.readS2();
       
   467                 c.writeU2(constVal);  // ??? U vs S
       
   468                 if (Inject.verbose) {
       
   469                     trace(lvIndex + " " + constVal);
       
   470                 }
       
   471                 break;
       
   472             default:
       
   473                 throw new Error("Invalid wide opcode: " + wopcode);
       
   474             }
       
   475         } else {
       
   476             if (Inject.verbose) {
       
   477                 trace(opcNames[opcode]);
       
   478             }
       
   479             switch (opcode) {
       
   480 
       
   481             case opc_tableswitch:{
       
   482                 int header = (pos+1+3) & (~3);   // 4byte boundry
       
   483                 int newHeader = (newPos+1+3) & (~3); // 4byte boundry
       
   484 
       
   485                 c.skip(header - (pos+1));             // skip old padding
       
   486 
       
   487                 Span defaultSkip = new Span(c.readU4());
       
   488                 int low = c.readU4();
       
   489                 int high = c.readU4();
       
   490 
       
   491                 c.writeU1(opcode);                   // copy instruction
       
   492                 for (int i = newPos+1; i < newHeader; ++i) {
       
   493                     c.writeU1(0);                    // write new padding
       
   494                 }
       
   495                 c.writeU4(defaultSkip.newDelta);
       
   496                 c.writeU4(low);
       
   497                 c.writeU4(high);
       
   498 
       
   499                 if (Inject.verbose) {
       
   500                     trace(" " + low + " to " + high);
       
   501                     trace(": default= [was] " + defaultSkip.target);
       
   502                     trace(" [now] " + defaultSkip.newTarget);
       
   503                 }
       
   504                 for (int i = low; i <= high; ++i) {
       
   505                     Span jump = new Span(c.readU4());
       
   506                     c.writeU4(jump.newDelta);
       
   507                     if (Inject.verbose) {
       
   508                         traceln("");
       
   509                         trace('\t');
       
   510                         traceFixedWidthInt(i, 5);
       
   511                         trace(": " + jump.newTarget);
       
   512                     }
       
   513                 }
       
   514                 break;
       
   515             }
       
   516 
       
   517             case opc_lookupswitch:{
       
   518                 int header = (pos+1+3) & (~3);   // 4byte boundry
       
   519                 int newHeader = (newPos+1+3) & (~3); // 4byte boundry
       
   520 
       
   521                 c.skip(header - (pos+1));             // skip old padding
       
   522 
       
   523                 Span defaultSkip = new Span(c.readU4());
       
   524                 int npairs = c.readU4();
       
   525                 if (Inject.verbose) {
       
   526                     trace(" npairs: " + npairs);
       
   527                     trace(": default= [was] " + defaultSkip.target);
       
   528                     trace(" [now] " + defaultSkip.newTarget);
       
   529                 }
       
   530                 c.writeU1(opcode);                   // copy instruction
       
   531                 for (int i = newPos+1; i < newHeader; ++i) {
       
   532                     c.writeU1(0);                    // write new padding
       
   533                 }
       
   534                 c.writeU4(defaultSkip.newDelta);
       
   535                 c.writeU4(npairs);
       
   536                 for (int i = 0; i< npairs; ++i) {
       
   537                     int match = c.readU4();
       
   538                     Span jump = new Span(c.readU4());
       
   539                     c.writeU4(match);
       
   540                     c.writeU4(jump.newDelta);
       
   541                     if (Inject.verbose) {
       
   542                         traceln("");
       
   543                         trace('\t');
       
   544                         traceFixedWidthInt(match, 5);
       
   545                         trace(": " + jump.newTarget);
       
   546                     }
       
   547                 }
       
   548                 break;
       
   549             }
       
   550 
       
   551             case opc_jsr: case opc_goto:
       
   552             case opc_ifeq: case opc_ifge: case opc_ifgt:
       
   553             case opc_ifle: case opc_iflt: case opc_ifne:
       
   554             case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge:
       
   555             case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt:
       
   556             case opc_if_acmpeq: case opc_if_acmpne:
       
   557             case opc_ifnull: case opc_ifnonnull: {
       
   558                 int widened = widening[pos];
       
   559                 Span jump = new Span(c.readS2());
       
   560                 int newOpcode = opcode;   // default to unchanged
       
   561                 if (widened == 0) {        // not widened
       
   562                     c.writeU1(opcode);    // rewrite instruction
       
   563                     c.writeU2(jump.newDelta);
       
   564                 } else if (widened == 2) { // wide form
       
   565                     switch (opcode) {
       
   566                     case opc_jsr:
       
   567                         newOpcode = opc_jsr_w;
       
   568                         break;
       
   569                     case opc_goto:
       
   570                         newOpcode = opc_jsr_w;
       
   571                         break;
       
   572                     default:
       
   573                         throw new Error("unexpected opcode: " +
       
   574                                    opcode);
       
   575                     }
       
   576                     c.writeU1(newOpcode);      // write wide instruction
       
   577                     c.writeU4(jump.newDelta);  // write new and wide delta
       
   578                 } else if (widened == 5) {      // insert goto_w
       
   579                     switch (opcode) {
       
   580                     case opc_ifeq:
       
   581                         newOpcode = opc_ifne;
       
   582                         break;
       
   583                     case opc_ifge:
       
   584                         newOpcode = opc_iflt;
       
   585                         break;
       
   586                     case opc_ifgt:
       
   587                         newOpcode = opc_ifle;
       
   588                         break;
       
   589                     case opc_ifle:
       
   590                         newOpcode = opc_ifgt;
       
   591                         break;
       
   592                     case opc_iflt:
       
   593                         newOpcode = opc_ifge;
       
   594                         break;
       
   595                     case opc_ifne:
       
   596                         newOpcode = opc_ifeq;
       
   597                         break;
       
   598                     case opc_if_icmpeq:
       
   599                         newOpcode = opc_if_icmpne;
       
   600                         break;
       
   601                     case opc_if_icmpne:
       
   602                         newOpcode = opc_if_icmpeq;
       
   603                         break;
       
   604                     case opc_if_icmpge:
       
   605                         newOpcode = opc_if_icmplt;
       
   606                         break;
       
   607                     case opc_if_icmpgt:
       
   608                         newOpcode = opc_if_icmple;
       
   609                         break;
       
   610                     case opc_if_icmple:
       
   611                         newOpcode = opc_if_icmpgt;
       
   612                         break;
       
   613                     case opc_if_icmplt:
       
   614                         newOpcode = opc_if_icmpge;
       
   615                         break;
       
   616                     case opc_if_acmpeq:
       
   617                         newOpcode = opc_if_acmpne;
       
   618                         break;
       
   619                     case opc_if_acmpne:
       
   620                         newOpcode = opc_if_acmpeq;
       
   621                         break;
       
   622                     case opc_ifnull:
       
   623                         newOpcode = opc_ifnonnull;
       
   624                         break;
       
   625                     case opc_ifnonnull:
       
   626                         newOpcode = opc_ifnull;
       
   627                         break;
       
   628                     default:
       
   629                         throw new Error("unexpected opcode: " +
       
   630                                    opcode);
       
   631                     }
       
   632                     c.writeU1(newOpcode); // write inverse branch
       
   633                     c.writeU2(3 + 5);     // beyond if and goto_w
       
   634                     c.writeU1(opc_goto_w);// add a goto_w
       
   635                     c.writeU4(jump.newDelta);  // write new and wide delta
       
   636                 } else {
       
   637                     throw new Error("unexpected widening");
       
   638                 }
       
   639 
       
   640                 if (Inject.verbose) {
       
   641                     trace(" [was] " + jump.target + " ==> " +
       
   642                           opcNames[newOpcode] +
       
   643                           " [now] " + jump.newTarget);
       
   644                 }
       
   645                 break;
       
   646             }
       
   647 
       
   648             case opc_jsr_w:
       
   649             case opc_goto_w: {
       
   650                 Span jump = new Span(c.readU4());
       
   651                 c.writeU1(opcode);        // instruction itself
       
   652                 c.writeU4(jump.newDelta);
       
   653                 if (Inject.verbose) {
       
   654                     trace(" [was] " + jump.target +
       
   655                           " [now] " + jump.newTarget);
       
   656                 }
       
   657                 break;
       
   658             }
       
   659 
       
   660             default: {
       
   661                 int instrLen = opcLengths[opcode];
       
   662                 c.writeU1(opcode);        // instruction itself
       
   663                 c.copy(instrLen-1);
       
   664             }
       
   665             }
       
   666         }
       
   667     }
       
   668 
       
   669     /**
       
   670      * Copy the exception table for this method code
       
   671      */
       
   672     void copyExceptionTable() throws IOException {
       
   673         int tableLength = c.copyU2();   // exception table len
       
   674         if (tableLength > 0) {
       
   675             traceln();
       
   676             traceln("Exception table:");
       
   677             traceln(" from:old/new  to:old/new target:old/new type");
       
   678             for (int tcnt = tableLength; tcnt > 0; --tcnt) {
       
   679                 int startPC = c.readU2();
       
   680                 int newStartPC = map[startPC];
       
   681                 c.writeU2(newStartPC);
       
   682                 int endPC = c.readU2();
       
   683                 int newEndPC = map[endPC];
       
   684                 c.writeU2(newEndPC);
       
   685                 int handlerPC = c.readU2();
       
   686                 int newHandlerPC = map[handlerPC];
       
   687                 c.writeU2(newHandlerPC);
       
   688                 int catchType = c.copyU2();
       
   689                 if (Inject.verbose) {
       
   690                     traceFixedWidthInt(startPC, 6);
       
   691                     traceFixedWidthInt(newStartPC, 6);
       
   692                     traceFixedWidthInt(endPC, 6);
       
   693                     traceFixedWidthInt(newEndPC, 6);
       
   694                     traceFixedWidthInt(handlerPC, 6);
       
   695                     traceFixedWidthInt(newHandlerPC, 6);
       
   696                     trace("    ");
       
   697                     if (catchType == 0)
       
   698                         traceln("any");
       
   699                     else {
       
   700                         traceln("" + catchType);
       
   701                     }
       
   702                 }
       
   703             }
       
   704         }
       
   705     }
       
   706 
       
   707     /**
       
   708      * Copy the line number table for this method code
       
   709      */
       
   710     void copyLineNumberAttr() throws IOException {
       
   711         // name index already read
       
   712         c.copy(4);                      // attr len
       
   713         int tableLength = c.copyU2();   // line table len
       
   714         if (tableLength > 0) {
       
   715             if (Inject.verbose) {
       
   716                 traceln();
       
   717                 traceln("Line numbers for method " + methodName);
       
   718             }
       
   719             for (int tcnt = tableLength; tcnt > 0; --tcnt) {
       
   720                 int startPC = c.readU2();
       
   721                 int newStartPC = map[startPC];
       
   722                 c.writeU2(newStartPC);
       
   723                 int lineNumber = c.copyU2();
       
   724                 if (Inject.verbose) {
       
   725                     traceln("   line " + lineNumber +
       
   726                             ": [was] " + startPC +
       
   727                             " [now] " + newStartPC);
       
   728                 }
       
   729             }
       
   730         }
       
   731     }
       
   732 
       
   733     /**
       
   734      * Copy the local variable table for this method code
       
   735      */
       
   736     void copyLocalVarAttr() throws IOException {
       
   737         // name index already read
       
   738         c.copy(4);                      // attr len
       
   739         int tableLength = c.copyU2();   // local var table len
       
   740         if (tableLength > 0) {
       
   741             if (Inject.verbose) {
       
   742                 traceln();
       
   743                 traceln("Local variables for method " + methodName);
       
   744             }
       
   745             for (int tcnt = tableLength; tcnt > 0; --tcnt) {
       
   746                 int startPC = c.readU2();
       
   747                 int newStartPC = map[startPC];
       
   748                 c.writeU2(newStartPC);
       
   749                 int length = c.readU2();
       
   750                 int endPC = startPC + length;
       
   751                 int newEndPC = map[endPC];
       
   752                 int newLength = newEndPC - newStartPC;
       
   753                 c.writeU2(newLength);
       
   754                 int nameIndex = c.copyU2();
       
   755                 int descriptorIndex = c.copyU2();
       
   756                 int index = c.copyU2();
       
   757                 if (Inject.verbose) {
       
   758                     trace("   ");
       
   759                     trace(descriptorIndex);
       
   760                     trace(" ");
       
   761                     trace(nameIndex);
       
   762                     traceln("  pc= [was] " + startPC + " [now] " + newStartPC +
       
   763                             ", length= [was] " + length + " [now] " + newLength +
       
   764                             ", slot=" + index);
       
   765                 }
       
   766             }
       
   767         }
       
   768     }
       
   769 }