1 30 package org.objectweb.asm.commons; 31 32 import java.util.AbstractMap ; 33 import java.util.ArrayList ; 34 import java.util.BitSet ; 35 import java.util.HashMap ; 36 import java.util.Iterator ; 37 import java.util.LinkedList ; 38 import java.util.List ; 39 import java.util.Map ; 40 import java.util.Set ; 41 42 import org.objectweb.asm.Label; 43 import org.objectweb.asm.MethodVisitor; 44 import org.objectweb.asm.Opcodes; 45 import org.objectweb.asm.Type; 46 import org.objectweb.asm.tree.AbstractInsnNode; 47 import org.objectweb.asm.tree.InsnList; 48 import org.objectweb.asm.tree.InsnNode; 49 import org.objectweb.asm.tree.JumpInsnNode; 50 import org.objectweb.asm.tree.LabelNode; 51 import org.objectweb.asm.tree.LookupSwitchInsnNode; 52 import org.objectweb.asm.tree.MethodNode; 53 import org.objectweb.asm.tree.TableSwitchInsnNode; 54 import org.objectweb.asm.tree.TryCatchBlockNode; 55 import org.objectweb.asm.tree.LocalVariableNode; 56 57 65 public class JSRInlinerAdapter extends MethodNode implements Opcodes { 66 67 private final static boolean LOGGING = false; 68 69 73 private MethodVisitor mv; 74 75 79 private final Map subroutineHeads = new HashMap (); 80 81 86 private final Subroutine mainSubroutine = new Subroutine(); 87 88 92 private final BitSet dualCitizens = new BitSet (); 93 94 109 public JSRInlinerAdapter( 110 final MethodVisitor mv, 111 final int access, 112 final String name, 113 final String desc, 114 final String signature, 115 final String [] exceptions) 116 { 117 super(access, name, desc, signature, exceptions); 118 this.mv = mv; 119 } 120 121 125 public void visitJumpInsn(final int opcode, final Label lbl) { 126 super.visitJumpInsn(opcode, lbl); 127 LabelNode ln = ((JumpInsnNode) instructions.getLast()).label; 128 if (opcode == JSR && !subroutineHeads.containsKey(ln)) { 129 subroutineHeads.put(ln, new Subroutine()); 130 } 131 } 132 133 137 public void visitEnd() { 138 if (!subroutineHeads.isEmpty()) { 139 markSubroutines(); 140 if (LOGGING) { 141 log(mainSubroutine.toString()); 142 Iterator it = subroutineHeads.values().iterator(); 143 while (it.hasNext()) { 144 Subroutine sub = (Subroutine) it.next(); 145 log(sub.toString()); 146 } 147 } 148 emitCode(); 149 } 150 151 if (mv != null) { 153 accept(mv); 154 } 155 } 156 157 161 private void markSubroutines() { 162 BitSet anyvisited = new BitSet (); 163 164 markSubroutineWalk(mainSubroutine, 0, anyvisited); 167 168 for (Iterator it = subroutineHeads.entrySet().iterator(); it.hasNext();) 171 { 172 Map.Entry entry = (Map.Entry ) it.next(); 173 LabelNode lab = (LabelNode) entry.getKey(); 174 Subroutine sub = (Subroutine) entry.getValue(); 175 int index = instructions.indexOf(lab); 176 markSubroutineWalk(sub, index, anyvisited); 177 } 178 } 179 180 193 private void markSubroutineWalk( 194 final Subroutine sub, 195 final int index, 196 final BitSet anyvisited) 197 { 198 if (LOGGING) { 199 log("markSubroutineWalk: sub=" + sub + " index=" + index); 200 } 201 202 markSubroutineWalkDFS(sub, index, anyvisited); 204 205 boolean loop = true; 207 while (loop) { 208 loop = false; 209 for (Iterator it = tryCatchBlocks.iterator(); it.hasNext();) { 210 TryCatchBlockNode trycatch = (TryCatchBlockNode) it.next(); 211 212 if (LOGGING) { 213 log("Scanning try/catch " + trycatch); 214 } 215 216 int handlerindex = instructions.indexOf(trycatch.handler); 218 if (sub.instructions.get(handlerindex)) { 219 continue; 220 } 221 222 int startindex = instructions.indexOf(trycatch.start); 223 int endindex = instructions.indexOf(trycatch.end); 224 int nextbit = sub.instructions.nextSetBit(startindex); 225 if (nextbit != -1 && nextbit < endindex) { 226 if (LOGGING) { 227 log("Adding exception handler: " + startindex + "-" 228 + endindex + " due to " + nextbit + " handler " 229 + handlerindex); 230 } 231 markSubroutineWalkDFS(sub, handlerindex, anyvisited); 232 loop = true; 233 } 234 } 235 } 236 } 237 238 247 private void markSubroutineWalkDFS( 248 final Subroutine sub, 249 int index, 250 final BitSet anyvisited) 251 { 252 while (true) { 253 AbstractInsnNode node = instructions.get(index); 254 255 if (sub.instructions.get(index)) { 257 return; 258 } 259 sub.instructions.set(index); 260 261 if (anyvisited.get(index)) { 263 dualCitizens.set(index); 264 if (LOGGING) { 265 log("Instruction #" + index + " is dual citizen."); 266 } 267 } 268 anyvisited.set(index); 269 270 if (node.getType() == AbstractInsnNode.JUMP_INSN 271 && node.getOpcode() != JSR) 272 { 273 JumpInsnNode jnode = (JumpInsnNode) node; 276 int destidx = instructions.indexOf(jnode.label); 277 markSubroutineWalkDFS(sub, destidx, anyvisited); 278 } 279 if (node.getType() == AbstractInsnNode.TABLESWITCH_INSN) { 280 TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node; 281 int destidx = instructions.indexOf(tsnode.dflt); 282 markSubroutineWalkDFS(sub, destidx, anyvisited); 283 for (int i = tsnode.labels.size() - 1; i >= 0; --i) { 284 LabelNode l = (LabelNode) tsnode.labels.get(i); 285 destidx = instructions.indexOf(l); 286 markSubroutineWalkDFS(sub, destidx, anyvisited); 287 } 288 } 289 if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) { 290 LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node; 291 int destidx = instructions.indexOf(lsnode.dflt); 292 markSubroutineWalkDFS(sub, destidx, anyvisited); 293 for (int i = lsnode.labels.size() - 1; i >= 0; --i) { 294 LabelNode l = (LabelNode) lsnode.labels.get(i); 295 destidx = instructions.indexOf(l); 296 markSubroutineWalkDFS(sub, destidx, anyvisited); 297 } 298 } 299 300 switch (instructions.get(index).getOpcode()) { 303 case GOTO: 304 case RET: 305 case TABLESWITCH: 306 case LOOKUPSWITCH: 307 case IRETURN: 308 case LRETURN: 309 case FRETURN: 310 case DRETURN: 311 case ARETURN: 312 case RETURN: 313 case ATHROW: 314 318 return; 319 } 320 321 index++; 324 } 325 } 326 327 331 private void emitCode() { 332 LinkedList worklist = new LinkedList (); 333 worklist.add(new Instantiation(null, mainSubroutine)); 336 337 InsnList newInstructions = new InsnList(); 340 List newTryCatchBlocks = new ArrayList (); 341 List newLocalVariables = new ArrayList (); 342 while (!worklist.isEmpty()) { 343 Instantiation inst = (Instantiation) worklist.removeFirst(); 344 emitSubroutine(inst, 345 worklist, 346 newInstructions, 347 newTryCatchBlocks, 348 newLocalVariables); 349 } 350 instructions = newInstructions; 351 tryCatchBlocks = newTryCatchBlocks; 352 localVariables = newLocalVariables; 353 } 354 355 366 private void emitSubroutine( 367 final Instantiation instant, 368 final List worklist, 369 final InsnList newInstructions, 370 final List newTryCatchBlocks, 371 final List newLocalVariables) 372 { 373 LabelNode duplbl = null; 374 375 if (LOGGING) { 376 log("--------------------------------------------------------"); 377 log("Emitting instantiation of subroutine " + instant.subroutine); 378 } 379 380 for (int i = 0, c = instructions.size(); i < c; i++) { 383 AbstractInsnNode insn = instructions.get(i); 384 Instantiation owner = instant.findOwner(i); 385 386 if (insn.getType() == AbstractInsnNode.LABEL) { 388 LabelNode ilbl = (LabelNode) insn; 393 LabelNode remap = instant.rangeLabel(ilbl); 394 if (LOGGING) { 395 log("Translating lbl #" + i + ":" + ilbl + " to " + remap); 396 } 397 if (remap != duplbl) { 398 newInstructions.add(remap); 399 duplbl = remap; 400 } 401 continue; 402 } 403 404 if (owner != instant) { 410 continue; 411 } 412 413 if (LOGGING) { 414 log("Emitting inst #" + i); 415 } 416 417 if (insn.getOpcode() == RET) { 418 LabelNode retlabel = null; 427 for (Instantiation p = instant; p != null; p = p.previous) { 428 if (p.subroutine.ownsInstruction(i)) { 429 retlabel = p.returnLabel; 430 } 431 } 432 if (retlabel == null) { 433 throw new RuntimeException ("Instruction #" + i 437 + " is a RET not owned by any subroutine"); 438 } 439 newInstructions.add(new JumpInsnNode(GOTO, retlabel)); 440 } else if (insn.getOpcode() == JSR) { 441 LabelNode lbl = ((JumpInsnNode) insn).label; 442 Subroutine sub = (Subroutine) subroutineHeads.get(lbl); 443 Instantiation newinst = new Instantiation(instant, sub); 444 LabelNode startlbl = newinst.gotoLabel(lbl); 445 446 if (LOGGING) { 447 log(" Creating instantiation of subr " + sub); 448 } 449 450 newInstructions.add(new InsnNode(ACONST_NULL)); 456 newInstructions.add(new JumpInsnNode(GOTO, startlbl)); 457 newInstructions.add(newinst.returnLabel); 458 459 worklist.add(newinst); 462 } else { 463 newInstructions.add(insn.clone(instant)); 464 } 465 } 466 467 for (Iterator it = tryCatchBlocks.iterator(); it.hasNext();) { 469 TryCatchBlockNode trycatch = (TryCatchBlockNode) it.next(); 470 471 if (LOGGING) { 472 log("try catch block original labels=" + trycatch.start + "-" 473 + trycatch.end + "->" + trycatch.handler); 474 } 475 476 final LabelNode start = instant.rangeLabel(trycatch.start); 477 final LabelNode end = instant.rangeLabel(trycatch.end); 478 479 if (start == end) { 481 if (LOGGING) { 482 log(" try catch block empty in this subroutine"); 483 } 484 continue; 485 } 486 487 final LabelNode handler = instant.gotoLabel(trycatch.handler); 488 489 if (LOGGING) { 490 log(" try catch block new labels=" + start + "-" + end + "->" 491 + handler); 492 } 493 494 if (start == null || end == null || handler == null) { 495 throw new RuntimeException ("Internal error!"); 496 } 497 498 newTryCatchBlocks.add(new TryCatchBlockNode(start, 499 end, 500 handler, 501 trycatch.type)); 502 } 503 504 for (Iterator it = localVariables.iterator(); it.hasNext();) { 505 LocalVariableNode lvnode = (LocalVariableNode) it.next(); 506 if (LOGGING) { 507 log("local var " + lvnode.name); 508 } 509 final LabelNode start = instant.rangeLabel(lvnode.start); 510 final LabelNode end = instant.rangeLabel(lvnode.end); 511 if (start == end) { 512 if (LOGGING) { 513 log(" local variable empty in this sub"); 514 } 515 continue; 516 } 517 newLocalVariables.add(new LocalVariableNode(lvnode.name, 518 lvnode.desc, 519 lvnode.signature, 520 start, 521 end, 522 lvnode.index)); 523 } 524 } 525 526 private void log(final String str) { 527 System.err.println(str); 528 } 529 530 protected static class Subroutine { 531 532 public final BitSet instructions = new BitSet (); 533 534 public void addInstruction(final int idx) { 535 instructions.set(idx); 536 } 537 538 public boolean ownsInstruction(final int idx) { 539 return instructions.get(idx); 540 } 541 542 public String toString() { 543 return "Subroutine: " + instructions; 544 } 545 } 546 547 555 private class Instantiation extends AbstractMap { 556 557 561 final Instantiation previous; 562 563 566 public final Subroutine subroutine; 567 568 582 public final Map rangeTable = new HashMap (); 583 584 587 public final LabelNode returnLabel; 588 589 public Instantiation(final Instantiation prev, final Subroutine sub) { 590 previous = prev; 591 subroutine = sub; 592 for (Instantiation p = prev; p != null; p = p.previous) { 593 if (p.subroutine == sub) { 594 throw new RuntimeException ("Recursive invocation of " + sub); 595 } 596 } 597 598 if (prev != null) { 601 returnLabel = new LabelNode(); 602 } else { 603 returnLabel = null; 604 } 605 606 LabelNode duplbl = null; 613 for (int i = 0, c = instructions.size(); i < c; i++) { 614 AbstractInsnNode insn = instructions.get(i); 615 616 if (insn.getType() == AbstractInsnNode.LABEL) { 617 LabelNode ilbl = (LabelNode) insn; 618 619 if (duplbl == null) { 620 duplbl = new LabelNode(); 623 } 624 625 rangeTable.put(ilbl, duplbl); 629 } else if (findOwner(i) == this) { 630 duplbl = null; 634 } 635 } 636 } 637 638 660 public Instantiation findOwner(final int i) { 661 if (!subroutine.ownsInstruction(i)) { 662 return null; 663 } 664 if (!dualCitizens.get(i)) { 665 return this; 666 } 667 Instantiation own = this; 668 for (Instantiation p = previous; p != null; p = p.previous) { 669 if (p.subroutine.ownsInstruction(i)) { 670 own = p; 671 } 672 } 673 return own; 674 } 675 676 686 public LabelNode gotoLabel(final LabelNode l) { 687 Instantiation owner = findOwner(instructions.indexOf(l)); 690 return (LabelNode) owner.rangeTable.get(l); 691 } 692 693 704 public LabelNode rangeLabel(final LabelNode l) { 705 return (LabelNode) rangeTable.get(l); 706 } 707 708 710 public Set entrySet() { 711 return null; 712 } 713 714 public Object get(final Object o) { 715 return gotoLabel((LabelNode) o); 716 } 717 } 718 } 719 | Popular Tags |