KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > aspectj > compiler > crosscuts > joinpoints > JpPlan


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.joinpoints;
26
27 import org.aspectj.compiler.crosscuts.ast.*;
28 import org.aspectj.compiler.base.ast.*;
29 import org.aspectj.compiler.base.*;
30
31 import org.aspectj.compiler.crosscuts.AspectJCompiler;
32
33 import org.aspectj.util.PartialOrder;
34
35 import java.util.*;
36
37 /**
38  */

39
40 public class JpPlan extends CompilerObject implements PartialOrder.PartialComparable {
41     // no sorting by kind:
42
public static final int CFLOWENTRY_ROOT = 0;
43     public static final int EACHOBJECT = 0;
44     public static final int AROUND = 1;
45     public static final int AFTER = 1;
46     public static final int BEFORE = 1;
47     public static final int CFLOWENTRY_NOROOT = 2;
48     public static final int SOFT_THROWABLE = 0;
49     
50     public JoinPoint joinPoint;
51     
52     
53     /**
54      * Maps the formals of the advice (or other jp planner) to expressions at this join point
55      * that provide the appropriate values
56      */

57     public Map/*FormalDec, Expr*/ bindings = new HashMap();
58     public Expr test;
59     public Expr ifTest;
60     public Expr instance;
61     
62     public static final JpPlan NO_PLAN = new JpPlan(null) {
63         public boolean isPossible() { return false; }
64         public JpPlan or(JpPlan other) {
65             return other;
66         }
67         
68         public JpPlan and(JpPlan other) {
69             return NO_PLAN;
70         }
71         
72         public JpPlan not() {
73             return JpPlan.ANY_PLAN;
74         }
75         public String JavaDoc toString() { return "NO_PLAN"; }
76     };
77     
78     
79     public static final JpPlan NEVER_PLAN = new JpPlan(null) {
80         public boolean isPossible() { return false; }
81         public JpPlan or(JpPlan other) {
82             return this;
83         }
84         
85         public JpPlan and(JpPlan other) {
86             return this;
87         }
88         
89         public JpPlan not() {
90             return this;
91         }
92         public String JavaDoc toString() { return "NEVER_PLAN"; }
93     };
94     
95     public static final JpPlan ANY_PLAN = new JpPlan(null) {
96         public JpPlan or(JpPlan other) {
97             if (other == JpPlan.ANY_PLAN) return JpPlan.ANY_PLAN;
98             else return other.or(JpPlan.ANY_PLAN);
99         }
100         
101         public JpPlan and(JpPlan other) {
102             return other;
103         }
104         
105         public JpPlan not() {
106             return NO_PLAN;
107         }
108         
109         public String JavaDoc toString() { return "ANY_PLAN"; }
110     };
111
112     public JpPlan(JoinPoint jp) {
113         super(jp == null ? null : jp.getCompiler());
114         this.joinPoint = jp;
115     }
116     
117     public boolean isPossible() {
118         if (ifTest == null) {
119             return test == null || !isAlwaysFalse(test);
120         }
121         
122         if (test == null) {
123             return ifTest == null || !isAlwaysFalse(ifTest);
124         }
125         
126         return !(isAlwaysFalse(test) || isAlwaysFalse(ifTest));
127     }
128     
129     public JoinPoint getJoinPoint() { return joinPoint; }
130     public Expr getInstance() {
131         return instance;
132 // if (instance == null) return null;
133
// return getAST().makeCast(getAspectDec().getType(), instance);
134
}
135     
136     public void wrapJoinPoint(JoinPoint jp) {
137         System.err.println("shouldn't be making this JpPlan concrete!");
138     }
139
140     // this field is used solely to track dependencies between cflow entries
141
// there's got to be a cheaper way to do this
142
protected List dependencies = new LinkedList();
143     public boolean dependsOn(Object JavaDoc o) {
144         //System.out.println(this + " dependsOn? " + o + " :: " + dependencies);
145
return dependencies.contains(o);
146     }
147     
148     public void addDependency(Object JavaDoc o) {
149         dependencies.add(o);
150     }
151     
152     public int getPreSortOrder() { return 0; }
153
154     /**
155      * Sorting is based purely on the adviceDec. See AdviceDec.dominates for
156      * detailed rules.
157      */

158     public int compareTo(Object JavaDoc o) {
159         if (!(o instanceof JpPlan) || this == o) return 0;
160
161         JpPlan otherPlan = (JpPlan)o;
162         
163         if (getPreSortOrder() < otherPlan.getPreSortOrder()) return -1;
164         if (getPreSortOrder() > otherPlan.getPreSortOrder()) return +1;
165         
166         return 0;
167     }
168     
169     public int fallbackCompareTo(Object JavaDoc o) { return 0; }
170     
171     public boolean matches(JpPlan other) {
172         //XXX knows that this is only used for CalleeSideCallPoint
173
return this == other; //false;
174
// if (getAdviceDec() != null && getAdviceDec().needsCallSiteContext()) return false;
175
//
176
// if (getAdviceDec() != other.getAdviceDec()) return false;
177
//
178
// if (hasDynamicTest() || other.hasDynamicTest()) return false;
179
//
180
// return true;
181
}
182
183     public JpPlan or(JpPlan other) {
184         if (other == NEVER_PLAN) return other;
185         
186         if (!other.isPossible()) return this;
187         
188         JpPlan plan = new JpPlan(joinPoint);
189         
190         plan.test = orExprs(test, other.test);
191         plan.ifTest = orExprs(ifTest, other.ifTest);
192         plan.instance = mergeInstance(instance, other.instance);
193         plan.bindings = mergeBindings(bindings, other.bindings);
194         plan.dependencies.addAll(other.dependencies);
195
196         return plan;
197     }
198     
199     public JpPlan and(JpPlan other) {
200         if (other == NEVER_PLAN) return other;
201
202         if (!other.isPossible()) return NO_PLAN;
203         
204         JpPlan plan = new JpPlan(joinPoint);
205         
206         plan.test = andExprs(test, other.test);
207         plan.ifTest = andExprs(ifTest, other.ifTest);
208         plan.instance = mergeInstance(instance, other.instance);
209         plan.bindings = mergeBindings(bindings, other.bindings);
210         plan.dependencies.addAll(other.dependencies);
211
212         return plan;
213     }
214
215     public JpPlan not() {
216         if (!isPossible()) return JpPlan.ANY_PLAN;
217         
218         //if (!hasDynamicTest()) return JpPlan.NO_PLAN;
219
if (test == null && ifTest == null) return JpPlan.NO_PLAN;
220
221         JpPlan newPlan = new JpPlan(joinPoint);
222         newPlan.test = notExpr(this.test);
223         newPlan.ifTest = notExpr(this.ifTest);
224         newPlan.dependencies = dependencies;
225         return newPlan;
226     }
227     
228     public void setInstanceExpr(Expr i) {
229         instance = i;
230     }
231     
232     public void addExprTest(Expr t1) {
233         test = andExprs(test, t1);
234     }
235     
236     public void addIfTest(Expr t1) {
237         ifTest = andExprs(ifTest, t1);
238     }
239     
240     Expr andExprs(Expr e1, Expr e2) {
241         if (e1 == null) return e2;
242         if (e2 == null) return e1;
243         return getAST().makeBinop("&&", e1, e2);
244     }
245     
246     Expr orExprs(Expr e1, Expr e2) {
247         if (e1 == null) return e2;
248         if (e2 == null) return e1;
249         return getAST().makeBinop("||", e1, e2);
250     }
251     
252     Expr notExpr(Expr e) {
253         //System.out.println(this + "!" + e);
254

255         if (e == null) return null;
256         return getAST().makeUnop("!", e);
257     }
258     
259     //XXX this will produce too many errors
260
void checkEquivalent(FormalDec fd, Expr e1, Expr e2) {
261         if (!e1.equals(e2)) {
262             joinPoint.showError(fd, "incompatible bindings for this formal: both " +
263                                     e1.unparse() + " and " + e2.unparse());
264         }
265     }
266     
267     Map mergeBindings(Map b1, Map b2) {
268         Map ret = new HashMap(b1);
269         for (Iterator i = b2.entrySet().iterator(); i.hasNext(); ) {
270             Map.Entry entry = (Map.Entry)i.next();
271             Object JavaDoc key = entry.getKey();
272             if (ret.containsKey(key)) {
273                checkEquivalent((FormalDec)key, (Expr)ret.get(key), (Expr)entry.getValue());
274             } else {
275                 ret.put(key, entry.getValue());
276             }
277         }
278         return ret;
279     }
280     
281     Expr mergeInstance(Expr i1, Expr i2) {
282         //XXX should detect error when both are non-null
283
if (i1 == null) return i2;
284         else return i1;
285     }
286     
287     //???
288
public void bindInstance(Expr expr) {
289         instance = expr;
290     }
291     
292     public void bindExpr(FormalDec formalDec, Expr expr) {
293         //System.out.println("binding: " + formalDec + " to " + expr);
294
if (bindings.containsKey(formalDec)) {
295             checkEquivalent(formalDec, expr, (Expr)bindings.get(formalDec));
296         } else {
297             bindings.put(formalDec, expr);
298         }
299     }
300
301
302     /* returns trueStmt if no dynamic test is needed, otherwise returns a block containing
303      * a one-armed-if with the dynamic test.
304      */

305     public Stmt wrapDynamicTest(Stmt trueStmt) {
306         Expr dynamicTest = getDynamicTest();
307         if (dynamicTest != null) {
308             final AST ast = getAST();
309             return ast.makeBlock(ast.makeIf(dynamicTest, trueStmt));
310         } else {
311             return trueStmt;
312         }
313     }
314
315     private Expr makeDynamicTest(Expr expr, boolean keepTypes) {
316         if (expr == null) return null;
317         if (expr != null) {
318             expr = (Expr)new ExprMover(getCompiler(), keepTypes).process(expr);
319             expr = simplify(expr);
320             if (isAlwaysTrue(expr)) expr = null;
321         }
322         return expr;
323     }
324
325     
326     private Expr getBasicDynamicTest() {
327         return makeDynamicTest(test, false);
328     }
329
330     
331     private Expr getIfDynamicTest() {
332         return makeDynamicTest(ifTest, true);
333     }
334     
335     
336     public Expr getDynamicTest() {
337         return andExprs(getBasicDynamicTest(), getIfDynamicTest());
338     }
339     
340     boolean isAlwaysFalse(Expr expr) {
341         return expr instanceof BooleanLiteralExpr &&
342                 !((BooleanLiteralExpr)expr).getBooleanValue();
343     }
344     boolean isAlwaysTrue(Expr expr) {
345         return expr instanceof BooleanLiteralExpr &&
346                 ((BooleanLiteralExpr)expr).getBooleanValue();
347     }
348     
349     Expr simplify(Expr expr) {
350         if (expr == null) return null;
351         return (Expr)new BooleanExprSimplifier(getCompiler()).process(expr);
352     }
353     
354     private class BooleanExprSimplifier extends Walker {
355         public BooleanExprSimplifier(JavaCompiler compiler) { super(compiler); }
356         
357         public ASTObject process(ASTObject node) {
358             node.walk(this);
359             
360             if (node instanceof InstanceofExpr) {
361                 return ((InstanceofExpr)node).simplify();
362             } else if (node instanceof AndAndOpExpr) {
363                 AndAndOpExpr e = (AndAndOpExpr)node;
364                 if (isAlwaysFalse(e.getRand1()) || isAlwaysFalse(e.getRand2())) {
365                     return node.getAST().makeLiteral(false);
366                 }
367                 if (isAlwaysTrue(e.getRand1())) return e.getRand2();
368                 if (isAlwaysTrue(e.getRand2())) return e.getRand1();
369                 return node;
370             } else if (node instanceof OrOrOpExpr) {
371                 OrOrOpExpr e = (OrOrOpExpr)node;
372                 if (isAlwaysTrue(e.getRand1()) || isAlwaysTrue(e.getRand2())) {
373                     return node.getAST().makeLiteral(true);
374                 }
375                 if (isAlwaysFalse(e.getRand1())) return e.getRand2();
376                 if (isAlwaysFalse(e.getRand2())) return e.getRand1();
377                 return node;
378             } else if (node instanceof ParenExpr) {
379                 ParenExpr e = (ParenExpr)node;
380                 if (isAlwaysFalse(e.getExpr())) return e.getExpr();
381                 if (isAlwaysTrue(e.getExpr())) return e.getExpr();
382                 return node;
383             } else if (node instanceof LogNotOpExpr) {
384                 LogNotOpExpr e = (LogNotOpExpr)node;
385                 if (isAlwaysTrue(e.getRand1())) return node.getAST().makeLiteral(false);
386                 if (isAlwaysFalse(e.getRand1())) return node.getAST().makeLiteral(true);
387                 return node;
388             } else {
389                 return node;
390             }
391         }
392     }
393     
394     /**
395      * Moves bindings of expressions to formals to a different set of formals
396      */

397     public void moveBindings(final Map remap) {
398         // before we move our bindings map, use the current one on our test exprs
399
test = getBasicDynamicTest();
400         ifTest = getIfDynamicTest();
401         
402         for (Iterator i = remap.entrySet().iterator(); i.hasNext(); ) {
403             Map.Entry entry = (Map.Entry)i.next();
404             Object JavaDoc key = entry.getKey();
405             if (bindings.containsKey(key)) {
406                 bindings.put(entry.getValue(), bindings.get(key));
407                 //??? remove old entry
408
} else {
409                 //??? error
410
}
411         }
412     }
413
414     
415     private class ExprMover extends Walker {
416         private boolean keepTypes;
417         public ExprMover(JavaCompiler compiler, boolean keepTypes) {
418             super(compiler);
419             this.keepTypes = keepTypes;
420         }
421         
422         public ASTObject process(ASTObject object) {
423             object.walk(this);
424             if (object instanceof VarExpr) {
425                 VarExpr var = (VarExpr)object;
426                 if (var.getId().equals("thisJoinPoint")) {
427                     return joinPoint.makeDynamicJoinPointVarExpr();
428                 } else if (var.getId().equals("thisJoinPointStaticPart")) {
429                     return joinPoint.makeStaticJoinPointVarExpr();
430                 } else if (var.getId().equals("aspect$instance")) {
431                     //XXX handle keepTypes
432
if (instance != null) return instance.copy();
433                 }
434                 
435                 VarDec varDec = var.getVarDec();
436                 Expr expr = (Expr)bindings.get(varDec);
437                 if (expr != null) {
438                     expr = (Expr)expr.copy();
439                     if (keepTypes) {
440                         return getAST().forceCast(varDec.getType(), expr);
441                     } else {
442                         return expr;
443                     }
444                 } else {
445                     return var;
446                 }
447             }
448             return object;
449         }
450     }
451
452     void showFormalNotBound(FormalDec formalDec) {
453         formalDec.showError("formal not bound on " + joinPoint);
454     }
455
456     public Exprs getCallExprs(Formals formals) {
457         final AST ast = getAST();
458         
459         //System.out.println("formals: " + formals.toShortString() + ", " + bindings);
460

461         Exprs exprs = ast.makeExprs();
462         for (int i=0; i<formals.size(); i++) {
463             Expr expr = (Expr)bindings.get(formals.get(i));
464             if (expr == null) {
465                 showFormalNotBound(formals.get(i));
466                 break;
467             }
468             exprs.add(makeLegalExpr(expr, formals.get(i).getType()));
469             //??? is this cast actually ever needed
470
}
471         return exprs;
472     }
473     
474     Expr makeLegalExpr(Expr expr, Type type) {
475         Type exprType = expr.getType();
476         if (type.isObject()) {
477             return exprType.makeObject(expr);
478         } else {
479             return getAST().makeCast(type, expr);
480         }
481     }
482
483     public String JavaDoc toString() {
484         if (joinPoint != null) return "plan(" + joinPoint.toString() + ")";
485         else return super.toString();
486     }
487 }
488
Popular Tags