KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > dev > jjs > impl > CompoundAssignmentNormalizer


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.dev.jjs.impl;
17
18 import com.google.gwt.dev.jjs.ast.Context;
19 import com.google.gwt.dev.jjs.ast.JArrayRef;
20 import com.google.gwt.dev.jjs.ast.JBinaryOperation;
21 import com.google.gwt.dev.jjs.ast.JBinaryOperator;
22 import com.google.gwt.dev.jjs.ast.JExpression;
23 import com.google.gwt.dev.jjs.ast.JFieldRef;
24 import com.google.gwt.dev.jjs.ast.JLocal;
25 import com.google.gwt.dev.jjs.ast.JLocalRef;
26 import com.google.gwt.dev.jjs.ast.JMethod;
27 import com.google.gwt.dev.jjs.ast.JModVisitor;
28 import com.google.gwt.dev.jjs.ast.JNullLiteral;
29 import com.google.gwt.dev.jjs.ast.JParameterRef;
30 import com.google.gwt.dev.jjs.ast.JProgram;
31 import com.google.gwt.dev.jjs.ast.JThisRef;
32 import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
33
34 import java.util.ArrayList JavaDoc;
35 import java.util.List JavaDoc;
36
37 /**
38  * Replace any complex assignments that will cause problems down the road with
39  * broken expressions; replace side-effect expressions in the lhs with temps to
40  * prevent multiple evaluation.
41  */

42 public class CompoundAssignmentNormalizer {
43
44   /**
45    * Breaks apart certain complex assignments.
46    */

47   private class BreakupAssignOpsVisitor extends JModVisitor {
48
49     // @Override
50
public void endVisit(JBinaryOperation x, Context ctx) {
51       /*
52        * Convert to a normal divide operation so we can cast the result. Since
53        * the left hand size must be computed twice, we have to replace any
54        * left-hand side expressions that could have side effects with
55        * temporaries, so that they are only run once.
56        */

57       if (x.getOp() == JBinaryOperator.ASG_DIV
58           && x.getType() != program.getTypePrimitiveFloat()
59           && x.getType() != program.getTypePrimitiveDouble()) {
60
61         /*
62          * Convert to a normal divide operation so we can cast the result. Since
63          * the left hand size must be computed twice, we have to replace any
64          * left-hand side expressions that could have side effects with
65          * temporaries, so that they are only run once.
66          */

67         final int pushUsedLocals = localIndex;
68         JMultiExpression multi = new JMultiExpression(program,
69             x.getSourceInfo());
70         ReplaceSideEffectsInLvalue replacer = new ReplaceSideEffectsInLvalue(
71             multi);
72         JExpression newLhs = replacer.accept(x.getLhs());
73         localIndex = pushUsedLocals;
74
75         JNullLiteral litNull = program.getLiteralNull();
76         JBinaryOperation operation = new JBinaryOperation(program,
77             x.getSourceInfo(), newLhs.getType(), JBinaryOperator.DIV, newLhs,
78             x.getRhs());
79         JBinaryOperation asg = new JBinaryOperation(program, x.getSourceInfo(),
80             newLhs.getType(), JBinaryOperator.ASG, newLhs, operation);
81
82         JMultiExpression multiExpr = replacer.getMultiExpr();
83         if (multiExpr.exprs.isEmpty()) {
84           // just use the split assignment expression
85
ctx.replaceMe(asg);
86         } else {
87           // add the assignment as the last item in the multi
88
multi.exprs.add(asg);
89           ctx.replaceMe(multi);
90         }
91       }
92     }
93
94     // @Override
95
public void endVisit(JMethod x, Context ctx) {
96       clearLocals();
97       currentMethod = null;
98     }
99
100     // @Override
101
public boolean visit(JMethod x, Context ctx) {
102       currentMethod = x;
103       clearLocals();
104       return true;
105     }
106   }
107   /**
108    * Replaces side effects in lvalue.
109    */

110   private class ReplaceSideEffectsInLvalue extends JModVisitor {
111
112     private final JMultiExpression multi;
113
114     ReplaceSideEffectsInLvalue(JMultiExpression multi) {
115       this.multi = multi;
116     }
117
118     public JMultiExpression getMultiExpr() {
119       return multi;
120     }
121
122     // @Override
123
public boolean visit(JArrayRef x, Context ctx) {
124       JExpression newInstance = possiblyReplace(x.getInstance());
125       JExpression newIndexExpr = possiblyReplace(x.getIndexExpr());
126       if (newInstance != x.getInstance() || newIndexExpr != x.getIndexExpr()) {
127         JArrayRef newExpr = new JArrayRef(program, x.getSourceInfo(),
128             newInstance, newIndexExpr);
129         ctx.replaceMe(newExpr);
130       }
131       return false;
132     }
133
134     // @Override
135
public boolean visit(JFieldRef x, Context ctx) {
136       if (x.getInstance() != null) {
137         JExpression newInstance = possiblyReplace(x.getInstance());
138         if (newInstance != x.getInstance()) {
139           JFieldRef newExpr = new JFieldRef(program, x.getSourceInfo(),
140               newInstance, x.getField(), x.getEnclosingType());
141           ctx.replaceMe(newExpr);
142         }
143       }
144       return false;
145     }
146
147     // @Override
148
public boolean visit(JLocalRef x, Context ctx) {
149       return false;
150     }
151
152     // @Override
153
public boolean visit(JParameterRef x, Context ctx) {
154       return false;
155     }
156
157     // @Override
158
public boolean visit(JThisRef x, Context ctx) {
159       return false;
160     }
161
162     private JExpression possiblyReplace(JExpression x) {
163       if (!x.hasSideEffects()) {
164         return x;
165       }
166
167       // Create a temp local
168
JLocal tempLocal = getTempLocal();
169
170       // Create an assignment for this temp and add it to multi.
171
JLocalRef tempRef = new JLocalRef(program, x.getSourceInfo(), tempLocal);
172       JBinaryOperation asg = new JBinaryOperation(program, x.getSourceInfo(),
173           x.getType(), JBinaryOperator.ASG, tempRef, x);
174       multi.exprs.add(asg);
175       // Update me with the temp
176
return tempRef;
177     }
178   }
179
180   public static void exec(JProgram program) {
181     new CompoundAssignmentNormalizer(program).execImpl();
182   }
183
184   private JMethod currentMethod;
185   private int localIndex;
186   private final JProgram program;
187   private final List JavaDoc/* <JLocal> */tempLocals = new ArrayList JavaDoc/* <JLocal> */();
188
189   private CompoundAssignmentNormalizer(JProgram program) {
190     this.program = program;
191   }
192
193   private void clearLocals() {
194     tempLocals.clear();
195     localIndex = 0;
196   }
197
198   private void execImpl() {
199     BreakupAssignOpsVisitor breaker = new BreakupAssignOpsVisitor();
200     breaker.accept(program);
201   }
202
203   private JLocal getTempLocal() {
204     if (localIndex < tempLocals.size()) {
205       return (JLocal) tempLocals.get(localIndex++);
206     }
207     JLocal newTemp = program.createLocal(null,
208         ("$t" + localIndex++).toCharArray(), program.getTypeVoid(), false,
209         currentMethod);
210     tempLocals.add(newTemp);
211     return newTemp;
212   }
213
214 }
215
Popular Tags