Package dk.brics.xact.analysis.transformations

Source Code of dk.brics.xact.analysis.transformations.ArrayTransformer$Component

package dk.brics.xact.analysis.transformations;

import java.util.LinkedHashSet;

import dk.brics.automaton.Automaton;
import dk.brics.xact.analysis.Debug;
import dk.brics.xact.analysis.flowgraph.Edge;
import dk.brics.xact.analysis.flowgraph.FlowGraph;
import dk.brics.xact.analysis.flowgraph.Statement;
import dk.brics.xact.analysis.flowgraph.Variable;
import dk.brics.xact.analysis.flowgraph.VariableFilter;
import dk.brics.xact.analysis.flowgraph.statements.AnalyzeStm;
import dk.brics.xact.analysis.flowgraph.statements.ArrayReadStm;
import dk.brics.xact.analysis.flowgraph.statements.ArrayWriteStm;
import dk.brics.xact.analysis.flowgraph.statements.ArrayWriteStringStm;
import dk.brics.xact.analysis.flowgraph.statements.Assignment;
import dk.brics.xact.analysis.flowgraph.statements.BasicStatementVisitor;
import dk.brics.xact.analysis.flowgraph.statements.CallStm;
import dk.brics.xact.analysis.flowgraph.statements.CastStm;
import dk.brics.xact.analysis.flowgraph.statements.CheckStm;
import dk.brics.xact.analysis.flowgraph.statements.ConcatStm;
import dk.brics.xact.analysis.flowgraph.statements.ConstStm;
import dk.brics.xact.analysis.flowgraph.statements.CopyStm;
import dk.brics.xact.analysis.flowgraph.statements.EmptyStm;
import dk.brics.xact.analysis.flowgraph.statements.EscapeStm;
import dk.brics.xact.analysis.flowgraph.statements.GapifyStm;
import dk.brics.xact.analysis.flowgraph.statements.GetStm;
import dk.brics.xact.analysis.flowgraph.statements.InsertStm;
import dk.brics.xact.analysis.flowgraph.statements.NodeStm;
import dk.brics.xact.analysis.flowgraph.statements.NopStm;
import dk.brics.xact.analysis.flowgraph.statements.PlugStm;
import dk.brics.xact.analysis.flowgraph.statements.RemoveStm;
import dk.brics.xact.analysis.flowgraph.statements.SetStm;
import dk.brics.xact.analysis.flowgraph.statements.StatementVisitor;
import dk.brics.xact.analysis.flowgraph.statements.UnknownStm;
import dk.brics.xact.analysis.flowgraph.statements.ValidateStm;
import dk.brics.xact.analysis.flowgraph.statements.VarStm;
import dk.brics.xact.analysis.soot.ControlFlowBuilder;
import dk.brics.xact.analysis.soot.StatementPair;
import dk.brics.xact.analysis.util.UnionFindForest;

/**
* Flow graph transformation for linking array variables using weak updating.
* All assignments of a non-array value to an array is made into a weak update.
* All assignments between array variables cause variable aliasing.
* Aliased variables are joined.
* Arrays are classified as XML arrays and non-XML arrays. Concat statements
* whose argument is an XML array have their string source replaced by the
* empty language automaton.
*/
public class ArrayTransformer {

  /**
   * Constructs a new <code>ArrayTransformer</code>.
   */
  public ArrayTransformer() {}

  private static class Component {
    public boolean array;
    public boolean escaped;
    public Automaton stringsrc;
    public Component() {
      this.array = this.escaped = false;
      this.stringsrc = Automaton.makeEmpty();
    }
  }

  /**
   * Transforms the given flow graph.
   */
  public void run(final FlowGraph graph) {
    final ControlFlowBuilder cfg = new ControlFlowBuilder(graph, null);
    final UnionFindForest<Variable,Component> var_alias = new UnionFindForest<Variable, Component>() {
      @Override
      protected Component mergeNodeData(Component a, Component b) {
        a.array |= b.array;
        a.escaped |= b.escaped;
        a.stringsrc = a.stringsrc.union(b.stringsrc);
        return a;
      }
      @Override
      protected Component defaultNodeData() {
        return new Component();
      }
    };
    for (Statement s : graph.getNodes()) {
      s.visitBy(new BasicStatementVisitor() {
        @Override
        public void visitEmptyStm(EmptyStm s) {
          if (s.isArray()) {
            var_alias.getData(s.getDest()).array = true;
          }
        }
        @Override
        public void visitEscapeStm(EscapeStm s) {
          var_alias.getData(s.getVar()).escaped = true;
        }
        @Override
        public void visitUnknownStm(UnknownStm s) {
          var_alias.getData(s.getDest()).escaped = true;
        }
        @Override
        public void visitArrayWriteStringStm(ArrayWriteStringStm s) {
          Component c = var_alias.getData(s.getDest());
          c.stringsrc = c.stringsrc.union(s.getStringsrc());
        }
        @Override
        public void visitArrayReadStm(ArrayReadStm s) {
          var_alias.getData(s.getSource()).array = true;
        }
        @Override
        public void visitArrayWriteStm(ArrayWriteStm s) {
          var_alias.getData(s.getDest()).array = true;
        }
        @Override
        public void visitConcatStm(ConcatStm s) {
          var_alias.getData(s.getXMLSource()).array = true;
        }
        @Override
        public void visitPlugStm(PlugStm s) {
          if (s.getKind() == PlugStm.Kind.PLUGMULTI || s.getKind() == PlugStm.Kind.PLUGWRAP)
            var_alias.getData(s.getXMLSource()).array = true;
        }
        @Override
        public void visitVarStm(VarStm s) {
          var_alias.merge(s.getSource(), s.getDest());
        }
      });
    }
    for (Statement s : new LinkedHashSet<Statement>(graph.getNodes())) {
      if (s instanceof Assignment) {
        if (var_alias.getData(((Assignment) s).getDest()).array) {
          NopStm nop = new NopStm(s.getOrigin());
          graph.addNode(nop);
          for (Edge<Statement,VariableFilter> e : graph.getInEdges(s)) {
            graph.addEdge(e.getFrom(), nop, e.getData());
          }
          for (Edge<Statement,VariableFilter> e : graph.getOutEdges(s)) {
            graph.addEdge(nop, e.getTo(), e.getData());
          }
        }
      }
      s.visitBy(new BasicStatementVisitor() {
        private void replace(Statement old, StatementPair st) {
          replaceNode(graph, old, st);
        }

        @Override
        public void visitArrayWriteStringStm(ArrayWriteStringStm s) {
          replace(s, cfg.finish()); // replace the statement with a nop
        }
        @Override
        public void visitArrayReadStm(ArrayReadStm s) {
          // merge arrays if one array is stored in the other
          if (var_alias.getData(s.getDest()).array) {
            var_alias.merge(s.getSource(), s.getDest());
          }
          cfg.addStatement(new VarStm(s.getDest(), s.getSource(), s.getOrigin()));
          replace(s, cfg.finish());
        }
        @Override
        public void visitArrayWriteStm(ArrayWriteStm s) {
          // merge arrays if one array is stored in the other
          if (var_alias.getData(s.getSource()).array) {
            var_alias.merge(s.getSource(), s.getDest());
          }
          cfg.addStatement(new VarStm(s.getDest(), s.getSource(), s.getOrigin()));
          replace(s, cfg.finish());
        }
        @Override
        public void visitCallStm(CallStm s) {
          for (int i=0; i<s.getArguments().length; i++) {
            // merge argument and parameter if either one is used as an array
            Variable arg = s.getArgument(i);
            Variable param = s.getMethod().getParameter(i);
            if (var_alias.getData(arg).array || var_alias.getData(param).array) {
              var_alias.merge(arg, param);
              s.setArgumentMutable(i, true);
            }
          }
          // merge return var and result if ether one is used as an array
          if (var_alias.getData(s.getResult()).array || var_alias.getData(s.getMethod().getReturnVar()).array) {
            var_alias.merge(s.getResult(), s.getMethod().getReturnVar());
          }
        }
        @Override
        public void visitEscapeStm(EscapeStm s) {
          Component c = var_alias.getData(s.getVar());
          if (c.array) {
            cfg.addStatement(new UnknownStm(s.getVar(), s.getOrigin()));
            replace(s, cfg.finish());
          } else {
            cfg.setOrigin(s.getOrigin());
            replace(s, cfg.finish());
          }
        }
      });
    }
    // replace each variable by its component representative IF the representative is an array
    for (Statement s : graph.getNodes()) {

      // replace variables in nodes
      s.visitBy(new StatementVisitor() {

        private Variable getrep(Variable var) {
          return var_alias.getRepresentativeKey(var);
        }

        private Variable replace(Variable var) {
          Variable rep = getrep(var);
          if (!var_alias.getData(rep).array) {
            return var;
          } else {
            Debug.println(6, true, "Aliasing: " + var);
            return rep;
          }
        }
        private Automaton getStringSource(Variable var) {
          return var_alias.getData(var).stringsrc;
        }

        public void visitAnalyzeStm(AnalyzeStm s) {
          s.setBase(replace(s.getBase()));
          s.setDest(replace(s.getDest()));
        }

        public void visitConcatStm(ConcatStm s) {
          s.setDest(replace(s.getDest()));
          s.setXMLSource(replace(s.getXMLSource()));
          s.setStringSource(getStringSource(s.getXMLSource()));
        }

        public void visitConstStm(ConstStm s) {
          s.setDest(replace(s.getDest()));
        }

        public void visitCopyStm(CopyStm s) {
          s.setBase(replace(s.getBase()));
          s.setDest(replace(s.getDest()));
          if (s.getFirstChild() != null)
            s.setFirstChild(replace(s.getFirstChild()));
          if (s.getFirstAttr() != null)
            s.setFirstAttr(replace(s.getFirstAttr()));
          if (s.getNextNode() != null)
            s.setNextNode(replace(s.getNextNode()));
        }

        public void visitCastStm(CastStm s) {
          s.setBase(replace(s.getBase()));
          s.setDest(replace(s.getDest()));
        }

        public void visitCheckStm(CheckStm s) {
          if (s.getBase() != null)
            s.setBase(replace(s.getBase()));
        }

        public void visitEmptyStm(EmptyStm s) {
          s.setDest(replace(s.getDest()));
        }

        public void visitGapifyStm(GapifyStm s) {
          s.setBase(replace(s.getBase()));
          s.setDest(replace(s.getDest()));
        }

        public void visitGetStm(GetStm s) {
          s.setBase(replace(s.getBase()));
          s.setDest(replace(s.getDest()));
        }

        public void visitInsertStm(InsertStm s) {
          s.setBase(replace(s.getBase()));
          s.setDest(replace(s.getDest()));
          if (s.getXMLSource() != null)
            s.setXMLSource(replace(s.getXMLSource()));
        }

        public void visitNodeStm(NodeStm s) {
          s.setDest(replace(s.getDest()));
          if (s.getFirstChild() != null)
            s.setFirstChild(replace(s.getFirstChild()));
          if (s.getFirstAttr() != null)
            s.setFirstAttr(replace(s.getFirstAttr()));
          if (s.getNextNode() != null)
            s.setNextNode(replace(s.getNextNode()));
        }

        public void visitNopStm(NopStm s) {
          // do nothing
        }

        public void visitPlugStm(PlugStm s) {
          s.setBase(replace(s.getBase()));
          s.setDest(replace(s.getDest()));
          if (s.getXMLSource() != null)
            s.setXMLSource(replace(s.getXMLSource()));
          if (s.getKind() == PlugStm.Kind.PLUGMULTI || s.getKind() == PlugStm.Kind.PLUGWRAP)
            s.setStringSource(getStringSource(s.getXMLSource()));
        }

        public void visitRemoveStm(RemoveStm s) {
          s.setBase(replace(s.getBase()));
          s.setDest(replace(s.getDest()));
        }

        public void visitSetStm(SetStm s) {
          s.setBase(replace(s.getBase()));
          s.setDest(replace(s.getDest()));
          if (s.getXMLSource() != null)
            s.setXMLSource(replace(s.getXMLSource()));
        }

        public void visitUnknownStm(UnknownStm s) {
          s.setDest(replace(s.getDest()));
        }

        public void visitValidateStm(ValidateStm s) {
          if (s.getBase() != null)
            s.setBase(replace(s.getBase()));
          s.setDest(replace(s.getDest()));
        }

        public void visitVarStm(VarStm s) {
          s.setSource(replace(s.getSource()));
          s.setDest(replace(s.getDest()));
        }

        public void visitCallStm(CallStm s) {
          s.setResult(replace(s.getResult()));
          for (int i=0; i<s.getArguments().length; i++) {
            s.setArgument(i, replace(s.getArgument(i)));
            s.getMethod().setParameter(i, replace(s.getMethod().getParameter(i)));
          }
        }
       
        // not present anymore
        public void visitEscapeStm(EscapeStm s) {
        }
        public void visitArrayReadStm(ArrayReadStm s) {
        }
        public void visitArrayWriteStm(ArrayWriteStm s) {
        }
        public void visitArrayWriteStringStm(ArrayWriteStringStm s) {
        }
      });

      // replace variables in edges
      // XXX this could take quadratic time. it could be improved easily
      for (Edge<Statement,VariableFilter> edge : graph.getOutEdges(s)) {
        VariableFilter filter = edge.getData();
        for (Variable var : var_alias.getKeys())
          if (filter.containsVariable(var))
            filter.addVariable(var_alias.getRepresentativeKey(var)); // XXX: no need to remove var?
      }
    }
  }

  private void replaceNode(final FlowGraph graph, Statement old,
      StatementPair st) {
    for (Edge<Statement,VariableFilter> edge : graph.getInEdges(old))
      graph.addEdge(edge.getFrom(), st.first, edge.getData());
    for (Edge<Statement,VariableFilter> edge : graph.getOutEdges(old))
      graph.addEdge(st.last, edge.getTo(), edge.getData());
    graph.removeNode(old);
  }
}
TOP

Related Classes of dk.brics.xact.analysis.transformations.ArrayTransformer$Component

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.