Package com.google.gwt.dev.jjs.impl

Source Code of com.google.gwt.dev.jjs.impl.CompoundAssignmentNormalizer$ReplaceSideEffectsInLvalue

/*
* Copyright 2007 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.JArrayRef;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBinaryOperator;
import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JFieldRef;
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.JModVisitor;
import com.google.gwt.dev.jjs.ast.JNullLiteral;
import com.google.gwt.dev.jjs.ast.JParameterRef;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JThisRef;
import com.google.gwt.dev.jjs.ast.js.JMultiExpression;

import java.util.ArrayList;
import java.util.List;

/**
* Replace any complex assignments that will cause problems down the road with
* broken expressions; replace side-effect expressions in the lhs with temps to
* prevent multiple evaluation.
*/
public class CompoundAssignmentNormalizer {

  /**
   * Breaks apart certain complex assignments.
   */
  private class BreakupAssignOpsVisitor extends JModVisitor {

    // @Override
    public void endVisit(JBinaryOperation x, Context ctx) {
      /*
       * Convert to a normal divide operation so we can cast the result. Since
       * the left hand size must be computed twice, we have to replace any
       * left-hand side expressions that could have side effects with
       * temporaries, so that they are only run once.
       */
      if (x.getOp() == JBinaryOperator.ASG_DIV
          && x.getType() != program.getTypePrimitiveFloat()
          && x.getType() != program.getTypePrimitiveDouble()) {

        /*
         * Convert to a normal divide operation so we can cast the result. Since
         * the left hand size must be computed twice, we have to replace any
         * left-hand side expressions that could have side effects with
         * temporaries, so that they are only run once.
         */
        final int pushUsedLocals = localIndex;
        JMultiExpression multi = new JMultiExpression(program,
            x.getSourceInfo());
        ReplaceSideEffectsInLvalue replacer = new ReplaceSideEffectsInLvalue(
            multi);
        JExpression newLhs = replacer.accept(x.getLhs());
        localIndex = pushUsedLocals;

        JNullLiteral litNull = program.getLiteralNull();
        JBinaryOperation operation = new JBinaryOperation(program,
            x.getSourceInfo(), newLhs.getType(), JBinaryOperator.DIV, newLhs,
            x.getRhs());
        JBinaryOperation asg = new JBinaryOperation(program, x.getSourceInfo(),
            newLhs.getType(), JBinaryOperator.ASG, newLhs, operation);

        JMultiExpression multiExpr = replacer.getMultiExpr();
        if (multiExpr.exprs.isEmpty()) {
          // just use the split assignment expression
          ctx.replaceMe(asg);
        } else {
          // add the assignment as the last item in the multi
          multi.exprs.add(asg);
          ctx.replaceMe(multi);
        }
      }
    }

    // @Override
    public void endVisit(JMethod x, Context ctx) {
      clearLocals();
      currentMethod = null;
    }

    // @Override
    public boolean visit(JMethod x, Context ctx) {
      currentMethod = x;
      clearLocals();
      return true;
    }
  }
  /**
   * 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(program, 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(program, 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();

      // Create an assignment for this temp and add it to multi.
      JLocalRef tempRef = new JLocalRef(program, x.getSourceInfo(), tempLocal);
      JBinaryOperation asg = new JBinaryOperation(program, x.getSourceInfo(),
          x.getType(), JBinaryOperator.ASG, tempRef, x);
      multi.exprs.add(asg);
      // Update me with the temp
      return tempRef;
    }
  }

  public static void exec(JProgram program) {
    new CompoundAssignmentNormalizer(program).execImpl();
  }

  private JMethod currentMethod;
  private int localIndex;
  private final JProgram program;
  private final List/* <JLocal> */tempLocals = new ArrayList/* <JLocal> */();

  private CompoundAssignmentNormalizer(JProgram program) {
    this.program = program;
  }

  private void clearLocals() {
    tempLocals.clear();
    localIndex = 0;
  }

  private void execImpl() {
    BreakupAssignOpsVisitor breaker = new BreakupAssignOpsVisitor();
    breaker.accept(program);
  }

  private JLocal getTempLocal() {
    if (localIndex < tempLocals.size()) {
      return (JLocal) tempLocals.get(localIndex++);
    }
    JLocal newTemp = program.createLocal(null,
        ("$t" + localIndex++).toCharArray(), program.getTypeVoid(), false,
        currentMethod);
    tempLocals.add(newTemp);
    return newTemp;
  }

}
TOP

Related Classes of com.google.gwt.dev.jjs.impl.CompoundAssignmentNormalizer$ReplaceSideEffectsInLvalue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.