KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > aspectj > compiler > base > ast > CallExpr


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.ast;
26
27 import org.aspectj.compiler.base.*;
28 import org.aspectj.compiler.crosscuts.AccessFixer;
29 import org.aspectj.compiler.crosscuts.joinpoints.CalleeSideCallJp;
30
31 import org.aspectj.compiler.base.cst.BlockScope;
32
33 import org.aspectj.compiler.base.bcg.CodeBuilder;
34 import org.aspectj.compiler.base.bcg.Label;
35
36 import java.util.*;
37
38
39 /**
40   * @grammar expr.id(args)
41   * @child Expr expr
42   * @property String id
43   * @child Exprs args
44   * @property Method method
45   * @property boolean isSuper
46   */

47 public class CallExpr extends AnyCallExpr implements SOLink {
48
49     // ------------------------------
50
// INTRO from FlowCheckerPass
51

52     public void walkFlow(FlowCheckerPass w) {
53         if (getExpr() != null) {
54             w.process(getExpr());
55         }
56         w.process(getArgs());
57         if (getMethod().getThrows() != null) {
58             TypeDs ts = getMethod().getThrows();
59             for (int i = 0, len = ts.size(); i < len; i++) {
60                 w.setExns(w.getExns().add((NameType) ts.get(i).getType()));
61             }
62         }
63     }
64
65     //INTRO from MovingWalker
66
public ASTObject postMove(MovingWalker walker) {
67         return walker.moveLinkExpr(this);
68     }
69
70     //INTRO from ScopeWalker
71
public ASTObject postScope(ScopeWalker walker) {
72         if (method != null)
73             return this;
74
75         Type lookupType;
76         if (expr != null) {
77             lookupType = expr.getType();
78         } else {
79             lookupType = walker.getScope().findMethodLookupType(id, this);
80             if (lookupType == null) {
81                 this.showError("can't find any method with name: " + id);
82                 return this;
83             }
84         }
85
86         method = lookupType.getMethod(id, this, args, true);
87         //!!! do the fill a la typeScope
88
if (method == null) {
89             setType(getTypeManager().TYPE_NOT_FOUND);
90             return this;
91         }
92
93         if (expr != null && expr instanceof SuperExpr) {
94             if (method.isStatic()) {
95             } else {
96                 setIsSuper(true);
97             }
98         }
99           
100         if (getExpr() == null) {
101             setExpr(
102                 (method.isStatic())
103                     ? getAST().makeTypeExpr(lookupType)
104                     : (Expr) getAST().makeQualifiedThis(lookupType));
105         }
106
107         //super.bindNamesSelf(scope);
108
return super.postScope(walker);
109     }
110
111     // ------------------------------
112
// INTRO from InnerInfoPass -- should have a more generic name
113

114     public void postInnerInfo(InnerInfoPass w) {
115         if (expr == null && method != null) {
116             w.checkStaticAccess(this, method);
117             setExpr(getAST().makePrimary(getMethod(), w.currentType()));
118         }
119     }
120
121     /**
122      * Section 6.6.2.1 from JLSv2
123      * E.Id requires that E is subtype of S
124      */

125     public boolean hasLegalProtectedAccess(Type fromType) {
126         if (expr == null || getIsSuper() || expr instanceof SuperExpr)
127             return true;
128         return expr.getType().isSubtypeOf(fromType);
129     }
130
131     public void checkSpec() {
132         if (method == null)
133             return;
134         if (expr instanceof TypeExpr && !method.isStatic()) {
135             showError(
136                 "non-static method "
137                     + method.toShortString()
138                     + " cannot be accessed through a static reference");
139         }
140         if (getIsSuper()) {
141             if (method.isAbstract()) {
142                 showError(
143                     "abstract method " + method.toShortString() + " cannot be target of super");
144             }
145         }
146     }
147
148     public boolean isLegalStmt() {
149         return true;
150     }
151
152     public ASTObject postFixAST(final ASTFixerPass fixer) {
153         if (getIsSuper()) {
154             MethodDec superMethodDec = getMethodDec();
155             CalleeSideCallJp targetPoint =
156                 (CalleeSideCallJp) getWorld().calleeSideCallPoints.get(superMethodDec);
157             if (targetPoint == null || !targetPoint.hasPlans()) {
158                 return this;
159             }
160
161             setMethod(targetPoint.getPostMethodDec().getMethod());
162         }
163         // handle introduced statics on interfaces
164
setExpr(method.updateTargetExpr(getExpr()));
165         return this;
166     }
167
168     //INTRO from AccessFixer
169
public ASTObject fixAccessPost(AccessFixer fixer) {
170         if (getMethod() == null)
171             return this; //XXX should be error
172
//TypeDec fromTypeDec = getBytecodeTypeDec(); //fixer.fromTypeDec;
173
if (getMethod().isAccessible(this, true))
174             return this;
175
176         getCompiler().showMessage(
177             " fixing privileged call: " + getMethod().toShortString());
178         //this.getParent().getParent().display(2);
179

180         Method newMethod = getMethod().getBackdoorMethod();
181         if (!fixer.apply)
182             return this;
183
184         CallExpr newCallExpr = getAST().makeCall(newMethod, getExpr(), getArgs());
185         newCallExpr.setSource(this);
186         return newCallExpr;
187     }
188
189     public MethodDec getMethodDec() {
190         return (MethodDec) method.getCorrespondingDec();
191     }
192     public void setMethodDec(MethodDec md) {
193         setMethod((Method) md.getCorrespondingSemanticObject());
194     }
195     public CodeDec getCodeDec() {
196         return getMethodDec();
197     }
198     public SemanticObject getTarget() {
199         return getMethod();
200     }
201     public void setTarget(SemanticObject newTarget) {
202         setMethod((Method) newTarget);
203     }
204
205     public Type getReturnType() {
206         return getMethod().getReturnType();
207     }
208
209     public Type getCalledType() {
210         if (expr == null) {
211             return getDeclaringType();
212         } else {
213             return expr.getType();
214         }
215     }
216
217     public CallExpr(SourceLocation source, Expr expr, String JavaDoc id) {
218         this(source, expr, id, new Exprs(source));
219     }
220
221     public Type discoverType() {
222         if (getMethod() == null)
223             return getTypeManager().anyType;
224         else
225             return getMethod().getReturnType();
226     }
227
228     static Expr makeParentExpr(Method md, Expr instance) {
229         if (instance != null)
230             return instance;
231         if (md.isStatic()) {
232             return md.getAST().makeTypeExpr(md.getDeclaringType());
233         } else {
234             return null; //return new ThisExpr(md.getDeclaringTypeDec().getNameTypeD());
235
}
236     }
237
238     public Expr getExprOrThis() {
239         if (method.isStatic())
240             return null;
241         //new TypeExpr(getCompiler(), getMethodDec().getDeclaringType().makeTypeD());
242
if (expr != null)
243             return expr;
244         return new ThisExpr(getSourceLocation(), method.getDeclaringType());
245     }
246     
247     private boolean isInlinableTarget(Expr e, Type bytecodeType) {
248         if (e == null) return true;
249         if (e instanceof TypeExpr) return true;
250         if (e instanceof ThisExpr) {
251             ThisExpr thisExpr = (ThisExpr)e;
252             if (thisExpr.getType() == bytecodeType) return true;
253         }
254         return false;
255     }
256     
257     public boolean tryToInline(Type bytecodeType) {
258         //System.out.println(this.unparse() + ", " + this.getParent());
259
//if (getArgs() != null && getArgs().size() != 0) return false;
260
if (!isInlinableTarget(getExpr(), bytecodeType)) return false;
261         
262         
263         
264         MethodDec md = getMethodDec();
265     if (md.containsTypes()) return false;
266
267         final AST ast = getAST();
268            
269         try {
270             if (getParent() instanceof ReturnStmt) {
271                 //System.err.println("GOT HERE " + getParent().unparse());
272
RemapWalker rw = new RemapWalker(getCompiler(), args, md, null, null);
273                 
274                 getParent().replaceWith(rw.remap());
275             } else if (getParent() instanceof ExprStmt) {
276                 //System.err.println("GOT HERE1 " + getParent().unparse());
277
String JavaDoc label = getWorld().genLabel();
278                 RemapWalker rw = new RemapWalker(getCompiler(), args, md, label, null);
279                 getParent().replaceWith(rw.remap());
280             } else if (isEffectiveCast(getParent())) {
281                 ReturnStmt s = getEnclosingReturnStmt(this);
282                 RemapWalker rw = new RemapWalker(getCompiler(), args, md, null, s.getExpr().getType());
283                 s.replaceWith(rw.remap());
284             } else {
285                 return false;
286             }
287         } catch (InvalidOptimizationException e) {
288             return false;
289         }
290         
291         md.getDeclaringType().getTypeDec().getBody().remove(md);
292         return true;
293     }
294     
295     private ReturnStmt getEnclosingReturnStmt(ASTObject o) {
296         if (o instanceof ReturnStmt) return (ReturnStmt) o;
297         else return getEnclosingReturnStmt(o.getParent());
298     }
299     
300     
301     /** is o a possible cast inside a return statement */
302     private boolean isEffectiveCast(ASTObject o) {
303     if (o instanceof ParenExpr) return isEffectiveCast(o.getParent());
304     if (o instanceof CastExpr) return isEffectiveCast1(o.getParent());
305         else return false;
306     }
307     
308     /** seen a cast */
309     private boolean isEffectiveCast1(ASTObject o) {
310         if (o instanceof ParenExpr) return isEffectiveCast1(o.getParent());
311         if (o instanceof ReturnStmt) return true;
312         else return false;
313     }
314     
315     static class InvalidOptimizationException extends RuntimeException JavaDoc {}
316     
317     class RemapWalker extends MovingWalker {
318         private Exprs args;
319         private MethodDec calledMethodDec;
320         private String JavaDoc breakLabel;
321         
322         private Type desiredReturnType;
323         
324         // This is a list of Exprs that either are references or
325
// are ReferenceExprs that we will have squirrled away the appropriate
326
// VarDec for
327
private List/*Exprs*/ argRefs;
328         private VarDec returnVarDec;
329         
330         public RemapWalker(JavaCompiler compiler, Exprs args, MethodDec calledMethodDec,
331                     String JavaDoc breakLabel,
332                     Type desiredReturnType) {
333             super(compiler);
334             this.args = args;
335             this.calledMethodDec = calledMethodDec;
336             this.breakLabel = breakLabel;
337             this.desiredReturnType = desiredReturnType;
338         }
339         
340         
341         public Stmt remap() {
342             final AST ast = this.getAST();
343             
344 // if (!methodDec.getResultType().isVoid()) {
345
// returnVarDec =
346
// ast.makeVarDec(methodDec.getResultType(), "returnValue", null, true);
347
// }
348

349             Stmts stmts = this.remapStmts();
350             //if (returnVarDec != null) stmts.add(0, returnVarDec);
351
Stmt ret = ast.makeBlock(stmts);
352             //System.out.println(ret);
353
//System.out.println(ret.unparse());
354
if (breakLabel != null) ret = ast.makeLabeled(breakLabel, ret);
355             return ret;
356         }
357         
358         public Stmts remapStmts() {
359             final AST ast = this.getAST();
360             Stmts block = ast.makeStmts();
361             //System.out.println(block + ": " + System.identityHashCode(block));
362
this.argRefs = new ArrayList();
363             
364             Set effectivelyFinalFormals = calledMethodDec.getEffectivelyFinalFormals();
365             
366             for (int i=0; i<args.size(); i++) {
367                 FormalDec formal = calledMethodDec.getFormals().get(i);
368                 Type type = formal.getType();
369                 
370                 Expr arg = (Expr)args.get(i).copy();
371                 
372                 if (effectivelyFinalFormals.contains(formal) && args.get(i).canBeCopied()) {
373                     argRefs.add(ast.makeCast(type, arg));
374                 } else {
375                     VarDec dec = ast.makeVarDec(type, formal.getId(), arg);
376                     block.add(dec);
377                     argRefs.add(ast.makeVar(dec));
378                 }
379             }
380             
381             Stmts body = (Stmts)calledMethodDec.getBody().getStmts().copy();
382             //body.checkNoSharing(methodDec);
383
//System.out.println(body + ": " + System.identityHashCode(body));
384
//System.out.println(methodDec.getBody().getStmts() + ": " + System.identityHashCode(methodDec.getBody().getStmts()));
385

386             //try {
387
body = (Stmts)process(body);
388 // } finally {
389
// body.checkNoSharing(methodDec);
390
// block.checkNoSharing(methodDec);
391
// }
392
block.addAll(body); //methodDec.getBody().getStmts());
393
return block;
394         }
395         
396         protected Expr handleFreeVar(VarExpr var) {
397             VarDec varDec = var.getVarDec();
398             if (!(varDec instanceof FormalDec)) {
399                 return super.handleFreeVar(var);
400             }
401             
402             FormalDec formalDec = (FormalDec)varDec;
403             int index = calledMethodDec.getFormals().indexOf(formalDec);
404             if (index == -1) return super.handleFreeVar(var);
405             
406             
407             //note: makeReference copies for non-ReferenceExprs
408
// and makes the apprpriate VarExpr for ReferenceExprs
409
return (Expr)((Expr)argRefs.get(index)).copy();
410         }
411
412         private ASTObject handleReturn(ReturnStmt object) {
413             final AST ast = this.getAST();
414             // are we in a return context, not an exprStmt context ?
415
if (breakLabel == null) {
416                 // do we care about the return type? If yes, there's
417
// a cast involved (we came from a
418
// return (TYPE) [here]; context.
419
if (desiredReturnType != null) {
420             // is the cast to our desired type is guaranteed to succeed?
421
if (desiredReturnType.isAssignableFrom(object.getExpr().getType())) {
422                 object.setExpr(ast.makeCast(desiredReturnType, object.getExpr()));
423             } else {
424                 // otherwise, we came from...
425
throw new InvalidOptimizationException();
426             }
427         }
428         return object;
429             }
430         
431             Stmt stmt = ast.makeBreak(breakLabel);
432             
433             Expr expr = object.getExpr();
434             if (expr == null) return stmt;
435             if (expr.canBeCopied()) return stmt;
436             if (expr.isLegalStmt()) return ast.makeBlock(ast.makeStmt(expr), stmt);
437             
438             return ast.makeVarDec(calledMethodDec.getResultType(), "retValue", expr, true);
439         }
440 //
441
//
442
// if (returnVarDec != null) {
443
// stmt = ast.makeBlock(
444
// ast.makeSet(returnVarDec, object.getExpr()),
445
// stmt);
446
// }
447
//
448
// return stmt;
449
// }
450
//
451

452         public Expr moveThisExpr(ThisExpr thisExpr, Type thisType) {
453             return thisExpr;
454         }
455         
456         public ASTObject process(ASTObject object) {
457             //System.out.println(object);
458
if (object instanceof TypeDec || object instanceof CodeDec) {
459                 return object;
460             }
461             
462             object = super.process(object);
463             if (object instanceof ReturnStmt) {
464                 return handleReturn((ReturnStmt)object);
465             } else {
466                 return object;
467             }
468         }
469     
470
471     }
472     
473     public void unparse(CodeWriter writer) {
474         if (expr != null) {
475             writer.write(expr);
476             writer.write('.');
477         }
478
479         if (method != null)
480             id = method.getBytecodeId();
481         writer.write(id);
482         writer.openParen('(');
483         writer.write(args);
484         writer.closeParen(')');
485     }
486
487     public CallExpr(
488         SourceLocation source,
489         Method toMethod,
490         Expr instance,
491         Exprs args) {
492         this(
493             source,
494             makeParentExpr(toMethod, instance),
495             toMethod.getId(),
496             args,
497             toMethod,
498             false);
499     }
500
501     public CallExpr(SourceLocation source, String JavaDoc _id, Exprs _args) {
502         this(source, new ThisExpr(source), _id, _args);
503     }
504
505     public CallExpr(SourceLocation source, Expr expr, String JavaDoc _id, Exprs _args) {
506         this(source, expr, _id, _args, null, false);
507     }
508
509     private boolean needsAccessMethod(InnerAccessFixer w) {
510         Expr q = getExpr();
511         MethodDec oldMethodDec = getMethodDec();
512
513         // there are no QualifiedThisExprs by this point
514
//XXX reformat later
515
// we believe that CallExpr should have a property that encodes whether or
516
// not it is a special super access call generated below
517
if (!w.isAccessible(oldMethodDec, q)) {
518             return true;
519         } else {
520             if (getIsSuper()) {
521                 //System.err.println(unparse());
522
if (getExpr() instanceof ThisExpr || getExpr() instanceof SuperExpr) {
523                     return false;
524                 } else {
525                     return true;
526                 }
527 // if (getIsSuperAccessMethodCall()) {
528
// return false;
529
// } else {
530
// return true;
531
// }
532
} else {
533                 return false;
534             }
535         }
536     }
537
538     // ------------------------------
539
//INTRO from InnerAccessFixer
540

541     public ASTObject postInnerAccess(InnerAccessFixer w) {
542         // if (getIsSuper()) {
543
// System.err.println("CEbefore: ");
544
// this.display(0);
545
// }
546

547         if (!needsAccessMethod(w))
548             return this;
549         // System.err.println("CE: " + this);
550

551         Expr q = getExpr();
552         MethodDec oldMethodDec = getMethodDec();
553
554         Type qType = q.getType();
555         MethodDec newMethodDec = w.getAccessMethod(qType, oldMethodDec, "", this);
556         setMethod(newMethodDec.getMethod());
557         if (!oldMethodDec.isStatic()) {
558             getArgs().add(0, q);
559             setExpr(getAST().makeTypeExpr(qType));
560         }
561         return this;
562     }
563
564     public MethodDec buildAccessMethod(InnerAccessFixer w) {
565         final AST ast = getAST();
566         Expr q = getExpr();
567         Type qType = q.getType();
568
569         Type returnType = getReturnType();
570         Method oldMethod = getMethod();
571
572         Formals newFormals = (Formals) oldMethod.getFormals().copy();
573         Exprs newArgs = ast.makeVars(newFormals);
574         Expr newExpr = w.makeInsidePrimary(oldMethod.isStatic(), newFormals, qType);
575
576         CallExpr newCall = ast.makeCall(oldMethod, newExpr, newArgs);
577         if (getIsSuper())
578             newCall.setIsSuper(true);
579
580         return w.makeAccessMethod(returnType, newFormals, newCall);
581     }
582
583     // ------------------------------
584
// bcg
585
protected void cgValue(CodeBuilder cb) {
586         cb.enterLocation(getSourceLocation());
587         MethodDec dec = getMethodDec();
588         String JavaDoc name = dec.getInternalId();
589         String JavaDoc descriptor = dec.getDescriptor();
590         int delta = dec.getStackDelta();
591         if (dec.isStatic())
592             getExpr().cgEffect(cb);
593         else
594             getExpr().cgValue(cb);
595         getArgs().cgValues(cb, dec.getFormals());
596         RefType refTy = (RefType) getExpr().getType();
597         NameType ty =
598             (refTy instanceof ArrayType)
599                 ? getTypeManager().getObjectType()
600                 : (NameType) refTy;
601         if (dec.getDeclaringType().isObject()) {
602             // this special cases the line in JLS 13.1: "Given a
603
// method invocation expression ... referencing a method
604
// named m declared in a class or interface D, we define
605
// the qualifying type of the method invocation as
606
// follows: If D is Object then the qualifying type of the
607
// expression is Object. Otherwise..."
608
ty = getTypeManager().getObjectType();
609         }
610         if (dec.isStatic()) {
611             cb.emitINVOKESTATIC(ty, name, descriptor, delta);
612         } else if (getIsSuper()) {
613             cb.emitINVOKESPECIAL(ty, name, descriptor, delta);
614         } else if (dec.isPrivate()) {
615             cb.emitINVOKESPECIAL(ty, name, descriptor, delta);
616         } else if (ty.isInterface()) {
617             int arglen = -delta + dec.getResultType().getSlotCount();
618             cb.emitINVOKEINTERFACE(ty, name, descriptor, delta, arglen);
619         } else {
620             cb.emitINVOKEVIRTUAL(ty, name, descriptor, delta);
621         }
622     }
623     
624     //BEGIN: Generated from @child and @property
625
protected Expr expr;
626     public Expr getExpr() { return expr; }
627     public void setExpr(Expr _expr) {
628         if (_expr != null) _expr.setParent(this);
629         expr = _expr;
630     }
631     
632     protected String JavaDoc id;
633     public String JavaDoc getId() { return id; }
634     public void setId(String JavaDoc _id) { id = _id; }
635     
636     protected Exprs args;
637     public Exprs getArgs() { return args; }
638     public void setArgs(Exprs _args) {
639         if (_args != null) _args.setParent(this);
640         args = _args;
641     }
642     
643     protected Method method;
644     public Method getMethod() { return method; }
645     public void setMethod(Method _method) { method = _method; }
646     
647     protected boolean isSuper;
648     public boolean getIsSuper() { return isSuper; }
649     public void setIsSuper(boolean _isSuper) { isSuper = _isSuper; }
650     
651     public CallExpr(SourceLocation location, Expr _expr, String JavaDoc _id, Exprs _args, Method _method, boolean _isSuper) {
652         super(location);
653         setExpr(_expr);
654         setId(_id);
655         setArgs(_args);
656         setMethod(_method);
657         setIsSuper(_isSuper);
658     }
659     protected CallExpr(SourceLocation source) {
660         super(source);
661     }
662     
663     public ASTObject copyWalk(CopyWalker walker) {
664         CallExpr ret = new CallExpr(getSourceLocation());
665         ret.preCopy(walker, this);
666         if (expr != null) ret.setExpr( (Expr)walker.process(expr) );
667         ret.id = id;
668         if (args != null) ret.setArgs( (Exprs)walker.process(args) );
669         ret.method = method;
670         ret.isSuper = isSuper;
671         return ret;
672     }
673     
674     public ASTObject getChildAt(int childIndex) {
675         switch(childIndex) {
676         case 0: return expr;
677         case 1: return args;
678         default: return super.getChildAt(childIndex);
679         }
680     }
681      public String JavaDoc getChildNameAt(int childIndex) {
682         switch(childIndex) {
683         case 0: return "expr";
684         case 1: return "args";
685         default: return super.getChildNameAt(childIndex);
686         }
687     }
688      public void setChildAt(int childIndex, ASTObject child) {
689         switch(childIndex) {
690         case 0: setExpr((Expr)child); return;
691         case 1: setArgs((Exprs)child); return;
692         default: super.setChildAt(childIndex, child); return;
693         }
694     }
695      public int getChildCount() {
696         return 2;
697     }
698     
699     public String JavaDoc getDefaultDisplayName() {
700         return "CallExpr(id: "+id+", "+"method: "+method+", "+"isSuper: "+isSuper+")";
701     }
702     
703     //END: Generated from @child and @property
704
}
705
Popular Tags