001 /* Copyright 2000, 2001, Compaq Computer Corporation */
002
003 package escjava.translate;
004
005 import java.util.Vector;
006 import java.util.Hashtable;
007 import javafe.util.Assert;
008 import javafe.util.Location;
009 import javafe.ast.*;
010 import javafe.parser.ParseUtil;
011 import escjava.ast.TagConstants;
012 import escjava.translate.Substitute;
013
014 /* This class performs an experiment with inlining to remove spurious warnings
015 caused by the lack of object invariant annotations. In particular, the class
016 takes a method declaration and replaces it by a method declaration consisting
017 of an appropriate constructor call, followed by an inlined call to the
018 original method. */
019
020 public class InlineConstructor {
021
022 //@ requires cus != null;
023 public static void inlineConstructorsEverywhere(Vector cus) {
024 int size = cus.size();
025 for (int i = 0; i < size; i++) {
026 CompilationUnit cu = (CompilationUnit) cus.elementAt(i);
027 int numClasses = cu.elems.size();
028 for (int j = 0; j < numClasses; j++) {
029 TypeDecl td = (TypeDecl) cu.elems.elementAt(j);
030 if (!Modifiers.isAbstract(td.modifiers))
031 inlineConstructorsInAllMethods(td);
032 }
033 }
034 }
035
036 public static void inlineConstructorsInAllMethods(TypeDecl td) {
037 // find the appropriate modifier for STATIC
038
039 // create a static field for the replacement for <code>this</code>
040 Identifier newThis = uniquifyName("this");
041 TypeName selfType0 = TypeName.make(SimpleName.make(td.id, td.locId));
042 FieldDecl newField = FieldDecl.make(Modifiers.ACC_STATIC, null,
043 newThis,
044 selfType0, td.locOpenBrace, null,
045 td.locOpenBrace);
046 newField.setParent(td);
047 td.elems.addElement(newField);
048
049 // find all constructors
050 TypeDeclElemVec constructors = TypeDeclElemVec.make();
051 int size = td.elems.size();
052 for (int i = 0; i < size; i++) {
053 TypeDeclElem elem = td.elems.elementAt(i);
054 if (elem instanceof ConstructorDecl)
055 constructors.addElement(elem);
056 }
057
058 int numConstructors = constructors.size();
059
060 // if we couldn't find any constructors, we're done
061 if (numConstructors == 0)
062 return;
063
064 // for each non-static method, create a constructor-inlined version of
065 // it with each constructor
066 for (int j = 0; j < size; j++) {
067 TypeDeclElem tde = td.elems.elementAt(j);
068 if (isConstructorInlinable(tde)) {
069 for (int i = 0; i < numConstructors; i++)
070 createMethodDecl((MethodDecl) tde, td,
071 (ConstructorDecl) constructors.elementAt(i),
072 newThis, i);
073 }
074 }
075 }
076
077
078 private static void createMethodDecl(MethodDecl md, TypeDecl td,
079 ConstructorDecl cd,
080 Identifier newThis,
081 int count) {
082
083 // create the constructor invocation statement
084 TypeName selfType1 = TypeName.make(SimpleName.make(td.id, cd.locId));
085 ExprVec evec = ExprVec.make();
086 int size = cd.args.size();
087 for (int i = 0; i < size; i++) {
088 Identifier argName = uniquifyName(cd.args.elementAt(i).id);
089 Name name = SimpleName.make(argName, cd.locId);
090 evec.addElement(AmbiguousVariableAccess.make(name));
091 }
092 NewInstanceExpr newexpr = NewInstanceExpr.make(null, cd.locId,
093 selfType1, evec,
094 null, cd.locId,
095 cd.locId);
096 // inline this call, assuming the preconditions and all body checks
097 Translate.inlineDecoration.set(newexpr,
098 new InlineSettings(true, true, true));
099
100 AmbiguousVariableAccess newThisVar =
101 AmbiguousVariableAccess.make(SimpleName.make(newThis, cd.locId));
102 BinaryExpr assignExpr = BinaryExpr.make(TagConstants.ASSIGN, newThisVar,
103 newexpr, cd.locId);
104 EvalStmt firstStmt = EvalStmt.make(assignExpr);
105
106
107 // create the method invocation statement
108 evec = ExprVec.make();
109 size = md.args.size();
110 for (int i = 0; i < size; i++) {
111 Name name = SimpleName.make(md.args.elementAt(i).id, md.locId);
112 evec.addElement(AmbiguousVariableAccess.make(name));
113 }
114 // inline this call, checking all of the body checks
115 AmbiguousVariableAccess receiver =
116 AmbiguousVariableAccess.make(SimpleName.make(newThis,
117 md.locId));
118 ObjectDesignator od = ExprObjectDesignator.make(md.locId, receiver);
119 MethodInvocation invocation =
120 MethodInvocation.make(od, md.id, md.tmodifiers, md.locId,
121 md.locId, evec);
122 invocation.decl = md;
123 //inline the call, assuming the preconditions and checking the body
124 Translate.inlineDecoration.set(invocation,
125 new InlineSettings(true, false, false));
126 Stmt secondStmt;
127 if (md.returnType instanceof PrimitiveType &&
128 ((PrimitiveType) md.returnType).tag == TagConstants.VOIDTYPE)
129 secondStmt = EvalStmt.make(invocation);
130 else
131 secondStmt = ReturnStmt.make(invocation, md.locId);
132
133 // create the new method
134 StmtVec stmts = StmtVec.make(2);
135 stmts.addElement(firstStmt);
136 stmts.addElement(secondStmt);
137 BlockStmt body = BlockStmt.make(stmts, md.loc, md.loc);
138
139 FormalParaDeclVec args = FormalParaDeclVec.make();
140 size = md.args.size();
141 for (int i = 0; i < size; i++) {
142 FormalParaDecl arg = md.args.elementAt(i);
143 args.addElement(FormalParaDecl.make(arg.modifiers, arg.pmodifiers,
144 arg.id, arg.type, arg.locId));
145 }
146 // we uniquify constructor arg names so they don't clash with
147 // the names of the parameters above
148 size = cd.args.size();
149 for (int i = 0; i < size; i++) {
150 FormalParaDecl arg = cd.args.elementAt(i);
151 Identifier newName = uniquifyName(arg.id);
152 args.addElement(FormalParaDecl.make(arg.modifiers, arg.pmodifiers,
153 newName, arg.type,
154 arg.locId));
155 }
156
157
158 /** ***TODO**
159
160 // copy <code>md</code>'s postconditions, with "this" replaced by our
161 // newThis.
162 ModifierPragmaVec postconds = null;
163 boolean first = true;
164 if (md.pmodifiers != null) {
165 size = md.pmodifiers.size();
166 for (int i = 0; i < size; i++) {
167 ModifierPragma mp = md.pmodifiers.elementAt(i);
168 int tag = mp.getTag();
169 if (tag == TagConstants.ENSURES ||
170 tag == TagConstants.ALSO_ENSURES) {
171 if (first) {
172 postconds = ModifierPragmaVec.make();
173 first = false;
174 }
175 }
176 }
177 }
178 **/
179
180 /* create the throws clause of the new method
181 Note: We don't check for duplicates, so this may contain
182 the same exception twice. Is that a problem?
183 */
184 TypeNameVec raises = null;
185 if (md.raises != null) {
186 size = md.raises.size();
187 raises = TypeNameVec.make();
188 for (int i = 0; i < size; i++)
189 raises.addElement(copyTypeName(md.raises.elementAt(i), md));
190 }
191 if (cd.raises != null) {
192 size = cd.raises.size();
193 if (raises == null)
194 raises = TypeNameVec.make(size);
195 for (int i = 0; i < size; i++)
196 raises.addElement(copyTypeName(cd.raises.elementAt(i), cd));
197 }
198
199 MethodDecl newMethod = MethodDecl.make(Modifiers.ACC_STATIC, null,
200 null, args, raises, body,
201 md.loc, md.loc, md.loc, md.loc,
202 uniquifyName(md.id.toString()
203 + "_" + count),
204 copyType(md.returnType, md),
205 md.loc);
206 newMethod.setParent(td);
207 td.elems.addElement(newMethod);
208
209 }
210
211
212 /**
213 ** Returns true if the given method is a constructor-inlined version
214 ** of some other method
215 **/
216 public static boolean isConstructorInlinedMethod(MethodDecl md) {
217 return md.id.toString().startsWith("*");
218 }
219
220
221 /* Returns true iff the given TypeDeclElem is a non-static, non-helper
222 method.
223 */
224 public static boolean isConstructorInlinable(TypeDeclElem tde) {
225 if (tde instanceof MethodDecl) {
226 MethodDecl md = (MethodDecl) tde;
227 if (!(Modifiers.isStatic(md.modifiers) ||
228 Helper.isHelper(md)))
229 return true;
230 }
231 return false;
232 }
233
234
235 /* Return a new copy of a Type, using the location of the surrounding
236 RoutineDecl.
237 */
238 private static Type copyType(Type t, RoutineDecl rd) {
239 if (t instanceof PrimitiveType) {
240 PrimitiveType pt = (PrimitiveType) t;
241 return JavafePrimitiveType.make(pt.tag, rd.loc);
242 }
243 else if (t instanceof TypeName) {
244 return copyTypeName((TypeName) t, rd);
245 }
246 else if (t instanceof ArrayType) {
247 ArrayType at = (ArrayType) t;
248 return ArrayType.make(copyType(at.elemType, rd), rd.loc);
249 }
250 else {
251 Assert.fail("Unknown kind of Type");
252 return null;
253 }
254 }
255
256 private static TypeName copyTypeName(TypeName tn, RoutineDecl rd) {
257 return TypeName.make(copyName(tn.name, rd));
258 }
259
260 /* Return a new copy of a Name, with all locations nulled out. */
261 private static Name copyName(Name n, RoutineDecl rd) {
262 if (n instanceof SimpleName) {
263 SimpleName sn = (SimpleName) n;
264 return SimpleName.make(sn.id, rd.loc);
265 }
266 else if (n instanceof CompoundName) {
267 CompoundName cn = (CompoundName) n;
268 int size = cn.ids.size();
269 IdentifierVec iv = IdentifierVec.make(size);
270 int[] ids = new int[size];
271 int[] dots = new int[size];
272 for (int i = 0; i < size; i++) {
273 iv.addElement(cn.ids.elementAt(i));
274 ids[i] = rd.loc;
275 dots[i] = rd.loc;
276 }
277 return CompoundName.make(iv, ids, dots);
278 }
279 else {
280 Assert.fail("Unknown kind of Name");
281 return null;
282 }
283 }
284
285
286 /* surround an identifier by '*'s. */
287 private static Identifier uniquifyName(String s) {
288 return Identifier.intern("*" + s + "*");
289 }
290
291 private static Identifier uniquifyName(Identifier i) {
292 return uniquifyName(i.toString());
293 }
294
295 }
296