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 PrimitiveType.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