soot.shimple.internal
Class ShimpleBodyBuilder

java.lang.Object
  extended bysoot.shimple.internal.ShimpleBodyBuilder

public class ShimpleBodyBuilder
extends Object

This class does the real high-level work. It takes a Jimple body or Jimple/Shimple hybrid body and produces pure Shimple.

The work is done in two main steps:

  1. Trivial Phi nodes are added.
  2. A renaming algorithm is executed.

This class can also translate out of Shimple by producing an equivalent Jimple body with all Phi nodes removed.

Note that this is an internal class, understanding it should not be necessary from a user point-of-view and relying on it directly is not recommended.

Author:
Navindra Umanee
See Also:
ShimpleBody, Efficiently Computing Static Single Assignment Form and the Control Dependence Graph

Field Summary
protected  int[] assignmentCounters
           
protected  ShimpleBody body
           
protected  BlockGraph cfg
           
protected  DominanceFrontier df
           
protected  DominatorTree dt
           
protected  GuaranteedDefs gd
          An analysis class that allows us to verify that a variable is guaranteed to be defined at program point P.
protected  Stack[] namingStacks
           
protected  Map newLocals
          Maps new name Strings to Locals.
protected  Map newLocalsToOldLocal
          Maps renamed Locals to original Locals.
protected  Set newPhiNodes
          Contains a list of all the Phi nodes added to the body by current invocation.
protected  List origLocals
          A fixed list of all original Locals.
protected  ShimpleFactory sf
           
protected  Map unitToBlock
           
 
Constructor Summary
ShimpleBodyBuilder(ShimpleBody body)
          Transforms the provided body to pure SSA form.
 
Method Summary
static boolean doEliminatePhiNodes(ShimpleBody body)
          Eliminate Phi nodes in block by naively replacing them with shimple assignment statements in the control flow predecessors.
 boolean dominates(Unit champ, Unit challenger)
          Returns true if champ dominates challenger.
static void eliminatePhiNodes(ShimpleBody body)
          Remove Phi nodes from current body, high probablity this destroys SSA form.
protected  Local fetchNewLocal(Local local, Integer subscript)
          Clever convenience function to fetch or create new Local's given a Local and the desired subscript.
static List getDefBoxesFromBlock(Block block)
          Convenience function that really ought to be implemented in soot.toolkits.graph.Block.
static Map getUnitToBlockMap(BlockGraph blocks)
          Convenience function that maps units to blocks.
static List getUseBoxesFromBlock(Block block)
          Convenience function that really ought to be implemented in soot.toolkits.graph.Block
protected  int indexOfLocal(Value local)
          Convenient function that maps new Locals to the originating Local, and finds the appropriate array index into the naming structures.
 void initialize()
           
 void insertTrivialPhiNodes()
          Phi node Insertion Algorithm from Cytron et al 91, P24-5, implemented in various bits and pieces by the next functions.
static String makeUniqueLocalName(String dupName, Set localNames)
          Given a set of Strings, return a new name for dupName that is not currently in the set.
static void makeUniqueLocalNames(ShimpleBody body)
          Make sure the locals in the given body all have unique String names.
protected  boolean needsPhiNode(Local local, Block block)
          Function that allows us to weed out special cases where we do not require Phi nodes.
 void prependTrivialPhiNode(Local local, Block frontierBlock)
          Inserts a trivial Phi node with the appropriate number of arguments.
 void renameLocals()
          Variable Renaming Algorithm from Cytron et al 91, P26-8, implemented in various bits and pieces by the next functions.
 void renameLocalsSearch(Block block)
          Driven by renameLocals().
 void transform()
           
 void trimExceptionalPhiNodes()
          Exceptional Phi nodes have a huge number of arguments and control flow predecessors by default.
 void trimPhiNode(PhiExpr phiExpr)
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

body

protected ShimpleBody body

sf

protected ShimpleFactory sf

dt

protected DominatorTree dt

df

protected DominanceFrontier df

cfg

protected BlockGraph cfg

origLocals

protected List origLocals
A fixed list of all original Locals.


gd

protected GuaranteedDefs gd
An analysis class that allows us to verify that a variable is guaranteed to be defined at program point P. Used as an accessory to tweaking our Phi node insertion algorithm.


newPhiNodes

protected Set newPhiNodes
Contains a list of all the Phi nodes added to the body by current invocation. Pre-existing Phi nodes are treated as normal def/uses in the renaming algorithm.


newLocals

protected Map newLocals
Maps new name Strings to Locals.


newLocalsToOldLocal

protected Map newLocalsToOldLocal
Maps renamed Locals to original Locals.


assignmentCounters

protected int[] assignmentCounters

namingStacks

protected Stack[] namingStacks

unitToBlock

protected Map unitToBlock
Constructor Detail

ShimpleBodyBuilder

public ShimpleBodyBuilder(ShimpleBody body)
Transforms the provided body to pure SSA form.

Method Detail

initialize

public void initialize()

transform

public void transform()

insertTrivialPhiNodes

public void insertTrivialPhiNodes()
Phi node Insertion Algorithm from Cytron et al 91, P24-5, implemented in various bits and pieces by the next functions.

For each definition of variable V, find the iterated dominance frontier. Each block in the iterated dominance frontier is prepended with a trivial Phi node.

We found out the hard way that this isn't the ideal solution for Jimple because a lot of redundant Phi nodes get inserted probably due to the fact that the algorithm assumes all variables have an initial definition on entry.

While this assumption does not produce incorrect results, it produces hopelessly complicated and ineffectual code.

Our quick solution was to ensure that a variable was defined along all paths to the block where we were considering insertion of a Phi node. If the variable was not defined along at least one path (isLocalDefinedOnEntry()), then certainly a Phi node was superfluous and meaningless. Our GuaranteedDefs flow analysis provided us with the necessary information.

Better and more efficient alternatives suggest themselves. We later found this formulation from IBM's Jikes RVM:

Special Java case: if node N dominates all defs of V, then N does not need a Phi node for V.


prependTrivialPhiNode

public void prependTrivialPhiNode(Local local,
                                  Block frontierBlock)
Inserts a trivial Phi node with the appropriate number of arguments.


needsPhiNode

protected boolean needsPhiNode(Local local,
                               Block block)
Function that allows us to weed out special cases where we do not require Phi nodes.

Temporary implementation, with much room for improvement.


renameLocals

public void renameLocals()
Variable Renaming Algorithm from Cytron et al 91, P26-8, implemented in various bits and pieces by the next functions. Must be called after trivial Phi nodes have been added.
  call search(entry)

  search(X):
  for each statement A in X do
     if A is an ordinary assignment
       for each variable V used do
            replace use of V by use of V_i where i = Top(S(V))
       done
     fi
    for each V in LHS(A) do
       i <- C(V)
       replace V by new V_i in LHS(A)
       push i onto S(V)
       C(V) <- i+1
    done
  done (end of first loop)
  for each Y in succ(X) do
      j <- whichPred(Y, X)
      for each Phi-function F in Y do
       replace the j-th operand V in RHS(F) by V_i with i = TOP(S(V))
     done
  done (end of second loop)
  for each Y in Children(X) do
    call search(Y)
  done (end of third loop)
  for each assignment A in X do
     for each V in oldLHS(A) do
       pop(S(V))
    done
  done (end of fourth loop)
  end
 


renameLocalsSearch

public void renameLocalsSearch(Block block)
Driven by renameLocals().


fetchNewLocal

protected Local fetchNewLocal(Local local,
                              Integer subscript)
Clever convenience function to fetch or create new Local's given a Local and the desired subscript.


indexOfLocal

protected int indexOfLocal(Value local)
Convenient function that maps new Locals to the originating Local, and finds the appropriate array index into the naming structures.


trimExceptionalPhiNodes

public void trimExceptionalPhiNodes()
Exceptional Phi nodes have a huge number of arguments and control flow predecessors by default. Since it is useless trying to keep the number of arguments and control flow predecessors in synch, we might as well trim out all redundant arguments and eliminate a huge number of copy statements when we get out of SSA form in the process.


trimPhiNode

public void trimPhiNode(PhiExpr phiExpr)
See Also:
trimExceptionalPhiNodes()

dominates

public boolean dominates(Unit champ,
                         Unit challenger)
Returns true if champ dominates challenger. Note that false doesn't necessarily mean that challenger dominates champ.


eliminatePhiNodes

public static void eliminatePhiNodes(ShimpleBody body)
Remove Phi nodes from current body, high probablity this destroys SSA form.

Dead code elimination + register aggregation are performed as recommended by Cytron. The Aggregator looks like it could use some improvements.

See Also:
ShimpleOptions

doEliminatePhiNodes

public static boolean doEliminatePhiNodes(ShimpleBody body)
Eliminate Phi nodes in block by naively replacing them with shimple assignment statements in the control flow predecessors. Returns true if new locals were added to the body during the process, false otherwise.


makeUniqueLocalNames

public static void makeUniqueLocalNames(ShimpleBody body)
Make sure the locals in the given body all have unique String names. Renaming is done if necessary.


makeUniqueLocalName

public static String makeUniqueLocalName(String dupName,
                                         Set localNames)
Given a set of Strings, return a new name for dupName that is not currently in the set.


getDefBoxesFromBlock

public static List getDefBoxesFromBlock(Block block)
Convenience function that really ought to be implemented in soot.toolkits.graph.Block.


getUseBoxesFromBlock

public static List getUseBoxesFromBlock(Block block)
Convenience function that really ought to be implemented in soot.toolkits.graph.Block


getUnitToBlockMap

public static Map getUnitToBlockMap(BlockGraph blocks)
Convenience function that maps units to blocks. Should probably be in BlockGraph.