annotate src/clojure/asm/MethodWriter.java @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
rev   line source
rlm@10 1 /***
rlm@10 2 * ASM: a very small and fast Java bytecode manipulation framework
rlm@10 3 * Copyright (c) 2000-2005 INRIA, France Telecom
rlm@10 4 * All rights reserved.
rlm@10 5 *
rlm@10 6 * Redistribution and use in source and binary forms, with or without
rlm@10 7 * modification, are permitted provided that the following conditions
rlm@10 8 * are met:
rlm@10 9 * 1. Redistributions of source code must retain the above copyright
rlm@10 10 * notice, this list of conditions and the following disclaimer.
rlm@10 11 * 2. Redistributions in binary form must reproduce the above copyright
rlm@10 12 * notice, this list of conditions and the following disclaimer in the
rlm@10 13 * documentation and/or other materials provided with the distribution.
rlm@10 14 * 3. Neither the name of the copyright holders nor the names of its
rlm@10 15 * contributors may be used to endorse or promote products derived from
rlm@10 16 * this software without specific prior written permission.
rlm@10 17 *
rlm@10 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
rlm@10 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
rlm@10 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
rlm@10 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
rlm@10 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
rlm@10 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
rlm@10 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
rlm@10 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
rlm@10 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
rlm@10 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
rlm@10 28 * THE POSSIBILITY OF SUCH DAMAGE.
rlm@10 29 */
rlm@10 30 package clojure.asm;
rlm@10 31
rlm@10 32 /**
rlm@10 33 * A {@link MethodVisitor} that generates methods in bytecode form. Each visit
rlm@10 34 * method of this class appends the bytecode corresponding to the visited
rlm@10 35 * instruction to a byte vector, in the order these methods are called.
rlm@10 36 *
rlm@10 37 * @author Eric Bruneton
rlm@10 38 * @author Eugene Kuleshov
rlm@10 39 */
rlm@10 40 class MethodWriter implements MethodVisitor{
rlm@10 41
rlm@10 42 /**
rlm@10 43 * Pseudo access flag used to denote constructors.
rlm@10 44 */
rlm@10 45 final static int ACC_CONSTRUCTOR = 262144;
rlm@10 46
rlm@10 47 /**
rlm@10 48 * Frame has exactly the same locals as the previous stack map frame and
rlm@10 49 * number of stack items is zero.
rlm@10 50 */
rlm@10 51 final static int SAME_FRAME = 0; // to 63 (0-3f)
rlm@10 52
rlm@10 53 /**
rlm@10 54 * Frame has exactly the same locals as the previous stack map frame and
rlm@10 55 * number of stack items is 1
rlm@10 56 */
rlm@10 57 final static int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f)
rlm@10 58
rlm@10 59 /**
rlm@10 60 * Reserved for future use
rlm@10 61 */
rlm@10 62 final static int RESERVED = 128;
rlm@10 63
rlm@10 64 /**
rlm@10 65 * Frame has exactly the same locals as the previous stack map frame and
rlm@10 66 * number of stack items is 1. Offset is bigger then 63;
rlm@10 67 */
rlm@10 68 final static int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
rlm@10 69
rlm@10 70 /**
rlm@10 71 * Frame where current locals are the same as the locals in the previous
rlm@10 72 * frame, except that the k last locals are absent. The value of k is given
rlm@10 73 * by the formula 251-frame_type.
rlm@10 74 */
rlm@10 75 final static int CHOP_FRAME = 248; // to 250 (f8-fA)
rlm@10 76
rlm@10 77 /**
rlm@10 78 * Frame has exactly the same locals as the previous stack map frame and
rlm@10 79 * number of stack items is zero. Offset is bigger then 63;
rlm@10 80 */
rlm@10 81 final static int SAME_FRAME_EXTENDED = 251; // fb
rlm@10 82
rlm@10 83 /**
rlm@10 84 * Frame where current locals are the same as the locals in the previous
rlm@10 85 * frame, except that k additional locals are defined. The value of k is
rlm@10 86 * given by the formula frame_type-251.
rlm@10 87 */
rlm@10 88 final static int APPEND_FRAME = 252; // to 254 // fc-fe
rlm@10 89
rlm@10 90 /**
rlm@10 91 * Full frame
rlm@10 92 */
rlm@10 93 final static int FULL_FRAME = 255; // ff
rlm@10 94
rlm@10 95 /**
rlm@10 96 * Indicates that the stack map frames must be recomputed from scratch. In
rlm@10 97 * this case the maximum stack size and number of local variables is also
rlm@10 98 * recomputed from scratch.
rlm@10 99 *
rlm@10 100 * @see #compute
rlm@10 101 */
rlm@10 102 private final static int FRAMES = 0;
rlm@10 103
rlm@10 104 /**
rlm@10 105 * Indicates that the maximum stack size and number of local variables must
rlm@10 106 * be automatically computed.
rlm@10 107 *
rlm@10 108 * @see #compute
rlm@10 109 */
rlm@10 110 private final static int MAXS = 1;
rlm@10 111
rlm@10 112 /**
rlm@10 113 * Indicates that nothing must be automatically computed.
rlm@10 114 *
rlm@10 115 * @see #compute
rlm@10 116 */
rlm@10 117 private final static int NOTHING = 2;
rlm@10 118
rlm@10 119 /**
rlm@10 120 * Next method writer (see {@link ClassWriter#firstMethod firstMethod}).
rlm@10 121 */
rlm@10 122 MethodWriter next;
rlm@10 123
rlm@10 124 /**
rlm@10 125 * The class writer to which this method must be added.
rlm@10 126 */
rlm@10 127 ClassWriter cw;
rlm@10 128
rlm@10 129 /**
rlm@10 130 * Access flags of this method.
rlm@10 131 */
rlm@10 132 private int access;
rlm@10 133
rlm@10 134 /**
rlm@10 135 * The index of the constant pool item that contains the name of this
rlm@10 136 * method.
rlm@10 137 */
rlm@10 138 private int name;
rlm@10 139
rlm@10 140 /**
rlm@10 141 * The index of the constant pool item that contains the descriptor of this
rlm@10 142 * method.
rlm@10 143 */
rlm@10 144 private int desc;
rlm@10 145
rlm@10 146 /**
rlm@10 147 * The descriptor of this method.
rlm@10 148 */
rlm@10 149 private String descriptor;
rlm@10 150
rlm@10 151 /**
rlm@10 152 * The signature of this method.
rlm@10 153 */
rlm@10 154 String signature;
rlm@10 155
rlm@10 156 /**
rlm@10 157 * If not zero, indicates that the code of this method must be copied from
rlm@10 158 * the ClassReader associated to this writer in <code>cw.cr</code>. More
rlm@10 159 * precisely, this field gives the index of the first byte to copied from
rlm@10 160 * <code>cw.cr.b</code>.
rlm@10 161 */
rlm@10 162 int classReaderOffset;
rlm@10 163
rlm@10 164 /**
rlm@10 165 * If not zero, indicates that the code of this method must be copied from
rlm@10 166 * the ClassReader associated to this writer in <code>cw.cr</code>. More
rlm@10 167 * precisely, this field gives the number of bytes to copied from
rlm@10 168 * <code>cw.cr.b</code>.
rlm@10 169 */
rlm@10 170 int classReaderLength;
rlm@10 171
rlm@10 172 /**
rlm@10 173 * Number of exceptions that can be thrown by this method.
rlm@10 174 */
rlm@10 175 int exceptionCount;
rlm@10 176
rlm@10 177 /**
rlm@10 178 * The exceptions that can be thrown by this method. More precisely, this
rlm@10 179 * array contains the indexes of the constant pool items that contain the
rlm@10 180 * internal names of these exception classes.
rlm@10 181 */
rlm@10 182 int[] exceptions;
rlm@10 183
rlm@10 184 /**
rlm@10 185 * The annotation default attribute of this method. May be <tt>null</tt>.
rlm@10 186 */
rlm@10 187 private ByteVector annd;
rlm@10 188
rlm@10 189 /**
rlm@10 190 * The runtime visible annotations of this method. May be <tt>null</tt>.
rlm@10 191 */
rlm@10 192 private AnnotationWriter anns;
rlm@10 193
rlm@10 194 /**
rlm@10 195 * The runtime invisible annotations of this method. May be <tt>null</tt>.
rlm@10 196 */
rlm@10 197 private AnnotationWriter ianns;
rlm@10 198
rlm@10 199 /**
rlm@10 200 * The runtime visible parameter annotations of this method. May be
rlm@10 201 * <tt>null</tt>.
rlm@10 202 */
rlm@10 203 private AnnotationWriter[] panns;
rlm@10 204
rlm@10 205 /**
rlm@10 206 * The runtime invisible parameter annotations of this method. May be
rlm@10 207 * <tt>null</tt>.
rlm@10 208 */
rlm@10 209 private AnnotationWriter[] ipanns;
rlm@10 210
rlm@10 211 /**
rlm@10 212 * The non standard attributes of the method.
rlm@10 213 */
rlm@10 214 private Attribute attrs;
rlm@10 215
rlm@10 216 /**
rlm@10 217 * The bytecode of this method.
rlm@10 218 */
rlm@10 219 private ByteVector code = new ByteVector();
rlm@10 220
rlm@10 221 /**
rlm@10 222 * Maximum stack size of this method.
rlm@10 223 */
rlm@10 224 private int maxStack;
rlm@10 225
rlm@10 226 /**
rlm@10 227 * Maximum number of local variables for this method.
rlm@10 228 */
rlm@10 229 private int maxLocals;
rlm@10 230
rlm@10 231 /**
rlm@10 232 * Number of stack map frames in the StackMapTable attribute.
rlm@10 233 */
rlm@10 234 private int frameCount;
rlm@10 235
rlm@10 236 /**
rlm@10 237 * The StackMapTable attribute.
rlm@10 238 */
rlm@10 239 private ByteVector stackMap;
rlm@10 240
rlm@10 241 /**
rlm@10 242 * The offset of the last frame that was written in the StackMapTable
rlm@10 243 * attribute.
rlm@10 244 */
rlm@10 245 private int previousFrameOffset;
rlm@10 246
rlm@10 247 /**
rlm@10 248 * The last frame that was written in the StackMapTable attribute.
rlm@10 249 *
rlm@10 250 * @see #frame
rlm@10 251 */
rlm@10 252 private int[] previousFrame;
rlm@10 253
rlm@10 254 /**
rlm@10 255 * Index of the next element to be added in {@link #frame}.
rlm@10 256 */
rlm@10 257 private int frameIndex;
rlm@10 258
rlm@10 259 /**
rlm@10 260 * The current stack map frame. The first element contains the offset of the
rlm@10 261 * instruction to which the frame corresponds, the second element is the
rlm@10 262 * number of locals and the third one is the number of stack elements. The
rlm@10 263 * local variables start at index 3 and are followed by the operand stack
rlm@10 264 * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] =
rlm@10 265 * nStack, frame[3] = nLocal. All types are encoded as integers, with the
rlm@10 266 * same format as the one used in {@link Label}, but limited to BASE types.
rlm@10 267 */
rlm@10 268 private int[] frame;
rlm@10 269
rlm@10 270 /**
rlm@10 271 * Number of elements in the exception handler list.
rlm@10 272 */
rlm@10 273 private int handlerCount;
rlm@10 274
rlm@10 275 /**
rlm@10 276 * The first element in the exception handler list.
rlm@10 277 */
rlm@10 278 private Handler firstHandler;
rlm@10 279
rlm@10 280 /**
rlm@10 281 * The last element in the exception handler list.
rlm@10 282 */
rlm@10 283 private Handler lastHandler;
rlm@10 284
rlm@10 285 /**
rlm@10 286 * Number of entries in the LocalVariableTable attribute.
rlm@10 287 */
rlm@10 288 private int localVarCount;
rlm@10 289
rlm@10 290 /**
rlm@10 291 * The LocalVariableTable attribute.
rlm@10 292 */
rlm@10 293 private ByteVector localVar;
rlm@10 294
rlm@10 295 /**
rlm@10 296 * Number of entries in the LocalVariableTypeTable attribute.
rlm@10 297 */
rlm@10 298 private int localVarTypeCount;
rlm@10 299
rlm@10 300 /**
rlm@10 301 * The LocalVariableTypeTable attribute.
rlm@10 302 */
rlm@10 303 private ByteVector localVarType;
rlm@10 304
rlm@10 305 /**
rlm@10 306 * Number of entries in the LineNumberTable attribute.
rlm@10 307 */
rlm@10 308 private int lineNumberCount;
rlm@10 309
rlm@10 310 /**
rlm@10 311 * The LineNumberTable attribute.
rlm@10 312 */
rlm@10 313 private ByteVector lineNumber;
rlm@10 314
rlm@10 315 /**
rlm@10 316 * The non standard attributes of the method's code.
rlm@10 317 */
rlm@10 318 private Attribute cattrs;
rlm@10 319
rlm@10 320 /**
rlm@10 321 * Indicates if some jump instructions are too small and need to be resized.
rlm@10 322 */
rlm@10 323 private boolean resize;
rlm@10 324
rlm@10 325 /**
rlm@10 326 * Indicates if the instructions contain at least one JSR instruction.
rlm@10 327 */
rlm@10 328 private boolean jsr;
rlm@10 329
rlm@10 330 // ------------------------------------------------------------------------
rlm@10 331
rlm@10 332 /*
rlm@10 333 * Fields for the control flow graph analysis algorithm (used to compute the
rlm@10 334 * maximum stack size). A control flow graph contains one node per "basic
rlm@10 335 * block", and one edge per "jump" from one basic block to another. Each
rlm@10 336 * node (i.e., each basic block) is represented by the Label object that
rlm@10 337 * corresponds to the first instruction of this basic block. Each node also
rlm@10 338 * stores the list of its successors in the graph, as a linked list of Edge
rlm@10 339 * objects.
rlm@10 340 */
rlm@10 341
rlm@10 342 /**
rlm@10 343 * Indicates what must be automatically computed.
rlm@10 344 *
rlm@10 345 * @see FRAMES
rlm@10 346 * @see MAXS
rlm@10 347 * @see NOTHING
rlm@10 348 */
rlm@10 349 private int compute;
rlm@10 350
rlm@10 351 /**
rlm@10 352 * A list of labels. This list is the list of basic blocks in the method,
rlm@10 353 * i.e. a list of Label objects linked to each other by their
rlm@10 354 * {@link Label#successor} field, in the order they are visited by
rlm@10 355 * {@link visitLabel}, and starting with the first basic block.
rlm@10 356 */
rlm@10 357 private Label labels;
rlm@10 358
rlm@10 359 /**
rlm@10 360 * The previous basic block.
rlm@10 361 */
rlm@10 362 private Label previousBlock;
rlm@10 363
rlm@10 364 /**
rlm@10 365 * The current basic block.
rlm@10 366 */
rlm@10 367 private Label currentBlock;
rlm@10 368
rlm@10 369 /**
rlm@10 370 * The (relative) stack size after the last visited instruction. This size
rlm@10 371 * is relative to the beginning of the current basic block, i.e., the true
rlm@10 372 * stack size after the last visited instruction is equal to the
rlm@10 373 * {@link Label#inputStackTop beginStackSize} of the current basic block
rlm@10 374 * plus <tt>stackSize</tt>.
rlm@10 375 */
rlm@10 376 private int stackSize;
rlm@10 377
rlm@10 378 /**
rlm@10 379 * The (relative) maximum stack size after the last visited instruction.
rlm@10 380 * This size is relative to the beginning of the current basic block, i.e.,
rlm@10 381 * the true maximum stack size after the last visited instruction is equal
rlm@10 382 * to the {@link Label#inputStackTop beginStackSize} of the current basic
rlm@10 383 * block plus <tt>stackSize</tt>.
rlm@10 384 */
rlm@10 385 private int maxStackSize;
rlm@10 386
rlm@10 387 // ------------------------------------------------------------------------
rlm@10 388 // Constructor
rlm@10 389 // ------------------------------------------------------------------------
rlm@10 390
rlm@10 391 /**
rlm@10 392 * Constructs a new {@link MethodWriter}.
rlm@10 393 *
rlm@10 394 * @param cw the class writer in which the method must be added.
rlm@10 395 * @param access the method's access flags (see {@link Opcodes}).
rlm@10 396 * @param name the method's name.
rlm@10 397 * @param desc the method's descriptor (see {@link Type}).
rlm@10 398 * @param signature the method's signature. May be <tt>null</tt>.
rlm@10 399 * @param exceptions the internal names of the method's exceptions. May be
rlm@10 400 * <tt>null</tt>.
rlm@10 401 * @param computeMaxs <tt>true</tt> if the maximum stack size and number
rlm@10 402 * of local variables must be automatically computed.
rlm@10 403 * @param computeFrames <tt>true</tt> if the stack map tables must be
rlm@10 404 * recomputed from scratch.
rlm@10 405 */
rlm@10 406 MethodWriter(
rlm@10 407 final ClassWriter cw,
rlm@10 408 final int access,
rlm@10 409 final String name,
rlm@10 410 final String desc,
rlm@10 411 final String signature,
rlm@10 412 final String[] exceptions,
rlm@10 413 final boolean computeMaxs,
rlm@10 414 final boolean computeFrames){
rlm@10 415 if(cw.firstMethod == null)
rlm@10 416 {
rlm@10 417 cw.firstMethod = this;
rlm@10 418 }
rlm@10 419 else
rlm@10 420 {
rlm@10 421 cw.lastMethod.next = this;
rlm@10 422 }
rlm@10 423 cw.lastMethod = this;
rlm@10 424 this.cw = cw;
rlm@10 425 this.access = access;
rlm@10 426 this.name = cw.newUTF8(name);
rlm@10 427 this.desc = cw.newUTF8(desc);
rlm@10 428 this.descriptor = desc;
rlm@10 429 this.signature = signature;
rlm@10 430 if(exceptions != null && exceptions.length > 0)
rlm@10 431 {
rlm@10 432 exceptionCount = exceptions.length;
rlm@10 433 this.exceptions = new int[exceptionCount];
rlm@10 434 for(int i = 0; i < exceptionCount; ++i)
rlm@10 435 {
rlm@10 436 this.exceptions[i] = cw.newClass(exceptions[i]);
rlm@10 437 }
rlm@10 438 }
rlm@10 439 this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING);
rlm@10 440 if(computeMaxs || computeFrames)
rlm@10 441 {
rlm@10 442 if(computeFrames && name.equals("<init>"))
rlm@10 443 {
rlm@10 444 this.access |= ACC_CONSTRUCTOR;
rlm@10 445 }
rlm@10 446 // updates maxLocals
rlm@10 447 int size = getArgumentsAndReturnSizes(descriptor) >> 2;
rlm@10 448 if((access & Opcodes.ACC_STATIC) != 0)
rlm@10 449 {
rlm@10 450 --size;
rlm@10 451 }
rlm@10 452 maxLocals = size;
rlm@10 453 // creates and visits the label for the first basic block
rlm@10 454 labels = new Label();
rlm@10 455 labels.status |= Label.PUSHED;
rlm@10 456 visitLabel(labels);
rlm@10 457 }
rlm@10 458 }
rlm@10 459
rlm@10 460 // ------------------------------------------------------------------------
rlm@10 461 // Implementation of the MethodVisitor interface
rlm@10 462 // ------------------------------------------------------------------------
rlm@10 463
rlm@10 464 public AnnotationVisitor visitAnnotationDefault(){
rlm@10 465 annd = new ByteVector();
rlm@10 466 return new AnnotationWriter(cw, false, annd, null, 0);
rlm@10 467 }
rlm@10 468
rlm@10 469 public AnnotationVisitor visitAnnotation(
rlm@10 470 final String desc,
rlm@10 471 final boolean visible){
rlm@10 472 ByteVector bv = new ByteVector();
rlm@10 473 // write type, and reserve space for values count
rlm@10 474 bv.putShort(cw.newUTF8(desc)).putShort(0);
rlm@10 475 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
rlm@10 476 if(visible)
rlm@10 477 {
rlm@10 478 aw.next = anns;
rlm@10 479 anns = aw;
rlm@10 480 }
rlm@10 481 else
rlm@10 482 {
rlm@10 483 aw.next = ianns;
rlm@10 484 ianns = aw;
rlm@10 485 }
rlm@10 486 return aw;
rlm@10 487 }
rlm@10 488
rlm@10 489 public AnnotationVisitor visitParameterAnnotation(
rlm@10 490 final int parameter,
rlm@10 491 final String desc,
rlm@10 492 final boolean visible){
rlm@10 493 ByteVector bv = new ByteVector();
rlm@10 494 // write type, and reserve space for values count
rlm@10 495 bv.putShort(cw.newUTF8(desc)).putShort(0);
rlm@10 496 AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
rlm@10 497 if(visible)
rlm@10 498 {
rlm@10 499 if(panns == null)
rlm@10 500 {
rlm@10 501 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
rlm@10 502 }
rlm@10 503 aw.next = panns[parameter];
rlm@10 504 panns[parameter] = aw;
rlm@10 505 }
rlm@10 506 else
rlm@10 507 {
rlm@10 508 if(ipanns == null)
rlm@10 509 {
rlm@10 510 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
rlm@10 511 }
rlm@10 512 aw.next = ipanns[parameter];
rlm@10 513 ipanns[parameter] = aw;
rlm@10 514 }
rlm@10 515 return aw;
rlm@10 516 }
rlm@10 517
rlm@10 518 public void visitAttribute(final Attribute attr){
rlm@10 519 if(attr.isCodeAttribute())
rlm@10 520 {
rlm@10 521 attr.next = cattrs;
rlm@10 522 cattrs = attr;
rlm@10 523 }
rlm@10 524 else
rlm@10 525 {
rlm@10 526 attr.next = attrs;
rlm@10 527 attrs = attr;
rlm@10 528 }
rlm@10 529 }
rlm@10 530
rlm@10 531 public void visitCode(){
rlm@10 532 }
rlm@10 533
rlm@10 534 public void visitFrame(
rlm@10 535 final int type,
rlm@10 536 final int nLocal,
rlm@10 537 final Object[] local,
rlm@10 538 final int nStack,
rlm@10 539 final Object[] stack){
rlm@10 540 if(compute == FRAMES)
rlm@10 541 {
rlm@10 542 return;
rlm@10 543 }
rlm@10 544
rlm@10 545 if(type == Opcodes.F_NEW)
rlm@10 546 {
rlm@10 547 startFrame(code.length, nLocal, nStack);
rlm@10 548 for(int i = 0; i < nLocal; ++i)
rlm@10 549 {
rlm@10 550 if(local[i] instanceof String)
rlm@10 551 {
rlm@10 552 frame[frameIndex++] = Frame.OBJECT
rlm@10 553 | cw.addType((String) local[i]);
rlm@10 554 }
rlm@10 555 else if(local[i] instanceof Integer)
rlm@10 556 {
rlm@10 557 frame[frameIndex++] = ((Integer) local[i]).intValue();
rlm@10 558 }
rlm@10 559 else
rlm@10 560 {
rlm@10 561 frame[frameIndex++] = Frame.UNINITIALIZED
rlm@10 562 | cw.addUninitializedType("",
rlm@10 563 ((Label) local[i]).position);
rlm@10 564 }
rlm@10 565 }
rlm@10 566 for(int i = 0; i < nStack; ++i)
rlm@10 567 {
rlm@10 568 if(stack[i] instanceof String)
rlm@10 569 {
rlm@10 570 frame[frameIndex++] = Frame.OBJECT
rlm@10 571 | cw.addType((String) stack[i]);
rlm@10 572 }
rlm@10 573 else if(stack[i] instanceof Integer)
rlm@10 574 {
rlm@10 575 frame[frameIndex++] = ((Integer) stack[i]).intValue();
rlm@10 576 }
rlm@10 577 else
rlm@10 578 {
rlm@10 579 frame[frameIndex++] = Frame.UNINITIALIZED
rlm@10 580 | cw.addUninitializedType("",
rlm@10 581 ((Label) stack[i]).position);
rlm@10 582 }
rlm@10 583 }
rlm@10 584 endFrame();
rlm@10 585 }
rlm@10 586 else
rlm@10 587 {
rlm@10 588 int delta;
rlm@10 589 if(stackMap == null)
rlm@10 590 {
rlm@10 591 stackMap = new ByteVector();
rlm@10 592 delta = code.length;
rlm@10 593 }
rlm@10 594 else
rlm@10 595 {
rlm@10 596 delta = code.length - previousFrameOffset - 1;
rlm@10 597 }
rlm@10 598
rlm@10 599 switch(type)
rlm@10 600 {
rlm@10 601 case Opcodes.F_FULL:
rlm@10 602 stackMap.putByte(FULL_FRAME)
rlm@10 603 .putShort(delta)
rlm@10 604 .putShort(nLocal);
rlm@10 605 for(int i = 0; i < nLocal; ++i)
rlm@10 606 {
rlm@10 607 writeFrameType(local[i]);
rlm@10 608 }
rlm@10 609 stackMap.putShort(nStack);
rlm@10 610 for(int i = 0; i < nStack; ++i)
rlm@10 611 {
rlm@10 612 writeFrameType(stack[i]);
rlm@10 613 }
rlm@10 614 break;
rlm@10 615 case Opcodes.F_APPEND:
rlm@10 616 stackMap.putByte(SAME_FRAME_EXTENDED + nLocal)
rlm@10 617 .putShort(delta);
rlm@10 618 for(int i = 0; i < nLocal; ++i)
rlm@10 619 {
rlm@10 620 writeFrameType(local[i]);
rlm@10 621 }
rlm@10 622 break;
rlm@10 623 case Opcodes.F_CHOP:
rlm@10 624 stackMap.putByte(SAME_FRAME_EXTENDED - nLocal)
rlm@10 625 .putShort(delta);
rlm@10 626 break;
rlm@10 627 case Opcodes.F_SAME:
rlm@10 628 if(delta < 64)
rlm@10 629 {
rlm@10 630 stackMap.putByte(delta);
rlm@10 631 }
rlm@10 632 else
rlm@10 633 {
rlm@10 634 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
rlm@10 635 }
rlm@10 636 break;
rlm@10 637 case Opcodes.F_SAME1:
rlm@10 638 if(delta < 64)
rlm@10 639 {
rlm@10 640 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
rlm@10 641 }
rlm@10 642 else
rlm@10 643 {
rlm@10 644 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
rlm@10 645 .putShort(delta);
rlm@10 646 }
rlm@10 647 writeFrameType(stack[0]);
rlm@10 648 break;
rlm@10 649 }
rlm@10 650
rlm@10 651 previousFrameOffset = code.length;
rlm@10 652 ++frameCount;
rlm@10 653 }
rlm@10 654 }
rlm@10 655
rlm@10 656 public void visitInsn(final int opcode){
rlm@10 657 // adds the instruction to the bytecode of the method
rlm@10 658 code.putByte(opcode);
rlm@10 659 // update currentBlock
rlm@10 660 // Label currentBlock = this.currentBlock;
rlm@10 661 if(currentBlock != null)
rlm@10 662 {
rlm@10 663 if(compute == FRAMES)
rlm@10 664 {
rlm@10 665 currentBlock.frame.execute(opcode, 0, null, null);
rlm@10 666 }
rlm@10 667 else
rlm@10 668 {
rlm@10 669 // updates current and max stack sizes
rlm@10 670 int size = stackSize + Frame.SIZE[opcode];
rlm@10 671 if(size > maxStackSize)
rlm@10 672 {
rlm@10 673 maxStackSize = size;
rlm@10 674 }
rlm@10 675 stackSize = size;
rlm@10 676 }
rlm@10 677 // if opcode == ATHROW or xRETURN, ends current block (no successor)
rlm@10 678 if((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
rlm@10 679 || opcode == Opcodes.ATHROW)
rlm@10 680 {
rlm@10 681 noSuccessor();
rlm@10 682 }
rlm@10 683 }
rlm@10 684 }
rlm@10 685
rlm@10 686 public void visitIntInsn(final int opcode, final int operand){
rlm@10 687 // Label currentBlock = this.currentBlock;
rlm@10 688 if(currentBlock != null)
rlm@10 689 {
rlm@10 690 if(compute == FRAMES)
rlm@10 691 {
rlm@10 692 currentBlock.frame.execute(opcode, operand, null, null);
rlm@10 693 }
rlm@10 694 else if(opcode != Opcodes.NEWARRAY)
rlm@10 695 {
rlm@10 696 // updates current and max stack sizes only for NEWARRAY
rlm@10 697 // (stack size variation = 0 for BIPUSH or SIPUSH)
rlm@10 698 int size = stackSize + 1;
rlm@10 699 if(size > maxStackSize)
rlm@10 700 {
rlm@10 701 maxStackSize = size;
rlm@10 702 }
rlm@10 703 stackSize = size;
rlm@10 704 }
rlm@10 705 }
rlm@10 706 // adds the instruction to the bytecode of the method
rlm@10 707 if(opcode == Opcodes.SIPUSH)
rlm@10 708 {
rlm@10 709 code.put12(opcode, operand);
rlm@10 710 }
rlm@10 711 else
rlm@10 712 { // BIPUSH or NEWARRAY
rlm@10 713 code.put11(opcode, operand);
rlm@10 714 }
rlm@10 715 }
rlm@10 716
rlm@10 717 public void visitVarInsn(final int opcode, final int var){
rlm@10 718 // Label currentBlock = this.currentBlock;
rlm@10 719 if(currentBlock != null)
rlm@10 720 {
rlm@10 721 if(compute == FRAMES)
rlm@10 722 {
rlm@10 723 currentBlock.frame.execute(opcode, var, null, null);
rlm@10 724 }
rlm@10 725 else
rlm@10 726 {
rlm@10 727 // updates current and max stack sizes
rlm@10 728 if(opcode == Opcodes.RET)
rlm@10 729 {
rlm@10 730 // no stack change, but end of current block (no successor)
rlm@10 731 currentBlock.status |= Label.RET;
rlm@10 732 // save 'stackSize' here for future use
rlm@10 733 // (see {@link #findSubroutineSuccessors})
rlm@10 734 currentBlock.inputStackTop = stackSize;
rlm@10 735 noSuccessor();
rlm@10 736 }
rlm@10 737 else
rlm@10 738 { // xLOAD or xSTORE
rlm@10 739 int size = stackSize + Frame.SIZE[opcode];
rlm@10 740 if(size > maxStackSize)
rlm@10 741 {
rlm@10 742 maxStackSize = size;
rlm@10 743 }
rlm@10 744 stackSize = size;
rlm@10 745 }
rlm@10 746 }
rlm@10 747 }
rlm@10 748 if(compute != NOTHING)
rlm@10 749 {
rlm@10 750 // updates max locals
rlm@10 751 int n;
rlm@10 752 if(opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD
rlm@10 753 || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE)
rlm@10 754 {
rlm@10 755 n = var + 2;
rlm@10 756 }
rlm@10 757 else
rlm@10 758 {
rlm@10 759 n = var + 1;
rlm@10 760 }
rlm@10 761 if(n > maxLocals)
rlm@10 762 {
rlm@10 763 maxLocals = n;
rlm@10 764 }
rlm@10 765 }
rlm@10 766 // adds the instruction to the bytecode of the method
rlm@10 767 if(var < 4 && opcode != Opcodes.RET)
rlm@10 768 {
rlm@10 769 int opt;
rlm@10 770 if(opcode < Opcodes.ISTORE)
rlm@10 771 {
rlm@10 772 /* ILOAD_0 */
rlm@10 773 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
rlm@10 774 }
rlm@10 775 else
rlm@10 776 {
rlm@10 777 /* ISTORE_0 */
rlm@10 778 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
rlm@10 779 }
rlm@10 780 code.putByte(opt);
rlm@10 781 }
rlm@10 782 else if(var >= 256)
rlm@10 783 {
rlm@10 784 code.putByte(196 /* WIDE */).put12(opcode, var);
rlm@10 785 }
rlm@10 786 else
rlm@10 787 {
rlm@10 788 code.put11(opcode, var);
rlm@10 789 }
rlm@10 790 if(opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0)
rlm@10 791 {
rlm@10 792 visitLabel(new Label());
rlm@10 793 }
rlm@10 794 }
rlm@10 795
rlm@10 796 public void visitTypeInsn(final int opcode, final String desc){
rlm@10 797 Item i = cw.newClassItem(desc);
rlm@10 798 // Label currentBlock = this.currentBlock;
rlm@10 799 if(currentBlock != null)
rlm@10 800 {
rlm@10 801 if(compute == FRAMES)
rlm@10 802 {
rlm@10 803 currentBlock.frame.execute(opcode, code.length, cw, i);
rlm@10 804 }
rlm@10 805 else if(opcode == Opcodes.NEW)
rlm@10 806 {
rlm@10 807 // updates current and max stack sizes only if opcode == NEW
rlm@10 808 // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
rlm@10 809 int size = stackSize + 1;
rlm@10 810 if(size > maxStackSize)
rlm@10 811 {
rlm@10 812 maxStackSize = size;
rlm@10 813 }
rlm@10 814 stackSize = size;
rlm@10 815 }
rlm@10 816 }
rlm@10 817 // adds the instruction to the bytecode of the method
rlm@10 818 code.put12(opcode, i.index);
rlm@10 819 }
rlm@10 820
rlm@10 821 public void visitFieldInsn(
rlm@10 822 final int opcode,
rlm@10 823 final String owner,
rlm@10 824 final String name,
rlm@10 825 final String desc){
rlm@10 826 Item i = cw.newFieldItem(owner, name, desc);
rlm@10 827 // Label currentBlock = this.currentBlock;
rlm@10 828 if(currentBlock != null)
rlm@10 829 {
rlm@10 830 if(compute == FRAMES)
rlm@10 831 {
rlm@10 832 currentBlock.frame.execute(opcode, 0, cw, i);
rlm@10 833 }
rlm@10 834 else
rlm@10 835 {
rlm@10 836 int size;
rlm@10 837 // computes the stack size variation
rlm@10 838 char c = desc.charAt(0);
rlm@10 839 switch(opcode)
rlm@10 840 {
rlm@10 841 case Opcodes.GETSTATIC:
rlm@10 842 size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
rlm@10 843 break;
rlm@10 844 case Opcodes.PUTSTATIC:
rlm@10 845 size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
rlm@10 846 break;
rlm@10 847 case Opcodes.GETFIELD:
rlm@10 848 size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
rlm@10 849 break;
rlm@10 850 // case Constants.PUTFIELD:
rlm@10 851 default:
rlm@10 852 size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
rlm@10 853 break;
rlm@10 854 }
rlm@10 855 // updates current and max stack sizes
rlm@10 856 if(size > maxStackSize)
rlm@10 857 {
rlm@10 858 maxStackSize = size;
rlm@10 859 }
rlm@10 860 stackSize = size;
rlm@10 861 }
rlm@10 862 }
rlm@10 863 // adds the instruction to the bytecode of the method
rlm@10 864 code.put12(opcode, i.index);
rlm@10 865 }
rlm@10 866
rlm@10 867 public void visitMethodInsn(
rlm@10 868 final int opcode,
rlm@10 869 final String owner,
rlm@10 870 final String name,
rlm@10 871 final String desc){
rlm@10 872 boolean itf = opcode == Opcodes.INVOKEINTERFACE;
rlm@10 873 Item i = cw.newMethodItem(owner, name, desc, itf);
rlm@10 874 int argSize = i.intVal;
rlm@10 875 // Label currentBlock = this.currentBlock;
rlm@10 876 if(currentBlock != null)
rlm@10 877 {
rlm@10 878 if(compute == FRAMES)
rlm@10 879 {
rlm@10 880 currentBlock.frame.execute(opcode, 0, cw, i);
rlm@10 881 }
rlm@10 882 else
rlm@10 883 {
rlm@10 884 /*
rlm@10 885 * computes the stack size variation. In order not to recompute
rlm@10 886 * several times this variation for the same Item, we use the
rlm@10 887 * intVal field of this item to store this variation, once it
rlm@10 888 * has been computed. More precisely this intVal field stores
rlm@10 889 * the sizes of the arguments and of the return value
rlm@10 890 * corresponding to desc.
rlm@10 891 */
rlm@10 892 if(argSize == 0)
rlm@10 893 {
rlm@10 894 // the above sizes have not been computed yet,
rlm@10 895 // so we compute them...
rlm@10 896 argSize = getArgumentsAndReturnSizes(desc);
rlm@10 897 // ... and we save them in order
rlm@10 898 // not to recompute them in the future
rlm@10 899 i.intVal = argSize;
rlm@10 900 }
rlm@10 901 int size;
rlm@10 902 if(opcode == Opcodes.INVOKESTATIC)
rlm@10 903 {
rlm@10 904 size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
rlm@10 905 }
rlm@10 906 else
rlm@10 907 {
rlm@10 908 size = stackSize - (argSize >> 2) + (argSize & 0x03);
rlm@10 909 }
rlm@10 910 // updates current and max stack sizes
rlm@10 911 if(size > maxStackSize)
rlm@10 912 {
rlm@10 913 maxStackSize = size;
rlm@10 914 }
rlm@10 915 stackSize = size;
rlm@10 916 }
rlm@10 917 }
rlm@10 918 // adds the instruction to the bytecode of the method
rlm@10 919 if(itf)
rlm@10 920 {
rlm@10 921 if(argSize == 0)
rlm@10 922 {
rlm@10 923 argSize = getArgumentsAndReturnSizes(desc);
rlm@10 924 i.intVal = argSize;
rlm@10 925 }
rlm@10 926 code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
rlm@10 927 }
rlm@10 928 else
rlm@10 929 {
rlm@10 930 code.put12(opcode, i.index);
rlm@10 931 }
rlm@10 932 }
rlm@10 933
rlm@10 934 public void visitJumpInsn(final int opcode, final Label label){
rlm@10 935 Label nextInsn = null;
rlm@10 936 // Label currentBlock = this.currentBlock;
rlm@10 937 if(currentBlock != null)
rlm@10 938 {
rlm@10 939 if(compute == FRAMES)
rlm@10 940 {
rlm@10 941 currentBlock.frame.execute(opcode, 0, null, null);
rlm@10 942 // 'label' is the target of a jump instruction
rlm@10 943 label.getFirst().status |= Label.TARGET;
rlm@10 944 // adds 'label' as a successor of this basic block
rlm@10 945 addSuccessor(Edge.NORMAL, label);
rlm@10 946 if(opcode != Opcodes.GOTO)
rlm@10 947 {
rlm@10 948 // creates a Label for the next basic block
rlm@10 949 nextInsn = new Label();
rlm@10 950 }
rlm@10 951 }
rlm@10 952 else
rlm@10 953 {
rlm@10 954 if(opcode == Opcodes.JSR)
rlm@10 955 {
rlm@10 956 jsr = true;
rlm@10 957 currentBlock.status |= Label.JSR;
rlm@10 958 addSuccessor(stackSize + 1, label);
rlm@10 959 // creates a Label for the next basic block
rlm@10 960 nextInsn = new Label();
rlm@10 961 /*
rlm@10 962 * note that, by construction in this method, a JSR block
rlm@10 963 * has at least two successors in the control flow graph:
rlm@10 964 * the first one leads the next instruction after the JSR,
rlm@10 965 * while the second one leads to the JSR target.
rlm@10 966 */
rlm@10 967 }
rlm@10 968 else
rlm@10 969 {
rlm@10 970 // updates current stack size (max stack size unchanged
rlm@10 971 // because stack size variation always negative in this
rlm@10 972 // case)
rlm@10 973 stackSize += Frame.SIZE[opcode];
rlm@10 974 addSuccessor(stackSize, label);
rlm@10 975 }
rlm@10 976 }
rlm@10 977 }
rlm@10 978 // adds the instruction to the bytecode of the method
rlm@10 979 if((label.status & Label.RESOLVED) != 0
rlm@10 980 && label.position - code.length < Short.MIN_VALUE)
rlm@10 981 {
rlm@10 982 /*
rlm@10 983 * case of a backward jump with an offset < -32768. In this case we
rlm@10 984 * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
rlm@10 985 * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the
rlm@10 986 * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'>
rlm@10 987 * designates the instruction just after the GOTO_W.
rlm@10 988 */
rlm@10 989 if(opcode == Opcodes.GOTO)
rlm@10 990 {
rlm@10 991 code.putByte(200); // GOTO_W
rlm@10 992 }
rlm@10 993 else if(opcode == Opcodes.JSR)
rlm@10 994 {
rlm@10 995 code.putByte(201); // JSR_W
rlm@10 996 }
rlm@10 997 else
rlm@10 998 {
rlm@10 999 // if the IF instruction is transformed into IFNOT GOTO_W the
rlm@10 1000 // next instruction becomes the target of the IFNOT instruction
rlm@10 1001 if(nextInsn != null)
rlm@10 1002 {
rlm@10 1003 nextInsn.status |= Label.TARGET;
rlm@10 1004 }
rlm@10 1005 code.putByte(opcode <= 166
rlm@10 1006 ? ((opcode + 1) ^ 1) - 1
rlm@10 1007 : opcode ^ 1);
rlm@10 1008 code.putShort(8); // jump offset
rlm@10 1009 code.putByte(200); // GOTO_W
rlm@10 1010 }
rlm@10 1011 label.put(this, code, code.length - 1, true);
rlm@10 1012 }
rlm@10 1013 else
rlm@10 1014 {
rlm@10 1015 /*
rlm@10 1016 * case of a backward jump with an offset >= -32768, or of a forward
rlm@10 1017 * jump with, of course, an unknown offset. In these cases we store
rlm@10 1018 * the offset in 2 bytes (which will be increased in
rlm@10 1019 * resizeInstructions, if needed).
rlm@10 1020 */
rlm@10 1021 code.putByte(opcode);
rlm@10 1022 label.put(this, code, code.length - 1, false);
rlm@10 1023 }
rlm@10 1024 if(currentBlock != null)
rlm@10 1025 {
rlm@10 1026 if(nextInsn != null)
rlm@10 1027 {
rlm@10 1028 // if the jump instruction is not a GOTO, the next instruction
rlm@10 1029 // is also a successor of this instruction. Calling visitLabel
rlm@10 1030 // adds the label of this next instruction as a successor of the
rlm@10 1031 // current block, and starts a new basic block
rlm@10 1032 visitLabel(nextInsn);
rlm@10 1033 }
rlm@10 1034 if(opcode == Opcodes.GOTO)
rlm@10 1035 {
rlm@10 1036 noSuccessor();
rlm@10 1037 }
rlm@10 1038 }
rlm@10 1039 }
rlm@10 1040
rlm@10 1041 public void visitLabel(final Label label){
rlm@10 1042 // resolves previous forward references to label, if any
rlm@10 1043 resize |= label.resolve(this, code.length, code.data);
rlm@10 1044 // updates currentBlock
rlm@10 1045 if((label.status & Label.DEBUG) != 0)
rlm@10 1046 {
rlm@10 1047 return;
rlm@10 1048 }
rlm@10 1049 if(compute == FRAMES)
rlm@10 1050 {
rlm@10 1051 if(currentBlock != null)
rlm@10 1052 {
rlm@10 1053 if(label.position == currentBlock.position)
rlm@10 1054 {
rlm@10 1055 // successive labels, do not start a new basic block
rlm@10 1056 currentBlock.status |= (label.status & Label.TARGET);
rlm@10 1057 label.frame = currentBlock.frame;
rlm@10 1058 return;
rlm@10 1059 }
rlm@10 1060 // ends current block (with one new successor)
rlm@10 1061 addSuccessor(Edge.NORMAL, label);
rlm@10 1062 }
rlm@10 1063 // begins a new current block
rlm@10 1064 currentBlock = label;
rlm@10 1065 if(label.frame == null)
rlm@10 1066 {
rlm@10 1067 label.frame = new Frame();
rlm@10 1068 label.frame.owner = label;
rlm@10 1069 }
rlm@10 1070 // updates the basic block list
rlm@10 1071 if(previousBlock != null)
rlm@10 1072 {
rlm@10 1073 if(label.position == previousBlock.position)
rlm@10 1074 {
rlm@10 1075 previousBlock.status |= (label.status & Label.TARGET);
rlm@10 1076 label.frame = previousBlock.frame;
rlm@10 1077 currentBlock = previousBlock;
rlm@10 1078 return;
rlm@10 1079 }
rlm@10 1080 previousBlock.successor = label;
rlm@10 1081 }
rlm@10 1082 previousBlock = label;
rlm@10 1083 }
rlm@10 1084 else if(compute == MAXS)
rlm@10 1085 {
rlm@10 1086 if(currentBlock != null)
rlm@10 1087 {
rlm@10 1088 // ends current block (with one new successor)
rlm@10 1089 currentBlock.outputStackMax = maxStackSize;
rlm@10 1090 addSuccessor(stackSize, label);
rlm@10 1091 }
rlm@10 1092 // begins a new current block
rlm@10 1093 currentBlock = label;
rlm@10 1094 // resets the relative current and max stack sizes
rlm@10 1095 stackSize = 0;
rlm@10 1096 maxStackSize = 0;
rlm@10 1097 // updates the basic block list
rlm@10 1098 if(previousBlock != null)
rlm@10 1099 {
rlm@10 1100 previousBlock.successor = label;
rlm@10 1101 }
rlm@10 1102 previousBlock = label;
rlm@10 1103 }
rlm@10 1104 }
rlm@10 1105
rlm@10 1106 public void visitLdcInsn(final Object cst){
rlm@10 1107 Item i = cw.newConstItem(cst);
rlm@10 1108 // Label currentBlock = this.currentBlock;
rlm@10 1109 if(currentBlock != null)
rlm@10 1110 {
rlm@10 1111 if(compute == FRAMES)
rlm@10 1112 {
rlm@10 1113 currentBlock.frame.execute(Opcodes.LDC, 0, cw, i);
rlm@10 1114 }
rlm@10 1115 else
rlm@10 1116 {
rlm@10 1117 int size;
rlm@10 1118 // computes the stack size variation
rlm@10 1119 if(i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE)
rlm@10 1120 {
rlm@10 1121 size = stackSize + 2;
rlm@10 1122 }
rlm@10 1123 else
rlm@10 1124 {
rlm@10 1125 size = stackSize + 1;
rlm@10 1126 }
rlm@10 1127 // updates current and max stack sizes
rlm@10 1128 if(size > maxStackSize)
rlm@10 1129 {
rlm@10 1130 maxStackSize = size;
rlm@10 1131 }
rlm@10 1132 stackSize = size;
rlm@10 1133 }
rlm@10 1134 }
rlm@10 1135 // adds the instruction to the bytecode of the method
rlm@10 1136 int index = i.index;
rlm@10 1137 if(i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE)
rlm@10 1138 {
rlm@10 1139 code.put12(20 /* LDC2_W */, index);
rlm@10 1140 }
rlm@10 1141 else if(index >= 256)
rlm@10 1142 {
rlm@10 1143 code.put12(19 /* LDC_W */, index);
rlm@10 1144 }
rlm@10 1145 else
rlm@10 1146 {
rlm@10 1147 code.put11(Opcodes.LDC, index);
rlm@10 1148 }
rlm@10 1149 }
rlm@10 1150
rlm@10 1151 public void visitIincInsn(final int var, final int increment){
rlm@10 1152 if(currentBlock != null)
rlm@10 1153 {
rlm@10 1154 if(compute == FRAMES)
rlm@10 1155 {
rlm@10 1156 currentBlock.frame.execute(Opcodes.IINC, var, null, null);
rlm@10 1157 }
rlm@10 1158 }
rlm@10 1159 if(compute != NOTHING)
rlm@10 1160 {
rlm@10 1161 // updates max locals
rlm@10 1162 int n = var + 1;
rlm@10 1163 if(n > maxLocals)
rlm@10 1164 {
rlm@10 1165 maxLocals = n;
rlm@10 1166 }
rlm@10 1167 }
rlm@10 1168 // adds the instruction to the bytecode of the method
rlm@10 1169 if((var > 255) || (increment > 127) || (increment < -128))
rlm@10 1170 {
rlm@10 1171 code.putByte(196 /* WIDE */)
rlm@10 1172 .put12(Opcodes.IINC, var)
rlm@10 1173 .putShort(increment);
rlm@10 1174 }
rlm@10 1175 else
rlm@10 1176 {
rlm@10 1177 code.putByte(Opcodes.IINC).put11(var, increment);
rlm@10 1178 }
rlm@10 1179 }
rlm@10 1180
rlm@10 1181 public void visitTableSwitchInsn(
rlm@10 1182 final int min,
rlm@10 1183 final int max,
rlm@10 1184 final Label dflt,
rlm@10 1185 final Label labels[]){
rlm@10 1186 // adds the instruction to the bytecode of the method
rlm@10 1187 int source = code.length;
rlm@10 1188 code.putByte(Opcodes.TABLESWITCH);
rlm@10 1189 code.length += (4 - code.length % 4) % 4;
rlm@10 1190 dflt.put(this, code, source, true);
rlm@10 1191 code.putInt(min).putInt(max);
rlm@10 1192 for(int i = 0; i < labels.length; ++i)
rlm@10 1193 {
rlm@10 1194 labels[i].put(this, code, source, true);
rlm@10 1195 }
rlm@10 1196 // updates currentBlock
rlm@10 1197 visitSwitchInsn(dflt, labels);
rlm@10 1198 }
rlm@10 1199
rlm@10 1200 public void visitLookupSwitchInsn(
rlm@10 1201 final Label dflt,
rlm@10 1202 final int keys[],
rlm@10 1203 final Label labels[]){
rlm@10 1204 // adds the instruction to the bytecode of the method
rlm@10 1205 int source = code.length;
rlm@10 1206 code.putByte(Opcodes.LOOKUPSWITCH);
rlm@10 1207 code.length += (4 - code.length % 4) % 4;
rlm@10 1208 dflt.put(this, code, source, true);
rlm@10 1209 code.putInt(labels.length);
rlm@10 1210 for(int i = 0; i < labels.length; ++i)
rlm@10 1211 {
rlm@10 1212 code.putInt(keys[i]);
rlm@10 1213 labels[i].put(this, code, source, true);
rlm@10 1214 }
rlm@10 1215 // updates currentBlock
rlm@10 1216 visitSwitchInsn(dflt, labels);
rlm@10 1217 }
rlm@10 1218
rlm@10 1219 private void visitSwitchInsn(final Label dflt, final Label[] labels){
rlm@10 1220 // Label currentBlock = this.currentBlock;
rlm@10 1221 if(currentBlock != null)
rlm@10 1222 {
rlm@10 1223 if(compute == FRAMES)
rlm@10 1224 {
rlm@10 1225 currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
rlm@10 1226 // adds current block successors
rlm@10 1227 addSuccessor(Edge.NORMAL, dflt);
rlm@10 1228 dflt.getFirst().status |= Label.TARGET;
rlm@10 1229 for(int i = 0; i < labels.length; ++i)
rlm@10 1230 {
rlm@10 1231 addSuccessor(Edge.NORMAL, labels[i]);
rlm@10 1232 labels[i].getFirst().status |= Label.TARGET;
rlm@10 1233 }
rlm@10 1234 }
rlm@10 1235 else
rlm@10 1236 {
rlm@10 1237 // updates current stack size (max stack size unchanged)
rlm@10 1238 --stackSize;
rlm@10 1239 // adds current block successors
rlm@10 1240 addSuccessor(stackSize, dflt);
rlm@10 1241 for(int i = 0; i < labels.length; ++i)
rlm@10 1242 {
rlm@10 1243 addSuccessor(stackSize, labels[i]);
rlm@10 1244 }
rlm@10 1245 }
rlm@10 1246 // ends current block
rlm@10 1247 noSuccessor();
rlm@10 1248 }
rlm@10 1249 }
rlm@10 1250
rlm@10 1251 public void visitMultiANewArrayInsn(final String desc, final int dims){
rlm@10 1252 Item i = cw.newClassItem(desc);
rlm@10 1253 // Label currentBlock = this.currentBlock;
rlm@10 1254 if(currentBlock != null)
rlm@10 1255 {
rlm@10 1256 if(compute == FRAMES)
rlm@10 1257 {
rlm@10 1258 currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i);
rlm@10 1259 }
rlm@10 1260 else
rlm@10 1261 {
rlm@10 1262 // updates current stack size (max stack size unchanged because
rlm@10 1263 // stack size variation always negative or null)
rlm@10 1264 stackSize += 1 - dims;
rlm@10 1265 }
rlm@10 1266 }
rlm@10 1267 // adds the instruction to the bytecode of the method
rlm@10 1268 code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims);
rlm@10 1269 }
rlm@10 1270
rlm@10 1271 public void visitTryCatchBlock(
rlm@10 1272 final Label start,
rlm@10 1273 final Label end,
rlm@10 1274 final Label handler,
rlm@10 1275 final String type){
rlm@10 1276 ++handlerCount;
rlm@10 1277 Handler h = new Handler();
rlm@10 1278 h.start = start;
rlm@10 1279 h.end = end;
rlm@10 1280 h.handler = handler;
rlm@10 1281 h.desc = type;
rlm@10 1282 h.type = type != null ? cw.newClass(type) : 0;
rlm@10 1283 if(lastHandler == null)
rlm@10 1284 {
rlm@10 1285 firstHandler = h;
rlm@10 1286 }
rlm@10 1287 else
rlm@10 1288 {
rlm@10 1289 lastHandler.next = h;
rlm@10 1290 }
rlm@10 1291 lastHandler = h;
rlm@10 1292 }
rlm@10 1293
rlm@10 1294 public void visitLocalVariable(
rlm@10 1295 final String name,
rlm@10 1296 final String desc,
rlm@10 1297 final String signature,
rlm@10 1298 final Label start,
rlm@10 1299 final Label end,
rlm@10 1300 final int index){
rlm@10 1301 if(signature != null)
rlm@10 1302 {
rlm@10 1303 if(localVarType == null)
rlm@10 1304 {
rlm@10 1305 localVarType = new ByteVector();
rlm@10 1306 }
rlm@10 1307 ++localVarTypeCount;
rlm@10 1308 localVarType.putShort(start.position)
rlm@10 1309 .putShort(end.position - start.position)
rlm@10 1310 .putShort(cw.newUTF8(name))
rlm@10 1311 .putShort(cw.newUTF8(signature))
rlm@10 1312 .putShort(index);
rlm@10 1313 }
rlm@10 1314 if(localVar == null)
rlm@10 1315 {
rlm@10 1316 localVar = new ByteVector();
rlm@10 1317 }
rlm@10 1318 ++localVarCount;
rlm@10 1319 localVar.putShort(start.position)
rlm@10 1320 .putShort(end.position - start.position)
rlm@10 1321 .putShort(cw.newUTF8(name))
rlm@10 1322 .putShort(cw.newUTF8(desc))
rlm@10 1323 .putShort(index);
rlm@10 1324 if(compute != NOTHING)
rlm@10 1325 {
rlm@10 1326 // updates max locals
rlm@10 1327 char c = desc.charAt(0);
rlm@10 1328 int n = index + (c == 'J' || c == 'D' ? 2 : 1);
rlm@10 1329 if(n > maxLocals)
rlm@10 1330 {
rlm@10 1331 maxLocals = n;
rlm@10 1332 }
rlm@10 1333 }
rlm@10 1334 }
rlm@10 1335
rlm@10 1336 public void visitLineNumber(final int line, final Label start){
rlm@10 1337 if(lineNumber == null)
rlm@10 1338 {
rlm@10 1339 lineNumber = new ByteVector();
rlm@10 1340 }
rlm@10 1341 ++lineNumberCount;
rlm@10 1342 lineNumber.putShort(start.position);
rlm@10 1343 lineNumber.putShort(line);
rlm@10 1344 }
rlm@10 1345
rlm@10 1346 public void visitMaxs(final int maxStack, final int maxLocals){
rlm@10 1347 if(compute == FRAMES)
rlm@10 1348 {
rlm@10 1349 // completes the control flow graph with exception handler blocks
rlm@10 1350 Handler handler = firstHandler;
rlm@10 1351 while(handler != null)
rlm@10 1352 {
rlm@10 1353 Label l = handler.start.getFirst();
rlm@10 1354 Label h = handler.handler.getFirst();
rlm@10 1355 Label e = handler.end.getFirst();
rlm@10 1356 // computes the kind of the edges to 'h'
rlm@10 1357 String t = handler.desc == null
rlm@10 1358 ? "java/lang/Throwable"
rlm@10 1359 : handler.desc;
rlm@10 1360 int kind = Frame.OBJECT | cw.addType(t);
rlm@10 1361 // h is an exception handler
rlm@10 1362 h.status |= Label.TARGET;
rlm@10 1363 // adds 'h' as a successor of labels between 'start' and 'end'
rlm@10 1364 while(l != e)
rlm@10 1365 {
rlm@10 1366 // creates an edge to 'h'
rlm@10 1367 Edge b = new Edge();
rlm@10 1368 b.info = kind;
rlm@10 1369 b.successor = h;
rlm@10 1370 // adds it to the successors of 'l'
rlm@10 1371 b.next = l.successors;
rlm@10 1372 l.successors = b;
rlm@10 1373 // goes to the next label
rlm@10 1374 l = l.successor;
rlm@10 1375 }
rlm@10 1376 handler = handler.next;
rlm@10 1377 }
rlm@10 1378
rlm@10 1379 // creates and visits the first (implicit) frame
rlm@10 1380 Frame f = labels.frame;
rlm@10 1381 Type[] args = Type.getArgumentTypes(descriptor);
rlm@10 1382 f.initInputFrame(cw, access, args, this.maxLocals);
rlm@10 1383 visitFrame(f);
rlm@10 1384
rlm@10 1385 /*
rlm@10 1386 * fix point algorithm: mark the first basic block as 'changed'
rlm@10 1387 * (i.e. put it in the 'changed' list) and, while there are changed
rlm@10 1388 * basic blocks, choose one, mark it as unchanged, and update its
rlm@10 1389 * successors (which can be changed in the process).
rlm@10 1390 */
rlm@10 1391 int max = 0;
rlm@10 1392 Label changed = labels;
rlm@10 1393 while(changed != null)
rlm@10 1394 {
rlm@10 1395 // removes a basic block from the list of changed basic blocks
rlm@10 1396 Label l = changed;
rlm@10 1397 changed = changed.next;
rlm@10 1398 l.next = null;
rlm@10 1399 f = l.frame;
rlm@10 1400 // a reacheable jump target must be stored in the stack map
rlm@10 1401 if((l.status & Label.TARGET) != 0)
rlm@10 1402 {
rlm@10 1403 l.status |= Label.STORE;
rlm@10 1404 }
rlm@10 1405 // all visited labels are reacheable, by definition
rlm@10 1406 l.status |= Label.REACHABLE;
rlm@10 1407 // updates the (absolute) maximum stack size
rlm@10 1408 int blockMax = f.inputStack.length + l.outputStackMax;
rlm@10 1409 if(blockMax > max)
rlm@10 1410 {
rlm@10 1411 max = blockMax;
rlm@10 1412 }
rlm@10 1413 // updates the successors of the current basic block
rlm@10 1414 Edge e = l.successors;
rlm@10 1415 while(e != null)
rlm@10 1416 {
rlm@10 1417 Label n = e.successor.getFirst();
rlm@10 1418 boolean change = f.merge(cw, n.frame, e.info);
rlm@10 1419 if(change && n.next == null)
rlm@10 1420 {
rlm@10 1421 // if n has changed and is not already in the 'changed'
rlm@10 1422 // list, adds it to this list
rlm@10 1423 n.next = changed;
rlm@10 1424 changed = n;
rlm@10 1425 }
rlm@10 1426 e = e.next;
rlm@10 1427 }
rlm@10 1428 }
rlm@10 1429 this.maxStack = max;
rlm@10 1430
rlm@10 1431 // visits all the frames that must be stored in the stack map
rlm@10 1432 Label l = labels;
rlm@10 1433 while(l != null)
rlm@10 1434 {
rlm@10 1435 f = l.frame;
rlm@10 1436 if((l.status & Label.STORE) != 0)
rlm@10 1437 {
rlm@10 1438 visitFrame(f);
rlm@10 1439 }
rlm@10 1440 if((l.status & Label.REACHABLE) == 0)
rlm@10 1441 {
rlm@10 1442 // finds start and end of dead basic block
rlm@10 1443 Label k = l.successor;
rlm@10 1444 int start = l.position;
rlm@10 1445 int end = (k == null ? code.length : k.position) - 1;
rlm@10 1446 // if non empty basic block
rlm@10 1447 if(end >= start)
rlm@10 1448 {
rlm@10 1449 // replaces instructions with NOP ... NOP ATHROW
rlm@10 1450 for(int i = start; i < end; ++i)
rlm@10 1451 {
rlm@10 1452 code.data[i] = Opcodes.NOP;
rlm@10 1453 }
rlm@10 1454 code.data[end] = (byte) Opcodes.ATHROW;
rlm@10 1455 // emits a frame for this unreachable block
rlm@10 1456 startFrame(start, 0, 1);
rlm@10 1457 frame[frameIndex++] = Frame.OBJECT
rlm@10 1458 | cw.addType("java/lang/Throwable");
rlm@10 1459 endFrame();
rlm@10 1460 }
rlm@10 1461 }
rlm@10 1462 l = l.successor;
rlm@10 1463 }
rlm@10 1464 }
rlm@10 1465 else if(compute == MAXS)
rlm@10 1466 {
rlm@10 1467 // completes the control flow graph with exception handler blocks
rlm@10 1468 Handler handler = firstHandler;
rlm@10 1469 while(handler != null)
rlm@10 1470 {
rlm@10 1471 Label l = handler.start;
rlm@10 1472 Label h = handler.handler;
rlm@10 1473 Label e = handler.end;
rlm@10 1474 // adds 'h' as a successor of labels between 'start' and 'end'
rlm@10 1475 while(l != e)
rlm@10 1476 {
rlm@10 1477 // creates an edge to 'h'
rlm@10 1478 Edge b = new Edge();
rlm@10 1479 b.info = Edge.EXCEPTION;
rlm@10 1480 b.successor = h;
rlm@10 1481 // adds it to the successors of 'l'
rlm@10 1482 if((l.status & Label.JSR) != 0)
rlm@10 1483 {
rlm@10 1484 // if l is a JSR block, adds b after the first two edges
rlm@10 1485 // to preserve the hypothesis about JSR block successors
rlm@10 1486 // order (see {@link #visitJumpInsn})
rlm@10 1487 b.next = l.successors.next.next;
rlm@10 1488 l.successors.next.next = b;
rlm@10 1489 }
rlm@10 1490 else
rlm@10 1491 {
rlm@10 1492 b.next = l.successors;
rlm@10 1493 l.successors = b;
rlm@10 1494 }
rlm@10 1495 // goes to the next label
rlm@10 1496 l = l.successor;
rlm@10 1497 }
rlm@10 1498 handler = handler.next;
rlm@10 1499 }
rlm@10 1500
rlm@10 1501 if(jsr)
rlm@10 1502 {
rlm@10 1503 // completes the control flow graph with the RET successors
rlm@10 1504 /*
rlm@10 1505 * first step: finds the subroutines. This step determines, for
rlm@10 1506 * each basic block, to which subroutine(s) it belongs, and
rlm@10 1507 * stores this set as a bit set in the {@link Label#status}
rlm@10 1508 * field. Subroutines are numbered with powers of two, from
rlm@10 1509 * 0x1000 to 0x80000000 (so there must be at most 20 subroutines
rlm@10 1510 * in a method).
rlm@10 1511 */
rlm@10 1512 // finds the basic blocks that belong to the "main" subroutine
rlm@10 1513 int id = 0x1000;
rlm@10 1514 findSubroutine(labels, id);
rlm@10 1515 // finds the basic blocks that belong to the real subroutines
rlm@10 1516 Label l = labels;
rlm@10 1517 while(l != null)
rlm@10 1518 {
rlm@10 1519 if((l.status & Label.JSR) != 0)
rlm@10 1520 {
rlm@10 1521 // the subroutine is defined by l's TARGET, not by l
rlm@10 1522 Label subroutine = l.successors.next.successor;
rlm@10 1523 // if this subroutine does not have an id yet...
rlm@10 1524 if((subroutine.status & ~0xFFF) == 0)
rlm@10 1525 {
rlm@10 1526 // ...assigns it a new id and finds its basic blocks
rlm@10 1527 id = id << 1;
rlm@10 1528 findSubroutine(subroutine, id);
rlm@10 1529 }
rlm@10 1530 }
rlm@10 1531 l = l.successor;
rlm@10 1532 }
rlm@10 1533 // second step: finds the successors of RET blocks
rlm@10 1534 findSubroutineSuccessors(0x1000, new Label[10], 0);
rlm@10 1535 }
rlm@10 1536
rlm@10 1537 /*
rlm@10 1538 * control flow analysis algorithm: while the block stack is not
rlm@10 1539 * empty, pop a block from this stack, update the max stack size,
rlm@10 1540 * compute the true (non relative) begin stack size of the
rlm@10 1541 * successors of this block, and push these successors onto the
rlm@10 1542 * stack (unless they have already been pushed onto the stack).
rlm@10 1543 * Note: by hypothesis, the {@link Label#inputStackTop} of the
rlm@10 1544 * blocks in the block stack are the true (non relative) beginning
rlm@10 1545 * stack sizes of these blocks.
rlm@10 1546 */
rlm@10 1547 int max = 0;
rlm@10 1548 Label stack = labels;
rlm@10 1549 while(stack != null)
rlm@10 1550 {
rlm@10 1551 // pops a block from the stack
rlm@10 1552 Label l = stack;
rlm@10 1553 stack = stack.next;
rlm@10 1554 // computes the true (non relative) max stack size of this block
rlm@10 1555 int start = l.inputStackTop;
rlm@10 1556 int blockMax = start + l.outputStackMax;
rlm@10 1557 // updates the global max stack size
rlm@10 1558 if(blockMax > max)
rlm@10 1559 {
rlm@10 1560 max = blockMax;
rlm@10 1561 }
rlm@10 1562 // analyses the successors of the block
rlm@10 1563 Edge b = l.successors;
rlm@10 1564 if((l.status & Label.JSR) != 0)
rlm@10 1565 {
rlm@10 1566 // ignores the first edge of JSR blocks (virtual successor)
rlm@10 1567 b = b.next;
rlm@10 1568 }
rlm@10 1569 while(b != null)
rlm@10 1570 {
rlm@10 1571 l = b.successor;
rlm@10 1572 // if this successor has not already been pushed...
rlm@10 1573 if((l.status & Label.PUSHED) == 0)
rlm@10 1574 {
rlm@10 1575 // computes its true beginning stack size...
rlm@10 1576 l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start
rlm@10 1577 + b.info;
rlm@10 1578 // ...and pushes it onto the stack
rlm@10 1579 l.status |= Label.PUSHED;
rlm@10 1580 l.next = stack;
rlm@10 1581 stack = l;
rlm@10 1582 }
rlm@10 1583 b = b.next;
rlm@10 1584 }
rlm@10 1585 }
rlm@10 1586 this.maxStack = max;
rlm@10 1587 }
rlm@10 1588 else
rlm@10 1589 {
rlm@10 1590 this.maxStack = maxStack;
rlm@10 1591 this.maxLocals = maxLocals;
rlm@10 1592 }
rlm@10 1593 }
rlm@10 1594
rlm@10 1595 public void visitEnd(){
rlm@10 1596 }
rlm@10 1597
rlm@10 1598 // ------------------------------------------------------------------------
rlm@10 1599 // Utility methods: control flow analysis algorithm
rlm@10 1600 // ------------------------------------------------------------------------
rlm@10 1601
rlm@10 1602 /**
rlm@10 1603 * Computes the size of the arguments and of the return value of a method.
rlm@10 1604 *
rlm@10 1605 * @param desc the descriptor of a method.
rlm@10 1606 * @return the size of the arguments of the method (plus one for the
rlm@10 1607 * implicit this argument), argSize, and the size of its return
rlm@10 1608 * value, retSize, packed into a single int i =
rlm@10 1609 * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal
rlm@10 1610 * to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
rlm@10 1611 */
rlm@10 1612 static int getArgumentsAndReturnSizes(final String desc){
rlm@10 1613 int n = 1;
rlm@10 1614 int c = 1;
rlm@10 1615 while(true)
rlm@10 1616 {
rlm@10 1617 char car = desc.charAt(c++);
rlm@10 1618 if(car == ')')
rlm@10 1619 {
rlm@10 1620 car = desc.charAt(c);
rlm@10 1621 return n << 2
rlm@10 1622 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
rlm@10 1623 }
rlm@10 1624 else if(car == 'L')
rlm@10 1625 {
rlm@10 1626 while(desc.charAt(c++) != ';')
rlm@10 1627 {
rlm@10 1628 }
rlm@10 1629 n += 1;
rlm@10 1630 }
rlm@10 1631 else if(car == '[')
rlm@10 1632 {
rlm@10 1633 while((car = desc.charAt(c)) == '[')
rlm@10 1634 {
rlm@10 1635 ++c;
rlm@10 1636 }
rlm@10 1637 if(car == 'D' || car == 'J')
rlm@10 1638 {
rlm@10 1639 n -= 1;
rlm@10 1640 }
rlm@10 1641 }
rlm@10 1642 else if(car == 'D' || car == 'J')
rlm@10 1643 {
rlm@10 1644 n += 2;
rlm@10 1645 }
rlm@10 1646 else
rlm@10 1647 {
rlm@10 1648 n += 1;
rlm@10 1649 }
rlm@10 1650 }
rlm@10 1651 }
rlm@10 1652
rlm@10 1653 /**
rlm@10 1654 * Adds a successor to the {@link #currentBlock currentBlock} block.
rlm@10 1655 *
rlm@10 1656 * @param info information about the control flow edge to be added.
rlm@10 1657 * @param successor the successor block to be added to the current block.
rlm@10 1658 */
rlm@10 1659 private void addSuccessor(final int info, final Label successor){
rlm@10 1660 // creates and initializes an Edge object...
rlm@10 1661 Edge b = new Edge();
rlm@10 1662 b.info = info;
rlm@10 1663 b.successor = successor;
rlm@10 1664 // ...and adds it to the successor list of the currentBlock block
rlm@10 1665 b.next = currentBlock.successors;
rlm@10 1666 currentBlock.successors = b;
rlm@10 1667 }
rlm@10 1668
rlm@10 1669 /**
rlm@10 1670 * Ends the current basic block. This method must be used in the case where
rlm@10 1671 * the current basic block does not have any successor.
rlm@10 1672 */
rlm@10 1673 private void noSuccessor(){
rlm@10 1674 if(compute == FRAMES)
rlm@10 1675 {
rlm@10 1676 Label l = new Label();
rlm@10 1677 l.frame = new Frame();
rlm@10 1678 l.frame.owner = l;
rlm@10 1679 l.resolve(this, code.length, code.data);
rlm@10 1680 previousBlock.successor = l;
rlm@10 1681 previousBlock = l;
rlm@10 1682 }
rlm@10 1683 else
rlm@10 1684 {
rlm@10 1685 currentBlock.outputStackMax = maxStackSize;
rlm@10 1686 }
rlm@10 1687 currentBlock = null;
rlm@10 1688 }
rlm@10 1689
rlm@10 1690 /**
rlm@10 1691 * Finds the basic blocks that belong to a given subroutine, and marks these
rlm@10 1692 * blocks as belonging to this subroutine (by using {@link Label#status} as
rlm@10 1693 * a bit set (see {@link #visitMaxs}). This recursive method follows the
rlm@10 1694 * control flow graph to find all the blocks that are reachable from the
rlm@10 1695 * given block WITHOUT following any JSR target.
rlm@10 1696 *
rlm@10 1697 * @param block a block that belongs to the subroutine
rlm@10 1698 * @param id the id of this subroutine
rlm@10 1699 */
rlm@10 1700 private void findSubroutine(final Label block, final int id){
rlm@10 1701 // if 'block' is already marked as belonging to subroutine 'id', returns
rlm@10 1702 if((block.status & id) != 0)
rlm@10 1703 {
rlm@10 1704 return;
rlm@10 1705 }
rlm@10 1706 // marks 'block' as belonging to subroutine 'id'
rlm@10 1707 block.status |= id;
rlm@10 1708 // calls this method recursively on each successor, except JSR targets
rlm@10 1709 Edge e = block.successors;
rlm@10 1710 while(e != null)
rlm@10 1711 {
rlm@10 1712 // if 'block' is a JSR block, then 'block.successors.next' leads
rlm@10 1713 // to the JSR target (see {@link #visitJumpInsn}) and must therefore
rlm@10 1714 // not be followed
rlm@10 1715 if((block.status & Label.JSR) == 0 || e != block.successors.next)
rlm@10 1716 {
rlm@10 1717 findSubroutine(e.successor, id);
rlm@10 1718 }
rlm@10 1719 e = e.next;
rlm@10 1720 }
rlm@10 1721 }
rlm@10 1722
rlm@10 1723 /**
rlm@10 1724 * Finds the successors of the RET blocks of the specified subroutine, and
rlm@10 1725 * of any nested subroutine it calls.
rlm@10 1726 *
rlm@10 1727 * @param id id of the subroutine whose RET block successors must be found.
rlm@10 1728 * @param JSRs the JSR blocks that were followed to reach this subroutine.
rlm@10 1729 * @param nJSRs number of JSR blocks in the JSRs array.
rlm@10 1730 */
rlm@10 1731 private void findSubroutineSuccessors(
rlm@10 1732 final int id,
rlm@10 1733 final Label[] JSRs,
rlm@10 1734 final int nJSRs){
rlm@10 1735 // iterates over all the basic blocks...
rlm@10 1736 Label l = labels;
rlm@10 1737 while(l != null)
rlm@10 1738 {
rlm@10 1739 // for those that belong to subroutine 'id'...
rlm@10 1740 if((l.status & id) != 0)
rlm@10 1741 {
rlm@10 1742 if((l.status & Label.JSR) != 0)
rlm@10 1743 {
rlm@10 1744 // finds the subroutine to which 'l' leads by following the
rlm@10 1745 // second edge of l.successors (see {@link #visitJumpInsn})
rlm@10 1746 int nId = l.successors.next.successor.status & ~0xFFF;
rlm@10 1747 if(nId != id)
rlm@10 1748 {
rlm@10 1749 // calls this method recursively with l pushed onto the
rlm@10 1750 // JSRs stack to find the successors of the RET blocks
rlm@10 1751 // of this nested subroutine 'nId'
rlm@10 1752 JSRs[nJSRs] = l;
rlm@10 1753 findSubroutineSuccessors(nId, JSRs, nJSRs + 1);
rlm@10 1754 }
rlm@10 1755 }
rlm@10 1756 else if((l.status & Label.RET) != 0)
rlm@10 1757 {
rlm@10 1758 /*
rlm@10 1759 * finds the JSR block in the JSRs stack that corresponds to
rlm@10 1760 * this RET block, and updates the successors of this RET
rlm@10 1761 * block accordingly. This corresponding JSR is the one that
rlm@10 1762 * leads to the subroutine to which the RET block belongs.
rlm@10 1763 * But the RET block can belong to several subroutines (if a
rlm@10 1764 * nested subroutine returns to its parent subroutine
rlm@10 1765 * implicitely, without a RET). So, in fact, the JSR that
rlm@10 1766 * corresponds to this RET is the first block in the JSRs
rlm@10 1767 * stack, starting from the bottom of the stack, that leads
rlm@10 1768 * to a subroutine to which the RET block belongs.
rlm@10 1769 */
rlm@10 1770 for(int i = 0; i < nJSRs; ++i)
rlm@10 1771 {
rlm@10 1772 int JSRstatus = JSRs[i].successors.next.successor.status;
rlm@10 1773 if(((JSRstatus & ~0xFFF) & (l.status & ~0xFFF)) != 0)
rlm@10 1774 {
rlm@10 1775 Edge e = new Edge();
rlm@10 1776 e.info = l.inputStackTop;
rlm@10 1777 e.successor = JSRs[i].successors.successor;
rlm@10 1778 e.next = l.successors;
rlm@10 1779 l.successors = e;
rlm@10 1780 break;
rlm@10 1781 }
rlm@10 1782 }
rlm@10 1783 }
rlm@10 1784 }
rlm@10 1785 l = l.successor;
rlm@10 1786 }
rlm@10 1787 }
rlm@10 1788
rlm@10 1789 // ------------------------------------------------------------------------
rlm@10 1790 // Utility methods: stack map frames
rlm@10 1791 // ------------------------------------------------------------------------
rlm@10 1792
rlm@10 1793 /**
rlm@10 1794 * Visits a frame that has been computed from scratch.
rlm@10 1795 *
rlm@10 1796 * @param f the frame that must be visited.
rlm@10 1797 */
rlm@10 1798 private void visitFrame(final Frame f){
rlm@10 1799 int i, t;
rlm@10 1800 int nTop = 0;
rlm@10 1801 int nLocal = 0;
rlm@10 1802 int nStack = 0;
rlm@10 1803 int[] locals = f.inputLocals;
rlm@10 1804 int[] stacks = f.inputStack;
rlm@10 1805 // computes the number of locals (ignores TOP types that are just after
rlm@10 1806 // a LONG or a DOUBLE, and all trailing TOP types)
rlm@10 1807 for(i = 0; i < locals.length; ++i)
rlm@10 1808 {
rlm@10 1809 t = locals[i];
rlm@10 1810 if(t == Frame.TOP)
rlm@10 1811 {
rlm@10 1812 ++nTop;
rlm@10 1813 }
rlm@10 1814 else
rlm@10 1815 {
rlm@10 1816 nLocal += nTop + 1;
rlm@10 1817 nTop = 0;
rlm@10 1818 }
rlm@10 1819 if(t == Frame.LONG || t == Frame.DOUBLE)
rlm@10 1820 {
rlm@10 1821 ++i;
rlm@10 1822 }
rlm@10 1823 }
rlm@10 1824 // computes the stack size (ignores TOP types that are just after
rlm@10 1825 // a LONG or a DOUBLE)
rlm@10 1826 for(i = 0; i < stacks.length; ++i)
rlm@10 1827 {
rlm@10 1828 t = stacks[i];
rlm@10 1829 ++nStack;
rlm@10 1830 if(t == Frame.LONG || t == Frame.DOUBLE)
rlm@10 1831 {
rlm@10 1832 ++i;
rlm@10 1833 }
rlm@10 1834 }
rlm@10 1835 // visits the frame and its content
rlm@10 1836 startFrame(f.owner.position, nLocal, nStack);
rlm@10 1837 for(i = 0; nLocal > 0; ++i, --nLocal)
rlm@10 1838 {
rlm@10 1839 t = locals[i];
rlm@10 1840 frame[frameIndex++] = t;
rlm@10 1841 if(t == Frame.LONG || t == Frame.DOUBLE)
rlm@10 1842 {
rlm@10 1843 ++i;
rlm@10 1844 }
rlm@10 1845 }
rlm@10 1846 for(i = 0; i < stacks.length; ++i)
rlm@10 1847 {
rlm@10 1848 t = stacks[i];
rlm@10 1849 frame[frameIndex++] = t;
rlm@10 1850 if(t == Frame.LONG || t == Frame.DOUBLE)
rlm@10 1851 {
rlm@10 1852 ++i;
rlm@10 1853 }
rlm@10 1854 }
rlm@10 1855 endFrame();
rlm@10 1856 }
rlm@10 1857
rlm@10 1858 /**
rlm@10 1859 * Starts the visit of a stack map frame.
rlm@10 1860 *
rlm@10 1861 * @param offset the offset of the instruction to which the frame
rlm@10 1862 * corresponds.
rlm@10 1863 * @param nLocal the number of local variables in the frame.
rlm@10 1864 * @param nStack the number of stack elements in the frame.
rlm@10 1865 */
rlm@10 1866 private void startFrame(final int offset, final int nLocal, final int nStack){
rlm@10 1867 int n = 3 + nLocal + nStack;
rlm@10 1868 if(frame == null || frame.length < n)
rlm@10 1869 {
rlm@10 1870 frame = new int[n];
rlm@10 1871 }
rlm@10 1872 frame[0] = offset;
rlm@10 1873 frame[1] = nLocal;
rlm@10 1874 frame[2] = nStack;
rlm@10 1875 frameIndex = 3;
rlm@10 1876 }
rlm@10 1877
rlm@10 1878 /**
rlm@10 1879 * Checks if the visit of the current frame {@link #frame} is finished, and
rlm@10 1880 * if yes, write it in the StackMapTable attribute.
rlm@10 1881 */
rlm@10 1882 private void endFrame(){
rlm@10 1883 if(previousFrame != null)
rlm@10 1884 { // do not write the first frame
rlm@10 1885 if(stackMap == null)
rlm@10 1886 {
rlm@10 1887 stackMap = new ByteVector();
rlm@10 1888 }
rlm@10 1889 writeFrame();
rlm@10 1890 ++frameCount;
rlm@10 1891 }
rlm@10 1892 previousFrame = frame;
rlm@10 1893 frame = null;
rlm@10 1894 }
rlm@10 1895
rlm@10 1896 /**
rlm@10 1897 * Compress and writes the current frame {@link #frame} in the StackMapTable
rlm@10 1898 * attribute.
rlm@10 1899 */
rlm@10 1900 private void writeFrame(){
rlm@10 1901 int clocalsSize = frame[1];
rlm@10 1902 int cstackSize = frame[2];
rlm@10 1903 if((cw.version & 0xFFFF) < Opcodes.V1_6)
rlm@10 1904 {
rlm@10 1905 stackMap.putShort(frame[0]).putShort(clocalsSize);
rlm@10 1906 writeFrameTypes(3, 3 + clocalsSize);
rlm@10 1907 stackMap.putShort(cstackSize);
rlm@10 1908 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
rlm@10 1909 return;
rlm@10 1910 }
rlm@10 1911 int localsSize = previousFrame[1];
rlm@10 1912 int type = FULL_FRAME;
rlm@10 1913 int k = 0;
rlm@10 1914 int delta;
rlm@10 1915 if(frameCount == 0)
rlm@10 1916 {
rlm@10 1917 delta = frame[0];
rlm@10 1918 }
rlm@10 1919 else
rlm@10 1920 {
rlm@10 1921 delta = frame[0] - previousFrame[0] - 1;
rlm@10 1922 }
rlm@10 1923 if(cstackSize == 0)
rlm@10 1924 {
rlm@10 1925 k = clocalsSize - localsSize;
rlm@10 1926 switch(k)
rlm@10 1927 {
rlm@10 1928 case-3:
rlm@10 1929 case-2:
rlm@10 1930 case-1:
rlm@10 1931 type = CHOP_FRAME;
rlm@10 1932 localsSize = clocalsSize;
rlm@10 1933 break;
rlm@10 1934 case 0:
rlm@10 1935 type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
rlm@10 1936 break;
rlm@10 1937 case 1:
rlm@10 1938 case 2:
rlm@10 1939 case 3:
rlm@10 1940 type = APPEND_FRAME;
rlm@10 1941 break;
rlm@10 1942 }
rlm@10 1943 }
rlm@10 1944 else if(clocalsSize == localsSize && cstackSize == 1)
rlm@10 1945 {
rlm@10 1946 type = delta < 63
rlm@10 1947 ? SAME_LOCALS_1_STACK_ITEM_FRAME
rlm@10 1948 : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
rlm@10 1949 }
rlm@10 1950 if(type != FULL_FRAME)
rlm@10 1951 {
rlm@10 1952 // verify if locals are the same
rlm@10 1953 int l = 3;
rlm@10 1954 for(int j = 0; j < localsSize; j++)
rlm@10 1955 {
rlm@10 1956 if(frame[l] != previousFrame[l])
rlm@10 1957 {
rlm@10 1958 type = FULL_FRAME;
rlm@10 1959 break;
rlm@10 1960 }
rlm@10 1961 l++;
rlm@10 1962 }
rlm@10 1963 }
rlm@10 1964 switch(type)
rlm@10 1965 {
rlm@10 1966 case SAME_FRAME:
rlm@10 1967 stackMap.putByte(delta);
rlm@10 1968 break;
rlm@10 1969 case SAME_LOCALS_1_STACK_ITEM_FRAME:
rlm@10 1970 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
rlm@10 1971 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
rlm@10 1972 break;
rlm@10 1973 case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
rlm@10 1974 stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
rlm@10 1975 .putShort(delta);
rlm@10 1976 writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
rlm@10 1977 break;
rlm@10 1978 case SAME_FRAME_EXTENDED:
rlm@10 1979 stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
rlm@10 1980 break;
rlm@10 1981 case CHOP_FRAME:
rlm@10 1982 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
rlm@10 1983 break;
rlm@10 1984 case APPEND_FRAME:
rlm@10 1985 stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
rlm@10 1986 writeFrameTypes(3 + localsSize, 3 + clocalsSize);
rlm@10 1987 break;
rlm@10 1988 // case FULL_FRAME:
rlm@10 1989 default:
rlm@10 1990 stackMap.putByte(FULL_FRAME)
rlm@10 1991 .putShort(delta)
rlm@10 1992 .putShort(clocalsSize);
rlm@10 1993 writeFrameTypes(3, 3 + clocalsSize);
rlm@10 1994 stackMap.putShort(cstackSize);
rlm@10 1995 writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
rlm@10 1996 }
rlm@10 1997 }
rlm@10 1998
rlm@10 1999 /**
rlm@10 2000 * Writes some types of the current frame {@link #frame} into the
rlm@10 2001 * StackMapTableAttribute. This method converts types from the format used
rlm@10 2002 * in {@link Label} to the format used in StackMapTable attributes. In
rlm@10 2003 * particular, it converts type table indexes to constant pool indexes.
rlm@10 2004 *
rlm@10 2005 * @param start index of the first type in {@link #frame} to write.
rlm@10 2006 * @param end index of last type in {@link #frame} to write (exclusive).
rlm@10 2007 */
rlm@10 2008 private void writeFrameTypes(final int start, final int end){
rlm@10 2009 for(int i = start; i < end; ++i)
rlm@10 2010 {
rlm@10 2011 int t = frame[i];
rlm@10 2012 int d = t & Frame.DIM;
rlm@10 2013 if(d == 0)
rlm@10 2014 {
rlm@10 2015 int v = t & Frame.BASE_VALUE;
rlm@10 2016 switch(t & Frame.BASE_KIND)
rlm@10 2017 {
rlm@10 2018 case Frame.OBJECT:
rlm@10 2019 stackMap.putByte(7)
rlm@10 2020 .putShort(cw.newClass(cw.typeTable[v].strVal1));
rlm@10 2021 break;
rlm@10 2022 case Frame.UNINITIALIZED:
rlm@10 2023 stackMap.putByte(8).putShort(cw.typeTable[v].intVal);
rlm@10 2024 break;
rlm@10 2025 default:
rlm@10 2026 stackMap.putByte(v);
rlm@10 2027 }
rlm@10 2028 }
rlm@10 2029 else
rlm@10 2030 {
rlm@10 2031 StringBuffer buf = new StringBuffer();
rlm@10 2032 d >>= 28;
rlm@10 2033 while(d-- > 0)
rlm@10 2034 {
rlm@10 2035 buf.append('[');
rlm@10 2036 }
rlm@10 2037 if((t & Frame.BASE_KIND) == Frame.OBJECT)
rlm@10 2038 {
rlm@10 2039 buf.append('L');
rlm@10 2040 buf.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1);
rlm@10 2041 buf.append(';');
rlm@10 2042 }
rlm@10 2043 else
rlm@10 2044 {
rlm@10 2045 switch(t & 0xF)
rlm@10 2046 {
rlm@10 2047 case 1:
rlm@10 2048 buf.append('I');
rlm@10 2049 break;
rlm@10 2050 case 2:
rlm@10 2051 buf.append('F');
rlm@10 2052 break;
rlm@10 2053 case 3:
rlm@10 2054 buf.append('D');
rlm@10 2055 break;
rlm@10 2056 case 9:
rlm@10 2057 buf.append('Z');
rlm@10 2058 break;
rlm@10 2059 case 10:
rlm@10 2060 buf.append('B');
rlm@10 2061 break;
rlm@10 2062 case 11:
rlm@10 2063 buf.append('C');
rlm@10 2064 break;
rlm@10 2065 case 12:
rlm@10 2066 buf.append('S');
rlm@10 2067 break;
rlm@10 2068 default:
rlm@10 2069 buf.append('J');
rlm@10 2070 }
rlm@10 2071 }
rlm@10 2072 stackMap.putByte(7).putShort(cw.newClass(buf.toString()));
rlm@10 2073 }
rlm@10 2074 }
rlm@10 2075 }
rlm@10 2076
rlm@10 2077 private void writeFrameType(final Object type){
rlm@10 2078 if(type instanceof String)
rlm@10 2079 {
rlm@10 2080 stackMap.putByte(7).putShort(cw.newClass((String) type));
rlm@10 2081 }
rlm@10 2082 else if(type instanceof Integer)
rlm@10 2083 {
rlm@10 2084 stackMap.putByte(((Integer) type).intValue());
rlm@10 2085 }
rlm@10 2086 else
rlm@10 2087 {
rlm@10 2088 stackMap.putByte(8).putShort(((Label) type).position);
rlm@10 2089 }
rlm@10 2090 }
rlm@10 2091
rlm@10 2092 // ------------------------------------------------------------------------
rlm@10 2093 // Utility methods: dump bytecode array
rlm@10 2094 // ------------------------------------------------------------------------
rlm@10 2095
rlm@10 2096 /**
rlm@10 2097 * Returns the size of the bytecode of this method.
rlm@10 2098 *
rlm@10 2099 * @return the size of the bytecode of this method.
rlm@10 2100 */
rlm@10 2101 final int getSize(){
rlm@10 2102 if(classReaderOffset != 0)
rlm@10 2103 {
rlm@10 2104 return 6 + classReaderLength;
rlm@10 2105 }
rlm@10 2106 if(resize)
rlm@10 2107 {
rlm@10 2108 // replaces the temporary jump opcodes introduced by Label.resolve.
rlm@10 2109 resizeInstructions();
rlm@10 2110 }
rlm@10 2111 int size = 8;
rlm@10 2112 if(code.length > 0)
rlm@10 2113 {
rlm@10 2114 cw.newUTF8("Code");
rlm@10 2115 size += 18 + code.length + 8 * handlerCount;
rlm@10 2116 if(localVar != null)
rlm@10 2117 {
rlm@10 2118 cw.newUTF8("LocalVariableTable");
rlm@10 2119 size += 8 + localVar.length;
rlm@10 2120 }
rlm@10 2121 if(localVarType != null)
rlm@10 2122 {
rlm@10 2123 cw.newUTF8("LocalVariableTypeTable");
rlm@10 2124 size += 8 + localVarType.length;
rlm@10 2125 }
rlm@10 2126 if(lineNumber != null)
rlm@10 2127 {
rlm@10 2128 cw.newUTF8("LineNumberTable");
rlm@10 2129 size += 8 + lineNumber.length;
rlm@10 2130 }
rlm@10 2131 if(stackMap != null)
rlm@10 2132 {
rlm@10 2133 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
rlm@10 2134 cw.newUTF8(zip ? "StackMapTable" : "StackMap");
rlm@10 2135 size += 8 + stackMap.length;
rlm@10 2136 }
rlm@10 2137 if(cattrs != null)
rlm@10 2138 {
rlm@10 2139 size += cattrs.getSize(cw,
rlm@10 2140 code.data,
rlm@10 2141 code.length,
rlm@10 2142 maxStack,
rlm@10 2143 maxLocals);
rlm@10 2144 }
rlm@10 2145 }
rlm@10 2146 if(exceptionCount > 0)
rlm@10 2147 {
rlm@10 2148 cw.newUTF8("Exceptions");
rlm@10 2149 size += 8 + 2 * exceptionCount;
rlm@10 2150 }
rlm@10 2151 if((access & Opcodes.ACC_SYNTHETIC) != 0
rlm@10 2152 && (cw.version & 0xffff) < Opcodes.V1_5)
rlm@10 2153 {
rlm@10 2154 cw.newUTF8("Synthetic");
rlm@10 2155 size += 6;
rlm@10 2156 }
rlm@10 2157 if((access & Opcodes.ACC_DEPRECATED) != 0)
rlm@10 2158 {
rlm@10 2159 cw.newUTF8("Deprecated");
rlm@10 2160 size += 6;
rlm@10 2161 }
rlm@10 2162 if(signature != null)
rlm@10 2163 {
rlm@10 2164 cw.newUTF8("Signature");
rlm@10 2165 cw.newUTF8(signature);
rlm@10 2166 size += 8;
rlm@10 2167 }
rlm@10 2168 if(annd != null)
rlm@10 2169 {
rlm@10 2170 cw.newUTF8("AnnotationDefault");
rlm@10 2171 size += 6 + annd.length;
rlm@10 2172 }
rlm@10 2173 if(anns != null)
rlm@10 2174 {
rlm@10 2175 cw.newUTF8("RuntimeVisibleAnnotations");
rlm@10 2176 size += 8 + anns.getSize();
rlm@10 2177 }
rlm@10 2178 if(ianns != null)
rlm@10 2179 {
rlm@10 2180 cw.newUTF8("RuntimeInvisibleAnnotations");
rlm@10 2181 size += 8 + ianns.getSize();
rlm@10 2182 }
rlm@10 2183 if(panns != null)
rlm@10 2184 {
rlm@10 2185 cw.newUTF8("RuntimeVisibleParameterAnnotations");
rlm@10 2186 size += 7 + 2 * panns.length;
rlm@10 2187 for(int i = panns.length - 1; i >= 0; --i)
rlm@10 2188 {
rlm@10 2189 size += panns[i] == null ? 0 : panns[i].getSize();
rlm@10 2190 }
rlm@10 2191 }
rlm@10 2192 if(ipanns != null)
rlm@10 2193 {
rlm@10 2194 cw.newUTF8("RuntimeInvisibleParameterAnnotations");
rlm@10 2195 size += 7 + 2 * ipanns.length;
rlm@10 2196 for(int i = ipanns.length - 1; i >= 0; --i)
rlm@10 2197 {
rlm@10 2198 size += ipanns[i] == null ? 0 : ipanns[i].getSize();
rlm@10 2199 }
rlm@10 2200 }
rlm@10 2201 if(attrs != null)
rlm@10 2202 {
rlm@10 2203 size += attrs.getSize(cw, null, 0, -1, -1);
rlm@10 2204 }
rlm@10 2205 return size;
rlm@10 2206 }
rlm@10 2207
rlm@10 2208 /**
rlm@10 2209 * Puts the bytecode of this method in the given byte vector.
rlm@10 2210 *
rlm@10 2211 * @param out the byte vector into which the bytecode of this method must be
rlm@10 2212 * copied.
rlm@10 2213 */
rlm@10 2214 final void put(final ByteVector out){
rlm@10 2215 out.putShort(access).putShort(name).putShort(desc);
rlm@10 2216 if(classReaderOffset != 0)
rlm@10 2217 {
rlm@10 2218 out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength);
rlm@10 2219 return;
rlm@10 2220 }
rlm@10 2221 int attributeCount = 0;
rlm@10 2222 if(code.length > 0)
rlm@10 2223 {
rlm@10 2224 ++attributeCount;
rlm@10 2225 }
rlm@10 2226 if(exceptionCount > 0)
rlm@10 2227 {
rlm@10 2228 ++attributeCount;
rlm@10 2229 }
rlm@10 2230 if((access & Opcodes.ACC_SYNTHETIC) != 0
rlm@10 2231 && (cw.version & 0xffff) < Opcodes.V1_5)
rlm@10 2232 {
rlm@10 2233 ++attributeCount;
rlm@10 2234 }
rlm@10 2235 if((access & Opcodes.ACC_DEPRECATED) != 0)
rlm@10 2236 {
rlm@10 2237 ++attributeCount;
rlm@10 2238 }
rlm@10 2239 if(signature != null)
rlm@10 2240 {
rlm@10 2241 ++attributeCount;
rlm@10 2242 }
rlm@10 2243 if(annd != null)
rlm@10 2244 {
rlm@10 2245 ++attributeCount;
rlm@10 2246 }
rlm@10 2247 if(anns != null)
rlm@10 2248 {
rlm@10 2249 ++attributeCount;
rlm@10 2250 }
rlm@10 2251 if(ianns != null)
rlm@10 2252 {
rlm@10 2253 ++attributeCount;
rlm@10 2254 }
rlm@10 2255 if(panns != null)
rlm@10 2256 {
rlm@10 2257 ++attributeCount;
rlm@10 2258 }
rlm@10 2259 if(ipanns != null)
rlm@10 2260 {
rlm@10 2261 ++attributeCount;
rlm@10 2262 }
rlm@10 2263 if(attrs != null)
rlm@10 2264 {
rlm@10 2265 attributeCount += attrs.getCount();
rlm@10 2266 }
rlm@10 2267 out.putShort(attributeCount);
rlm@10 2268 if(code.length > 0)
rlm@10 2269 {
rlm@10 2270 int size = 12 + code.length + 8 * handlerCount;
rlm@10 2271 if(localVar != null)
rlm@10 2272 {
rlm@10 2273 size += 8 + localVar.length;
rlm@10 2274 }
rlm@10 2275 if(localVarType != null)
rlm@10 2276 {
rlm@10 2277 size += 8 + localVarType.length;
rlm@10 2278 }
rlm@10 2279 if(lineNumber != null)
rlm@10 2280 {
rlm@10 2281 size += 8 + lineNumber.length;
rlm@10 2282 }
rlm@10 2283 if(stackMap != null)
rlm@10 2284 {
rlm@10 2285 size += 8 + stackMap.length;
rlm@10 2286 }
rlm@10 2287 if(cattrs != null)
rlm@10 2288 {
rlm@10 2289 size += cattrs.getSize(cw,
rlm@10 2290 code.data,
rlm@10 2291 code.length,
rlm@10 2292 maxStack,
rlm@10 2293 maxLocals);
rlm@10 2294 }
rlm@10 2295 out.putShort(cw.newUTF8("Code")).putInt(size);
rlm@10 2296 out.putShort(maxStack).putShort(maxLocals);
rlm@10 2297 out.putInt(code.length).putByteArray(code.data, 0, code.length);
rlm@10 2298 out.putShort(handlerCount);
rlm@10 2299 if(handlerCount > 0)
rlm@10 2300 {
rlm@10 2301 Handler h = firstHandler;
rlm@10 2302 while(h != null)
rlm@10 2303 {
rlm@10 2304 out.putShort(h.start.position)
rlm@10 2305 .putShort(h.end.position)
rlm@10 2306 .putShort(h.handler.position)
rlm@10 2307 .putShort(h.type);
rlm@10 2308 h = h.next;
rlm@10 2309 }
rlm@10 2310 }
rlm@10 2311 attributeCount = 0;
rlm@10 2312 if(localVar != null)
rlm@10 2313 {
rlm@10 2314 ++attributeCount;
rlm@10 2315 }
rlm@10 2316 if(localVarType != null)
rlm@10 2317 {
rlm@10 2318 ++attributeCount;
rlm@10 2319 }
rlm@10 2320 if(lineNumber != null)
rlm@10 2321 {
rlm@10 2322 ++attributeCount;
rlm@10 2323 }
rlm@10 2324 if(stackMap != null)
rlm@10 2325 {
rlm@10 2326 ++attributeCount;
rlm@10 2327 }
rlm@10 2328 if(cattrs != null)
rlm@10 2329 {
rlm@10 2330 attributeCount += cattrs.getCount();
rlm@10 2331 }
rlm@10 2332 out.putShort(attributeCount);
rlm@10 2333 if(localVar != null)
rlm@10 2334 {
rlm@10 2335 out.putShort(cw.newUTF8("LocalVariableTable"));
rlm@10 2336 out.putInt(localVar.length + 2).putShort(localVarCount);
rlm@10 2337 out.putByteArray(localVar.data, 0, localVar.length);
rlm@10 2338 }
rlm@10 2339 if(localVarType != null)
rlm@10 2340 {
rlm@10 2341 out.putShort(cw.newUTF8("LocalVariableTypeTable"));
rlm@10 2342 out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
rlm@10 2343 out.putByteArray(localVarType.data, 0, localVarType.length);
rlm@10 2344 }
rlm@10 2345 if(lineNumber != null)
rlm@10 2346 {
rlm@10 2347 out.putShort(cw.newUTF8("LineNumberTable"));
rlm@10 2348 out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
rlm@10 2349 out.putByteArray(lineNumber.data, 0, lineNumber.length);
rlm@10 2350 }
rlm@10 2351 if(stackMap != null)
rlm@10 2352 {
rlm@10 2353 boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
rlm@10 2354 out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap"));
rlm@10 2355 out.putInt(stackMap.length + 2).putShort(frameCount);
rlm@10 2356 out.putByteArray(stackMap.data, 0, stackMap.length);
rlm@10 2357 }
rlm@10 2358 if(cattrs != null)
rlm@10 2359 {
rlm@10 2360 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
rlm@10 2361 }
rlm@10 2362 }
rlm@10 2363 if(exceptionCount > 0)
rlm@10 2364 {
rlm@10 2365 out.putShort(cw.newUTF8("Exceptions"))
rlm@10 2366 .putInt(2 * exceptionCount + 2);
rlm@10 2367 out.putShort(exceptionCount);
rlm@10 2368 for(int i = 0; i < exceptionCount; ++i)
rlm@10 2369 {
rlm@10 2370 out.putShort(exceptions[i]);
rlm@10 2371 }
rlm@10 2372 }
rlm@10 2373 if((access & Opcodes.ACC_SYNTHETIC) != 0
rlm@10 2374 && (cw.version & 0xffff) < Opcodes.V1_5)
rlm@10 2375 {
rlm@10 2376 out.putShort(cw.newUTF8("Synthetic")).putInt(0);
rlm@10 2377 }
rlm@10 2378 if((access & Opcodes.ACC_DEPRECATED) != 0)
rlm@10 2379 {
rlm@10 2380 out.putShort(cw.newUTF8("Deprecated")).putInt(0);
rlm@10 2381 }
rlm@10 2382 if(signature != null)
rlm@10 2383 {
rlm@10 2384 out.putShort(cw.newUTF8("Signature"))
rlm@10 2385 .putInt(2)
rlm@10 2386 .putShort(cw.newUTF8(signature));
rlm@10 2387 }
rlm@10 2388 if(annd != null)
rlm@10 2389 {
rlm@10 2390 out.putShort(cw.newUTF8("AnnotationDefault"));
rlm@10 2391 out.putInt(annd.length);
rlm@10 2392 out.putByteArray(annd.data, 0, annd.length);
rlm@10 2393 }
rlm@10 2394 if(anns != null)
rlm@10 2395 {
rlm@10 2396 out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
rlm@10 2397 anns.put(out);
rlm@10 2398 }
rlm@10 2399 if(ianns != null)
rlm@10 2400 {
rlm@10 2401 out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
rlm@10 2402 ianns.put(out);
rlm@10 2403 }
rlm@10 2404 if(panns != null)
rlm@10 2405 {
rlm@10 2406 out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
rlm@10 2407 AnnotationWriter.put(panns, out);
rlm@10 2408 }
rlm@10 2409 if(ipanns != null)
rlm@10 2410 {
rlm@10 2411 out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
rlm@10 2412 AnnotationWriter.put(ipanns, out);
rlm@10 2413 }
rlm@10 2414 if(attrs != null)
rlm@10 2415 {
rlm@10 2416 attrs.put(cw, null, 0, -1, -1, out);
rlm@10 2417 }
rlm@10 2418 }
rlm@10 2419
rlm@10 2420 // ------------------------------------------------------------------------
rlm@10 2421 // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
rlm@10 2422 // ------------------------------------------------------------------------
rlm@10 2423
rlm@10 2424 /**
rlm@10 2425 * Resizes and replaces the temporary instructions inserted by
rlm@10 2426 * {@link Label#resolve} for wide forward jumps, while keeping jump offsets
rlm@10 2427 * and instruction addresses consistent. This may require to resize other
rlm@10 2428 * existing instructions, or even to introduce new instructions: for
rlm@10 2429 * example, increasing the size of an instruction by 2 at the middle of a
rlm@10 2430 * method can increases the offset of an IFEQ instruction from 32766 to
rlm@10 2431 * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
rlm@10 2432 * 32765. This, in turn, may require to increase the size of another jump
rlm@10 2433 * instruction, and so on... All these operations are handled automatically
rlm@10 2434 * by this method. <p> <i>This method must be called after all the method
rlm@10 2435 * that is being built has been visited</i>. In particular, the
rlm@10 2436 * {@link Label Label} objects used to construct the method are no longer
rlm@10 2437 * valid after this method has been called.
rlm@10 2438 */
rlm@10 2439 private void resizeInstructions(){
rlm@10 2440 byte[] b = code.data; // bytecode of the method
rlm@10 2441 int u, v, label; // indexes in b
rlm@10 2442 int i, j; // loop indexes
rlm@10 2443 /*
rlm@10 2444 * 1st step: As explained above, resizing an instruction may require to
rlm@10 2445 * resize another one, which may require to resize yet another one, and
rlm@10 2446 * so on. The first step of the algorithm consists in finding all the
rlm@10 2447 * instructions that need to be resized, without modifying the code.
rlm@10 2448 * This is done by the following "fix point" algorithm:
rlm@10 2449 *
rlm@10 2450 * Parse the code to find the jump instructions whose offset will need
rlm@10 2451 * more than 2 bytes to be stored (the future offset is computed from
rlm@10 2452 * the current offset and from the number of bytes that will be inserted
rlm@10 2453 * or removed between the source and target instructions). For each such
rlm@10 2454 * instruction, adds an entry in (a copy of) the indexes and sizes
rlm@10 2455 * arrays (if this has not already been done in a previous iteration!).
rlm@10 2456 *
rlm@10 2457 * If at least one entry has been added during the previous step, go
rlm@10 2458 * back to the beginning, otherwise stop.
rlm@10 2459 *
rlm@10 2460 * In fact the real algorithm is complicated by the fact that the size
rlm@10 2461 * of TABLESWITCH and LOOKUPSWITCH instructions depends on their
rlm@10 2462 * position in the bytecode (because of padding). In order to ensure the
rlm@10 2463 * convergence of the algorithm, the number of bytes to be added or
rlm@10 2464 * removed from these instructions is over estimated during the previous
rlm@10 2465 * loop, and computed exactly only after the loop is finished (this
rlm@10 2466 * requires another pass to parse the bytecode of the method).
rlm@10 2467 */
rlm@10 2468 int[] allIndexes = new int[0]; // copy of indexes
rlm@10 2469 int[] allSizes = new int[0]; // copy of sizes
rlm@10 2470 boolean[] resize; // instructions to be resized
rlm@10 2471 int newOffset; // future offset of a jump instruction
rlm@10 2472
rlm@10 2473 resize = new boolean[code.length];
rlm@10 2474
rlm@10 2475 // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
rlm@10 2476 int state = 3;
rlm@10 2477 do
rlm@10 2478 {
rlm@10 2479 if(state == 3)
rlm@10 2480 {
rlm@10 2481 state = 2;
rlm@10 2482 }
rlm@10 2483 u = 0;
rlm@10 2484 while(u < b.length)
rlm@10 2485 {
rlm@10 2486 int opcode = b[u] & 0xFF; // opcode of current instruction
rlm@10 2487 int insert = 0; // bytes to be added after this instruction
rlm@10 2488
rlm@10 2489 switch(ClassWriter.TYPE[opcode])
rlm@10 2490 {
rlm@10 2491 case ClassWriter.NOARG_INSN:
rlm@10 2492 case ClassWriter.IMPLVAR_INSN:
rlm@10 2493 u += 1;
rlm@10 2494 break;
rlm@10 2495 case ClassWriter.LABEL_INSN:
rlm@10 2496 if(opcode > 201)
rlm@10 2497 {
rlm@10 2498 // converts temporary opcodes 202 to 217, 218 and
rlm@10 2499 // 219 to IFEQ ... JSR (inclusive), IFNULL and
rlm@10 2500 // IFNONNULL
rlm@10 2501 opcode = opcode < 218 ? opcode - 49 : opcode - 20;
rlm@10 2502 label = u + readUnsignedShort(b, u + 1);
rlm@10 2503 }
rlm@10 2504 else
rlm@10 2505 {
rlm@10 2506 label = u + readShort(b, u + 1);
rlm@10 2507 }
rlm@10 2508 newOffset = getNewOffset(allIndexes, allSizes, u, label);
rlm@10 2509 if(newOffset < Short.MIN_VALUE
rlm@10 2510 || newOffset > Short.MAX_VALUE)
rlm@10 2511 {
rlm@10 2512 if(!resize[u])
rlm@10 2513 {
rlm@10 2514 if(opcode == Opcodes.GOTO
rlm@10 2515 || opcode == Opcodes.JSR)
rlm@10 2516 {
rlm@10 2517 // two additional bytes will be required to
rlm@10 2518 // replace this GOTO or JSR instruction with
rlm@10 2519 // a GOTO_W or a JSR_W
rlm@10 2520 insert = 2;
rlm@10 2521 }
rlm@10 2522 else
rlm@10 2523 {
rlm@10 2524 // five additional bytes will be required to
rlm@10 2525 // replace this IFxxx <l> instruction with
rlm@10 2526 // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx
rlm@10 2527 // is the "opposite" opcode of IFxxx (i.e.,
rlm@10 2528 // IFNE for IFEQ) and where <l'> designates
rlm@10 2529 // the instruction just after the GOTO_W.
rlm@10 2530 insert = 5;
rlm@10 2531 }
rlm@10 2532 resize[u] = true;
rlm@10 2533 }
rlm@10 2534 }
rlm@10 2535 u += 3;
rlm@10 2536 break;
rlm@10 2537 case ClassWriter.LABELW_INSN:
rlm@10 2538 u += 5;
rlm@10 2539 break;
rlm@10 2540 case ClassWriter.TABL_INSN:
rlm@10 2541 if(state == 1)
rlm@10 2542 {
rlm@10 2543 // true number of bytes to be added (or removed)
rlm@10 2544 // from this instruction = (future number of padding
rlm@10 2545 // bytes - current number of padding byte) -
rlm@10 2546 // previously over estimated variation =
rlm@10 2547 // = ((3 - newOffset%4) - (3 - u%4)) - u%4
rlm@10 2548 // = (-newOffset%4 + u%4) - u%4
rlm@10 2549 // = -(newOffset & 3)
rlm@10 2550 newOffset = getNewOffset(allIndexes, allSizes, 0, u);
rlm@10 2551 insert = -(newOffset & 3);
rlm@10 2552 }
rlm@10 2553 else if(!resize[u])
rlm@10 2554 {
rlm@10 2555 // over estimation of the number of bytes to be
rlm@10 2556 // added to this instruction = 3 - current number
rlm@10 2557 // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3
rlm@10 2558 insert = u & 3;
rlm@10 2559 resize[u] = true;
rlm@10 2560 }
rlm@10 2561 // skips instruction
rlm@10 2562 u = u + 4 - (u & 3);
rlm@10 2563 u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
rlm@10 2564 break;
rlm@10 2565 case ClassWriter.LOOK_INSN:
rlm@10 2566 if(state == 1)
rlm@10 2567 {
rlm@10 2568 // like TABL_INSN
rlm@10 2569 newOffset = getNewOffset(allIndexes, allSizes, 0, u);
rlm@10 2570 insert = -(newOffset & 3);
rlm@10 2571 }
rlm@10 2572 else if(!resize[u])
rlm@10 2573 {
rlm@10 2574 // like TABL_INSN
rlm@10 2575 insert = u & 3;
rlm@10 2576 resize[u] = true;
rlm@10 2577 }
rlm@10 2578 // skips instruction
rlm@10 2579 u = u + 4 - (u & 3);
rlm@10 2580 u += 8 * readInt(b, u + 4) + 8;
rlm@10 2581 break;
rlm@10 2582 case ClassWriter.WIDE_INSN:
rlm@10 2583 opcode = b[u + 1] & 0xFF;
rlm@10 2584 if(opcode == Opcodes.IINC)
rlm@10 2585 {
rlm@10 2586 u += 6;
rlm@10 2587 }
rlm@10 2588 else
rlm@10 2589 {
rlm@10 2590 u += 4;
rlm@10 2591 }
rlm@10 2592 break;
rlm@10 2593 case ClassWriter.VAR_INSN:
rlm@10 2594 case ClassWriter.SBYTE_INSN:
rlm@10 2595 case ClassWriter.LDC_INSN:
rlm@10 2596 u += 2;
rlm@10 2597 break;
rlm@10 2598 case ClassWriter.SHORT_INSN:
rlm@10 2599 case ClassWriter.LDCW_INSN:
rlm@10 2600 case ClassWriter.FIELDORMETH_INSN:
rlm@10 2601 case ClassWriter.TYPE_INSN:
rlm@10 2602 case ClassWriter.IINC_INSN:
rlm@10 2603 u += 3;
rlm@10 2604 break;
rlm@10 2605 case ClassWriter.ITFMETH_INSN:
rlm@10 2606 u += 5;
rlm@10 2607 break;
rlm@10 2608 // case ClassWriter.MANA_INSN:
rlm@10 2609 default:
rlm@10 2610 u += 4;
rlm@10 2611 break;
rlm@10 2612 }
rlm@10 2613 if(insert != 0)
rlm@10 2614 {
rlm@10 2615 // adds a new (u, insert) entry in the allIndexes and
rlm@10 2616 // allSizes arrays
rlm@10 2617 int[] newIndexes = new int[allIndexes.length + 1];
rlm@10 2618 int[] newSizes = new int[allSizes.length + 1];
rlm@10 2619 System.arraycopy(allIndexes,
rlm@10 2620 0,
rlm@10 2621 newIndexes,
rlm@10 2622 0,
rlm@10 2623 allIndexes.length);
rlm@10 2624 System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
rlm@10 2625 newIndexes[allIndexes.length] = u;
rlm@10 2626 newSizes[allSizes.length] = insert;
rlm@10 2627 allIndexes = newIndexes;
rlm@10 2628 allSizes = newSizes;
rlm@10 2629 if(insert > 0)
rlm@10 2630 {
rlm@10 2631 state = 3;
rlm@10 2632 }
rlm@10 2633 }
rlm@10 2634 }
rlm@10 2635 if(state < 3)
rlm@10 2636 {
rlm@10 2637 --state;
rlm@10 2638 }
rlm@10 2639 } while(state != 0);
rlm@10 2640
rlm@10 2641 // 2nd step:
rlm@10 2642 // copies the bytecode of the method into a new bytevector, updates the
rlm@10 2643 // offsets, and inserts (or removes) bytes as requested.
rlm@10 2644
rlm@10 2645 ByteVector newCode = new ByteVector(code.length);
rlm@10 2646
rlm@10 2647 u = 0;
rlm@10 2648 while(u < code.length)
rlm@10 2649 {
rlm@10 2650 int opcode = b[u] & 0xFF;
rlm@10 2651 switch(ClassWriter.TYPE[opcode])
rlm@10 2652 {
rlm@10 2653 case ClassWriter.NOARG_INSN:
rlm@10 2654 case ClassWriter.IMPLVAR_INSN:
rlm@10 2655 newCode.putByte(opcode);
rlm@10 2656 u += 1;
rlm@10 2657 break;
rlm@10 2658 case ClassWriter.LABEL_INSN:
rlm@10 2659 if(opcode > 201)
rlm@10 2660 {
rlm@10 2661 // changes temporary opcodes 202 to 217 (inclusive), 218
rlm@10 2662 // and 219 to IFEQ ... JSR (inclusive), IFNULL and
rlm@10 2663 // IFNONNULL
rlm@10 2664 opcode = opcode < 218 ? opcode - 49 : opcode - 20;
rlm@10 2665 label = u + readUnsignedShort(b, u + 1);
rlm@10 2666 }
rlm@10 2667 else
rlm@10 2668 {
rlm@10 2669 label = u + readShort(b, u + 1);
rlm@10 2670 }
rlm@10 2671 newOffset = getNewOffset(allIndexes, allSizes, u, label);
rlm@10 2672 if(resize[u])
rlm@10 2673 {
rlm@10 2674 // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
rlm@10 2675 // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is
rlm@10 2676 // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
rlm@10 2677 // and where <l'> designates the instruction just after
rlm@10 2678 // the GOTO_W.
rlm@10 2679 if(opcode == Opcodes.GOTO)
rlm@10 2680 {
rlm@10 2681 newCode.putByte(200); // GOTO_W
rlm@10 2682 }
rlm@10 2683 else if(opcode == Opcodes.JSR)
rlm@10 2684 {
rlm@10 2685 newCode.putByte(201); // JSR_W
rlm@10 2686 }
rlm@10 2687 else
rlm@10 2688 {
rlm@10 2689 newCode.putByte(opcode <= 166
rlm@10 2690 ? ((opcode + 1) ^ 1) - 1
rlm@10 2691 : opcode ^ 1);
rlm@10 2692 newCode.putShort(8); // jump offset
rlm@10 2693 newCode.putByte(200); // GOTO_W
rlm@10 2694 // newOffset now computed from start of GOTO_W
rlm@10 2695 newOffset -= 3;
rlm@10 2696 }
rlm@10 2697 newCode.putInt(newOffset);
rlm@10 2698 }
rlm@10 2699 else
rlm@10 2700 {
rlm@10 2701 newCode.putByte(opcode);
rlm@10 2702 newCode.putShort(newOffset);
rlm@10 2703 }
rlm@10 2704 u += 3;
rlm@10 2705 break;
rlm@10 2706 case ClassWriter.LABELW_INSN:
rlm@10 2707 label = u + readInt(b, u + 1);
rlm@10 2708 newOffset = getNewOffset(allIndexes, allSizes, u, label);
rlm@10 2709 newCode.putByte(opcode);
rlm@10 2710 newCode.putInt(newOffset);
rlm@10 2711 u += 5;
rlm@10 2712 break;
rlm@10 2713 case ClassWriter.TABL_INSN:
rlm@10 2714 // skips 0 to 3 padding bytes
rlm@10 2715 v = u;
rlm@10 2716 u = u + 4 - (v & 3);
rlm@10 2717 // reads and copies instruction
rlm@10 2718 newCode.putByte(Opcodes.TABLESWITCH);
rlm@10 2719 newCode.length += (4 - newCode.length % 4) % 4;
rlm@10 2720 label = v + readInt(b, u);
rlm@10 2721 u += 4;
rlm@10 2722 newOffset = getNewOffset(allIndexes, allSizes, v, label);
rlm@10 2723 newCode.putInt(newOffset);
rlm@10 2724 j = readInt(b, u);
rlm@10 2725 u += 4;
rlm@10 2726 newCode.putInt(j);
rlm@10 2727 j = readInt(b, u) - j + 1;
rlm@10 2728 u += 4;
rlm@10 2729 newCode.putInt(readInt(b, u - 4));
rlm@10 2730 for(; j > 0; --j)
rlm@10 2731 {
rlm@10 2732 label = v + readInt(b, u);
rlm@10 2733 u += 4;
rlm@10 2734 newOffset = getNewOffset(allIndexes, allSizes, v, label);
rlm@10 2735 newCode.putInt(newOffset);
rlm@10 2736 }
rlm@10 2737 break;
rlm@10 2738 case ClassWriter.LOOK_INSN:
rlm@10 2739 // skips 0 to 3 padding bytes
rlm@10 2740 v = u;
rlm@10 2741 u = u + 4 - (v & 3);
rlm@10 2742 // reads and copies instruction
rlm@10 2743 newCode.putByte(Opcodes.LOOKUPSWITCH);
rlm@10 2744 newCode.length += (4 - newCode.length % 4) % 4;
rlm@10 2745 label = v + readInt(b, u);
rlm@10 2746 u += 4;
rlm@10 2747 newOffset = getNewOffset(allIndexes, allSizes, v, label);
rlm@10 2748 newCode.putInt(newOffset);
rlm@10 2749 j = readInt(b, u);
rlm@10 2750 u += 4;
rlm@10 2751 newCode.putInt(j);
rlm@10 2752 for(; j > 0; --j)
rlm@10 2753 {
rlm@10 2754 newCode.putInt(readInt(b, u));
rlm@10 2755 u += 4;
rlm@10 2756 label = v + readInt(b, u);
rlm@10 2757 u += 4;
rlm@10 2758 newOffset = getNewOffset(allIndexes, allSizes, v, label);
rlm@10 2759 newCode.putInt(newOffset);
rlm@10 2760 }
rlm@10 2761 break;
rlm@10 2762 case ClassWriter.WIDE_INSN:
rlm@10 2763 opcode = b[u + 1] & 0xFF;
rlm@10 2764 if(opcode == Opcodes.IINC)
rlm@10 2765 {
rlm@10 2766 newCode.putByteArray(b, u, 6);
rlm@10 2767 u += 6;
rlm@10 2768 }
rlm@10 2769 else
rlm@10 2770 {
rlm@10 2771 newCode.putByteArray(b, u, 4);
rlm@10 2772 u += 4;
rlm@10 2773 }
rlm@10 2774 break;
rlm@10 2775 case ClassWriter.VAR_INSN:
rlm@10 2776 case ClassWriter.SBYTE_INSN:
rlm@10 2777 case ClassWriter.LDC_INSN:
rlm@10 2778 newCode.putByteArray(b, u, 2);
rlm@10 2779 u += 2;
rlm@10 2780 break;
rlm@10 2781 case ClassWriter.SHORT_INSN:
rlm@10 2782 case ClassWriter.LDCW_INSN:
rlm@10 2783 case ClassWriter.FIELDORMETH_INSN:
rlm@10 2784 case ClassWriter.TYPE_INSN:
rlm@10 2785 case ClassWriter.IINC_INSN:
rlm@10 2786 newCode.putByteArray(b, u, 3);
rlm@10 2787 u += 3;
rlm@10 2788 break;
rlm@10 2789 case ClassWriter.ITFMETH_INSN:
rlm@10 2790 newCode.putByteArray(b, u, 5);
rlm@10 2791 u += 5;
rlm@10 2792 break;
rlm@10 2793 // case MANA_INSN:
rlm@10 2794 default:
rlm@10 2795 newCode.putByteArray(b, u, 4);
rlm@10 2796 u += 4;
rlm@10 2797 break;
rlm@10 2798 }
rlm@10 2799 }
rlm@10 2800
rlm@10 2801 // recomputes the stack map frames
rlm@10 2802 if(frameCount > 0)
rlm@10 2803 {
rlm@10 2804 if(compute == FRAMES)
rlm@10 2805 {
rlm@10 2806 frameCount = 0;
rlm@10 2807 stackMap = null;
rlm@10 2808 previousFrame = null;
rlm@10 2809 frame = null;
rlm@10 2810 Frame f = new Frame();
rlm@10 2811 f.owner = labels;
rlm@10 2812 Type[] args = Type.getArgumentTypes(descriptor);
rlm@10 2813 f.initInputFrame(cw, access, args, maxLocals);
rlm@10 2814 visitFrame(f);
rlm@10 2815 Label l = labels;
rlm@10 2816 while(l != null)
rlm@10 2817 {
rlm@10 2818 /*
rlm@10 2819 * here we need the original label position. getNewOffset
rlm@10 2820 * must therefore never have been called for this label.
rlm@10 2821 */
rlm@10 2822 u = l.position - 3;
rlm@10 2823 if((l.status & Label.STORE) != 0 || (u >= 0 && resize[u]))
rlm@10 2824 {
rlm@10 2825 getNewOffset(allIndexes, allSizes, l);
rlm@10 2826 // TODO update offsets in UNINITIALIZED values
rlm@10 2827 visitFrame(l.frame);
rlm@10 2828 }
rlm@10 2829 l = l.successor;
rlm@10 2830 }
rlm@10 2831 }
rlm@10 2832 else
rlm@10 2833 {
rlm@10 2834 /*
rlm@10 2835 * Resizing an existing stack map frame table is really hard.
rlm@10 2836 * Not only the table must be parsed to update the offets, but
rlm@10 2837 * new frames may be needed for jump instructions that were
rlm@10 2838 * inserted by this method. And updating the offsets or
rlm@10 2839 * inserting frames can change the format of the following
rlm@10 2840 * frames, in case of packed frames. In practice the whole table
rlm@10 2841 * must be recomputed. For this the frames are marked as
rlm@10 2842 * potentially invalid. This will cause the whole class to be
rlm@10 2843 * reread and rewritten with the COMPUTE_FRAMES option (see the
rlm@10 2844 * ClassWriter.toByteArray method). This is not very efficient
rlm@10 2845 * but is much easier and requires much less code than any other
rlm@10 2846 * method I can think of.
rlm@10 2847 */
rlm@10 2848 cw.invalidFrames = true;
rlm@10 2849 }
rlm@10 2850 }
rlm@10 2851 // updates the exception handler block labels
rlm@10 2852 Handler h = firstHandler;
rlm@10 2853 while(h != null)
rlm@10 2854 {
rlm@10 2855 getNewOffset(allIndexes, allSizes, h.start);
rlm@10 2856 getNewOffset(allIndexes, allSizes, h.end);
rlm@10 2857 getNewOffset(allIndexes, allSizes, h.handler);
rlm@10 2858 h = h.next;
rlm@10 2859 }
rlm@10 2860 // updates the instructions addresses in the
rlm@10 2861 // local var and line number tables
rlm@10 2862 for(i = 0; i < 2; ++i)
rlm@10 2863 {
rlm@10 2864 ByteVector bv = i == 0 ? localVar : localVarType;
rlm@10 2865 if(bv != null)
rlm@10 2866 {
rlm@10 2867 b = bv.data;
rlm@10 2868 u = 0;
rlm@10 2869 while(u < bv.length)
rlm@10 2870 {
rlm@10 2871 label = readUnsignedShort(b, u);
rlm@10 2872 newOffset = getNewOffset(allIndexes, allSizes, 0, label);
rlm@10 2873 writeShort(b, u, newOffset);
rlm@10 2874 label += readUnsignedShort(b, u + 2);
rlm@10 2875 newOffset = getNewOffset(allIndexes, allSizes, 0, label)
rlm@10 2876 - newOffset;
rlm@10 2877 writeShort(b, u + 2, newOffset);
rlm@10 2878 u += 10;
rlm@10 2879 }
rlm@10 2880 }
rlm@10 2881 }
rlm@10 2882 if(lineNumber != null)
rlm@10 2883 {
rlm@10 2884 b = lineNumber.data;
rlm@10 2885 u = 0;
rlm@10 2886 while(u < lineNumber.length)
rlm@10 2887 {
rlm@10 2888 writeShort(b, u, getNewOffset(allIndexes,
rlm@10 2889 allSizes,
rlm@10 2890 0,
rlm@10 2891 readUnsignedShort(b, u)));
rlm@10 2892 u += 4;
rlm@10 2893 }
rlm@10 2894 }
rlm@10 2895 // updates the labels of the other attributes
rlm@10 2896 Attribute attr = cattrs;
rlm@10 2897 while(attr != null)
rlm@10 2898 {
rlm@10 2899 Label[] labels = attr.getLabels();
rlm@10 2900 if(labels != null)
rlm@10 2901 {
rlm@10 2902 for(i = labels.length - 1; i >= 0; --i)
rlm@10 2903 {
rlm@10 2904 getNewOffset(allIndexes, allSizes, labels[i]);
rlm@10 2905 }
rlm@10 2906 }
rlm@10 2907 attr = attr.next;
rlm@10 2908 }
rlm@10 2909
rlm@10 2910 // replaces old bytecodes with new ones
rlm@10 2911 code = newCode;
rlm@10 2912 }
rlm@10 2913
rlm@10 2914 /**
rlm@10 2915 * Reads an unsigned short value in the given byte array.
rlm@10 2916 *
rlm@10 2917 * @param b a byte array.
rlm@10 2918 * @param index the start index of the value to be read.
rlm@10 2919 * @return the read value.
rlm@10 2920 */
rlm@10 2921 static int readUnsignedShort(final byte[] b, final int index){
rlm@10 2922 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
rlm@10 2923 }
rlm@10 2924
rlm@10 2925 /**
rlm@10 2926 * Reads a signed short value in the given byte array.
rlm@10 2927 *
rlm@10 2928 * @param b a byte array.
rlm@10 2929 * @param index the start index of the value to be read.
rlm@10 2930 * @return the read value.
rlm@10 2931 */
rlm@10 2932 static short readShort(final byte[] b, final int index){
rlm@10 2933 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
rlm@10 2934 }
rlm@10 2935
rlm@10 2936 /**
rlm@10 2937 * Reads a signed int value in the given byte array.
rlm@10 2938 *
rlm@10 2939 * @param b a byte array.
rlm@10 2940 * @param index the start index of the value to be read.
rlm@10 2941 * @return the read value.
rlm@10 2942 */
rlm@10 2943 static int readInt(final byte[] b, final int index){
rlm@10 2944 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
rlm@10 2945 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
rlm@10 2946 }
rlm@10 2947
rlm@10 2948 /**
rlm@10 2949 * Writes a short value in the given byte array.
rlm@10 2950 *
rlm@10 2951 * @param b a byte array.
rlm@10 2952 * @param index where the first byte of the short value must be written.
rlm@10 2953 * @param s the value to be written in the given byte array.
rlm@10 2954 */
rlm@10 2955 static void writeShort(final byte[] b, final int index, final int s){
rlm@10 2956 b[index] = (byte) (s >>> 8);
rlm@10 2957 b[index + 1] = (byte) s;
rlm@10 2958 }
rlm@10 2959
rlm@10 2960 /**
rlm@10 2961 * Computes the future value of a bytecode offset. <p> Note: it is possible
rlm@10 2962 * to have several entries for the same instruction in the <tt>indexes</tt>
rlm@10 2963 * and <tt>sizes</tt>: two entries (index=a,size=b) and (index=a,size=b')
rlm@10 2964 * are equivalent to a single entry (index=a,size=b+b').
rlm@10 2965 *
rlm@10 2966 * @param indexes current positions of the instructions to be resized. Each
rlm@10 2967 * instruction must be designated by the index of its <i>last</i>
rlm@10 2968 * byte, plus one (or, in other words, by the index of the <i>first</i>
rlm@10 2969 * byte of the <i>next</i> instruction).
rlm@10 2970 * @param sizes the number of bytes to be <i>added</i> to the above
rlm@10 2971 * instructions. More precisely, for each i < <tt>len</tt>,
rlm@10 2972 * <tt>sizes</tt>[i] bytes will be added at the end of the
rlm@10 2973 * instruction designated by <tt>indexes</tt>[i] or, if
rlm@10 2974 * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
rlm@10 2975 * bytes of the instruction will be removed (the instruction size
rlm@10 2976 * <i>must not</i> become negative or null).
rlm@10 2977 * @param begin index of the first byte of the source instruction.
rlm@10 2978 * @param end index of the first byte of the target instruction.
rlm@10 2979 * @return the future value of the given bytecode offset.
rlm@10 2980 */
rlm@10 2981 static int getNewOffset(
rlm@10 2982 final int[] indexes,
rlm@10 2983 final int[] sizes,
rlm@10 2984 final int begin,
rlm@10 2985 final int end){
rlm@10 2986 int offset = end - begin;
rlm@10 2987 for(int i = 0; i < indexes.length; ++i)
rlm@10 2988 {
rlm@10 2989 if(begin < indexes[i] && indexes[i] <= end)
rlm@10 2990 {
rlm@10 2991 // forward jump
rlm@10 2992 offset += sizes[i];
rlm@10 2993 }
rlm@10 2994 else if(end < indexes[i] && indexes[i] <= begin)
rlm@10 2995 {
rlm@10 2996 // backward jump
rlm@10 2997 offset -= sizes[i];
rlm@10 2998 }
rlm@10 2999 }
rlm@10 3000 return offset;
rlm@10 3001 }
rlm@10 3002
rlm@10 3003 /**
rlm@10 3004 * Updates the offset of the given label.
rlm@10 3005 *
rlm@10 3006 * @param indexes current positions of the instructions to be resized. Each
rlm@10 3007 * instruction must be designated by the index of its <i>last</i>
rlm@10 3008 * byte, plus one (or, in other words, by the index of the <i>first</i>
rlm@10 3009 * byte of the <i>next</i> instruction).
rlm@10 3010 * @param sizes the number of bytes to be <i>added</i> to the above
rlm@10 3011 * instructions. More precisely, for each i < <tt>len</tt>,
rlm@10 3012 * <tt>sizes</tt>[i] bytes will be added at the end of the
rlm@10 3013 * instruction designated by <tt>indexes</tt>[i] or, if
rlm@10 3014 * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
rlm@10 3015 * bytes of the instruction will be removed (the instruction size
rlm@10 3016 * <i>must not</i> become negative or null).
rlm@10 3017 * @param label the label whose offset must be updated.
rlm@10 3018 */
rlm@10 3019 static void getNewOffset(
rlm@10 3020 final int[] indexes,
rlm@10 3021 final int[] sizes,
rlm@10 3022 final Label label){
rlm@10 3023 if((label.status & Label.RESIZED) == 0)
rlm@10 3024 {
rlm@10 3025 label.position = getNewOffset(indexes, sizes, 0, label.position);
rlm@10 3026 label.status |= Label.RESIZED;
rlm@10 3027 }
rlm@10 3028 }
rlm@10 3029 }