Revision: 6681 Author: [email protected] Date: Wed Nov 4 14:41:14 2009 Log: SameParameterValue optimization.
This optimization detects cases when the same value literal is used as parameter value across the whole program. Patch by: mike.aizatsky Review by: spoon http://code.google.com/p/google-web-toolkit/source/detail?r=6681 Added: /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/SameParameterValueOptimizer.java /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/SameParameterValueOptimizerTest.java Modified: /trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java ======================================= --- /dev/null +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/SameParameterValueOptimizer.java Wed Nov 4 14:41:14 2009 @@ -0,0 +1,186 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev.jjs.impl; + +import com.google.gwt.dev.jjs.ast.Context; +import com.google.gwt.dev.jjs.ast.JBinaryOperation; +import com.google.gwt.dev.jjs.ast.JExpression; +import com.google.gwt.dev.jjs.ast.JMethod; +import com.google.gwt.dev.jjs.ast.JMethodCall; +import com.google.gwt.dev.jjs.ast.JModVisitor; +import com.google.gwt.dev.jjs.ast.JNode; +import com.google.gwt.dev.jjs.ast.JParameter; +import com.google.gwt.dev.jjs.ast.JParameterRef; +import com.google.gwt.dev.jjs.ast.JPostfixOperation; +import com.google.gwt.dev.jjs.ast.JPrefixOperation; +import com.google.gwt.dev.jjs.ast.JProgram; +import com.google.gwt.dev.jjs.ast.JValueLiteral; +import com.google.gwt.dev.jjs.ast.JVisitor; + +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +/** + * Detects when same literal is passed as parameter value, and uses literal + * instead of parameter. The unused parameter will be removed by other analyses. + */ +public class SameParameterValueOptimizer { + /** + * Fill parameterValues map. + */ + private class AnalysisVisitor extends JVisitor { + @Override + public void endVisit(JBinaryOperation x, Context ctx) { + if (x.isAssignment() && x.getLhs() instanceof JParameterRef) { + parameterValues.put(((JParameterRef) x.getLhs()).getParameter(), null); + } + } + + @Override + public void endVisit(JMethodCall x, Context ctx) { + JMethod method = x.getTarget(); + if (x.canBePolymorphic() || method.isNative()) { + return; + } + + JMethod staticImpl = program.staticImplFor(method); + if (staticImpl != null && + staticImpl.getEnclosingType().getMethods().contains(staticImpl)) { + // instance method is still alive. + return; + } + + List<JExpression> args = x.getArgs(); + List<JParameter> params = method.getParams(); + + for (int i = 0; i < args.size() && i < params.size(); i++) { + JParameter param = params.get(i); + JExpression arg = args.get(i); + + if (!(arg instanceof JValueLiteral)) { + parameterValues.put(param, null); + continue; + } + + if (!parameterValues.containsKey(param)) { + parameterValues.put(param, (JValueLiteral) arg); + continue; + } + + JValueLiteral commonParamValue = parameterValues.get(param); + if (commonParamValue == null) { + continue; + } + + if (!equalLiterals(commonParamValue, (JValueLiteral) arg)) { + parameterValues.put(param, null); + } + } + } + + @Override + public void endVisit(JPostfixOperation x, Context ctx) { + if (x.getArg() instanceof JParameterRef) { + parameterValues.put(((JParameterRef) x.getArg()).getParameter(), null); + } + } + + @Override + public void endVisit(JPrefixOperation x, Context ctx) { + if (x.getArg() instanceof JParameterRef) { + parameterValues.put(((JParameterRef) x.getArg()).getParameter(), null); + } + } + + private boolean equalLiterals(JValueLiteral l1, JValueLiteral l2) { + Object v1 = l1.getValueObj(); + Object v2 = l2.getValueObj(); + + if (v1 == v2) { + return true; + } + + if (v1 == null || v2 == null) { + return false; + } + + return v1.equals(v2); + } + } + + /** + * Substitute all parameter references with expression. + */ + private class SubstituteParameterVisitor extends JModVisitor { + private CloneExpressionVisitor cloner; + private final JExpression expression; + private final JParameter parameter; + + public SubstituteParameterVisitor(JParameter parameter, + JExpression expression) { + this.parameter = parameter; + this.expression = expression; + cloner = new CloneExpressionVisitor(program); + } + + @Override + public void endVisit(JParameterRef x, Context ctx) { + if (x.getParameter() == parameter) { + ctx.replaceMe(cloner.cloneExpression(expression)); + } + } + } + + public static boolean exec(JProgram program) { + return new SameParameterValueOptimizer(program).execImpl(program); + } + + /** + * Parameter values. + * + * If doesn't contain a parameter, then its value is unknown. + * If contains parameter, and value is null - the parameter's value is not the + * same across all calls. + * If value is not null - the parameter's value is the same across all calls. + */ + private Map<JParameter, JValueLiteral> parameterValues = + new IdentityHashMap<JParameter, JValueLiteral>(); + + private final JProgram program; + + private SameParameterValueOptimizer(JProgram program) { + this.program = program; + } + + private boolean execImpl(JNode node) { + AnalysisVisitor analysisVisitor = new AnalysisVisitor(); + analysisVisitor.accept(node); + + boolean madeChanges = false; + for (JParameter parameter : parameterValues.keySet()) { + JValueLiteral valueLiteral = parameterValues.get(parameter); + if (valueLiteral != null) { + SubstituteParameterVisitor substituteParameterVisitor = + new SubstituteParameterVisitor(parameter, valueLiteral); + substituteParameterVisitor.accept(parameter.getEnclosingMethod()); + madeChanges |= substituteParameterVisitor.didChange(); + } + } + + return madeChanges; + } +} ======================================= --- /dev/null +++ /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/SameParameterValueOptimizerTest.java Wed Nov 4 14:41:14 2009 @@ -0,0 +1,64 @@ +// Copyright 2009 Google Inc. All Rights Reserved. + +package com.google.gwt.dev.jjs.impl; + +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.dev.jjs.ast.JMethod; +import com.google.gwt.dev.jjs.ast.JProgram; + +/** + * Test for SameParameterValueOptimizer. + */ +public class SameParameterValueOptimizerTest extends OptimizerTestBase { + public void testSameParameter() throws Exception { + assertOptimize("foo", "static void foo(int i) { int j = i; }", + "foo(1); foo(1);").into( + "public static void foo(int i){", + " int j = 1;", + "}"); + } + + public void testDifferentParameter() throws Exception { + assertOptimize("foo", "static void foo(int i) { int j = i; }", + "foo(1); foo(2);").into( + "public static void foo(int i){", + " int j = i;", + "}"); + } + + public void testNonConstParameter() throws Exception { + assertOptimize("foo", "static int foo(int i) { return i; }", + "foo(foo(1));").into( + "public static int foo(int i){", + " return i;", + "}"); + } + + private OptimizationResult assertOptimize(String methodName, + String methodDecl, String codeSnippet) throws UnableToCompleteException { + addSnippetClassDecl(methodDecl); + JProgram program = compileSnippet("void", codeSnippet); + SameParameterValueOptimizer.exec(program); + JMethod method = findMethod(program, methodName); + return new OptimizationResult(method); + } + + private static class OptimizationResult { + private final JMethod method; + + public OptimizationResult(JMethod method) { + this.method = method; + } + + public void into(String...expectedStrings) { + StringBuffer expected = new StringBuffer(); + for (String s : expectedStrings) { + if (expected.length() != 0) { + expected.append("\n"); + } + expected.append(s); + } + assertEquals(expected.toString(), method.toSource()); + } + } +} ======================================= --- /trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java Wed Oct 28 11:45:03 2009 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java Wed Nov 4 14:41:14 2009 @@ -85,6 +85,7 @@ import com.google.gwt.dev.jjs.impl.ReplaceRebinds; import com.google.gwt.dev.jjs.impl.ReplaceRunAsyncs; import com.google.gwt.dev.jjs.impl.ResolveRebinds; +import com.google.gwt.dev.jjs.impl.SameParameterValueOptimizer; import com.google.gwt.dev.jjs.impl.SourceGenerationVisitor; import com.google.gwt.dev.jjs.impl.TypeMap; import com.google.gwt.dev.jjs.impl.TypeTightener; @@ -637,7 +638,11 @@ if (isAggressivelyOptimize) { // inlining didChange = MethodInliner.exec(jprogram) || didChange; - } + + // remove same parameters value + didChange = SameParameterValueOptimizer.exec(jprogram) || didChange; + } + // prove that any types that have been culled from the main tree are // unreferenced due to type tightening? ======================================= --- /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java Wed Oct 28 09:10:53 2009 +++ /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java Wed Nov 4 14:41:14 2009 @@ -64,15 +64,18 @@ } public static JMethod findMainMethod(JProgram program) { + return findMethod(program, "onModuleLoad"); + } + + public static JMethod findMethod(JProgram program, String methodName) { JDeclaredType mainType = program.getFromTypeMap("test.EntryPoint"); - JMethod mainMethod = null; for (JMethod method : mainType.getMethods()) { - if (method.getName().equals("onModuleLoad")) { - mainMethod = method; - break; + if (method.getName().equals(methodName)) { + return method; } } - return mainMethod; + + return null; } /** --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---
