1 16 package com.google.gwt.dev.jjs.impl; 17 18 import com.google.gwt.dev.jjs.SourceInfo; 19 import com.google.gwt.dev.jjs.ast.Context; 20 import com.google.gwt.dev.jjs.ast.JBlock; 21 import com.google.gwt.dev.jjs.ast.JExpression; 22 import com.google.gwt.dev.jjs.ast.JExpressionStatement; 23 import com.google.gwt.dev.jjs.ast.JField; 24 import com.google.gwt.dev.jjs.ast.JFieldRef; 25 import com.google.gwt.dev.jjs.ast.JLiteral; 26 import com.google.gwt.dev.jjs.ast.JMethod; 27 import com.google.gwt.dev.jjs.ast.JMethodCall; 28 import com.google.gwt.dev.jjs.ast.JModVisitor; 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.JReferenceType; 32 import com.google.gwt.dev.jjs.ast.JReturnStatement; 33 import com.google.gwt.dev.jjs.ast.JStatement; 34 import com.google.gwt.dev.jjs.ast.JVisitor; 35 import com.google.gwt.dev.jjs.ast.js.JMultiExpression; 36 37 import java.util.ArrayList ; 38 import java.util.HashSet ; 39 import java.util.Iterator ; 40 import java.util.List ; 41 import java.util.Set ; 42 43 48 public class MethodInliner { 49 50 55 public class FlattenMultiVisitor extends JVisitor { 56 57 private boolean didChange = false; 58 59 public boolean didChange() { 60 return didChange; 61 } 62 63 public void endVisit(JMultiExpression x, Context ctx) { 65 ArrayList exprs = x.exprs; 66 67 72 for (int i = 0; i < exprs.size(); ++i) { 73 JExpression expr = (JExpression) exprs.get(i); 74 if (expr instanceof JMultiExpression) { 75 JMultiExpression sub = (JMultiExpression) expr; 76 exprs.addAll(i + 1, sub.exprs); 77 didChange = true; 78 } 79 } 80 81 for (Iterator it = exprs.iterator(); it.hasNext();) { 83 JExpression expr = (JExpression) it.next(); 84 if (expr instanceof JMultiExpression) { 85 it.remove(); 86 didChange = true; 87 } 88 } 89 } 90 } 91 94 public class InliningVisitor extends JModVisitor { 95 99 Set cannotInline = new HashSet (); 100 101 public void endVisit(JMethod x, Context ctx) { 102 currentMethod = null; 103 } 104 105 public void endVisit(JMethodCall x, Context ctx) { 107 JMethod method = x.getTarget(); 108 109 if (!method.isStatic() || method.isNative()) { 111 return; 112 } 113 114 if (cannotInline.contains(method)) { 115 return; 116 } 117 118 List stmts = method.body.statements; 119 boolean possibleToInline = false; 120 if (stmts.isEmpty()) { 121 tryInlineEmptyMethodCall(x, ctx); 122 possibleToInline = true; 123 } else if (stmts.size() == 1) { 124 JStatement stmt = (JStatement) stmts.get(0); 125 if (stmt instanceof JReturnStatement) { 126 possibleToInline = tryInlineExpression(x, ctx, 127 ((JReturnStatement) stmt).getExpr()); 128 } else if (stmt instanceof JExpressionStatement) { 129 possibleToInline = tryInlineExpression(x, ctx, 130 ((JExpressionStatement) stmt).getExpr()); 131 } 132 } 133 134 if (!possibleToInline) { 135 cannotInline.add(method); 136 } 137 } 138 139 public boolean visit(JMethod x, Context ctx) { 140 currentMethod = x; 141 return true; 142 } 143 144 159 private JExpression canInlineExpression(SourceInfo info, 160 JExpression targetExpr, List params, ArrayList args, 161 int[] magicArg) { 162 if (targetExpr instanceof JLiteral) { 163 169 magicArg[0] = args.size(); 170 return targetExpr; 171 } else if (targetExpr instanceof JParameterRef) { 172 int i = params.indexOf(((JParameterRef) targetExpr).getTarget()); 174 assert (i >= 0); 175 magicArg[0] = i; 176 return (JExpression) args.get(i); 177 } else if (targetExpr instanceof JFieldRef) { 178 JFieldRef oldFieldRef = (JFieldRef) targetExpr; 179 JField field = oldFieldRef.getField(); 180 JExpression instance = oldFieldRef.getInstance(); 181 if (instance != null) { 182 instance = canInlineExpression(info, instance, params, args, magicArg); 184 if (instance == null) { 185 return null; 186 } 187 } 188 JFieldRef newFieldRef = new JFieldRef(program, info, instance, field, 189 currentMethod.getEnclosingType()); 190 return newFieldRef; 191 } else { 192 196 return null; 197 } 198 } 199 200 204 private boolean checkClinitViolation(JMethodCall x, 205 JExpression resultExpression) { 206 JReferenceType targetEnclosingType = x.getTarget().getEnclosingType(); 207 if (!program.typeOracle.checkClinit(currentMethod.getEnclosingType(), targetEnclosingType)) { 208 return false; 210 } 211 if (program.isStaticImpl(x.getTarget())) { 212 return false; 214 } 215 216 221 222 if (!(resultExpression instanceof JFieldRef)) { 224 return true; 225 } 226 JFieldRef fieldRefResult = (JFieldRef) resultExpression; 227 JField fieldResult = fieldRefResult.getField(); 228 if (!fieldResult.isStatic()) { 229 return true; 231 } 232 if (fieldResult.getEnclosingType() != targetEnclosingType) { 233 return true; 236 } 237 return false; 239 } 240 241 244 private void tryInlineEmptyMethodCall(JMethodCall x, Context ctx) { 245 if (checkClinitViolation(x, null)) { 246 return; 247 } 248 JMultiExpression multi = new JMultiExpression(program, x.getSourceInfo()); 249 JExpression instance = x.getInstance(); 250 if (instance != null && instance.hasSideEffects()) { 251 multi.exprs.add(x.getInstance()); 252 } 253 for (int i = 0, c = x.getArgs().size(); i < c; ++i) { 254 if (((JExpression) x.getArgs().get(i)).hasSideEffects()) { 255 multi.exprs.add(x.getArgs().get(i)); 256 } 257 } 258 ctx.replaceMe(multi); 259 } 260 261 264 private boolean tryInlineExpression(JMethodCall x, Context ctx, 265 JExpression targetExpr) { 266 List params = x.getTarget().params; 267 ArrayList args = x.getArgs(); 268 269 JExpression resultExpression; 271 int magicArg[] = new int[1]; 273 274 resultExpression = canInlineExpression(x.getSourceInfo(), targetExpr, 275 params, args, magicArg); 276 277 if (resultExpression == null) { 278 return false; } 280 281 283 if (checkClinitViolation(x, resultExpression)) { 284 289 return true; 290 } 291 292 int iMagicArg = magicArg[0]; 294 295 JMultiExpression multi = new JMultiExpression(program, x.getSourceInfo()); 296 297 JExpression instance = x.getInstance(); 299 if (instance != null && instance.hasSideEffects()) { 300 multi.exprs.add(x.getInstance()); 301 } 302 303 for (int i = 0; i < params.size(); ++i) { 305 if (((JExpression) args.get(i)).hasSideEffects()) { 306 if (i < iMagicArg) { 307 multi.exprs.add(args.get(i)); 309 } else if (i == iMagicArg) { 310 } else { 312 assert (i > iMagicArg); 313 322 return true; 323 } 324 } 325 } 326 327 multi.exprs.add(resultExpression); 329 ctx.replaceMe(multi); 330 return true; 331 } 332 } 333 334 337 public class ReduceMultiVisitor extends JModVisitor { 338 339 public void endVisit(JBlock x, Context ctx) { 341 for (Iterator it = x.statements.iterator(); it.hasNext();) { 342 JStatement stmt = (JStatement) it.next(); 343 if (stmt instanceof JExpressionStatement) { 345 JExpression expr = ((JExpressionStatement) stmt).getExpr(); 346 if (!expr.hasSideEffects()) { 347 it.remove(); 348 didChange = true; 349 } 350 } 351 } 352 } 353 354 public void endVisit(JMultiExpression x, Context ctx) { 356 ArrayList exprs = x.exprs; 357 358 final int c = exprs.size(); 359 if (c == 0) { 360 return; 361 } 362 363 int countSideEffectsBeforeLast = 0; 364 for (int i = 0; i < c - 1; ++i) { 365 JExpression expr = (JExpression) exprs.get(i); 366 if (expr.hasSideEffects()) { 367 ++countSideEffectsBeforeLast; 368 } 369 } 370 371 if (countSideEffectsBeforeLast == 0) { 372 ctx.replaceMe((JExpression) x.exprs.get(c - 1)); 373 } else { 374 JMultiExpression newMulti = new JMultiExpression(program, 375 x.getSourceInfo()); 376 for (int i = 0; i < c - 1; ++i) { 377 JExpression expr = (JExpression) exprs.get(i); 378 if (expr.hasSideEffects()) { 379 newMulti.exprs.add(expr); 380 } 381 } 382 newMulti.exprs.add(x.exprs.get(c - 1)); 383 if (newMulti.exprs.size() < x.exprs.size()) { 384 ctx.replaceMe(newMulti); 385 } 386 } 387 } 388 } 389 390 public static boolean exec(JProgram program) { 391 return new MethodInliner(program).execImpl(); 392 } 393 394 private JMethod currentMethod; 395 private final JProgram program; 396 397 private MethodInliner(JProgram program) { 398 this.program = program; 399 } 400 401 private boolean execImpl() { 402 boolean madeChanges = false; 403 while (true) { 404 InliningVisitor inliner = new InliningVisitor(); 405 inliner.accept(program); 406 if (!inliner.didChange()) { 407 break; 408 } 409 madeChanges = true; 410 411 FlattenMultiVisitor flattener = new FlattenMultiVisitor(); 412 flattener.accept(program); 413 414 ReduceMultiVisitor reducer = new ReduceMultiVisitor(); 415 reducer.accept(program); 416 } 417 return madeChanges; 418 } 419 420 } 421 | Popular Tags |