KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > aspectj > compiler > crosscuts > ast > AroundAdviceDec


1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * This file is part of the compiler and core tools for the AspectJ(tm)
4  * programming language; see http://aspectj.org
5  *
6  * The contents of this file are subject to the Mozilla Public License
7  * Version 1.1 (the "License"); you may not use this file except in
8  * compliance with the License. You may obtain a copy of the License at
9  * either http://www.mozilla.org/MPL/ or http://aspectj.org/MPL/.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is AspectJ.
17  *
18  * The Initial Developer of the Original Code is Xerox Corporation. Portions
19  * created by Xerox Corporation are Copyright (C) 1999-2002 Xerox Corporation.
20  * All Rights Reserved.
21  *
22  * Contributor(s):
23  */

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 /**
34  * @grammar around {body; proceed(); body;};
35  * @child TypeD resultTypeD @after modifiers
36  */

37
38 public class AroundAdviceDec extends AdviceDec {
39     Collection returnStmts = new ArrayList();
40     Collection proceedExprs = new ArrayList();
41
42     /** returns true if we should inline the advice at its static join point. In the false
43      * case, use closure objects
44      */

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 JavaDoc 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     /** returns a new wrapped advised Stmts object.
95      *
96      * @param stmts -- the statements of the join point static shadow
97      * @param plan -- an object to give the parameters of the advice, among other things.
98      */

99     protected Stmts wrapStmts(Stmts stmts, AdvicePlan plan) {
100         // if my body hasn't been woven yet, this will switch to non-inline mode
101
if (shouldInline()) ensureBodyIsWoven(plan);
102
103         // if there's an error in the advice plan, there'll be an error, so just stop
104
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         // won't work for exception handlers (not that it was before) for these reasons:
143
// 1. we will eventually need to allocate store space for the closed over vars
144
// instead of copying. Or something like that.
145
// 2. we don't yet worry about breaks/continues/complicated control flow.
146
// 3. we don't get access to fields in local types
147

148         final AST ast = getAST();
149
150         // let s = free vars of STMTS
151
//
152

153         // new Closure137(references to s);
154

155         // add to target type:
156
// private <synthetic> class Closure137 implements AroundClosure {
157
// fields for s;
158
// Closure137(formals for s) { initializations for s; }
159
// public Object run() { if(true) STMTS[return x/RETURN wrap(x),s->fields;
160
// return/RETURN null]; RETURN null}
161
// }
162

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 JavaDoc 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         // we add an explictly non-synthetic constructor to the body before
206
// we ever create a type object. Then, when the type object is created,
207
// the type will have a non-default constructor, and so we won't eagerly create
208
// a default-constructor.
209
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         // see limitations for exception handlers
223
// while (parentTypeDec.isLocal()) {
224
// parentTypeDec = parentTypeDec.getEnclosingTypeDec();
225
// }
226

227         //??? can we expose this better
228
// set enclosing type dec so that various inner info will be "right"
229
// also add this to the type graph
230
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         // from a non-static context, we create new inner types
239
// when we do this after the InnerInfoPass, we need to set the inner flag
240
// and add enclosing instance exprs
241
//
242
// the extra formal to the constructor is added automatically if we do the above
243
// {@link:MemberClassMunger}. {@link:InnerInfoPass}
244
if (!plan.getJoinPoint().isStaticContext()) {
245             //System.err.println(parentTypeDec.getType() + ", " + closureName);
246
classDec.setIsInner(true);
247             newExpr.setEnclosingInstanceExpr(
248                                              ast.makeQualifiedThis(parentTypeDec.getType()));
249         }
250
251         // must be defined
252
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     /**
321      * Is there a ProceedExpr in this tree, but not in an enclosed method or type dec
322      */

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     // int around(int i): call(int m(int)) && args(i): {
351
// ... proceed(37);
352
//
353

354     // ==>
355

356     // m(10) --> A.around1(new Closure1())
357

358     // class Closure1() {
359
// Object run(Object[] args) {
360
// return (Object)m((int)args[0] /* wants x */);
361
// }
362

363     // aspect A {
364
// int around1(Closure c, int i) {
365
// ... c.run(new Object[] { (Integer) 37 }) ...
366
// }
367
// }
368

369
370     /**
371      * Make proceed map
372      *
373      * Returns a map from VarDec|"this" to Integers
374      */

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 JavaDoc(i));
387             } else if (value instanceof ThisExpr) { //XXX Vile encoding
388
Type toType = jp.getBytecodeType();
389                 proceedMap.put("this", new Integer JavaDoc(i));
390             } else if (value instanceof NewInstanceExpr) {
391                 //??? this case shows up because of casting primitives to Object
392
//??? we're pretty sure that those cases will always have a VarExpr as the param
393
VarExpr var = (VarExpr) ((NewInstanceExpr) value).getArgs().get(0);
394                 proceedMap.put(var.getVarDec(), new Integer JavaDoc(i));
395             } else {
396                 //proceedMap.put(, new Integer(i));
397
//getCompiler().internalError(this, "unexpected AST type: " + value);
398
}
399         }
400
401         return proceedMap;
402     }
403
404     /**
405      * !!! this must be in-sync with the matching done above in makeProceedMap
406      */

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             //System.out.println("code: " + codeDec);
440
codeDec = (CodeDec)super.process(codeDec);
441             Stmts stmts = codeDec.getBody().getStmts();
442             Set excTypes = codeDec.getPossibleCheckedExceptions();
443
444             //??? might want to get possible exceptions from stmts
445
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 /*<VarDec,FormalDec>*/ 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 // Expr thisExpr;
506
// if (enclosingCodeDec.isStatic()) {
507
// thisExpr = ast.makeTypeExpr(enclosingCodeDec.getBytecodeType());
508
// } else {
509
// thisExpr = ast.makeQualifiedThis(enclosingCodeDec.getBytecodeType());
510
// }
511

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)); //, ast.makeReturn());
535
} 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                     // skip
554
} 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             //dispatchMethodDec.owner = enclosingCodeDec;
570
return dispatchMethodDec;
571         }
572
573         //XXX this adds evidence to the hypothesis that QualifiedThisExpr is bad
574
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 JavaDoc)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         /** generates all sorts of stuff and puts them in the right places */
614         private FormalDec genFormal(VarDec dec) {
615             final AST ast = this.getAST();
616             final Type type = dec.getType();
617             final String JavaDoc 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 JavaDoc)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         // declare error:
643
// call(void setupBodyStmts(Stmts)) && !withincode(void setup(Stmts)):
644
// "only called from setup";
645
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 /*<FieldDec>*/ 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         } // could just get it from varMap
706

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         /** generates all sorts of stuff and puts them in the right places */
738         private FieldDec genField(VarDec dec) {
739             final AST ast = this.getAST();
740             final Type type = dec.getType();
741             final String JavaDoc 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         /**
756          * Does the following transformations
757          *
758          * <ul>
759          * <li> replaces free variables with field references to fields of the closure,
760          * for which the free values are passed in at closure creation time </li>
761          * <li> replaces references that are supposed to result in values that will be
762          * provided by proceed with references to the Object[] args of the run method
763          * which is passed in by the around method, and contains the arguments
764          * to proceed. </li>
765          * </ul>
766          */

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             //XXX odd encoding here
783
return ast.makeVar(getFormals().get(index)); //type.fromObject(ast.makeVar(getFormals().get(index)));
784
}
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             //aroundMethodDec.owner = enclosingCodeDec;
841
return aroundMethodDec;
842         }
843         
844         public void inlineSoleCallExpr(JoinPoint jp) {
845             //System.out.println(soleCallExpr + ", " + hasMultipleCallSites);
846
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                 //System.out.println("remap: " + expr);
896
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                         //System.out.println(proceedArg + ", " + expectedType);
902
return expectedType.fromObject(proceedArg);
903                     }
904                 }
905
906         //System.err.println("no remapping for: " + expr);
907

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     //XXX remove static state
926
static int closureNumber = 1;
927     private String JavaDoc genClosureName() {
928         return "Closure" + closureNumber++;
929     }
930     String JavaDoc genDispatchName(CodeDec codeDec) {
931         return getAST().makeGeneratedName("dispatch" + closureNumber++ + "_" + codeDec.getName());
932     }
933
934     static int aroundNumber = 1;
935     private String JavaDoc 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         //retStmts = wrapCatchThrowable(retStmts, new HashSet(jp.getPossibleCheckedExceptions()));
971

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 JavaDoc kind) {
992         // think about numbers more carefully
993
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        //super.checkPlan(jp);
1084
}
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    //INTRO from ScopePass
1097
public void preScope(ScopeWalker walker) {
1098        if (!walker.walkBodies()) {
1099            // remap CallExprs("proceed") -> ProceedExprs
1100
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                        //XXX should check that tryStmt.getBody() contains a proceed
1125
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            //System.out.println(arg + ", " + formal);
1169
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    //BEGIN: Generated from @child and @property
1182
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 JavaDoc 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 JavaDoc getDefaultDisplayName() {
1291        return "AroundAdviceDec()";
1292    }
1293
1294    //END: Generated from @child and @property
1295

1296}
1297
Popular Tags