KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > aspectj > compiler > base > LocalClassPass


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.base;
26
27 import org.aspectj.compiler.base.ast.*;
28 import java.util.*;
29
30 public class LocalClassPass extends AbstractCompilerPass {
31
32     public LocalClassPass(JavaCompiler compiler) {
33         super(compiler);
34     }
35
36     public String JavaDoc getDisplayName() {
37         return "lifting local classes ";
38     }
39
40     public void transform(TypeDec typeDec) {
41         //System.out.println("lifting: " + typeDec.unparse());
42

43         // pass one: analyze, set static, change names
44
AnalysisWalker analysisWalker = new AnalysisWalker(getCompiler());
45         analysisWalker.process(typeDec);
46
47         //System.err.println("needsVars: " + analysisWalker.needsVarTable);
48
//System.err.println("needsFields: " + analysisWalker.needsFieldTable);
49

50         // pass two: anonymous constructors, lift, initializersToConstructors
51
new LiftWalker(getCompiler()).process(typeDec);
52
53         // pass three: thread locals through constructors to where they want to go
54
new ThreadingWalker(getCompiler(), analysisWalker).process(typeDec);
55         
56         //System.err.println("lifted: " + typeDec.unparse());
57
}
58
59     // intro on TypeDec, VarDec, NewInstanceExpr, ConstructorCallExpr,
60
// ConstructorDec, MethodDec, ConstructorBody
61
public static class ThreadingWalker extends Walker {
62         HashMap/*<TypeDec, Set<VarDec>>*/ needsVarTable;
63         HashMap/*<TypeDec, Set<VarDec>>*/ needsFieldTable;
64
65         ThreadingWalker(JavaCompiler compiler, AnalysisWalker analysisWalker) {
66             super(compiler);
67             this.needsVarTable = analysisWalker.needsVarTable;
68             this.needsFieldTable = analysisWalker.needsFieldTable;
69         }
70         public ASTObject process(ASTObject object) {
71             object.preThreading(this);
72             object.walk(this);
73             return object.postThreading(this);
74         }
75
76         Stack/*<TypeDec>*/ typeContext = new Stack();
77         Stack/*<HashMap<VarDec, FieldDec>>*/ fieldContext = new Stack();
78         Stack/*<HashMap<VarDec, FieldDec + FormalDec>>*/ env = new Stack();
79
80         {
81             fieldContext.push(new HashMap());
82         }
83
84         public void pushConstructorEnv(Formals formals) {
85             final AST ast = getAST();
86             Map envMap = new HashMap();
87             Set s = (Set) needsVarTable.get(typeContext.peek());
88             if (s != null) {
89                 for (Iterator i = s.iterator(); i.hasNext(); ) {
90                     VarDec varDec = (VarDec)i.next();
91                     FormalDec formalDec =
92                         ast.makeFormal(varDec.getTypeD().getType(),
93                                        "val$" + varDec.getId());
94                     formals.add(0, formalDec);
95                     envMap.put(varDec, formalDec);
96                 }
97             }
98             env.push(envMap);
99         }
100         public void pushNonConstructorEnv() {
101             env.push(fieldContext.peek());
102         }
103         public void popEnv() {
104             env.pop();
105         }
106
107         public void pushTypeDec(TypeDec typeDec) {
108             respectOurParentsWishes(typeDec);
109             typeContext.push(typeDec);
110             addFields(typeDec);
111         }
112         public void popTypeDec() {
113             typeContext.pop();
114             fieldContext.pop();
115         }
116
117         private void addFields(TypeDec typeDec) {
118             final AST ast = getAST();
119             Map envMap = new HashMap();
120             Set s = (Set) needsFieldTable.get(typeContext.peek());
121             if (s != null) {
122                 for (Iterator i = s.iterator(); i.hasNext(); ) {
123                     VarDec varDec = (VarDec)i.next();
124                     FieldDec fieldDec =
125                         ast.makeField(ast.makeModifiers(Modifiers.FINAL),
126                                       varDec.getTypeD().getType(),
127                                       "val$" + varDec.getId());
128                     typeDec.getBody().add(fieldDec);
129                     envMap.put(varDec, fieldDec);
130                 }
131             }
132             fieldContext.push(envMap);
133         }
134         private void respectOurParentsWishes(TypeDec typeDec) {
135             Set weNeed = (Set) needsVarTable.get(typeDec);
136             Set parentNeeds = (Set) needsVarTable.get(typeDec.getSuperClassType().getTypeDec());
137             Set enclosingHas;
138             if (typeDec.isInner()) {
139                 enclosingHas = (Set) needsVarTable.get(typeDec.getEnclosingInstanceTypeDec());
140             } else {
141                 enclosingHas = null;
142             }
143
144             //System.err.println("needs of " + typeDec);
145
//System.err.println("we " + weNeed);
146
//System.err.println("rent " + parentNeeds);
147
//System.err.println("have " + enclosingHas);
148

149
150
151             if (weNeed == null) {
152                 if (parentNeeds != null) {
153                     weNeed = new HashSet(parentNeeds);
154                     if (enclosingHas != null) {
155                         weNeed.removeAll(enclosingHas);
156                     }
157                     needsVarTable.put(typeDec, weNeed);
158                 }
159             } else {
160                 if (parentNeeds != null) {
161                     weNeed.addAll(parentNeeds);
162                 }
163                 if (enclosingHas != null) {
164                     weNeed.removeAll(enclosingHas);
165                 }
166             }
167             //System.err.println("so we need " + needsVarTable.get(typeDec));
168

169         }
170
171         public Object JavaDoc /*FieldDec + FormalDec*/ lookup(VarDec varDec) {
172             for (int i = env.size() - 1; i >= 0; i--) {
173                 HashMap map = (HashMap) env.get(i);
174                 Object JavaDoc o = map.get(varDec);
175                 if (o != null) return o;
176             }
177             return null;
178         }
179
180         public void addArgs(Exprs args, TypeDec typeDec) {
181             final AST ast = getAST();
182             Set s = (Set) needsVarTable.get(typeDec);
183             if (s == null) return;
184             for (Iterator i = s.iterator(); i.hasNext(); ) {
185                 args.add(0, ast.makeVar((VarDec)i.next()));
186             }
187         }
188
189         public void addFieldSets(Stmts stmts) {
190             final AST ast = getAST();
191             for (Iterator i = ((Map)fieldContext.peek()).entrySet().iterator();
192                  i.hasNext(); ) {
193                 Map.Entry entry = (Map.Entry) i.next();
194                 VarDec varDec = (VarDec) entry.getKey();
195                 FieldDec fieldDec = (FieldDec) entry.getValue();
196                 stmts.add(0, ast.makeStmt(ast.makeSet(ast.makeDynamicGet(fieldDec),
197                                                       ast.makeVar(varDec))));
198             }
199         }
200     }
201
202     // intro to NewInstanceExpr, TypeDec
203
public static class LiftWalker extends Walker {
204         LiftWalker(JavaCompiler compiler) {
205             super(compiler);
206         }
207         public ASTObject process(ASTObject object) {
208             object.preLift(this); // NewInstanceExpr
209
object.walk(this);
210             return object.postLift(this); // TypeDec
211
}
212         private Stack/*<Decs>*/ decsStack = new Stack();
213
214         private Decs decs = getAST().makeDecs();
215
216         public void pushPendingDecs() {
217             decsStack.push(getAST().makeDecs());
218         }
219         public void addToPendingDecs(TypeDec dec) {
220             ((Decs) decsStack.peek()).add(dec);
221         }
222         public void popPendingDecsInto(TypeDec dec) {
223             dec.getBody().addAll((Decs) decsStack.pop()); // XXX may need to be reversed
224
}
225     }
226
227     // intro to VarExpr, TypeDec, CodeDec
228
public static class AnalysisWalker extends Walker {
229         AnalysisWalker(JavaCompiler compiler) {
230             super(compiler);
231         }
232         public ASTObject process(ASTObject object) {
233             final int saved = this.context;
234             object.walkAnalysis(this);
235             this.context = saved;
236             return object;
237         }
238         private static final int NOWHERE = 0;
239         private static final int DYNAMIC = 1; // dynamic method
240
private static final int SEMI_STATIC = 2; // constructor/dynamic init
241
private static final int NIGH_STATIC = 3; // constructorCall
242
private static final int STATIC = 4; // static method/init
243

244         /** context can be any of the 5 constants above */
245         private int context = NOWHERE;
246         public void inType() { context = NOWHERE; }
247         public void inConstructor() { context = SEMI_STATIC; }
248         public void inConstructorCall() { context = NIGH_STATIC; }
249         public void inCode(boolean isStatic) {
250             context = isStatic ? STATIC : DYNAMIC;
251         }
252
253         HashMap/*<TypeDec, Set<VarDec>>*/ needsVarTable = new HashMap();
254         HashMap/*<TypeDec, Set<VarDec>>*/ needsFieldTable = new HashMap();
255
256         /** XXX should be a stack of triples */
257         private Stack/* <CodeDec, Integer, TypeDec>, ... */ contextStack = new Stack();
258         public void enterTypeDec(TypeDec typeDec) {
259             if (context == NIGH_STATIC || context == STATIC) {
260                 typeDec.getModifiers().setStatic(true);
261             }
262             contextStack.push(new Integer JavaDoc(context));
263             contextStack.push(typeDec);
264         }
265         public void leaveTypeDec() {
266             contextStack.pop();
267             contextStack.pop();
268         }
269         public void enterCodeDec(CodeDec codeDec) {
270             contextStack.push(codeDec);
271         }
272         public void leaveCodeDec() {
273             contextStack.pop();
274         }
275
276         public void processVarExpr(VarExpr varExpr) {
277             VarDec varDec = varExpr.getVarDec();
278             CodeDec referenceContextDec = varDec.getEnclosingCodeDec();
279             int referenceContext = context;
280
281             // if the VarDec is truly local, then no more work is needed
282
if (contextStack.peek() == referenceContextDec) return;
283
284             if (!varDec.isFinal()) {
285                 varExpr.showError("local variable " + varDec.getId() +
286                   " is referenced from inside inner class; " +
287                   " needs to be declared final");
288                 return;
289             }
290             
291             for (int i = contextStack.size() - 2; i >= 0; i -= 3) {
292                 if (referenceContext == STATIC) {
293                     varExpr.showError("Not accessible from static context");
294                     break;
295                 }
296                 TypeDec typeDec = (TypeDec) contextStack.get(i);
297                 int typeDecContext = ((Integer JavaDoc) contextStack.get(i - 1)).intValue();
298                 CodeDec maybeDeclarationContextDec = (CodeDec) contextStack.get(i - 2);
299
300                 if (maybeDeclarationContextDec == referenceContextDec) {
301                     //System.err.println("HERE");
302
//System.err.println("adding " + varDec + " to " + typeDec);
303
//System.err.println("dynamic? " + (referenceContext == DYNAMIC));
304
// found it
305
addToTable(needsVarTable, typeDec, varDec);
306                     //if (referenceContext == DYNAMIC) {
307
addToTable(needsFieldTable, typeDec, varDec);
308                     //}
309
break;
310                 } else if (typeDecContext == NIGH_STATIC) {
311                     addToTable(needsVarTable, typeDec, varDec);
312                     if (referenceContext == DYNAMIC) {
313                         addToTable(needsFieldTable, typeDec, varDec);
314                     }
315                     referenceContext = NIGH_STATIC;
316                 } else {
317                     referenceContext = DYNAMIC;
318                 }
319             }
320         }
321
322         private static void addToTable(HashMap/*<Object, Set>*/ map,
323                                        Object JavaDoc key, Object JavaDoc elem) {
324             //System.err.println(key + " " + elem);
325
Object JavaDoc o = map.get(key);
326             if (o == null) {
327                 Set s = new HashSet();
328                 s.add(elem);
329                 map.put(key, s);
330             } else {
331                 ((Set) o).add(elem);
332             }
333         }
334
335         private int localCounter = 0;
336         //XXX JJH hacked these names for the sake of source generation
337
//XXX JJH needs to fix them to be nice to bcg again
338
public String JavaDoc makeNewId(TypeDec typeDec) {
339             return typeDec.isAnonymous() ?
340                 "_" + ++localCounter + "" :
341                 "_" + ++localCounter + "_" + typeDec.getId();
342         }
343     }
344 }
345
346 /*
347 First, a pass that annotates each inner typedec with the local
348 variables it needs. No replacements are done. Purely an analysis
349 pass, and only cares about varExprs.
350
351 On the way down the tree, build up an environment associating
352
353  * EnclosingCodeDec
354  * LocalTypeDec
355  * 'context'
356
357 where context can be
358
359  * DYNAMIC -- in non-static method: Will get closed over variables from
360                   fields of some enclosing type.
361
362  * SEMI_STATIC -- in constructor or non-static initializer. Will get
363                   some closed over variables from constructor args, if they are
364                   being passed in directly for some reason, and
365                   others from the fields of some enclosing type.
366
367  * NIGH_STATIC -- in a constructor call expr. Will get all closed-over
368                   variables from arguments to the constructor.
369
370  * STATIC -- in static method or initializer.
371
372 Then, for each varExpr v we find, in some context, wander down the
373 environment annotating each typeDec that needs to know about the varExpr.
374
375 A rule of thumb is that if the varExpr was found in dynamic context,
376 then some field will be built for it, either in the current class or
377 an enclosing class.
378
379 If the varExpr was found in static context, it's not allowed.
380
381 If the varExpr was found in semi or nigh static context, the
382 _enclosing_ class will not have a field added for the varExpr, but
383 some other enclosing class might.
384
385 End result is, for every typedec, both a set of 'needed' vars (NOT
386 INCLUDING those needed by the superclass), and a subset of those
387 'needed' vars that need fields.
388
389 ------------------------------
390
391 Second, a pass that lifts typeDecs and integrates initializers.
392
393 ------------------------------
394
395
396 Third, a pass that does everything else, including pushing needed
397 vars into subclasses, and making fields, and resetting varExprs, and
398 adding arguments to newInstance and ConstructorCall exprs.
399
400 typeDec T:
401
402   look at superclass. Get superclass's set of { v ... }. We are
403   guaranteed that superclass has already been processed.
404
405   for each { v : needs field }, create field.
406   Let {v ... } be union (our {v ... }, superclass' {v ...}):
407
408   for each constructor, process:
409      add {val$v ...} to constructor args
410      make environment: { v : val$v }
411      process body under said environment.
412      add set expr for each { v : needs field }
413
414   for each method, process:
415      make environment: { v : T.this.val$v }
416      process body
417
418 constructor call expr (both this and super), new instance expr:
419
420   let T be target type:
421   let { v ... } be T's needs
422   add v ... to args
423   process self... this will convert the v's, appropriately.
424
425 varExpr v:
426   replace with env.apply.
427
428 */

429
Popular Tags