package ca.mcgill.sable.soot.baf.toolkit.scalar; import java.util.*; import java.io.*; import ca.mcgill.sable.soot.*; import ca.mcgill.sable.soot.jimple.*; import ca.mcgill.sable.soot.baf.*; import ca.mcgill.sable.soot.toolkit.scalar.*; import ca.mcgill.sable.soot.baf.internal.*; public class LoadStoreOptimizer { // Constants final static boolean debug = false; // constants returned by the stackIndependent function. final static protected int FAILURE = 0; final static protected int SUCCESS = 1; final static protected int MAKE_DUP = 2; final static protected int MAKE_DUP1_X1 = 3; final static protected int HAS_CHANGED = 5; final static protected int STORE_LOAD_ELIMINATION = 0; final static protected int STORE_LOAD_LOAD_ELIMINATION = -1; // Statics private static LoadStoreOptimizer mSingleton = new LoadStoreOptimizer(); private static Tag sllTag, slTag, popTag; // Instance vars. protected Chain mUnits; protected Body mBody; protected CompleteUnitGraph mCompleteUnitGraph; protected LocalDefs mLocalDefs; protected LocalUses mLocalUses; protected Map mUnitToBlockMap; // maps a unit to it's containing block protected SootMethod mMtd; protected LoadStoreOptimizer() { } public static LoadStoreOptimizer v() { return mSingleton; } /* * Computes a map binding each unit in the method to the unique basic block * that contains it. */ protected void buildUnitToBlockMap() { BlockGraph blockGraph = new BriefBlockGraph(mBody); List blocks = blockGraph.getBlocks(); mUnitToBlockMap = new HashMap(); Iterator blockIt = blocks.iterator(); while(blockIt.hasNext() ) { Block block = (Block) blockIt.next(); Iterator unitIt = block.iterator(); while(unitIt.hasNext()) { Unit unit = (Unit) unitIt.next(); mUnitToBlockMap.put(unit, block); } } } // computes a list of all the stores in mUnits in order of their occurence therein. protected List buildStoreList() { Iterator it = mUnits.iterator(); List storeList = new ArrayList(); while(it.hasNext()) { Unit unit = (Unit) it.next(); if(unit instanceof StoreInst) storeList.add(unit); } return storeList; } protected void computeLocalDefsAndLocalUsesInfo() { mCompleteUnitGraph = new CompleteUnitGraph(mBody); mLocalDefs = new SimpleLocalDefs(mCompleteUnitGraph); mLocalUses = new SimpleLocalUses(mCompleteUnitGraph, mLocalDefs); } // method that drives the optimizations. The only public (non-static) method of this class. public void optimize(Body body) { mBody = body; mUnits = mBody.getUnits(); mMtd = body.getMethod(); sllTag = mMtd.newTag("sll.l"); slTag = mMtd.newTag("sl.l"); popTag = mMtd.newTag("pop.l"); if(debug) { System.out.println("Optimizing: " + body.getMethod().toString());} if(mUnits.isEmpty()) return; buildUnitToBlockMap(); computeLocalDefsAndLocalUsesInfo(); optimizeStoreLoads(); if(debug) System.out.println("pass 1"); doInterBlockOptimizations(); if(debug) System.out.println("pass 2"); computeLocalDefsAndLocalUsesInfo(); //propagateLoadsBackwards(); if(debug) System.out.println("pass 3"); //optimizeStoreLoads(); if(debug) System.out.println("pass 4"); //propagateLoadsForward(); if(debug) System.out.println("pass 5"); //propagateBackwardsIndependentHunk(); if(debug) System.out.println("pass 6"); optimizeStoreLoads(); if(debug) System.out.println("pass 7"); } // For each LoadInst in the method body, call propagateLoadBackwards to // try to relocate the load as close to the start of it's basic block as possible. protected void propagateLoadsBackwards() { boolean hasChanged = true; while(hasChanged) { hasChanged = false; List tempList = new ArrayList(); tempList.addAll(mUnits); Iterator it = tempList.iterator(); while(it.hasNext()) { Unit currentInst = (Unit) it.next(); if(currentInst instanceof LoadInst) { Block block = (Block) mUnitToBlockMap.get(currentInst); Unit insertPoint = propagateLoadBackwards(currentInst, block); if(insertPoint != null) { block.remove(currentInst); block.insertBefore(currentInst, insertPoint); hasChanged = true; } } } } } // Given a LoadInst and it's block, try to relocate the load as close as possible to // the start of it's block. protected Unit propagateLoadBackwards(Unit aInst, Block aBlock) { int h = 0; Unit candidate = null; Unit currentUnit = aInst; //List loadDefList = mLocalDefs.getDefsOfAt(((LoadInst)aInst).getLocal(), aInst); currentUnit = (Unit) aBlock.getPredOf(currentUnit); while( currentUnit != null) { if(!canMoveUnitOver(currentUnit, aInst)) break; h -= ((Inst)currentUnit).getOutCount(); if(h < 0) break; h += ((Inst)currentUnit).getInCount(); if(h == 0) candidate = currentUnit; currentUnit = (Unit) aBlock.getPredOf(currentUnit); } return candidate; } // main optimizing method public void optimizeStoreLoads() { Chain units = mUnits; List storeList; // build a list of all store units in mUnits storeList = buildStoreList(); // Eliminate store/load { boolean hasChanged = true; boolean hasChangedFlag = false; while(hasChanged) { hasChanged = false; // Iterate over the storeList Iterator unitIt = storeList.iterator(); nextUnit: while(unitIt.hasNext()){ Unit unit = (Unit) unitIt.next(); // check for $ /*String localName = ((StoreInst)unit).getLocal().getName(); if(!localName.startsWith("$")) continue nextUnit;*/ List uses = mLocalUses.getUsesOf(unit); // if uses of a store < 3, attempt some form of store/load elimination if(uses.size() < 3) { // check that all uses have only the current store as their definition { boolean invalidStore = false; Iterator useIt = uses.iterator(); while(useIt.hasNext()) { UnitValueBoxPair pair = (UnitValueBoxPair) useIt.next(); Unit loadUnit = pair.getUnit(); if(!(loadUnit instanceof LoadInst)) continue nextUnit; List defs = mLocalDefs.getDefsOfAt((Local) pair.getValueBox().getValue(), loadUnit); if(defs.size() > 1) { continue nextUnit; } else if(defs.get(0) != unit) { continue nextUnit; // xxx how can you get here? } } } // Check that all loads are in the same bb as the store { Block storeBlock = (Block) mUnitToBlockMap.get(unit); Iterator useIt = uses.iterator(); while(useIt.hasNext()) { UnitValueBoxPair pair = (UnitValueBoxPair) useIt.next(); Block useBlock = (Block) mUnitToBlockMap.get(pair.getUnit()); if(useBlock != storeBlock) continue nextUnit; } } // Check for stack independance (automatic reordering may be performed by stackIndependent() fcnt) { Block block; switch(uses.size()) { case 0: // replace store by a pop and remove store from store list replaceUnit(unit, Baf.v().newPopInst(((StoreInst)unit).getOpType())); unitIt.remove(); mMtd.incTagValue("pop.l"); hasChanged = true; hasChangedFlag = false; break; case 1: // try to eliminate store/load pair Unit loadUnit = ((UnitValueBoxPair)uses.get(0)).getUnit(); block = (Block) mUnitToBlockMap.get(unit); int test = stackIndependent(unit, loadUnit , block, STORE_LOAD_ELIMINATION); if(test == SUCCESS){ block.remove(unit); block.remove(loadUnit); unitIt.remove(); hasChanged = true; hasChangedFlag = false; mMtd.incTagValue("sl.l"); //delme[ if(debug) { System.out.println("Store/Load elimination occurred.");} //delme] } break; case 2: // try to replace store/load/load trio by a flavor of the dup unit Unit firstLoad = ((UnitValueBoxPair)uses.get(0)).getUnit(); Unit secondLoad = ((UnitValueBoxPair)uses.get(1)).getUnit(); block = (Block) mUnitToBlockMap.get(unit); Unit temp; // xxx try to optimize this if(mUnits.follows(firstLoad, secondLoad)) { temp = secondLoad; secondLoad = firstLoad; firstLoad = temp; } int result = stackIndependent(unit, firstLoad, block, STORE_LOAD_ELIMINATION); if(result == SUCCESS){ // move the first load just after it's defining store. block.remove(firstLoad); block.insertAfter(firstLoad, unit); int res = stackIndependent(unit, secondLoad, block, STORE_LOAD_LOAD_ELIMINATION); if(res == MAKE_DUP) { // replace store by dup, drop both loads replaceUnit(unit, Baf.v().newDup1Inst(((LoadInst) secondLoad).getOpType())); unitIt.remove(); // remove store from store list block.remove(firstLoad); block.remove(secondLoad); mMtd.incTagValue("sll.l"); hasChanged = true; hasChangedFlag = false; } else if(res == MAKE_DUP1_X1) { // replace store/load/load by a dup1_x1 Unit stackUnit = getStackItemAt2(unit, block, -2); if(stackUnit instanceof PushInst) break; Type underType = type(stackUnit); if(underType == null) { throw new RuntimeException("this has to be corrected (loadstoroptimiser.java)" + stackUnit); } if(debug) { System.out.println("stack unit is: " + stackUnit + " stack type is " + underType);} replaceUnit(unit, Baf.v().newDup1_x1Inst(((LoadInst) secondLoad).getOpType(),underType)); unitIt.remove(); block.remove(firstLoad); block.remove(secondLoad); mMtd.incTagValue("sll.l"); hasChanged = true; hasChangedFlag = false; break; } } else if(result == HAS_CHANGED){ if(!hasChangedFlag) { hasChangedFlag = true; hasChanged = true; } } } } } } } } } /** * Checks if the units occuring between [from, to] consume *. stack items not produced by these interval units. (ie if the * stack height ever goes negative between from and to, assuming the * stack height is set to 0 upon executing the instruction following 'from'. * */ protected boolean isRequiredByFollowingUnits(Unit from, Unit to) { Iterator it = mUnits.iterator(from, to); int stackHeight = 0; boolean res = false; if(from != to) { // advance past the 'from' unit it.next(); while(it.hasNext()) { Unit currentInst = (Unit) it.next(); if(currentInst == to) break; stackHeight -= ((Inst)currentInst).getInCount(); if(stackHeight < 0 ) { res = true; break; } stackHeight += ((Inst)currentInst).getOutCount(); } } return res; } /** * Finds a level block ending with aUnit. * @param aUnit the end unit for the level block sought * @return the start unit of a level block ending with aUnit */ protected Unit findLevelBlockEndingWith(Unit aUnit) { if(aUnit == null) throw new RuntimeException("findLevelBlockEndingWith was called w/ a null argument."); Block block = (Block) mUnitToBlockMap.get(aUnit); int h = 0; Unit currentUnit = aUnit; while(currentUnit != null) { h-= ((Inst)currentUnit).getOutCount(); if(h<0){ currentUnit = null; break; } h+= ((Inst)currentUnit).getInCount(); if(h == 0) break; currentUnit = (Unit) block.getPredOf(currentUnit); } return currentUnit; } /** * Find a level block ending with the from unit, and try to move and insert this level * block just before the to unit. * @param from some unit * @param to some other unit in the same block as from and occuring after from in the block * * @return SUCCESS if successful * @return FAILURE if unsuccessful */ protected int pushStoreToLoad(Unit from , Unit to) { // find a the start unit of a level block ending w/ from (if such a block exists) Block block = (Block) mUnitToBlockMap.get(from); Unit startOfLevelBlock = findLevelBlockEndingWith(from); if(startOfLevelBlock != null) { ArrayList unitsToMove = new ArrayList(); // put all units of the level block into unitsToMove container Iterator it = mUnits.iterator(startOfLevelBlock, from); while(it.hasNext()) { unitsToMove.add(it.next()); } // check that each unit in the level block can be moved past all units in the interleaving sequence Iterator interleavingIt = mUnits.iterator((Unit) block.getSuccOf(from), (Unit) block.getPredOf(to)); while(interleavingIt.hasNext()) { Unit interleavingUnit = (Unit) interleavingIt.next(); Iterator levelIt = unitsToMove.iterator(); while(levelIt.hasNext()) { Unit levelUnit = (Unit) levelIt.next(); if(!canMoveUnitOver(levelUnit, interleavingUnit)){ return FAILURE; } } } // if we get here it means we can move all the level block units pass the interleaving units Iterator moveIt = unitsToMove.iterator(); while(moveIt.hasNext()) { Unit moveable = (Unit) moveIt.next(); block.remove(moveable); block.insertBefore(moveable, to); } return SUCCESS; } return FAILURE; } /** * * * @return FAILURE when store load elimination is not possible in any form. * @return SUCCESS when a store load pair has been rid of interleaving instructions * @return MAKE_DUP when a store/load/load trio can be replaced by a dup unit. * @return MAKE_DUP_X1 when store/load/load trio can be replaced by a dup1_x1 unit * @retrun HAS_CHANGED when store load elimination is not possible in any form, but some unit reordering has occured */ protected int stackIndependent(Unit from, Unit to, Block block, int aContext) { if(debug) { System.out.println("trying: " + from);} int minStackHeightAttained = 0; // records the min stack height attained between [from, to] int stackHeight = 0; // records the stack height when similating the effects on the stack Iterator it = mUnits.iterator(mUnits.getSuccOf(from)); int res = FAILURE; Unit currentInst = (Unit) it.next(); // get unit following the store if(aContext == STORE_LOAD_LOAD_ELIMINATION) { currentInst = (Unit) it.next(); // jump after first load } // find minStackHeightAttained while(currentInst != to) { stackHeight -= ((Inst)currentInst).getInCount(); if(stackHeight < minStackHeightAttained) minStackHeightAttained = stackHeight; stackHeight += ((Inst)currentInst).getOutCount(); currentInst = (Unit) it.next(); } // note: now stackHeight contains the delta height of the stack after executing the units contained in // [from, to] non-inclusive. if(debug) { System.out.println("Stack height= " + stackHeight + "minattained: " + minStackHeightAttained + "from succ: " + block.getSuccOf(from));} boolean hasChanged = true; // Iterate until an elimination clause is taken or no reordering of the code occurs while(hasChanged) { hasChanged = false; // check for possible sll elimination if(aContext == STORE_LOAD_LOAD_ELIMINATION) { if(stackHeight == 0 && minStackHeightAttained == 0){if(debug) { System.out.println("xxx: succ: -1, makedup ");} return MAKE_DUP;} else if(stackHeight == -1 && minStackHeightAttained == -1){ if(debug) { System.out.println("xxx: succ: -1, makedup , -1");} return MAKE_DUP; } else if(stackHeight == -2 && minStackHeightAttained == -2){if(debug) { System.out.println("xxx: succ -1 , make dupx1 ");} return MAKE_DUP1_X1; } else if (minStackHeightAttained < -2) { if(debug) { System.out.println("xxx: failled due: minStackHeightAttained < -2 ");} return FAILURE; } } // check for possible sl elimination if(aContext == STORE_LOAD_ELIMINATION) { if(stackHeight == 0 && minStackHeightAttained == 0){ if(debug) { System.out.println("xxx: success due: 0, SUCCESS ");} return SUCCESS; } else if (minStackHeightAttained == -1 && stackHeight == -1) { Unit u = (Unit) block.getPredOf(from); if(((Inst)u).getOutCount() == 1) { if(block.getPredOf(u) instanceof DupInst) { block.remove(u); block.insertBefore(u, to); block.remove(from); block.insertBefore(from, to); if(debug) { System.out.println("xxx: success due to 1, SUCCESS");} return SUCCESS; } else if(u instanceof DupInst) { block.remove(from); block.insertBefore(from, to); return SUCCESS; } } } else if (minStackHeightAttained < 0){ return pushStoreToLoad(from , to); } } it = mUnits.iterator(mUnits.getSuccOf(from), to); Unit unitToMove = null; Unit u = (Unit) it.next(); if(aContext == STORE_LOAD_LOAD_ELIMINATION) { u = (Unit) it.next(); } int currentH = 0; // find a candidate to move before the store/load/(load) group while( u != to) { if(((Inst)u).getNetCount() == 1) { // xxx remove this check if(u instanceof LoadInst || u instanceof PushInst || u instanceof NewInst || u instanceof StaticGetInst || u instanceof Dup1Inst) { // verify that unitToMove is not required by following units (until the 'to' unit) if(!isRequiredByFollowingUnits(u, (LoadInst) to)) { unitToMove = u; } } else{ if(debug) { System.out.println("1003:(LoadStoreOptimizer@stackIndependent): found unknown unit w/ getNetCount == 1" + u);} } } if(unitToMove != null) { int flag = 0; //if(aContext == 0 || !(stackHeight > -2 && minStackHeightAttained == -2 ) ) { if(tryToMoveUnit(unitToMove, block, from, to, flag)) { if(stackHeight > -2 && minStackHeightAttained == -2){ return HAS_CHANGED; } stackHeight--; if(stackHeight < minStackHeightAttained) minStackHeightAttained = stackHeight; hasChanged = true; break; } } currentH += ((Inst)u).getNetCount(); unitToMove = null; u = (Unit) it.next(); } } if(isCommutativeBinOp((Unit) block.getSuccOf(to))) { if(aContext == STORE_LOAD_ELIMINATION && stackHeight == 1 && minStackHeightAttained == 0) { if(debug) { System.out.println("xxx: commutative ");} return SUCCESS; } else if( ((Inst) to).getOutCount() == 1 && ((Inst) to).getInCount() == 0 && ((Inst) mUnits.getPredOf(to)).getOutCount() == 1 && ((Inst) mUnits.getPredOf(to)).getInCount() == 0) { Object toPred = mUnits.getPredOf(to); block.remove(toPred); block.insertAfter(toPred, to); return HAS_CHANGED; // return has changed } else return FAILURE; } if (aContext == STORE_LOAD_ELIMINATION) return pushStoreToLoad(from , to); return res; } /** * @return true if aUnit perform a non-local read or write. false otherwise. */ protected boolean isNonLocalReadOrWrite(Unit aUnit) { if((aUnit instanceof FieldArgInst ) || (aUnit instanceof ArrayReadInst) || (aUnit instanceof ArrayWriteInst) ) return true; else return false; } /** * When reordering bytecode, check if it is safe to move aUnitToMove past aUnitToGoOver. * @return true if aUnitToMove can be moved past aUnitToGoOver. */ protected boolean canMoveUnitOver(Unit aUnitToMove, Unit aUnitToGoOver) // xxx missing cases { // can't change method call order or change fieldargInst and method call order if((aUnitToGoOver instanceof MethodArgInst && aUnitToMove instanceof MethodArgInst) || (aUnitToGoOver instanceof MethodArgInst && isNonLocalReadOrWrite(aUnitToMove)) || (isNonLocalReadOrWrite(aUnitToGoOver) && aUnitToMove instanceof MethodArgInst) || (aUnitToGoOver instanceof ArrayReadInst && aUnitToMove instanceof ArrayWriteInst) || (aUnitToGoOver instanceof ArrayWriteInst && aUnitToMove instanceof ArrayReadInst) || (aUnitToGoOver instanceof ArrayWriteInst && aUnitToMove instanceof ArrayWriteInst)|| (aUnitToGoOver instanceof FieldPutInst && aUnitToMove instanceof FieldGetInst && ((FieldArgInst)aUnitToGoOver).getField() == ((FieldArgInst)aUnitToMove).getField()) || (aUnitToGoOver instanceof FieldGetInst && aUnitToMove instanceof FieldPutInst && ((FieldArgInst)aUnitToGoOver).getField() == ((FieldArgInst)aUnitToMove).getField()) || (aUnitToGoOver instanceof FieldPutInst && aUnitToMove instanceof FieldPutInst && ((FieldArgInst)aUnitToGoOver).getField() == ((FieldArgInst)aUnitToMove).getField()) || (aUnitToGoOver instanceof StaticPutInst && aUnitToMove instanceof StaticGetInst && ((FieldArgInst)aUnitToGoOver).getField() == ((FieldArgInst)aUnitToMove).getField()) || (aUnitToGoOver instanceof StaticGetInst && aUnitToMove instanceof StaticPutInst && ((FieldArgInst)aUnitToGoOver).getField() == ((FieldArgInst)aUnitToMove).getField())|| (aUnitToGoOver instanceof StaticPutInst && aUnitToMove instanceof StaticPutInst && ((FieldArgInst)aUnitToGoOver).getField() == ((FieldArgInst)aUnitToMove).getField())) return false; // xxx to be safe don't mess w/ monitors. These rules could be relaxed. ? Maybe. if(aUnitToGoOver instanceof EnterMonitorInst || aUnitToGoOver instanceof ExitMonitorInst) return false; if(aUnitToMove instanceof EnterMonitorInst || aUnitToGoOver instanceof ExitMonitorInst) return false; if(aUnitToGoOver instanceof IdentityInst || aUnitToMove instanceof IdentityInst) return false; if(aUnitToMove instanceof LoadInst ) { if(aUnitToGoOver instanceof StoreInst) { if(((StoreInst)aUnitToGoOver).getLocal() == ((LoadInst)aUnitToMove).getLocal()) { return false; } } else if(aUnitToGoOver instanceof IncInst) { if(((IncInst)aUnitToGoOver).getLocal() == ((LoadInst)aUnitToMove).getLocal()){ return false; } } } // don't move def of load pass it. if(aUnitToMove instanceof StoreInst) { if(aUnitToGoOver instanceof LoadInst) { if(((LoadInst)aUnitToGoOver).getLocal() == ((StoreInst)aUnitToMove).getLocal()) { return false; } } else if(aUnitToGoOver instanceof IncInst) { if(((IncInst)aUnitToGoOver).getLocal() == ((StoreInst)aUnitToMove).getLocal()){ return false; } } } if(aUnitToMove instanceof IncInst) { if(aUnitToGoOver instanceof StoreInst) { if(((StoreInst)aUnitToGoOver).getLocal() == ((IncInst)aUnitToMove).getLocal()) { return false; } } else if(aUnitToGoOver instanceof LoadInst) { if(((LoadInst)aUnitToGoOver).getLocal() == ((IncInst)aUnitToMove).getLocal()){ return false; } } } return true; } protected boolean tryToMoveUnit(Unit unitToMove, Block block, Unit from, Unit to, int flag) { int h = 0; Unit current = unitToMove; boolean reachedStore = false; boolean reorderingOccurred =false; if(debug) {System.out.println("[tryToMoveUnit]: trying to move:" + unitToMove);} if(unitToMove == null) return false; while( current != block.getHead()) { // do not go past basic block limit current = (Unit) mUnits.getPredOf(current); if(!canMoveUnitOver(current, unitToMove)) return false; if(current == from) reachedStore = true; h -= ((Inst)current).getOutCount(); if(h < 0 ){ if(debug) { System.out.println("1006:(LoadStoreOptimizer@stackIndependent): Stack went negative while trying to reorder code.");} if(flag == 1) { if(current instanceof DupInst) { block.remove(unitToMove); block.insertAfter(unitToMove, current); // block.insertAfter( new BSwapInst( ) ,unitToMove); } } return false; } h += ((Inst)current).getInCount(); if(h == 0 && reachedStore == true) { if(!isRequiredByFollowingUnits(unitToMove, (LoadInst) to)) { if(debug) { System.out.println("10077:(LoadStoreOptimizer@stackIndependent): reordering bytecode move: " + unitToMove + "before: " + current);} block.remove(unitToMove); block.insertBefore(unitToMove, current); reorderingOccurred = true; break; } } } if(reorderingOccurred) { if(debug) { System.out.println("reordering occured");} return true; } else { if(debug) { System.out.println("1008:(LoadStoreOptimizer@stackIndependent):failled to find a new slot for unit to move");} return false; } } /* * Replace 1 or 2 units by a third unit in a block. Both units to * replace should be in the same block. The map 'mUnitToBlockMap' * is updated. The replacement unit is inserted in the position, * of the aToReplace2 if not null, otherwise in aToReplace1's slot. * * @param aToReplace1 Unit to replace. (shouldn't be null) * @param aToReplace2 Second Unit to replace (can be null) * @param aReplacement Unit that replaces the 2 previous units (shouldn't be null) */ protected void replaceUnit(Unit aToReplace1, Unit aToReplace2, Unit aReplacement) { Block block = (Block) mUnitToBlockMap.get(aToReplace1); if(aToReplace2 != null) { block.insertAfter(aReplacement, aToReplace2); block.remove(aToReplace2); } else { block.insertAfter(aReplacement, aToReplace1); } block.remove(aToReplace1); // add the new unit the block map mUnitToBlockMap.put(aReplacement, block); } protected void replaceUnit(Unit aToReplace, Unit aReplacement) { replaceUnit(aToReplace, null, aReplacement); } /** * Returns the type of the stack item produced by certain Unit objects. */ protected Type type(Unit aUnit) { if(aUnit instanceof InstanceCastInst || aUnit instanceof NewInst) { return RefType.v(); } else if(aUnit instanceof LoadInst) { return ((LoadInst)aUnit).getOpType(); } else if (aUnit instanceof FieldGetInst) return ((FieldGetInst)aUnit).getField().getType(); else if (aUnit instanceof Dup1Inst) return ((Dup1Inst)aUnit).getOp1Type(); else if(aUnit instanceof StaticGetInst) return ((StaticGetInst) aUnit).getField().getType(); else if(aUnit instanceof OpTypeArgInst) return ((OpTypeArgInst)aUnit).getOpType(); else if(aUnit instanceof PushInst) return ((PushInst)aUnit).getConstant().getType(); else if (aUnit instanceof MethodArgInst) return ((MethodArgInst) aUnit).getMethod().getReturnType(); else if(aUnit instanceof Dup1_x1Inst) return ((Dup1_x1Inst) aUnit).getOp1Type(); else if(aUnit instanceof Dup1Inst) return ((Dup1Inst) aUnit).getOp1Type(); else return null; } /* * @param some block * @return true if the block is an exception handler. */ protected boolean isExceptionHandlerBlock(Block aBlock) { Unit blockHead = aBlock.getHead(); Iterator it = mBody.getTraps().iterator(); while(it.hasNext()) { Trap trap = (Trap) it.next(); if(trap.getHandlerUnit() == blockHead) return true; } return false; } protected Unit getStackItemAt2(Unit aUnit, Block aBlock, int aDeltaHeight) { int h = 0; Unit currentUnit = aUnit; Unit candidate = null; while(currentUnit != null) { currentUnit = (Unit) aBlock.getPredOf(currentUnit); if(currentUnit == null) { if(debug) { System.out.println(aBlock);} System.out.println("xxxxxxxxxxxx " + h); if(isExceptionHandlerBlock(aBlock) ) { return new BLoadInst( RefType.v("dummy") , ((StoreInst) aUnit).getLocal()); // we have a ref type. } aBlock = (Block) aBlock.getPreds().get(0); currentUnit = (Unit) aBlock.getTail(); } h -= ((Inst)currentUnit).getOutCount(); if(h <= aDeltaHeight) { candidate = currentUnit; break; } h += ((Inst)currentUnit).getInCount(); } return candidate; } // not a save function :: goes over block boundries protected int getDeltaStackHeightFromTo(Unit aFrom, Unit aTo) { Iterator it = mUnits.iterator(aFrom, aTo); int h = 0; while(it.hasNext()) { h += ((Inst)it.next()).getNetCount(); } return h; } /** * Performs 2 simple inter-block optimizations in order to keep * some variables on the stack between blocks. Both are intented to catch * 'if' like constructs where the control flow branches temporarely into two paths * that join up at a latter point. * */ protected void doInterBlockOptimizations() { boolean hasChanged = true; while(hasChanged) { hasChanged = false; List tempList = new ArrayList(); tempList.addAll(mUnits); Iterator it = tempList.iterator(); while(it.hasNext()) { Unit u = (Unit) it.next(); if(u instanceof LoadInst) { if(debug) { System.out.println("inter trying: " + u);} Block loadBlock = (Block) mUnitToBlockMap.get(u); List defs = mLocalDefs.getDefsOfAt(((LoadInst)u).getLocal(), u); // first optimization if(defs.size() == 1) { Block defBlock =(Block) mUnitToBlockMap.get(defs.get(0)); if(defBlock != loadBlock) { Unit storeUnit = (Unit) defs.get(0); if(storeUnit instanceof StoreInst) { List uses = mLocalUses.getUsesOf(storeUnit); if(uses.size() == 1){ if(allSuccesorsOfAreThePredecessorsOf(defBlock, loadBlock)) { if(getDeltaStackHeightFromTo((Unit) defBlock.getSuccOf(storeUnit), (Unit)defBlock.getTail()) == 0) { Iterator it2 = defBlock.getSuccessors().iterator(); boolean res = true; while(it2.hasNext()) { Block b = (Block) it2.next(); if(getDeltaStackHeightFromTo((Unit) b.getHead(), (Unit) b.getTail()) != 0) { res = false; break; } if(b.getPreds().size() != 1 || b.getSuccessors().size() != 1){ res = false; break; } } if(debug) { System.out.println(defBlock.toString() + loadBlock.toString());} if(res) { defBlock.remove(storeUnit); mUnitToBlockMap.put(storeUnit, loadBlock); loadBlock.insertBefore(storeUnit, loadBlock.getHead()); hasChanged = true; if(debug) { System.out.println("inter-block opti occurred " + storeUnit + " " + u);} if(debug) { System.out.println(defBlock.toString() + loadBlock.toString());} } } } } } } } // second optimization else if(defs.size() == 2) { Unit def0 = (Unit) defs.get(0); Unit def1 = (Unit) defs.get(1); Block defBlock0 = (Block) mUnitToBlockMap.get(def0); Block defBlock1 = (Block) mUnitToBlockMap.get(def1); if(defBlock0 != loadBlock && defBlock1 != loadBlock && defBlock0 != defBlock1) { if(mLocalUses.getUsesOf(def0).size() == 1 && mLocalUses.getUsesOf(def1).size() == 1) { List def0Succs = defBlock0.getSuccessors(); List def1Succs = defBlock1.getSuccessors(); if(def0Succs.size()==1 && def1Succs.size()==1) { if(def0Succs.get(0) == loadBlock && def1Succs.get(0)== loadBlock) { if(loadBlock.getPreds().size() == 2) { if( (def0 == defBlock0.getTail()|| getDeltaStackHeightFromTo((Unit)defBlock0.getSuccOf(def0),(Unit) defBlock0.getTail()) == 0) && (def1 == defBlock1.getTail() || getDeltaStackHeightFromTo((Unit)defBlock1.getSuccOf(def1), (Unit) defBlock1.getTail()) == 0)) { defBlock0.remove(def0); defBlock1.remove(def1); loadBlock.insertBefore(def0, loadBlock.getHead()); mUnitToBlockMap.put(def0, loadBlock); hasChanged = true; if(debug) { System.out.println("inter-block opti2 occurred " + def0);} } else { if(debug) { System.out.println("failed: inter1");}} } else { if(debug) { System.out.println("failed: inter2");}} } else { if(debug) { System.out.println("failed: inter3");}} } else { if(debug) { System.out.println("failed: inter4");}} } else { if(debug) { System.out.println("failed: inter5");}} } else { if(debug) { System.out.println("failed: inter6");}} } } } } } /** * Given 2 blocks, assertains whether all the succesors of the first block are the predecessors * of the second block. */ protected boolean allSuccesorsOfAreThePredecessorsOf(Block aFirstBlock, Block aSecondBlock) { int size = aFirstBlock.getSuccessors().size(); Iterator it = aFirstBlock.getSuccessors().iterator(); List preds = aSecondBlock.getPreds(); while(it.hasNext()) { if(!preds.contains(it.next())) return false; } if(size == preds.size()) return true; else return false; } /** * @return true if aUnit is a commutative binary operator */ protected boolean isCommutativeBinOp(Unit aUnit) { if(aUnit == null ) return false; if(aUnit instanceof AddInst || aUnit instanceof MulInst || aUnit instanceof AndInst || aUnit instanceof OrInst || aUnit instanceof XorInst) return true; else return false; } /* * @param aInst */ protected boolean propagateLoadForward(Unit aInst) { Unit currentUnit; Block block = (Block) mUnitToBlockMap.get(aInst); boolean res = false; int h = 0; Unit candidate = null; if(aInst == block.getTail()) return false; currentUnit = (Unit) block.getSuccOf(aInst); while( currentUnit != block.getTail()) { if(!canMoveUnitOver(aInst, currentUnit)){ if(debug) { System.out.println("can't go over: " + currentUnit);} break;} h -= ((Inst)currentUnit).getInCount(); if(h < 0){ if(!(aInst instanceof Dup1Inst && currentUnit instanceof Dup1Inst)) { if(debug) { System.out.println("breaking at: " + currentUnit);} break; } } h += ((Inst)currentUnit).getOutCount(); if(h == 0){ candidate = currentUnit; // don't stop now; try to go still forward. } currentUnit = (Unit) block.getSuccOf(currentUnit); } if(candidate != null) { if(debug) { System.out.println("successfull propagation " + candidate + block.getTail());} block.remove(aInst); if(block.getTail() == mUnitToBlockMap.get(candidate)){ block.insertAfter(aInst, candidate); if(block.getTail() != aInst) throw new RuntimeException(); } block.insertAfter(aInst, candidate); return true; } return false; } /* * */ protected void propagateLoadsForward() { boolean hasChanged = true; while(hasChanged) { hasChanged = false; List tempList = new ArrayList(); tempList.addAll(mUnits); Iterator it = tempList.iterator(); while(it.hasNext()) { Unit u = (Unit) it.next(); if( u instanceof LoadInst || u instanceof Dup1Inst) { if(debug) { System.out.println("trying to push:" + u);} boolean res =propagateLoadForward(u); if(!hasChanged) hasChanged = res; } } } } // recycled code: /* void propagateBackwardsIndependentHunk() { List tempList = new ArrayList(); tempList.addAll(mUnits); Iterator it = tempList.iterator(); while(it.hasNext()) { Unit u = (Unit) it.next(); if( u instanceof NewInst) { Block block = (Block) mUnitToBlockMap.get(u); Unit succ = (Unit) block.getSuccOf(u); if( succ instanceof StoreInst) { Unit currentUnit = u; Unit candidate = null; while(currentUnit != block.getHead()) { currentUnit = (Unit) block.getPredOf(currentUnit); if(canMoveUnitOver(currentUnit, succ)){ candidate = currentUnit; } else break; } if(candidate != null) { block.remove(u); block.remove(succ); block.insertBefore(u, candidate); block.insertBefore(succ, candidate); } } } } } // convertsa series of loads into dups when applicable void superDuper1() { List tempList = new ArrayList(); tempList.addAll(mUnits); Iterator it = tempList.iterator(); boolean fetchUnit = true; while(it.hasNext()) { Unit currentInst = null; if(fetchUnit) { currentInst = (Unit) it.next(); } fetchUnit = true; if(currentInst instanceof LoadInst) { Block block = (Block) mUnitToBlockMap.get(currentInst); Local local = ((LoadInst)currentInst).getLocal(); // count the number of identical loads Unit u; for(;;){ if(it.hasNext()) { u = (Unit) it.next(); if(mUnitToBlockMap.get(u) != block) break; if(u instanceof LoadInst) { if(((LoadInst)u).getLocal() == local) { replaceUnit(u, Baf.v().newDup1Inst(((LoadInst) u).getOpType())); } else { fetchUnit =false; break; } } else { break; } } else break; } } } } //broken use superDuper1 void superDuper() { // compress a serie of loads using dup2's and dup's { List tempList = new ArrayList(); tempList.addAll(mUnits); Iterator it = tempList.iterator(); while(it.hasNext()) { Unit currentInst = (Unit) it.next(); if(currentInst instanceof LoadInst) { Block block = (Block) mUnitToBlockMap.get(currentInst); int loadCount = 1; Local local = ((LoadInst)currentInst).getLocal(); // count the number of identical loads Unit u; for(;;){ u = (Unit) it.next(); if(mUnitToBlockMap.get(u) != block) break; if(u instanceof LoadInst) { if(((LoadInst)u).getLocal() == local) loadCount++; else break; } else { break; } } if(loadCount > 1) { Type loadType = ((LoadInst)currentInst).getOpType(); // must leave at least one load on stack before dupping Unit currentLoad = (Unit) mUnits.getSuccOf(currentInst); loadCount--; if(loadType instanceof LongType || loadType instanceof DoubleType) { while(loadCount > 0) { Unit nextLoad = (Unit) mUnits.getSuccOf(currentLoad); replaceUnit(currentLoad, Baf.v().newDup1Inst(loadType)); currentLoad = nextLoad; loadCount--; } } else { boolean canMakeDup2 = false; if(loadCount >= 3) { canMakeDup2 = true; currentLoad = (Unit) mUnits.getSuccOf(currentLoad); loadCount--; } while(loadCount > 0) { if(loadCount == 1 || !canMakeDup2) { Unit nextLoad = (Unit) mUnits.getSuccOf(currentLoad); replaceUnit(currentLoad, Baf.v().newDup1Inst(loadType)); currentLoad = nextLoad; loadCount--; } else { if(canMakeDup2) { Unit nextLoad = (Unit) mUnits.getSuccOf(mUnits.getSuccOf(currentLoad)); replaceUnit(currentLoad, (Unit) mUnits.getSuccOf(currentLoad), Baf.v().newDup2Inst(loadType, loadType)); currentLoad = nextLoad; loadCount -= 2; } } } } } currentInst = u; } } } } void peephole() { boolean hasChanged = true; while(hasChanged) { hasChanged = false; List tempList = new ArrayList(); tempList.addAll(mUnits); Iterator it = tempList.iterator(); while(it.hasNext() ) { Unit currentUnit = (Unit) it.next(); if(currentUnit instanceof PopInst) { Block popBlock = (Block) mUnitToBlockMap.get(currentUnit); Unit prev = (Unit) popBlock.getPredOf(currentUnit); Unit succ = (Unit) popBlock.getSuccOf(currentUnit); if(prev instanceof LoadInst || prev instanceof PushInst) if(((AbstractInst)prev).getOutMachineCount() == ((AbstractInst)currentUnit).getInMachineCount()) { popBlock.remove(prev); popBlock.remove(currentUnit); } else if(succ instanceof ReturnInst) { popBlock.remove(currentUnit); popBlock.remove(succ); } } } } } protected boolean propagateStoreForward(Unit aInst, Unit aUnitToReach, Unit aCurrentUnit, int aStackHeight) { boolean res = false; Unit currentUnit = aCurrentUnit; Local storeLocal = ((StoreInst)aInst).getLocal(); Block block = (Block) mUnitToBlockMap.get(aCurrentUnit); while( currentUnit != block.getTail()) { if(currentUnit == aUnitToReach) { if(aStackHeight == 0) return true; else return false; } if(!canMoveUnitOver(aInst, currentUnit)) { res = false; break; } aStackHeight -= ((Inst)currentUnit).getInCount(); if(aStackHeight < 0){ res = false; break; } aStackHeight += ((Inst)currentUnit).getOutCount(); currentUnit = (Unit) block.getSuccOf(currentUnit); } // if we hit the block boundry if( currentUnit == block.getTail()) { Iterator it = block.getSuccessors().iterator(); while(it.hasNext()) { Block b = (Block) it.next(); if(!propagateStoreForward(aInst, aUnitToReach, b.getHead(), aStackHeight)) return false; } res = true; } return res; } */ }