Revision: 7984
Author: sco...@google.com
Date: Mon Apr 26 10:59:53 2010
Log: Unifies temp local tracking under a shared base visitor.

- All temps now definitely get their own JDeclarationStatement inserted into the AST at the appropriate point.

- Temp locals are never reused anymore; however, whenever legal we reuse names in order to produce smaller compiled output.

http://gwt-code-reviews.appspot.com/354801/show
Review by: spoon

http://code.google.com/p/google-web-toolkit/source/detail?r=7984

Added:
/branches/2.1/dev/core/src/com/google/gwt/dev/jjs/impl/TempLocalVisitor.java /branches/2.1/dev/core/test/com/google/gwt/dev/jjs/impl/TempLocalVisitorTest.java
Modified:
/branches/2.1/dev/core/src/com/google/gwt/dev/jjs/impl/CompoundAssignmentNormalizer.java /branches/2.1/dev/core/src/com/google/gwt/dev/jjs/impl/FixAssignmentToUnbox.java /branches/2.1/dev/core/src/com/google/gwt/dev/jjs/impl/PostOptimizationCompoundAssignmentNormalizer.java /branches/2.1/dev/core/test/com/google/gwt/dev/jjs/impl/SameParameterValueOptimizerTest.java

=======================================
--- /dev/null
+++ /branches/2.1/dev/core/src/com/google/gwt/dev/jjs/impl/TempLocalVisitor.java Mon Apr 26 10:59:53 2010
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2010 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.SourceInfo;
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JBlock;
+import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
+import com.google.gwt.dev.jjs.ast.JLocal;
+import com.google.gwt.dev.jjs.ast.JLocalRef;
+import com.google.gwt.dev.jjs.ast.JMethodBody;
+import com.google.gwt.dev.jjs.ast.JModVisitor;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JStatement;
+import com.google.gwt.dev.jjs.ast.JType;
+import com.google.gwt.dev.jjs.ast.JVariable;
+import com.google.gwt.dev.jjs.ast.JVisitor;
+
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * Utility base class for visitors that need to replace expressions with temp + * locals. This class specifically handles allocating temp locals, and inserting + * a {...@link JDeclarationStatement} at the appropriate point. It tracks scopes + * and assigns any potentially conflicting uses with unique names. Subclasses + * are only allowed to use a temp within the {...@link JBlock} within which it is
+ * allocated. Non-conflicting temp locals attempt to reuse as many names as
+ * possible in order to produce the most optimal output.
+ *
+ * <p>
+ * Subclasses must always visit a {...@link JMethodBody} naturally, rather than
+ * individual blocks.
+ * </p>
+ */
+public abstract class TempLocalVisitor extends JModVisitor {
+  /*
+   * TODO(scottb): right now our handling of for statements is sub-optimal.
+ * Technically, a for statement creates an implicit scope that is not part of + * any block. This scope is a child of the block containing the for statement, + * and a parent of the for statement's action block. We don't presently model + * this scope, instead we just allow the for statement's top-level constructs + * to bleed up into the containing block, which is correct if sub-optimal for
+   * name reuse.
+   */
+
+  /**
+   * Creates a Scope for each JBlock in the current method body.
+   */
+  private static class CollectScopes extends JVisitor {
+
+    private Scope curScope = null;
+
+    private final Map<JBlock, Scope> scopes;
+
+    public CollectScopes(Map<JBlock, Scope> scopes) {
+      this.scopes = scopes;
+    }
+
+    @Override
+    public void endVisit(JBlock x, Context ctx) {
+      exit(x);
+    }
+
+    @Override
+    public void endVisit(JDeclarationStatement x, Context ctx) {
+      JVariable target = x.getVariableRef().getTarget();
+      if (target instanceof JLocal) {
+        String name = target.getName();
+        if (name.startsWith(PREFIX)) {
+          curScope.recordTempAllocated(Integer.parseInt(
+              name.substring(PREFIX.length()), 10));
+        }
+      }
+    }
+
+    @Override
+    public boolean visit(JBlock x, Context ctx) {
+      enter(x);
+      return true;
+    }
+
+    private void enter(JBlock x) {
+      curScope = new Scope(curScope);
+      scopes.put(x, curScope);
+    }
+
+    private void exit(JBlock x) {
+      assert scopes.get(x) == curScope;
+      curScope = curScope.parent;
+    }
+  }
+
+  /**
+ * Represents a single logical scope (ie, JBlock), and tracks allocation and
+   * usage of any temps.
+   */
+  private static class Scope {
+    /**
+ * My containing scope, will be <code>null</code> if this scope corresponds
+     * to the top-level method body block.
+     */
+    public final Scope parent;
+
+    /**
+ * Caches which temps have been allocated both in this scope and all parent
+     * scopes.
+     */
+    private transient BitSet allAllocated;
+
+    /**
+     * Caches the last temp allocated in this scope, for speedier lookup.
+     */
+    private transient int lastTemp;
+
+    /**
+ * The set of all temps allocated by all my child blocks. This prevents me + * from allocating a temp one of my children already allocated; however it
+     * does not prevent my children from reusing temps also used by their
+     * siblings.
+     */
+    private final BitSet myChildTemps = new BitSet();
+
+    /**
+     * The set of temps that have been directly allocated in this scope.
+     */
+    private final BitSet myTemps = new BitSet();
+
+    public Scope(Scope parent) {
+      this.parent = parent;
+    }
+
+    /**
+     * Acquires the next free temp in this scope.
+     */
+    public int allocateNextFreeTemp() {
+      if (allAllocated == null) {
+        allAllocated = new BitSet();
+ // Any temps already allocated by my parents are not available to me.
+        for (Scope it = this; it != null; it = it.parent) {
+          allAllocated.or(it.myTemps);
+        }
+      }
+ // Any temps already allocated by my children are not available to me.
+      allAllocated.or(myChildTemps);
+      // Find the next free temp.
+      lastTemp = allAllocated.nextClearBit(lastTemp);
+      recordTempAllocated(lastTemp);
+      return lastTemp;
+    }
+
+    /**
+     * Called when entering this scope, clears transient state.
+     */
+    public void enter() {
+      // Assume dirty, lazy recompute.
+      allAllocated = null;
+      lastTemp = 0;
+    }
+
+    /**
+     * Called when exiting this scope.
+     */
+    public void exit() {
+      // Free the memory.
+      allAllocated = null;
+    }
+
+    /**
+     * Record a temp as being allocated in this scope.
+     */
+    public void recordTempAllocated(int tempNumber) {
+      assert !myTemps.get(tempNumber);
+      // Record my own usage.
+      myTemps.set(tempNumber);
+      if (allAllocated != null) {
+        allAllocated.set(tempNumber);
+      }
+      // Tell all my parents I'm now using this one.
+      for (Scope it = this.parent; it != null; it = it.parent) {
+        assert !it.myTemps.get(tempNumber);
+        it.myChildTemps.set(tempNumber);
+      }
+    }
+  }
+
+  /**
+   * Prefix for temp locals.
+   */
+  private static final String PREFIX = "$t";
+
+  private JMethodBody curMethodBody = null;
+  private Scope curScope = null;
+  private final Stack<Context> insertionStack = new Stack<Context>();
+  private Map<JBlock, Scope> scopes = null;
+
+  @Override
+  public final void endVisit(JBlock x, Context ctx) {
+    exit(x);
+    super.endVisit(x, ctx);
+  }
+
+  @Override
+  public final void endVisit(JMethodBody x, Context ctx) {
+    curMethodBody = null;
+    scopes = null;
+    super.endVisit(x, ctx);
+  }
+
+  @Override
+  public final void endVisit(JStatement x, Context ctx) {
+    if (ctx.canInsert()) {
+      Context popped = insertionStack.pop();
+      assert popped == ctx;
+    }
+    super.endVisit(x, ctx);
+  }
+
+  @Override
+  public final boolean visit(JBlock x, Context ctx) {
+    enter(x);
+    return super.visit(x, ctx);
+  }
+
+  @Override
+  public final boolean visit(JMethodBody x, Context ctx) {
+    curMethodBody = x;
+    scopes = new HashMap<JBlock, Scope>();
+    new CollectScopes(scopes).accept(x);
+    return super.visit(x, ctx);
+  }
+
+  @Override
+  public final boolean visit(JStatement x, Context ctx) {
+    if (ctx.canInsert()) {
+      insertionStack.push(ctx);
+    }
+    return super.visit(x, ctx);
+  }
+
+  protected JLocal createTempLocal(SourceInfo info, JType type) {
+    int tempNum = curScope.allocateNextFreeTemp();
+    String name = PREFIX + tempNum;
+ JLocal local = JProgram.createLocal(info, name, type, false, curMethodBody); + JDeclarationStatement init = new JDeclarationStatement(info, new JLocalRef(
+        info, local), null);
+    insertionStack.peek().insertBefore(init);
+    return local;
+  }
+
+  private boolean enter(JBlock x) {
+    Scope enterScope = scopes.get(x);
+    assert enterScope.parent == curScope;
+    curScope = enterScope;
+    enterScope.enter();
+    return true;
+  }
+
+  private void exit(JBlock x) {
+    assert scopes.get(x) == curScope;
+    curScope.exit();
+    curScope = curScope.parent;
+  }
+}
=======================================
--- /dev/null
+++ /branches/2.1/dev/core/test/com/google/gwt/dev/jjs/impl/TempLocalVisitorTest.java Mon Apr 26 10:59:53 2010
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2010 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.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JBinaryOperation;
+import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
+import com.google.gwt.dev.jjs.ast.JExpression;
+import com.google.gwt.dev.jjs.ast.JLocal;
+import com.google.gwt.dev.jjs.ast.JLocalRef;
+import com.google.gwt.dev.jjs.ast.JMethod;
+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.JType;
+
+/**
+ * Test for {...@link TempLocalVisitor}.
+ */
+public class TempLocalVisitorTest extends OptimizerTestBase {
+  /**
+   * For testing purposes; replaces all non-lvalue expressions with a temp.
+   */
+  private static final class AlwaysReplacer extends TempLocalVisitor {
+    @Override
+    public void endVisit(JExpression x, Context ctx) {
+      SourceInfo info = x.getSourceInfo();
+      JType type = x.getType();
+      JLocal local = createTempLocal(info, type);
+      local.getDeclarationStatement().initializer = x;
+      ctx.replaceMe(new JLocalRef(info, local));
+    }
+
+    @Override
+    public boolean visit(JBinaryOperation x, Context ctx) {
+      super.visit(x, ctx);
+      if (x.getRhs() != null) {
+        JExpression newRhs = accept(x.getRhs());
+        if (newRhs != x.getRhs()) {
+ ctx.replaceMe(new JBinaryOperation(x.getSourceInfo(), x.getType(),
+              x.getOp(), x.getLhs(), newRhs));
+        }
+      }
+      return false;
+    }
+
+    @Override
+    public boolean visit(JDeclarationStatement x, Context ctx) {
+      super.visit(x, ctx);
+      if (x.initializer != null) {
+        x.initializer = accept(x.initializer);
+      }
+      return false;
+    }
+
+    @Override
+    public boolean visit(JPostfixOperation x, Context ctx) {
+      if (x.getOp().isModifying()) {
+        return false;
+      }
+      return true;
+    }
+
+    @Override
+    public boolean visit(JPrefixOperation x, Context ctx) {
+      if (x.getOp().isModifying()) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  private final class Result {
+    private final String optimized;
+    private final String returnType;
+    private final String userCode;
+
+    public Result(String returnType, String userCode, String optimized) {
+      this.returnType = returnType;
+      this.userCode = userCode;
+      this.optimized = optimized;
+    }
+
+    public void into(String expected) throws UnableToCompleteException {
+      JProgram program = compileSnippet(returnType, expected);
+      expected = getMainMethodSource(program);
+      assertEquals(userCode, expected, optimized);
+    }
+  }
+
+  public void testBasic() throws Exception {
+    assertTransform("int i = 3;").into("int $t0 = 3; int i = $t0;");
+  }
+
+  public void testExisting() throws Exception {
+    assertTransform("int $t0 = 3; int i = $t0;").into(
+        "int $t1 = 3; int $t0 = $t1; int $t2 = $t0; int i = $t2;");
+  }
+
+  public void testForStatement() throws Exception {
+    StringBuilder original = new StringBuilder();
+    original.append("for (int i = 3; true; );");
+
+    StringBuilder expected = new StringBuilder();
+    /*
+     * TODO(scottb): technically $t1 could be part of the for statement's
+     * initializer list.
+     */
+    expected.append("boolean $t1 = true;");
+    expected.append("for (int $t0 = 3, i = $t0; $t1; );");
+
+    assertTransform(original.toString()).into(expected.toString());
+  }
+
+  public void testForStatementScoping() throws Exception {
+    StringBuilder original = new StringBuilder();
+    original.append("boolean f = false;");
+    original.append("for (int i = 3; f; );");
+    original.append("int j = 4;");
+
+    StringBuilder expected = new StringBuilder();
+    expected.append("boolean $t0 = false;");
+    expected.append("boolean f = $t0;");
+    expected.append("boolean $t2 = f;");
+    expected.append("for (int $t1 = 3, i = $t1; $t2; );");
+    /*
+ * TODO(scottb): technically we could reuse $t1 here as a minor improvement.
+     */
+    expected.append("int $t3 = 4; int j = $t3;");
+
+    assertTransform(original.toString()).into(expected.toString());
+  }
+
+  public void testNested() throws Exception {
+ assertTransform("{ int i = 3; } ").into("{ int $t0 = 3; int i = $t0; }");
+  }
+
+  public void testNestedPost() throws Exception {
+    StringBuilder original = new StringBuilder();
+    original.append("int i = 3;");
+    original.append("{ int j = 4; }");
+
+    StringBuilder expected = new StringBuilder();
+    expected.append("int $t0 = 3; int i = $t0;");
+    expected.append("{ int $t1 = 4; int j = $t1; }");
+
+    assertTransform(original.toString()).into(expected.toString());
+  }
+
+  public void testNestedPre() throws Exception {
+    StringBuilder original = new StringBuilder();
+    original.append("{ int i = 3; }");
+    original.append("int j = 4;");
+
+    StringBuilder expected = new StringBuilder();
+    expected.append("{ int $t0 = 3; int i = $t0; }");
+    expected.append("int $t1 = 4; int j = $t1;");
+
+    assertTransform(original.toString()).into(expected.toString());
+  }
+
+  public void testReuse() throws Exception {
+    StringBuilder original = new StringBuilder();
+    original.append("{ int i = 3; }");
+    original.append("{ int j = 4; }");
+
+    StringBuilder expected = new StringBuilder();
+    expected.append("{ int $t0 = 3; int i = $t0; }");
+    expected.append("{ int $t0 = 4; int j = $t0; }");
+
+    assertTransform(original.toString()).into(expected.toString());
+  }
+
+  public void testReuseTwice() throws Exception {
+    StringBuilder original = new StringBuilder();
+    original.append("{ int i = 3; int j = 4; }");
+    original.append("{ int i = 3; int j = 4; }");
+
+    StringBuilder expected = new StringBuilder();
+ expected.append("{ int $t0 = 3; int i = $t0; int $t1 = 4; int j = $t1; }"); + expected.append("{ int $t0 = 3; int i = $t0; int $t1 = 4; int j = $t1; }");
+
+    assertTransform(original.toString()).into(expected.toString());
+  }
+
+  public void testVeryComplex() throws Exception {
+    StringBuilder original = new StringBuilder();
+    original.append("int a = 0;");
+    original.append("{ int i = 3; int j = 4; }");
+    original.append("int b = 1;");
+    original.append("{ int i = 3; int j = 4; }");
+    original.append("int c = 2;");
+
+    StringBuilder expected = new StringBuilder();
+    expected.append("int $t0 = 0; int a = $t0;");
+ expected.append("{ int $t1 = 3; int i = $t1; int $t2 = 4; int j = $t2; }");
+    expected.append("int $t3 = 1; int b = $t3;");
+ expected.append("{ int $t1 = 3; int i = $t1; int $t2 = 4; int j = $t2; }");
+    expected.append("int $t4 = 2; int c = $t4;");
+
+    assertTransform(original.toString()).into(expected.toString());
+  }
+
+  private Result assertTransform(String codeSnippet)
+      throws UnableToCompleteException {
+    JProgram program = compileSnippet("void", codeSnippet);
+    JMethod mainMethod = findMainMethod(program);
+    new AlwaysReplacer().accept(mainMethod);
+ return new Result("void", codeSnippet, mainMethod.getBody().toSource());
+  }
+}
=======================================
--- /branches/2.1/dev/core/src/com/google/gwt/dev/jjs/impl/CompoundAssignmentNormalizer.java Fri Apr 2 14:35:01 2010 +++ /branches/2.1/dev/core/src/com/google/gwt/dev/jjs/impl/CompoundAssignmentNormalizer.java Mon Apr 26 10:59:53 2010
@@ -26,25 +26,16 @@
 import com.google.gwt.dev.jjs.ast.JLocal;
 import com.google.gwt.dev.jjs.ast.JLocalRef;
 import com.google.gwt.dev.jjs.ast.JLongLiteral;
-import com.google.gwt.dev.jjs.ast.JMethodBody;
 import com.google.gwt.dev.jjs.ast.JModVisitor;
 import com.google.gwt.dev.jjs.ast.JNode;
 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.JPrimitiveType;
-import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JThisRef;
-import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.dev.jjs.ast.JUnaryOperator;
 import com.google.gwt.dev.jjs.ast.js.JMultiExpression;

-import java.util.ArrayList;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Stack;
-
 /**
  * <p>
  * Replace problematic compound assignments with a sequence of simpler
@@ -75,7 +66,80 @@
   /**
    * Breaks apart certain complex assignments.
    */
-  private class BreakupAssignOpsVisitor extends JModVisitor {
+  private class BreakupAssignOpsVisitor extends TempLocalVisitor {
+
+    /**
+     * Replaces side effects in lvalue.
+     */
+    private class ReplaceSideEffectsInLvalue extends JModVisitor {
+
+      private final JMultiExpression multi;
+
+      ReplaceSideEffectsInLvalue(JMultiExpression multi) {
+        this.multi = multi;
+      }
+
+      public JMultiExpression getMultiExpr() {
+        return multi;
+      }
+
+      @Override
+      public boolean visit(JArrayRef x, Context ctx) {
+        JExpression newInstance = possiblyReplace(x.getInstance());
+        JExpression newIndexExpr = possiblyReplace(x.getIndexExpr());
+ if (newInstance != x.getInstance() || newIndexExpr != x.getIndexExpr()) {
+          JArrayRef newExpr = new JArrayRef(x.getSourceInfo(), newInstance,
+              newIndexExpr);
+          ctx.replaceMe(newExpr);
+        }
+        return false;
+      }
+
+      @Override
+      public boolean visit(JFieldRef x, Context ctx) {
+        if (x.getInstance() != null) {
+          JExpression newInstance = possiblyReplace(x.getInstance());
+          if (newInstance != x.getInstance()) {
+ JFieldRef newExpr = new JFieldRef(x.getSourceInfo(), newInstance,
+                x.getField(), x.getEnclosingType());
+            ctx.replaceMe(newExpr);
+          }
+        }
+        return false;
+      }
+
+      @Override
+      public boolean visit(JLocalRef x, Context ctx) {
+        return false;
+      }
+
+      @Override
+      public boolean visit(JParameterRef x, Context ctx) {
+        return false;
+      }
+
+      @Override
+      public boolean visit(JThisRef x, Context ctx) {
+        return false;
+      }
+
+      private JExpression possiblyReplace(JExpression x) {
+        if (!x.hasSideEffects()) {
+          return x;
+        }
+
+        // Create a temp local
+        JLocal tempLocal = createTempLocal(x.getSourceInfo(), x.getType());
+
+        // Create an assignment for this temp and add it to multi.
+        JLocalRef tempRef = new JLocalRef(x.getSourceInfo(), tempLocal);
+        JBinaryOperation asg = new JBinaryOperation(x.getSourceInfo(),
+            x.getType(), JBinaryOperator.ASG, tempRef, x);
+        multi.exprs.add(asg);
+        // Update me with the temp
+        return cloner.cloneExpression(tempRef);
+      }
+    }

     @Override
     public void endVisit(JBinaryOperation x, Context ctx) {
@@ -93,11 +157,9 @@
* expressions that could have side effects with temporaries, so that they
        * are only run once.
        */
-      enterTempUsageScope();
       ReplaceSideEffectsInLvalue replacer = new ReplaceSideEffectsInLvalue(
           new JMultiExpression(x.getSourceInfo()));
       JExpression newLhs = replacer.accept(x.getLhs());
-      exitTempUsageScope();

       JBinaryOperation operation = new JBinaryOperation(x.getSourceInfo(),
           newLhs.getType(), op.getNonAssignmentOf(), newLhs, x.getRhs());
@@ -116,12 +178,6 @@
         ctx.replaceMe(multiExpr);
       }
     }
-
-    @Override
-    public void endVisit(JMethodBody x, Context ctx) {
-      clearLocals();
-      currentMethodBody = null;
-    }

     @Override
     public void endVisit(JPostfixOperation x, Context ctx) {
@@ -137,7 +193,6 @@
       // (t = x, x += 1, t)

       // First, replace the arg with a non-side-effect causing one.
-      enterTempUsageScope();
       JMultiExpression multi = new JMultiExpression(x.getSourceInfo());
       ReplaceSideEffectsInLvalue replacer = new ReplaceSideEffectsInLvalue(
           multi);
@@ -146,7 +201,8 @@
       JExpression expressionReturn = expressionToReturn(newArg);

       // Now generate the appropriate expressions.
-      JLocal tempLocal = getTempLocal(expressionReturn.getType());
+      JLocal tempLocal = createTempLocal(x.getSourceInfo(),
+          expressionReturn.getType());

       // t = x
       JLocalRef tempRef = new JLocalRef(x.getSourceInfo(), tempLocal);
@@ -164,7 +220,6 @@
       multi.exprs.add(tempRef);

       ctx.replaceMe(multi);
-      exitTempUsageScope();
     }

     @Override
@@ -184,13 +239,6 @@
       // Visit the result to break it up even more.
       ctx.replaceMe(accept(asg));
     }
-
-    @Override
-    public boolean visit(JMethodBody x, Context ctx) {
-      currentMethodBody = x;
-      clearLocals();
-      return true;
-    }

     private JBinaryOperation createAsgOpFromUnary(JExpression arg,
         JUnaryOperator op) {
@@ -221,165 +269,7 @@
     }
   }

-  /**
-   * Replaces side effects in lvalue.
-   */
-  private class ReplaceSideEffectsInLvalue extends JModVisitor {
-
-    private final JMultiExpression multi;
-
-    ReplaceSideEffectsInLvalue(JMultiExpression multi) {
-      this.multi = multi;
-    }
-
-    public JMultiExpression getMultiExpr() {
-      return multi;
-    }
-
-    @Override
-    public boolean visit(JArrayRef x, Context ctx) {
-      JExpression newInstance = possiblyReplace(x.getInstance());
-      JExpression newIndexExpr = possiblyReplace(x.getIndexExpr());
- if (newInstance != x.getInstance() || newIndexExpr != x.getIndexExpr()) {
-        JArrayRef newExpr = new JArrayRef(x.getSourceInfo(), newInstance,
-            newIndexExpr);
-        ctx.replaceMe(newExpr);
-      }
-      return false;
-    }
-
-    @Override
-    public boolean visit(JFieldRef x, Context ctx) {
-      if (x.getInstance() != null) {
-        JExpression newInstance = possiblyReplace(x.getInstance());
-        if (newInstance != x.getInstance()) {
-          JFieldRef newExpr = new JFieldRef(x.getSourceInfo(), newInstance,
-              x.getField(), x.getEnclosingType());
-          ctx.replaceMe(newExpr);
-        }
-      }
-      return false;
-    }
-
-    @Override
-    public boolean visit(JLocalRef x, Context ctx) {
-      return false;
-    }
-
-    @Override
-    public boolean visit(JParameterRef x, Context ctx) {
-      return false;
-    }
-
-    @Override
-    public boolean visit(JThisRef x, Context ctx) {
-      return false;
-    }
-
-    private JExpression possiblyReplace(JExpression x) {
-      if (!x.hasSideEffects()) {
-        return x;
-      }
-
-      // Create a temp local
-      JLocal tempLocal = getTempLocal(x.getType());
-
-      // Create an assignment for this temp and add it to multi.
-      JLocalRef tempRef = new JLocalRef(x.getSourceInfo(), tempLocal);
- JBinaryOperation asg = new JBinaryOperation(x.getSourceInfo(), x.getType(),
-          JBinaryOperator.ASG, tempRef, x);
-      multi.exprs.add(asg);
-      // Update me with the temp
-      return cloner.cloneExpression(tempRef);
-    }
-  }
-
-  /**
- * For some particular type, tracks all usage of temporary local variables of
-   * that type within the current method.
-   */
-  private static class TempLocalTracker {
-    /**
- * Temps previously created in nested usage scopes that are now available
-     * for reuse by subsequent code.
-     */
-    private List<JLocal> reusable = new ArrayList<JLocal>();
-
-    /**
- * Temps in use in active scopes. They cannot currently be reused; however,
-     * any time a scope is exited, the set of locals at the top of stack is
- * popped off and all contained locals become reusable. The top of stack
-     * correlates to the current scope.
-     */
-    private Stack<List<JLocal>> usageStack = new Stack<List<JLocal>>();
-
-    public TempLocalTracker() {
-      /*
-       * Due to the lazy-creation nature, we must assume upon creation that
- * we're already in a valid scope (and thus create the initial empty scope
-       * ourselves).
-       */
-      enterScope();
-    }
-
-    public void enterScope() {
-      usageStack.push(new ArrayList<JLocal>());
-    }
-
-    public void exitScope() {
-      /*
-       * Due to the lazy-creation nature, the program flow might be several
- * levels deep already when this object is created. Since we don't know - * how many exitScope() calls to accept, we must be empty-tolerant. In
-       * other words, this isn't naively defensive programming. :)
-       */
-      if (!usageStack.isEmpty()) {
-        List<JLocal> freed = usageStack.pop();
-        reusable.addAll(freed);
-      }
-    }
-
-    public JLocal tryGetReusableLocal() {
-      if (!reusable.isEmpty()) {
-        return reusable.remove(reusable.size() - 1);
-      }
-      return null;
-    }
-
-    public void useLocal(JLocal local) {
-      usageStack.peek().add(local);
-    }
-  }
-
-  private final CloneExpressionVisitor cloner;
-
-  private JMethodBody currentMethodBody;
-
-  /**
- * Counter to generate a unique name for each temporary within the current
-   * method.
-   */
-  private int localCounter;
-
-  /**
-   * Map of type onto lazily-created local tracker.
-   */
- private Map<JType, TempLocalTracker> localTrackers = new IdentityHashMap<JType, TempLocalTracker>();
-
-  /**
-   * If <code>true</code>, reuse temps. The pre-optimization subclass does
- * not reuse temps because doing so can defeat optimizations because different
-   * uses impact each other and we do nothing to disambiguate usage. After
- * optimizations, it makes sense to reuse temps to reduce code size and memory
-   * consumption of the output.
-   */
-  private final boolean reuseTemps;
-
-  protected CompoundAssignmentNormalizer(boolean reuseTemps) {
-    this.reuseTemps = reuseTemps;
-    cloner = new CloneExpressionVisitor();
-    clearLocals();
-  }
+ private final CloneExpressionVisitor cloner = new CloneExpressionVisitor();

   public void accept(JNode node) {
     BreakupAssignOpsVisitor breaker = new BreakupAssignOpsVisitor();
@@ -394,56 +284,10 @@
   protected JExpression expressionToReturn(JExpression lhs) {
     return lhs;
   }
-
-  protected abstract String getTempPrefix();

   protected abstract boolean shouldBreakUp(JBinaryOperation x);

   protected abstract boolean shouldBreakUp(JPostfixOperation x);

   protected abstract boolean shouldBreakUp(JPrefixOperation x);
-
-  private void clearLocals() {
-    localCounter = 0;
-    localTrackers.clear();
-  }
-
-  private void enterTempUsageScope() {
-    for (TempLocalTracker tracker : localTrackers.values()) {
-      tracker.enterScope();
-    }
-  }
-
-  private void exitTempUsageScope() {
-    for (TempLocalTracker tracker : localTrackers.values()) {
-      tracker.exitScope();
-    }
-  }
-
-  /**
-   * Allocate a temporary local variable.
-   */
-  private JLocal getTempLocal(JType type) {
-    TempLocalTracker tracker = localTrackers.get(type);
-    if (tracker == null) {
-      tracker = new TempLocalTracker();
-      localTrackers.put(type, tracker);
-    }
-
-    JLocal temp = null;
-    if (reuseTemps) {
-      /*
-       * If the return is non-null, we now "own" the returned JLocal; it's
- * important to call tracker.useLocal() on the returned value (below).
-       */
-      temp = tracker.tryGetReusableLocal();
-    }
-
-    if (temp == null) {
-      temp = JProgram.createLocal(currentMethodBody.getSourceInfo(),
- getTempPrefix() + localCounter++, type, false, currentMethodBody);
-    }
-    tracker.useLocal(temp);
-    return temp;
-  }
-}
+}
=======================================
--- /branches/2.1/dev/core/src/com/google/gwt/dev/jjs/impl/FixAssignmentToUnbox.java Fri Apr 2 14:35:01 2010 +++ /branches/2.1/dev/core/src/com/google/gwt/dev/jjs/impl/FixAssignmentToUnbox.java Mon Apr 26 10:59:53 2010
@@ -52,7 +52,6 @@
     private final AutoboxUtils autoboxUtils;

     protected CompoundAssignmentToUnboxNormalizer(JProgram program) {
-      super(false);
       autoboxUtils = new AutoboxUtils(program);
     }

@@ -68,11 +67,6 @@
       }
       return lhs;
     }
-
-    @Override
-    protected String getTempPrefix() {
-      return "$tunbox";
-    }

     @Override
     protected boolean shouldBreakUp(JBinaryOperation x) {
=======================================
--- /branches/2.1/dev/core/src/com/google/gwt/dev/jjs/impl/PostOptimizationCompoundAssignmentNormalizer.java Fri Apr 2 14:35:01 2010 +++ /branches/2.1/dev/core/src/com/google/gwt/dev/jjs/impl/PostOptimizationCompoundAssignmentNormalizer.java Mon Apr 26 10:59:53 2010
@@ -33,12 +33,6 @@
   }

   protected PostOptimizationCompoundAssignmentNormalizer() {
-    super(true);
-  }
-
-  @Override
-  protected String getTempPrefix() {
-    return "$t";
   }

   @Override
=======================================
--- /branches/2.1/dev/core/test/com/google/gwt/dev/jjs/impl/SameParameterValueOptimizerTest.java Fri Feb 12 08:53:54 2010 +++ /branches/2.1/dev/core/test/com/google/gwt/dev/jjs/impl/SameParameterValueOptimizerTest.java Mon Apr 26 10:59:53 2010
@@ -1,5 +1,18 @@
-// Copyright 2009 Google Inc. All Rights Reserved.
-
+/*
+ * Copyright 2009 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.core.ext.UnableToCompleteException;

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to