1 24 25 package org.aspectj.compiler.crosscuts.ast; 26 27 import java.util.*; 28 29 import org.aspectj.compiler.base.*; 30 import org.aspectj.compiler.base.ast.*; 31 import org.aspectj.compiler.crosscuts.joinpoints.*; 32 33 37 38 public class AroundAdviceDec extends AdviceDec { 39 Collection returnStmts = new ArrayList(); 40 Collection proceedExprs = new ArrayList(); 41 42 45 private boolean shouldInline() { 46 return (!containsInners && !isTargetOfAnyAroundAdvice) && !getOptions().alwaysMakeAroundClosures; 47 } 48 49 private boolean containsInners = false; 50 private boolean isTargetOfAnyAroundAdvice = false; 51 52 public MethodDec getMethodDec() { 53 MethodDec md = super.getMethodDec(); 54 md.setThrows( 55 getAST().makeTypeDs(getTypeManager().getThrowableType().makeTypeD())); 56 return md; 57 } 58 59 protected String getAdviceKind() { 60 return "around"; 61 } 62 63 public List joinPoints1 = new ArrayList(); 64 public List joinPoints2 = new ArrayList(); 65 66 void implementPlans(List jps) { 67 for (Iterator i = jps.iterator(); i.hasNext();) { 68 JoinPoint joinPoint = (JoinPoint) i.next(); 69 joinPoint.implementPlans(); 70 } 71 } 72 73 private boolean ensuredIsWoven = false; 74 private boolean ensuringIsWoven = false; 75 76 private boolean ensureBodyIsWoven(AdvicePlan plan) { 77 if (ensuredIsWoven) 78 return true; 79 80 if (ensuringIsWoven) { 81 isTargetOfAnyAroundAdvice = true; 82 return false; 83 } 84 ensuringIsWoven = true; 85 86 implementPlans(joinPoints1); 87 implementPlans(joinPoints2); 88 89 ensuringIsWoven = false; 90 ensuredIsWoven = true; 91 return true; 92 } 93 94 99 protected Stmts wrapStmts(Stmts stmts, AdvicePlan plan) { 100 if (shouldInline()) ensureBodyIsWoven(plan); 102 103 if (!checkPlan(plan)) 105 return stmts; 106 107 JoinPoint jp = plan.getJoinPoint(); 108 if (jp instanceof AdviceExecutionJp) { 109 AdviceDec ad = (AdviceDec) jp.getTargetDec(); 110 if (ad instanceof AroundAdviceDec) { 111 AroundAdviceDec aad = (AroundAdviceDec)ad; 112 aad.isTargetOfAnyAroundAdvice = true; 113 aad.fixProceedCalls(); 114 } 115 } 116 117 if (jp instanceof ExceptionHandlerJp) { 118 showWarning("can't apply around advice to exception handler join points (compiler limitation)"); 119 jp.getSourceLocation().showWarning( 120 "trying to apply above around advice to execution of this exception handler"); 121 return stmts; 122 } 123 124 if (shouldInline()) { 125 return wrapStmtsInline(stmts, plan); 126 } else { 127 return wrapStmtsWithClosure(stmts, plan); 128 } 129 } 130 131 private Stmts wrapStmtsWithClosure(Stmts stmts, AdvicePlan plan) { 132 JoinPoint jp = plan.getJoinPoint(); 133 134 TypeDec parentTypeDec = stmts.getBytecodeTypeDec(); 135 136 if (parentTypeDec instanceof InterfaceDec) { 137 showWarning("can't apply around advice which contains inner types to interface methods (compiler limitation)"); 138 jp.getTargetNode().showWarning("trying to apply to this location"); 139 return stmts; 140 } 141 142 148 final AST ast = getAST(); 149 150 153 155 163 Modifiers m = ast.makeModifiers(Modifiers.PUBLIC); 164 165 FormalDec argsFormal = ast.makeFinalFormal(getTypeManager().getObjectType().getArrayType(), 166 "_args"); 167 168 ClosureWalker closureWalker = new ClosureWalker(getCompiler(), stmts, 169 makeProceedMap(plan), argsFormal); 170 171 Constructor superConstructor = 172 getTypeManager().getAroundClosureType().getConstructor( 173 stmts, 174 ast.makeExprs(), 175 false); 176 177 ConstructorDec constructorDec = 178 ast.makeConstructor( 179 ast.makeModifiers(0), 180 closureWalker.getConstructorFormals(), 181 ast.makeTypeDs(), 182 ast.makeConstructorCall(true, ast.makeExprs(), superConstructor), 183 closureWalker.getFieldInitStmts()); 184 185 MethodDec methodDec = 186 ast.makeMethod( 187 m, 188 getTypeManager().getObjectType(), 189 "run", 190 ast.makeFormals(argsFormal), 191 closureWalker.getRunBody()); 192 String closureName = genClosureName(); 193 194 ClassDec classDec = 195 ast.makeClass( 196 ast.makeModifiers(Modifiers.PRIVATE), 197 closureName, 198 getTypeManager().getAroundClosureType().makeTypeD(), 199 ast.makeTypeDs()); 200 201 if (plan.getJoinPoint().isStaticContext()) { 202 classDec.getModifiers().setStatic(true); 203 } 204 205 constructorDec.setExplicitlyNonSynthetic(); 210 classDec.addToBody(constructorDec); 211 212 methodDec.setAllEnclosingTypes(classDec.getType()); 213 214 classDec.getBody().add(methodDec); 215 216 for (Iterator i = closureWalker.getFields().iterator(); i.hasNext();) { 217 FieldDec fd = (FieldDec) i.next(); 218 classDec.getBody().add(fd); 219 } 220 221 222 227 parentTypeDec.getBody().add(classDec); 231 classDec.setEnclosingTypeDec(parentTypeDec); 232 classDec.getNameType().addToTypeGraph(); 233 classDec.getNameType().buildSignatures(); 234 235 NewInstanceExpr newExpr = 236 ast.makeNew(classDec.getType(), closureWalker.getConstructorArgs()); 237 238 if (!plan.getJoinPoint().isStaticContext()) { 245 classDec.setIsInner(true); 247 newExpr.setEnclosingInstanceExpr( 248 ast.makeQualifiedThis(parentTypeDec.getType())); 249 } 250 251 getMethodDec(); 253 254 Exprs args = plan.makeCallExprs(newExpr); 255 256 Expr ret = ast.makeCall(getMethodDec().getMethod(), plan.getInstance(), args); 257 258 Stmts retStmts; 259 260 if (plan.getJoinPoint().getResultType().isVoid()) { 261 retStmts = ast.makeStmts(ast.makeStmt(ret)); 262 } else { 263 ret = plan.getJoinPoint().getResultType().fromObject(ret); 264 retStmts = ast.makeStmts(ast.makeReturn(ret)); 265 } 266 267 retStmts = wrapCatchThrowable(retStmts, new HashSet(jp.getPossibleCheckedExceptions())); 268 269 Expr test = plan.getDynamicTest(); 270 271 if (test == null) return retStmts; 272 273 return ast.makeStmts(ast.makeIf(test, 274 ast.makeBlock(retStmts), 275 ast.makeBlock(closureWalker.makeDispatchCall()))); 276 277 } 278 279 280 private Stmts wrapCatchThrowable(Stmts s, Set checkedExcs) { 281 final AST ast = getAST(); 282 checkedExcs = new HashSet(checkedExcs); 283 CatchClauses clauses = new CatchClauses(ast.getSourceLocation()); 284 checkedExcs.add(getTypeManager().getErrorType()); 285 checkedExcs.add(getTypeManager().getRuntimeExceptionType()); 286 checkedExcs = Type.filterTopTypes(checkedExcs); 287 288 for (Iterator i = checkedExcs.iterator(); i.hasNext();) { 289 Type excType = (Type) i.next(); 290 FormalDec formal = ast.makeFinalFormal(excType, "ajc$exc"); 291 BlockStmt body = ast.makeBlock(ast.makeThrow(ast.makeVar(formal))); 292 clauses.add(ast.makeCatch(formal, body)); 293 } 294 295 clauses.add( 296 ast.makeCatch( 297 ast.makeFinalFormal(getTypeManager().getThrowableType(), "ajc$ignore"), 298 ast.makeBlock(ast.makeThrow(getTypeManager().getErrorType(), "can't throw")))); 299 300 Stmt tryStmt = 301 new TryCatchStmt(ast.getSourceLocation(), ast.makeBlock(s), clauses); 302 return ast.makeStmts(tryStmt); 303 } 304 305 public FormalDec getExtraFormal() { 306 if (closureFormal == null) { 307 closureFormal = makeExtraFormal(); 308 } 309 return closureFormal; 310 } 311 312 private FormalDec closureFormal = null; 313 314 private FormalDec makeExtraFormal() { 315 return getAST().makeFinalFormal( 316 getTypeManager().getAroundClosureType(), 317 "ajc$closure"); 318 } 319 320 323 private boolean containsProceed(ASTObject node) { 324 return new Walker(getCompiler()) { 325 private boolean hasProceed = false; 326 327 public boolean hasProceed(ASTObject node1) { 328 process(node1); 329 return hasProceed; 330 } 331 332 public ASTObject process(ASTObject object) { 333 if (hasProceed) return object; 334 335 if (object instanceof ProceedExpr) { 336 hasProceed = true; 337 return object; 338 } 339 340 if (object instanceof TypeDec || object instanceof MethodDec) { 341 return object; 342 } 343 344 return super.process(object); 345 } 346 }.hasProceed(node); 347 } 348 349 350 354 356 358 363 369 370 375 private Map makeProceedMap(AdvicePlan plan) { 376 JoinPoint jp = plan.getJoinPoint(); 377 378 Formals formals = getFormals(); 379 Map proceedMap = new HashMap(); 380 for (int i = 0, N=formals.size(); i < N; i++) { 381 FormalDec formal = formals.get(i); 382 Expr value = (Expr)plan.bindings.get(formal); 383 384 if (value instanceof VarExpr) { 385 VarExpr var = (VarExpr) value; 386 proceedMap.put(var.getVarDec(), new Integer (i)); 387 } else if (value instanceof ThisExpr) { Type toType = jp.getBytecodeType(); 389 proceedMap.put("this", new Integer (i)); 390 } else if (value instanceof NewInstanceExpr) { 391 VarExpr var = (VarExpr) ((NewInstanceExpr) value).getArgs().get(0); 394 proceedMap.put(var.getVarDec(), new Integer (i)); 395 } else { 396 } 399 } 400 401 return proceedMap; 402 } 403 404 407 private boolean isProceedChangable(Expr expr) { 408 return (expr instanceof VarExpr) 409 || (expr instanceof ThisExpr) 410 || (expr instanceof NewInstanceExpr); 411 } 412 413 414 415 class ClosureProceedFixer extends MovingWalker { 416 Stmts stmts; 417 418 public ClosureProceedFixer(JavaCompiler compiler, Stmts stmts) { 419 super(compiler); 420 this.stmts = stmts; 421 } 422 423 public ASTObject remapProceed(CodeDec enclosingCodeDec, ProceedExpr proceedExpr) { 424 final AST ast = this.getAST(); 425 Exprs args = ast.makeExprs(); 426 Exprs proceedArgs = proceedExpr.getArgs(); 427 for (int i=0, len=proceedArgs.size(); i<len; i++) { 428 Expr proceedArg = proceedArgs.get(i); 429 args.add(proceedArg.getType().makeObject(proceedArg)); 430 } 431 432 Expr expr = getReturnType().fromObject( 433 ast.makeCall(ast.makeVar(getExtraFormal()), "run", 434 ast.makeExprs(ast.makeArray(this.getTypeManager().getObjectType(), args)))); 435 return expr; 436 } 437 438 public CodeDec fixCodeDecExceptions(CodeDec codeDec) { 439 codeDec = (CodeDec)super.process(codeDec); 441 Stmts stmts = codeDec.getBody().getStmts(); 442 Set excTypes = codeDec.getPossibleCheckedExceptions(); 443 444 if (stmts.size() > 0) { 446 codeDec.getBody().setStmts(wrapCatchThrowable(stmts, excTypes)); 447 } 448 return codeDec; 449 } 450 451 public ASTObject process(ASTObject object) { 452 ASTObject original = object; 453 if (object instanceof CodeDec) { 454 return fixCodeDecExceptions((CodeDec)object); 455 } 456 457 object = super.process(object); 458 if (object instanceof ProceedExpr) { 459 return remapProceed(original.getEnclosingCodeDec(), (ProceedExpr) object); 460 } else { 461 return object; 462 } 463 } 464 } 465 466 private boolean fixedProceedCalls = false; 467 private void fixProceedCalls() { 468 if (fixedProceedCalls) return; 469 fixedProceedCalls = true; 470 ClosureProceedFixer fixer = 471 new ClosureProceedFixer(getCompiler(), getBody().getStmts()); 472 getBody().walk(fixer); 473 } 474 475 476 477 protected CodeBody makeMethodBody() { 478 fixProceedCalls(); 479 return getBody(); 480 } 481 482 483 abstract class DispatchWalker extends MovingWalker { 484 private boolean seenReturn = false; 485 486 private Map varMap = new HashMap(); 487 488 protected Exprs methodArgs = this.getAST().makeExprs(); 489 private Exprs baseMethodArgs = this.getAST().makeExprs(); 490 protected Formals methodFormals = this.getAST().makeFormals(); 491 protected MethodDec dispatchMethodDec; 492 493 protected Stmts newBodyStmts; 494 495 private Map proceedMap; 496 protected CodeDec enclosingCodeDec; 497 498 CallExpr soleCallExpr = null; 499 boolean hasMultipleCallSites = false; 500 501 502 public final Expr makeDispatchCallExpr(Expr thisExpr, Exprs args) { 503 final AST ast = this.getAST(); 504 MethodDec dec = makeDispatchMethod(); 505 512 CallExpr ret = ast.makeCall(dec, thisExpr, args); 513 if (soleCallExpr == null && !hasMultipleCallSites) { 514 soleCallExpr = ret; 515 } else { 516 soleCallExpr = null; 517 hasMultipleCallSites = true; 518 } 519 return ret; 520 } 521 522 523 public Stmts makeDispatchCall() { 524 final AST ast = this.getAST(); 525 Expr thisExpr; 526 if (enclosingCodeDec.isStatic()) { 527 thisExpr = ast.makeTypeExpr(enclosingCodeDec.getBytecodeType()); 528 } else { 529 thisExpr = ast.makeQualifiedThis(enclosingCodeDec.getBytecodeType()); 530 } 531 Expr callExpr = makeDispatchCallExpr(thisExpr, baseMethodArgs); 532 Type returnType = enclosingCodeDec.getResultType(); 533 if (returnType.isVoid()) { 534 return ast.makeStmts(ast.makeStmt(callExpr)); } else { 536 return ast.makeStmts(ast.makeReturn(callExpr)); 537 } 538 } 539 540 541 MethodDec makeDispatchMethod() { 542 if (dispatchMethodDec != null) return dispatchMethodDec; 543 544 final AST ast = this.getAST(); 545 Stmts body = newBodyStmts; 546 Type returnType = enclosingCodeDec.getResultType(); 547 if (returnType.isVoid()) { 548 returnType = this.getTypeManager().getObjectType(); 549 if (body.size() == 0) { 550 body.add(ast.makeReturn(ast.makeNull())); 551 } else if ( ( body.get(body.size()-1) instanceof ReturnStmt ) || 552 ( body.get(body.size()-1) instanceof ThrowStmt )) { 553 } else { 555 body = ast.makeStmts(ast.makeIf(ast.makeLiteral(true), ast.makeBlock(body)), 556 ast.makeReturn(ast.makeNull())); 557 } 558 } 559 560 561 562 dispatchMethodDec = ast.makeMethod(ast.makeModifiers(Modifiers.FINAL | 563 (enclosingCodeDec.isStatic() ? Modifiers.STATIC : 0)), 564 returnType, 565 genDispatchName(enclosingCodeDec), 566 methodFormals, 567 ast.makeBlock(body)); 568 enclosingCodeDec.getBytecodeTypeDec().addToBody(dispatchMethodDec); 569 return dispatchMethodDec; 571 } 572 573 public Expr moveThisExpr(ThisExpr thisExpr, Type thisType) { 575 if (thisExpr instanceof QualifiedThisExpr) 576 return thisExpr; 577 return this.getAST().makeQualifiedThis(thisExpr.getType()); 578 } 579 580 protected Expr makeThisRef() { 581 if (proceedMap.containsKey("this")) { 582 return makeArgRef(enclosingCodeDec.getBytecodeType(), ((Integer )proceedMap.get("this")).intValue()); 583 } else { 584 final AST ast = this.getAST(); 585 if (enclosingCodeDec.isStatic()) { 586 return ast.makeTypeExpr(enclosingCodeDec.getBytecodeType()); 587 } else { 588 return ast.makeQualifiedThis(enclosingCodeDec.getBytecodeType()); 589 } 590 } 591 } 592 593 protected Expr handleFreeVar(VarExpr var) { 594 VarDec dec = var.getVarDec(); 595 596 FormalDec formal = (FormalDec) varMap.get(dec); 597 if (formal == null) { 598 formal = genFormal(dec); 599 } 600 return this.getAST().makeVar(formal); 601 } 602 603 604 DispatchWalker(JavaCompiler compiler, Map proceedMap) { 605 super(compiler); 606 this.proceedMap = proceedMap; 607 } 608 609 abstract Expr makeArgRef(Type type, int index); 610 611 abstract Expr makeFreeRef(VarDec dec); 612 613 614 private FormalDec genFormal(VarDec dec) { 615 final AST ast = this.getAST(); 616 final Type type = dec.getType(); 617 final String name = dec.getName(); 618 FormalDec formalDec = 619 ast.makeFormal(type, name, dec.isFinal()); 620 621 Expr e; 622 if (proceedMap.containsKey(dec)) { 623 e = makeArgRef(dec.getType(), ((Integer )proceedMap.get(dec)).intValue()); 624 } else { 625 e = makeFreeRef(dec); 626 } 627 628 baseMethodArgs.add(ast.makeVar(dec)); 629 methodArgs.add(e); 630 methodFormals.add(formalDec); 631 varMap.put(dec, formalDec); 632 return formalDec; 633 634 } 635 636 public void setup(Stmts stmts) { 637 final AST ast = this.getAST(); 638 enclosingCodeDec = stmts.getEnclosingCodeDec(); 639 setupBodyStmts(stmts); 640 } 641 642 protected final void setupBodyStmts(Stmts stmts) { 646 newBodyStmts = (Stmts) process(stmts); 647 648 649 ReturnAndThrowFixer fixer = new ReturnAndThrowFixer(getCompiler()); 650 651 newBodyStmts = (Stmts)fixer.process(stmts); 652 this.seenReturn = fixer.hasSeenReturn(); 653 } 654 } 655 656 class ReturnAndThrowFixer extends Walker { 657 private boolean seenReturn = false; 658 public ReturnAndThrowFixer(JavaCompiler compiler) { 659 super(compiler); 660 } 661 662 public boolean hasSeenReturn() { 663 return seenReturn; 664 } 665 666 public final ASTObject process(ASTObject object) { 667 if (object instanceof TypeDec) return object; 668 if (object instanceof AnonymousMethodExpr) return object; 669 670 if (object instanceof ReturnStmt) { 671 ReturnStmt returnStmt = (ReturnStmt)object; 672 seenReturn = true; 673 if (returnStmt.getExpr() == null) { 674 returnStmt.setExpr(this.getAST().makeNull()); 675 } 676 } else if (object instanceof ThrowStmt) { 677 seenReturn = true; 678 } 679 return super.process(object); 680 } 681 } 682 683 684 class ClosureWalker extends DispatchWalker { 685 private Exprs constructorArgs = this.getAST().makeExprs(); 686 private Formals constructorFormals = this.getAST().makeFormals(); 687 688 private List fields = new ArrayList(); 689 private Stmts fieldInitStmts = this.getAST().makeStmts(); 690 691 private FormalDec argsFormal; 692 693 Exprs getConstructorArgs() { 694 return constructorArgs; 695 } 696 Formals getConstructorFormals() { 697 return constructorFormals; 698 } 699 700 Stmts getFieldInitStmts() { 701 return fieldInitStmts; 702 } 703 List getFields() { 704 return fields; 705 } 707 BlockStmt getRunBody() { 708 final AST ast = this.getAST(); 709 MethodDec dec = makeDispatchMethod(); 710 711 Expr thisExpr = makeThisRef(); 712 713 Expr callExpr = ast.makeCall(dec, thisExpr, methodArgs); 714 Type returnType = enclosingCodeDec.getResultType(); 715 if (returnType.isVoid()) { 716 return ast.makeBlock(ast.makeStmt(callExpr), ast.makeReturn(ast.makeNull())); 717 } else { 718 return ast.makeBlock(ast.makeReturn(returnType.makeObject(callExpr))); 719 } 720 } 721 722 Expr makeArgRef(Type type, int index) { 723 final AST ast = this.getAST(); 724 return type.fromObject(ast.makeArrayRef(ast.makeVar(argsFormal), index)); 725 } 726 727 Expr makeFreeRef(VarDec dec) { 728 return this.getAST().makeGet(genField(dec)); 729 } 730 731 ClosureWalker(JavaCompiler compiler, Stmts stmts, Map proceedMap, FormalDec argsFormal) { 732 super(compiler, proceedMap); 733 this.argsFormal = argsFormal; 734 setup(stmts); 735 } 736 737 738 private FieldDec genField(VarDec dec) { 739 final AST ast = this.getAST(); 740 final Type type = dec.getType(); 741 final String name = dec.getName(); 742 FieldDec fieldDec = 743 ast.makeField(ast.makeModifiers(Modifiers.PRIVATE), type, name); 744 745 FormalDec formalDec = ast.makeFinalFormal(type, name); 746 Stmt stmt = ast.makeStmt(ast.makeSet(fieldDec, ast.makeVar(formalDec))); 747 748 constructorArgs.add(ast.makeVar(dec)); 749 fields.add(fieldDec); 750 constructorFormals.add(formalDec); 751 fieldInitStmts.add(stmt); 752 return fieldDec; 753 } 754 755 767 } 768 769 770 class InlineWalker extends DispatchWalker { 771 private FormalDec aroundThisFormal = null; 772 private Exprs baseArgs; 773 private Expr baseThis; 774 775 Exprs aroundMethodArgs = this.getAST().makeExprs(); 776 private Formals aroundMethodFormals = this.getAST().makeFormals(); 777 778 private MethodDec aroundMethodDec; 779 780 Expr makeArgRef(Type type, int index) { 781 final AST ast = this.getAST(); 782 return ast.makeVar(getFormals().get(index)); } 785 786 Expr makeFreeRef(VarDec dec) { 787 final AST ast = this.getAST(); 788 789 FormalDec formal = ast.makeFinalFormal(dec.getType(), dec.getName()); 790 aroundMethodFormals.add(formal); 791 aroundMethodArgs.add(ast.makeVar(dec)); 792 793 return ast.makeVar(formal); 794 } 795 796 InlineWalker(JavaCompiler compiler, Stmts stmts, Map proceedMap, Exprs baseArgs, Expr baseThis) { 797 super(compiler, proceedMap); 798 this.baseArgs = baseArgs; 799 this.baseThis = baseThis; 800 setup(stmts); 801 } 802 803 public void setup(Stmts stmts) { 804 final AST ast = this.getAST(); 805 enclosingCodeDec = stmts.getEnclosingCodeDec(); 806 807 Formals formals = getMethodDec().getFormals(); 808 for (int i = 0, N=formals.size(); i<N; i++) { 809 FormalDec baseFormal = formals.get(i); 810 FormalDec formal = ast.makeFormal(baseFormal.getType(), baseFormal.getName(), 811 baseFormal.isFinal()); 812 aroundMethodFormals.add(formal); 813 aroundMethodArgs.add(baseArgs.get(i)); 814 } 815 816 aroundThisFormal = ast.makeFinalFormal(AroundAdviceDec.this.getBytecodeType(), "this_"); 817 aroundMethodFormals.add(aroundThisFormal); 818 aroundMethodArgs.add(baseThis); 819 820 setupBodyStmts(stmts); 821 } 822 823 824 public MethodDec makeInlineAroundMethod() { 825 if (aroundMethodDec != null) return aroundMethodDec; 826 827 final AST ast = this.getAST(); 828 829 InlineProceedFixer fixer = new InlineProceedFixer(this.getCompiler()); 830 Stmts stmts = (Stmts)fixer.process(getBody().getStmts()); 831 832 aroundMethodDec = ast.makeMethod(ast.makeModifiers(Modifiers.FINAL | 833 (enclosingCodeDec.isStatic() ? Modifiers.STATIC : 0)), 834 getResultType(), 835 genAroundName(enclosingCodeDec), 836 aroundMethodFormals, 837 ast.makeBlock(stmts)); 838 enclosingCodeDec.getBytecodeTypeDec().addToBody(aroundMethodDec); 839 aroundMethodDec.setLexicalType(AroundAdviceDec.this.getLexicalType()); 840 return aroundMethodDec; 842 } 843 844 public void inlineSoleCallExpr(JoinPoint jp) { 845 if (soleCallExpr == null || hasMultipleCallSites) { 847 if (hasMultipleCallSites) { 848 jp.showWarning(AroundAdviceDec.this, "couldn't inline sole call expr (multiple calls)"); 849 } 850 return; 851 } 852 853 if (!soleCallExpr.tryToInline(jp.getBytecodeType())) { 854 jp.showWarning(AroundAdviceDec.this, "couldn't inline sole call expr"); 855 } 856 } 857 858 class InlineProceedFixer extends CopyWalker { 859 public Expr moveThisExpr(ThisExpr thisExpr, Type thisType) { 860 return this.getAST().makeVar(aroundThisFormal); 861 } 862 863 public InlineProceedFixer(JavaCompiler compiler) { 864 super(compiler); 865 } 866 867 public ASTObject remapProceed(ProceedExpr proceedExpr) { 868 final AST ast = this.getAST(); 869 Exprs args = ast.makeExprs(); 870 Exprs baseArgs = methodArgs; 871 for (int i=0, N=baseArgs.size(); i<N; i++) { 872 args.add(remap(methodFormals.get(i).getType(), baseArgs.get(i), proceedExpr.getArgs())); 873 } 874 Expr thisExpr = remap(enclosingCodeDec.getDeclaringType(), makeThisRef(), proceedExpr.getArgs()); 875 Expr ret = makeDispatchCallExpr(thisExpr, args); 876 if (getResultType().isObject()) { 877 ret = ret.getType().makeObject(ret); 878 } 879 return ret; 880 } 881 882 protected Expr handleFreeVar(VarExpr var) { 883 VarDec dec = var.getVarDec(); 884 Formals formals = getMethodDec().getFormals(); 885 int index = formals.indexOf(dec); 886 if (index != -1) { 887 return this.getAST().makeVar(aroundMethodFormals.get(index)); 888 } else { 889 this.getCompiler().internalError("unbound free: " + var); 890 return var; 891 } 892 } 893 894 private Expr remap(Type expectedType, Expr expr, Exprs proceedArgs) { 895 if (expr instanceof VarExpr) { 897 VarDec dec = ((VarExpr)expr).getVarDec(); 898 int index = getFormals().indexOf(dec); 899 if (index != -1) { 900 Expr proceedArg = proceedArgs.get(index); 901 return expectedType.fromObject(proceedArg); 903 } 904 } 905 906 908 return (Expr)CopyWalker.copy(expr); 909 } 910 911 public ASTObject process(ASTObject object) { 912 ASTObject original = object; 913 914 object = super.process(object); 915 if (object instanceof ProceedExpr) { 916 return remapProceed((ProceedExpr) object); 917 } else { 918 return object; 919 } 920 } 921 } 922 } 923 924 925 static int closureNumber = 1; 927 private String genClosureName() { 928 return "Closure" + closureNumber++; 929 } 930 String genDispatchName(CodeDec codeDec) { 931 return getAST().makeGeneratedName("dispatch" + closureNumber++ + "_" + codeDec.getName()); 932 } 933 934 static int aroundNumber = 1; 935 private String genAroundName(CodeDec codeDec) { 936 return getAST().makeGeneratedName("around" + aroundNumber++ + "_" + codeDec.getName()); 937 } 938 939 940 private Stmts wrapStmtsInline(Stmts stmts, AdvicePlan plan) { 941 final AST ast = getAST(); 942 JoinPoint jp = plan.getJoinPoint(); 943 944 FormalDec argsFormal = ast.makeFinalFormal(getTypeManager().getObjectType().getArrayType(), 945 "_args"); 946 947 InlineWalker inlineWalker = new InlineWalker(getCompiler(), stmts, 948 makeProceedMap(plan), plan.makeCallExprs(ast.makeNull()), 949 plan.getInstance()); 950 951 952 Exprs args = inlineWalker.aroundMethodArgs; 953 954 CallExpr callAroundMethod = ast.makeCall(inlineWalker.makeInlineAroundMethod().getMethod(), 955 jp.makeThisExprOrType(), args); 956 957 callAroundMethod.setSourceLocation(jp.getTargetNode().getSourceLocation()); 958 959 Expr ret = callAroundMethod; 960 961 Stmts retStmts; 962 963 if (plan.getJoinPoint().getResultType().isVoid()) { 964 retStmts = ast.makeStmts(ast.makeStmt(ret)); 965 } else { 966 ret = plan.getJoinPoint().getResultType().fromObject(ret); 967 retStmts = ast.makeStmts(ast.makeReturn(ret)); 968 } 969 970 972 Expr test = plan.getDynamicTest(); 973 974 if (test != null) { 975 retStmts = ast.makeStmts(ast.makeIf(test, 976 ast.makeBlock(retStmts), 977 ast.makeBlock(inlineWalker.makeDispatchCall()))); 978 } 979 980 if (getOptions().XOcodeSize) { 981 inlineWalker.inlineSoleCallExpr(jp); 982 if (!callAroundMethod.tryToInline(jp.getBytecodeType())) { 983 jp.showWarning(this, "couldn't inline sole call expr"); 984 } 985 } 986 987 return retStmts; 988 } 989 990 991 boolean checkType(JoinPoint jp, Expr expr, Type type, String kind) { 992 if (expr.getType().isReferenceType()) { 994 type = type.getRefType(); 995 } 996 if (!expr.getType().isCoercableTo(type)) { 997 jp.showError( 998 expr, 999 expr.getType().getString() 1000 + " is not coercable to expected " 1001 + kind 1002 + " type " 1003 + type.getString()); 1004 return false; 1005 } 1006 return true; 1007 } 1008 1009 boolean checkImmutableReference(VarDec varDec, Expr expr) { 1010 if (!varDec.isFinal()) { 1011 varDec.showError("cflow-exposed state must be final (compiler limitation)"); 1012 return false; 1013 } 1014 1015 if ( !(expr instanceof VarExpr) 1016 || ((VarExpr)expr).getVarDec() != varDec ) { 1017 expr.showError("must be a simple reference to " + varDec.toShortString() + 1018 " (compiler limitation)"); 1019 return false; 1020 } 1021 1022 return true; 1023 } 1024 1025 1026 public boolean checkPlan(AdvicePlan plan) { 1027 JoinPoint jp = plan.getJoinPoint(); 1028 1029 Type resultType = resultTypeD.getType(); 1030 Type pointResultType = jp.getResultType(); 1031 1032 if (resultType.isEquivalent(getTypeManager().anyType)) { 1033 showError("returns * is not allowed (use returns Object instead)"); 1034 return false; 1035 } 1036 1037 if (!resultType.isEquivalent(getTypeManager().getObjectType())) { 1038 if (resultType.isEquivalent(getTypeManager().voidType)) { 1039 if (!pointResultType.isEquivalent(getTypeManager().voidType)) { 1040 jp.showError(this, "doesn't return void"); 1041 return false; 1042 } 1043 } else { 1044 if (!resultType.isAssignableFrom(pointResultType)) { 1045 jp.showError(this, "returns " + pointResultType.toShortString()); 1046 return false; 1047 } 1048 } 1049 } 1050 1051 for (Iterator i = proceedExprs.iterator(); i.hasNext(); ) { 1052 ProceedExpr proceedExpr = (ProceedExpr)i.next(); 1053 Exprs proceedArgs = proceedExpr.getArgs(); 1054 1055 for (int j = 0, N=formals.size(); j < N; j++) { 1056 FormalDec formal = formals.get(j); 1057 Expr value = (Expr)plan.bindings.get(formal); 1058 1059 if (!isProceedChangable(value)) { 1060 if (!checkImmutableReference(formal, proceedArgs.get(j))) { 1061 return false; 1062 } 1063 } 1064 1065 1066 if (!checkType(jp, proceedArgs.get(j), value.getType(), "arg")) { 1067 return false; 1068 } 1069 } 1070 } 1071 1072 if (resultType.isVoid()) return true; 1073 1074 for (Iterator i = returnStmts.iterator(); i.hasNext(); ) { 1075 ReturnStmt returnStmt = (ReturnStmt)i.next(); 1076 if (!checkType(jp, returnStmt.getExpr(), pointResultType, "return")) { 1077 return false; 1078 } 1079 } 1080 1081 return true; 1082 1083 } 1085 1086 public Type getReturnType() { 1087 Type resultType; 1088 if (resultTypeD == null) { 1089 resultType = getTypeManager().voidType; 1090 } else { 1091 resultType = resultTypeD.getType(); 1092 } 1093 return resultType; 1094 } 1095 1096 public void preScope(ScopeWalker walker) { 1098 if (!walker.walkBodies()) { 1099 new Walker(getCompiler()) { 1101 private boolean inCodeOrType = false; 1102 public ASTObject process(ASTObject o) { 1103 if (!inCodeOrType && (o instanceof TypeDec || o instanceof CodeDec)) { 1104 inCodeOrType = true; 1105 o.walk(this); 1106 inCodeOrType = false; 1107 } else { 1108 o.walk(this); 1109 } 1110 1111 1112 if (o instanceof CallExpr) { 1113 CallExpr callExpr = (CallExpr) o; 1114 if (callExpr.getId().equals("proceed")) { 1115 ProceedExpr ret = new ProceedExpr( 1116 callExpr.getSourceLocation(), 1117 callExpr.getArgs(), 1118 AroundAdviceDec.this); 1119 addProceedExpr(ret); 1120 return ret; 1121 } 1122 } else if (o instanceof TryStmt) { 1123 TryStmt tryStmt = (TryStmt) o; 1124 tryStmt.setIsOptional(true); 1126 return o; 1127 } else if (o instanceof TypeDec) { 1128 containsInners = true; 1129 } else if (!inCodeOrType && o instanceof ReturnStmt) { 1130 returnStmts.add(o); 1131 } 1132 return o; 1133 } 1134 } 1135 .process(getBody()); 1136 } 1137 1138 super.preScope(walker); 1139 } 1140 1141 public void checkSpec() { 1142 super.checkSpec(); 1143 checkAllProceedExprs(); 1144 } 1145 1146 private void checkAllProceedExprs() { 1147 for (Iterator i = proceedExprs.iterator(); i.hasNext(); ) { 1148 boolean valid = checkProceedExpr( (ProceedExpr)i.next() ); 1149 if (!valid) i.remove(); 1150 } 1151 } 1152 1153 1154 private boolean checkProceedExpr(ProceedExpr expr) { 1155 Formals formals = getFormals(); 1156 Exprs args = expr.getArgs(); 1157 1158 int nFormals = formals.size(); 1159 int nArgs = args.size(); 1160 if (nArgs != nFormals) { 1161 expr.showError("expected " + nFormals + " args, found " + nArgs); 1162 return false; 1163 } 1164 1165 for (int i=0; i < nFormals; i++) { 1166 FormalDec formal = formals.get(i); 1167 Expr arg = args.get(i); 1168 if (!arg.getType().isMethodConvertableTo(formal.getType())) { 1170 arg.showTypeError(arg.getType(), formal.getType()); 1171 return false; 1172 } 1173 } 1174 return true; 1175 } 1176 1177 private void addProceedExpr(ProceedExpr expr) { 1178 proceedExprs.add(expr); 1179 } 1180 1181 protected TypeD resultTypeD; 1183 public TypeD getResultTypeD() { 1184 return resultTypeD; 1185 } 1186 public void setResultTypeD(TypeD _resultTypeD) { 1187 if (_resultTypeD != null) 1188 _resultTypeD.setParent(this); 1189 resultTypeD = _resultTypeD; 1190 } 1191 1192 public AroundAdviceDec( 1193 SourceLocation location, 1194 Modifiers _modifiers, 1195 TypeD _resultTypeD, 1196 Formals _formals, 1197 TypeDs __throws, 1198 Pcd _pcd, 1199 CodeBody _body) { 1200 super(location, _modifiers, _formals, __throws, _pcd, _body); 1201 setResultTypeD(_resultTypeD); 1202 } 1203 protected AroundAdviceDec(SourceLocation source) { 1204 super(source); 1205 } 1206 1207 public ASTObject copyWalk(CopyWalker walker) { 1208 AroundAdviceDec ret = new AroundAdviceDec(getSourceLocation()); 1209 ret.preCopy(walker, this); 1210 if (modifiers != null) 1211 ret.setModifiers((Modifiers) walker.process(modifiers)); 1212 if (resultTypeD != null) 1213 ret.setResultTypeD((TypeD) walker.process(resultTypeD)); 1214 if (formals != null) 1215 ret.setFormals((Formals) walker.process(formals)); 1216 if (_throws != null) 1217 ret.setThrows((TypeDs) walker.process(_throws)); 1218 if (pcd != null) 1219 ret.setPcd((Pcd) walker.process(pcd)); 1220 if (body != null) 1221 ret.setBody((CodeBody) walker.process(body)); 1222 return ret; 1223 } 1224 1225 public ASTObject getChildAt(int childIndex) { 1226 switch (childIndex) { 1227 case 0 : 1228 return modifiers; 1229 case 1 : 1230 return resultTypeD; 1231 case 2 : 1232 return formals; 1233 case 3 : 1234 return _throws; 1235 case 4 : 1236 return pcd; 1237 case 5 : 1238 return body; 1239 default : 1240 return super.getChildAt(childIndex); 1241 } 1242 } 1243 public String getChildNameAt(int childIndex) { 1244 switch (childIndex) { 1245 case 0 : 1246 return "modifiers"; 1247 case 1 : 1248 return "resultTypeD"; 1249 case 2 : 1250 return "formals"; 1251 case 3 : 1252 return "throws"; 1253 case 4 : 1254 return "pcd"; 1255 case 5 : 1256 return "body"; 1257 default : 1258 return super.getChildNameAt(childIndex); 1259 } 1260 } 1261 public void setChildAt(int childIndex, ASTObject child) { 1262 switch (childIndex) { 1263 case 0 : 1264 setModifiers((Modifiers) child); 1265 return; 1266 case 1 : 1267 setResultTypeD((TypeD) child); 1268 return; 1269 case 2 : 1270 setFormals((Formals) child); 1271 return; 1272 case 3 : 1273 setThrows((TypeDs) child); 1274 return; 1275 case 4 : 1276 setPcd((Pcd) child); 1277 return; 1278 case 5 : 1279 setBody((CodeBody) child); 1280 return; 1281 default : 1282 super.setChildAt(childIndex, child); 1283 return; 1284 } 1285 } 1286 public int getChildCount() { 1287 return 6; 1288 } 1289 1290 public String getDefaultDisplayName() { 1291 return "AroundAdviceDec()"; 1292 } 1293 1294 1296} 1297 | Popular Tags |