Revision: 6681
Author: sp...@google.com
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to