soot.shimple.internal
Class ShimpleBodyBuilder

java.lang.Object
  |
  +--soot.shimple.internal.ShimpleBodyBuilder

public class ShimpleBodyBuilder
extends java.lang.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.

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  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  java.util.Stack[] namingStacks
           
protected  java.util.Map newLocals
          Maps new name Strings to Locals.
protected  java.util.Map newLocalsToOldLocal
          Maps renamed Locals to original Locals.
protected  java.util.List origLocals
          A fixed list of all original Locals.
protected  java.util.Map unitToBlock
           
 
Constructor Summary
ShimpleBodyBuilder(ShimpleBody body, boolean hasPhiNodes)
          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, java.lang.Integer subscript)
          Clever convenience function to fetch or create new Local's given a Local and the desired subscript.
static java.util.List getDefBoxesFromBlock(Block block)
          Convenience function that really ought to be implemented in soot.toolkits.graph.Block.
static java.util.Map getUnitToBlockMap(BlockGraph blocks)
          Convenience function that maps units to blocks.
static java.util.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 insertTrivialPhiNodes()
          Phi node Insertion Algorithm from Cytron et al 91, P24-5, implemented in various bits and pieces by the next functions.
protected  boolean isLocalDefinedOnEntry(Local local, Block block)
          Function that allows us to weed out special cases where we do not require Phi nodes.
static java.lang.String makeUniqueLocalName(java.lang.String dupName, java.util.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.
 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 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

dt

protected DominatorTree dt

cfg

protected BlockGraph cfg

origLocals

protected java.util.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.

newLocals

protected java.util.Map newLocals
Maps new name Strings to Locals.

newLocalsToOldLocal

protected java.util.Map newLocalsToOldLocal
Maps renamed Locals to original Locals.

assignmentCounters

protected int[] assignmentCounters

namingStacks

protected java.util.Stack[] namingStacks

unitToBlock

protected java.util.Map unitToBlock
Constructor Detail

ShimpleBodyBuilder

public ShimpleBodyBuilder(ShimpleBody body,
                          boolean hasPhiNodes)
Transforms the provided body to pure SSA form.
Method Detail

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.

isLocalDefinedOnEntry

protected boolean isLocalDefinedOnEntry(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,
                              java.lang.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 java.lang.String makeUniqueLocalName(java.lang.String dupName,
                                                   java.util.Set localNames)
Given a set of Strings, return a new name for dupName that is not currently in the set.

getDefBoxesFromBlock

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

getUseBoxesFromBlock

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

getUnitToBlockMap

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