1 15 16 package javassist; 17 18 import javassist.bytecode.*; 19 import javassist.compiler.Javac; 20 import javassist.compiler.CompileError; 21 import javassist.expr.ExprEditor; 22 23 29 public abstract class CtBehavior extends CtMember { 30 protected MethodInfo methodInfo; 31 32 protected CtBehavior(CtClass clazz, MethodInfo minfo) { 33 super(clazz); 34 methodInfo = minfo; 35 } 36 37 protected void extendToString(StringBuffer buffer) { 38 buffer.append(' '); 39 buffer.append(getName()); 40 buffer.append(' '); 41 buffer.append(methodInfo.getDescriptor()); 42 } 43 44 48 public MethodInfo getMethodInfo() { 49 declaringClass.checkModify(); 50 return methodInfo; 51 } 52 53 56 public MethodInfo getMethodInfo2() { return methodInfo; } 57 58 65 public int getModifiers() { 66 return AccessFlag.toModifier(methodInfo.getAccessFlags()); 67 } 68 69 78 public void setModifiers(int mod) { 79 declaringClass.checkModify(); 80 methodInfo.setAccessFlags(AccessFlag.of(mod)); 81 } 82 83 86 public CtClass[] getParameterTypes() throws NotFoundException { 87 return Descriptor.getParameterTypes(methodInfo.getDescriptor(), 88 declaringClass.getClassPool()); 89 } 90 91 94 CtClass getReturnType0() throws NotFoundException { 95 return Descriptor.getReturnType(methodInfo.getDescriptor(), 96 declaringClass.getClassPool()); 97 } 98 99 106 public String getSignature() { 107 return methodInfo.getDescriptor(); 108 } 109 110 115 public CtClass[] getExceptionTypes() throws NotFoundException { 116 String [] exceptions; 117 ExceptionsAttribute ea = methodInfo.getExceptionsAttribute(); 118 if (ea == null) 119 exceptions = null; 120 else 121 exceptions = ea.getExceptions(); 122 123 return declaringClass.getClassPool().get(exceptions); 124 } 125 126 129 public void setExceptionTypes(CtClass[] types) throws NotFoundException { 130 declaringClass.checkModify(); 131 if (types == null || types.length == 0) { 132 methodInfo.removeExceptionsAttribute(); 133 return; 134 } 135 136 String [] names = new String [types.length]; 137 for (int i = 0; i < types.length; ++i) 138 names[i] = types[i].getName(); 139 140 ExceptionsAttribute ea = methodInfo.getExceptionsAttribute(); 141 if (ea == null) { 142 ea = new ExceptionsAttribute(methodInfo.getConstPool()); 143 methodInfo.setExceptionsAttribute(ea); 144 } 145 146 ea.setExceptions(names); 147 } 148 149 152 public abstract boolean isEmpty(); 153 154 162 public void setBody(String src) throws CannotCompileException { 163 setBody(src, null, null); 164 } 165 166 178 public void setBody(String src, 179 String delegateObj, String delegateMethod) 180 throws CannotCompileException 181 { 182 declaringClass.checkModify(); 183 try { 184 Javac jv = new Javac(declaringClass); 185 if (delegateMethod != null) 186 jv.recordProceed(delegateObj, delegateMethod); 187 188 Bytecode b = jv.compileBody(this, src); 189 methodInfo.setCodeAttribute(b.toCodeAttribute()); 190 methodInfo.setAccessFlags(methodInfo.getAccessFlags() 191 & ~AccessFlag.ABSTRACT); 192 } 193 catch (CompileError e) { 194 throw new CannotCompileException(e); 195 } 196 } 197 198 static void setBody0(CtClass srcClass, MethodInfo srcInfo, 199 CtClass destClass, MethodInfo destInfo, 200 ClassMap map) 201 throws CannotCompileException 202 { 203 destClass.checkModify(); 204 205 if (map == null) 206 map = new ClassMap(); 207 208 map.put(srcClass.getName(), destClass.getName()); 209 try { 210 CodeAttribute cattr = srcInfo.getCodeAttribute(); 211 if (cattr != null) { 212 ConstPool cp = destInfo.getConstPool(); 213 CodeAttribute ca = (CodeAttribute)cattr.copy(cp, map); 214 destInfo.setCodeAttribute(ca); 215 } 216 } 217 catch (CodeAttribute.RuntimeCopyException e) { 218 220 throw new CannotCompileException(e); 221 } 222 223 destInfo.setAccessFlags(destInfo.getAccessFlags() 224 & ~AccessFlag.ABSTRACT); 225 } 226 227 234 public byte[] getAttribute(String name) { 235 AttributeInfo ai = methodInfo.getAttribute(name); 236 if (ai == null) 237 return null; 238 else 239 return ai.get(); 240 } 241 242 248 public void setAttribute(String name, byte[] data) { 249 declaringClass.checkModify(); 250 methodInfo.addAttribute(new AttributeInfo(methodInfo.getConstPool(), 251 name, data)); 252 } 253 254 271 public void useCflow(String name) throws CannotCompileException { 272 CtClass cc = declaringClass; 273 cc.checkModify(); 274 ClassPool pool = cc.getClassPool(); 275 String fname; 276 int i = 0; 277 while (true) { 278 fname = "_cflow$" + i++; 279 try { 280 cc.getDeclaredField(fname); 281 } 282 catch(NotFoundException e) { 283 break; 284 } 285 } 286 287 pool.recordCflow(name, declaringClass.getName(), fname); 288 try { 289 CtClass type = pool.get("javassist.runtime.Cflow"); 290 CtField field = new CtField(type, fname, cc); 291 field.setModifiers(Modifier.PUBLIC | Modifier.STATIC); 292 cc.addField(field, CtField.Initializer.byNew(type)); 293 insertBefore(fname + ".enter();"); 294 String src = fname + ".exit();"; 295 insertAfter(src, true); 296 } 297 catch (NotFoundException e) { 298 throw new CannotCompileException(e); 299 } 300 } 301 302 313 public void addLocalVariable(String name, CtClass type) 314 throws CannotCompileException 315 { 316 declaringClass.checkModify(); 317 ConstPool cp = methodInfo.getConstPool(); 318 CodeAttribute ca = methodInfo.getCodeAttribute(); 319 if (ca == null) 320 throw new CannotCompileException("no method body"); 321 322 LocalVariableAttribute va = (LocalVariableAttribute)ca.getAttribute( 323 LocalVariableAttribute.tag); 324 if (va == null) { 325 va = new LocalVariableAttribute(cp); 326 ca.getAttributes().add(va); 327 } 328 329 int maxLocals = ca.getMaxLocals(); 330 String desc = Descriptor.of(type); 331 va.addEntry(0, ca.getCodeLength(), 332 cp.addUtf8Info(name), cp.addUtf8Info(desc), maxLocals); 333 ca.setMaxLocals(maxLocals + Descriptor.dataSize(desc)); 334 } 335 336 341 public void instrument(CodeConverter converter) 342 throws CannotCompileException 343 { 344 declaringClass.checkModify(); 345 ConstPool cp = methodInfo.getConstPool(); 346 converter.doit(getDeclaringClass(), methodInfo, cp); 347 } 348 349 354 public void instrument(ExprEditor editor) 355 throws CannotCompileException 356 { 357 if (declaringClass.isFrozen()) 360 declaringClass.checkModify(); 361 362 if (editor.doit(declaringClass, methodInfo)) 363 declaringClass.checkModify(); 364 } 365 366 382 public void insertBefore(String src) throws CannotCompileException { 383 declaringClass.checkModify(); 384 CodeAttribute ca = methodInfo.getCodeAttribute(); 385 if (ca == null) 386 throw new CannotCompileException("no method body"); 387 388 CodeIterator iterator = ca.iterator(); 389 Javac jv = new Javac(declaringClass); 390 try { 391 int nvars = jv.recordParams(getParameterTypes(), 392 Modifier.isStatic(getModifiers())); 393 jv.recordParamNames(ca, nvars); 394 jv.recordLocalVariables(ca, 0); 395 jv.compileStmnt(src); 396 Bytecode b = jv.getBytecode(); 397 int stack = b.getMaxStack(); 398 int locals = b.getMaxLocals(); 399 400 if (stack > ca.getMaxStack()) 401 ca.setMaxStack(stack); 402 403 if (locals > ca.getMaxLocals()) 404 ca.setMaxLocals(locals); 405 406 int pos = iterator.insertEx(b.get()); 407 iterator.insert(b.getExceptionTable(), pos); 408 } 409 catch (NotFoundException e) { 410 throw new CannotCompileException(e); 411 } 412 catch (CompileError e) { 413 throw new CannotCompileException(e); 414 } 415 catch (BadBytecode e) { 416 throw new CannotCompileException(e); 417 } 418 } 419 420 428 public void insertAfter(String src) 429 throws CannotCompileException 430 { 431 insertAfter(src, false); 432 } 433 434 444 public void insertAfter(String src, boolean asFinally) 445 throws CannotCompileException 446 { 447 declaringClass.checkModify(); 448 ConstPool pool = methodInfo.getConstPool(); 449 CodeAttribute ca = methodInfo.getCodeAttribute(); 450 if (ca == null) 451 throw new CannotCompileException("no method body"); 452 453 CodeIterator iterator = ca.iterator(); 454 int retAddr = ca.getMaxLocals(); 455 Bytecode b = new Bytecode(pool, 0, retAddr + 1); 456 b.setStackDepth(ca.getMaxStack() + 1); 457 Javac jv = new Javac(b, declaringClass); 458 try { 459 int nvars = jv.recordParams(getParameterTypes(), 460 Modifier.isStatic(getModifiers())); 461 jv.recordParamNames(ca, nvars); 462 CtClass rtype = getReturnType0(); 463 int varNo = jv.recordReturnType(rtype, true); 464 jv.recordLocalVariables(ca, 0); 465 466 int handlerLen = insertAfterHandler(asFinally, b, rtype, varNo); 467 468 byte[] save = makeSaveCode(pool, rtype, varNo); 469 byte[] restore = makeRestoreCode(b, pool, rtype, varNo); 470 471 b.addAstore(retAddr); 472 jv.compileStmnt(src); 473 b.addRet(retAddr); 474 ca.setMaxStack(b.getMaxStack()); 475 ca.setMaxLocals(b.getMaxLocals()); 476 477 int gapPos = iterator.append(b.get()); 478 iterator.append(b.getExceptionTable(), gapPos); 479 480 if (asFinally) 481 ca.getExceptionTable().add(0, gapPos, gapPos, 0); 482 483 int gapLen = iterator.getCodeLength() - gapPos - handlerLen; 484 int subr = iterator.getCodeLength() - gapLen; 485 486 while (iterator.hasNext()) { 487 int pos = iterator.next(); 488 if (pos >= subr) 489 break; 490 491 int c = iterator.byteAt(pos); 492 if (c == Opcode.ARETURN || c == Opcode.IRETURN 493 || c == Opcode.FRETURN || c == Opcode.LRETURN 494 || c == Opcode.DRETURN || c == Opcode.RETURN) { 495 insertJSR(iterator, subr, pos, save, restore); 496 subr = iterator.getCodeLength() - gapLen; 497 } 498 } 499 } 500 catch (NotFoundException e) { 501 throw new CannotCompileException(e); 502 } 503 catch (CompileError e) { 504 throw new CannotCompileException(e); 505 } 506 catch (BadBytecode e) { 507 throw new CannotCompileException(e); 508 } 509 } 510 511 private byte[] makeSaveCode(ConstPool cp, CtClass rtype, int varNo) { 512 Bytecode b = new Bytecode(cp, 0, 0); 513 if (rtype == CtClass.voidType) { 514 b.addOpcode(Opcode.ACONST_NULL); 515 b.addAstore(varNo); 516 return b.get(); 517 } 518 else { 519 b.addStore(varNo, rtype); 520 return b.get(); 521 } 522 } 523 524 private byte[] makeRestoreCode(Bytecode code, ConstPool cp, 525 CtClass rtype, int varNo) { 526 if (rtype == CtClass.voidType) { 527 if (code.getMaxLocals() < 1) 528 code.setMaxLocals(1); 529 530 return new byte[0]; 531 } 532 else { 533 Bytecode b = new Bytecode(cp, 0, 0); 534 b.addLoad(varNo, rtype); 535 return b.get(); 536 } 537 } 538 539 private void insertJSR(CodeIterator iterator, int subr, int pos, 540 byte[] save, byte[] restore) 541 throws BadBytecode 542 { 543 int gapSize = 5 + save.length + restore.length; 544 boolean wide = subr - pos > Short.MAX_VALUE - gapSize - 4; 545 gapSize = iterator.insertGap(pos, wide ? gapSize : gapSize - 2); 546 547 iterator.write(save, pos); 548 pos += save.length; 549 if (wide) { 550 iterator.writeByte(Opcode.JSR_W, pos); 551 iterator.write32bit(subr - pos + gapSize, pos + 1); 552 pos += 5; 553 } 554 else { 555 iterator.writeByte(Opcode.JSR, pos); 556 iterator.write16bit(subr - pos + gapSize, pos + 1); 557 pos += 3; 558 } 559 560 iterator.write(restore, pos); 561 } 562 563 private int insertAfterHandler(boolean asFinally, Bytecode b, 564 CtClass rtype, int returnVarNo) 565 { 566 if (!asFinally) 567 return 0; 568 569 int var = b.getMaxLocals(); 570 b.incMaxLocals(1); 571 int pc = b.currentPc(); 572 b.addAstore(var); 573 if (rtype.isPrimitive()) { 574 char c = ((CtPrimitiveType)rtype).getDescriptor(); 575 if (c == 'D') { 576 b.addDconst(0.0); 577 b.addDstore(returnVarNo); 578 } 579 else if (c == 'F') { 580 b.addFconst(0); 581 b.addFstore(returnVarNo); 582 } 583 else if (c == 'J') { 584 b.addLconst(0); 585 b.addLstore(returnVarNo); 586 } 587 else if (c != 'V') { b.addIconst(0); 589 b.addIstore(returnVarNo); 590 } 591 } 592 else { 593 b.addOpcode(Opcode.ACONST_NULL); 594 b.addAstore(returnVarNo); 595 } 596 597 b.addOpcode(Opcode.JSR); 598 int pc2 = b.currentPc(); 599 b.addIndex(0); b.addAload(var); 601 b.addOpcode(Opcode.ATHROW); 602 int pc3 = b.currentPc(); 603 b.write16bit(pc2, pc3 - pc2 + 1); 604 return pc3 - pc; 605 } 606 607 657 658 667 public void addCatch(String src, CtClass exceptionType) 668 throws CannotCompileException 669 { 670 addCatch(src, exceptionType, "$e"); 671 } 672 673 685 public void addCatch(String src, CtClass exceptionType, 686 String exceptionName) 687 throws CannotCompileException 688 { 689 declaringClass.checkModify(); 690 ConstPool cp = methodInfo.getConstPool(); 691 CodeAttribute ca = methodInfo.getCodeAttribute(); 692 CodeIterator iterator = ca.iterator(); 693 Bytecode b = new Bytecode(cp, ca.getMaxStack(), ca.getMaxLocals()); 694 b.setStackDepth(1); 695 Javac jv = new Javac(b, declaringClass); 696 try { 697 jv.recordParams(getParameterTypes(), 698 Modifier.isStatic(getModifiers())); 699 int var = jv.recordVariable(exceptionType, exceptionName); 700 b.addAstore(var); 701 jv.compileStmnt(src); 702 703 int stack = b.getMaxStack(); 704 int locals = b.getMaxLocals(); 705 706 if (stack > ca.getMaxStack()) 707 ca.setMaxStack(stack); 708 709 if (locals > ca.getMaxLocals()) 710 ca.setMaxLocals(locals); 711 712 int len = iterator.getCodeLength(); 713 int pos = iterator.append(b.get()); 714 ca.getExceptionTable().add(getStartPosOfBody(ca), len, len, 715 cp.addClassInfo(exceptionType)); 716 iterator.append(b.getExceptionTable(), pos); 717 } 718 catch (NotFoundException e) { 719 throw new CannotCompileException(e); 720 } 721 catch (CompileError e) { 722 throw new CannotCompileException(e); 723 } 724 } 725 726 728 int getStartPosOfBody(CodeAttribute ca) throws CannotCompileException { 729 return 0; 730 } 731 732 749 public int insertAt(int lineNum, String src) 750 throws CannotCompileException 751 { 752 return insertAt(lineNum, true, src); 753 } 754 755 777 public int insertAt(int lineNum, boolean modify, String src) 778 throws CannotCompileException 779 { 780 CodeAttribute ca = methodInfo.getCodeAttribute(); 781 if (ca == null) 782 throw new CannotCompileException("no method body"); 783 784 LineNumberAttribute ainfo 785 = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag); 786 if (ainfo == null) 787 throw new CannotCompileException("no line number info"); 788 789 LineNumberAttribute.Pc pc = ainfo.toNearPc(lineNum); 790 lineNum = pc.line; 791 int index = pc.index; 792 if (!modify) 793 return lineNum; 794 795 declaringClass.checkModify(); 796 CodeIterator iterator = ca.iterator(); 797 Javac jv = new Javac(declaringClass); 798 try { 799 jv.recordLocalVariables(ca, index); 800 jv.recordParams(getParameterTypes(), 801 Modifier.isStatic(getModifiers())); 802 jv.compileStmnt(src); 803 Bytecode b = jv.getBytecode(); 804 int stack = b.getMaxStack(); 805 int locals = b.getMaxLocals(); 806 807 810 if (stack > ca.getMaxStack()) 811 ca.setMaxStack(stack); 812 813 if (locals > ca.getMaxLocals()) 814 ca.setMaxLocals(locals); 815 816 iterator.insert(index, b.get()); 817 iterator.insert(b.getExceptionTable(), index); 818 return lineNum; 819 } 820 catch (NotFoundException e) { 821 throw new CannotCompileException(e); 822 } 823 catch (CompileError e) { 824 throw new CannotCompileException(e); 825 } 826 catch (BadBytecode e) { 827 throw new CannotCompileException(e); 828 } 829 } 830 } 831 | Popular Tags |