/*
* Copyright (C) 2001 Mika Riekkinen, Joni Suominen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package alt.jiapi.instrumentor;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Category;
import alt.jiapi.Instrumentor;
import alt.jiapi.Runtime;
import alt.jiapi.reflect.InstructionList;
/**
* SplitInstrumentor splits input InstructionList into a set of
* InstructionLists. Strategy pattern is used in deciding how the
* split is to be done.<p>
* If the InstructionList, that is being instrumented is as follows :<br>
*
* <blockquote>
* <code>iiiiiiiXXXXXXXiiiiiiiXXXXiXXX</code>
* </blockquote>
*
* where <code>i</code> represents an Instruction, that is not of interest.
* <code>X</code> represents an interesting Instruction, which is
* found by Strategy given to this Instrumentor. InstructionList
* is then split into four InstructionLists as follows:
* <blockquote>
* <code>iiiiiii XXXXXXX iiiiiii XXXX i XXX</code>
* </blockquote>
* each of which are forwarded to the following Instrumentor in chain.
*
* @see Strategy
* @author Mika Riekkinen
* @author Joni Suominen
* @version $Revision: 1.7 $ $Date: 2004/03/15 14:47:53 $
*/
public class SplitInstrumentor extends AbstractInstrumentor {
private static Category log = Runtime.getLogCategory(SplitInstrumentor.class);
private Strategy strategy;
/**
* Constructor.
* @param strategy A strategy used in splitting.
*/
public SplitInstrumentor(Strategy strategy) {
log.info("SplitInstrumentor: " + strategy);
this.strategy = strategy;
}
/**
* Splits given Instructionlist into set of InstructionLists.
* InstructionLists forwarded to next Instrumentor in chain,
* have no gaps between each other. That is, if instruction list
* is split into <code>il1</code> and <code>il2</code>, and next
* instrumentor appends these two lists together, resulting instruction
* list will be the original one.
* <pre>
* il -> il1, il2
* il1 + il2 -> il
* <pre>
*
* @param il InstructionList to consider.
*/
public void instrument(InstructionList il) {
log.info("Instrumenting " + getCurrentClass().getName() + "." +
il.getDeclaringMethod().getName());
((AbstractStrategy)strategy).setInstrumentation(getInstrumentation());
List boundaries = strategy.findHotSpots(il);
//List boundaries = strategy.findBoundaries(il);
Iterator iter = boundaries.iterator();
int start = 0;
int count = 0;
HotSpot boundary = null;
while (iter.hasNext()) {
count++;
boundary = (HotSpot)iter.next();
//Boundary h = (Boundary)iter.next();
int end = boundary.getStart() - 1; // just before hot spot
if (end < start) {
// Case: start==0, end==0
// Should we continue here or not.
end = start;
}
InstructionList view = il.createView(start, end);
forward(view);
start = boundary.getEnd() + 1; // Just after hotspot
}
// Last list after last hotspot
if (boundary != null) {
//forward(il.createView(boundary.getEnd() + 1));
int end = boundary.getEnd() + 1;
if (end > il.size()) {
// HotSpot contains the last instruction in il.
// Should we forward it or not(empty list)
// Uncomment, if empty list gets forwarded
//forward(il.createView(il.size(), il.size()));
}
else {
forward(il.createView(end, il.size()));
}
}
}
/**
* Converts this Insturmentor to String.
*/
public String toString() {
return super.toString() + "#" + strategy.toString();
}
}