/*
* 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.ArrayList;
import java.util.List;
import org.apache.log4j.Category;
import alt.jiapi.JiapiException;
import alt.jiapi.Rule;
import alt.jiapi.Runtime;
import alt.jiapi.reflect.Instruction;
import alt.jiapi.reflect.InstructionFactory;
import alt.jiapi.reflect.InstructionList;
import alt.jiapi.reflect.JiapiMethod;
import alt.jiapi.reflect.TryBlock;
import alt.jiapi.reflect.TryBlock.ExceptionHandler;
import alt.jiapi.reflect.instruction.OpcodeGroups;
import alt.jiapi.reflect.instruction.Opcodes;
/*
* NOTE :
* It is assumed that provider is able to update Exception tables
* without any assistance from instrumentors that are in chain!!!!
*/
/**
* This Instrumentor forwards all the catch blocks of the method
* being instrumented.
*
* @author Mika Riekkinen
* @author Joni Suominen
* @version $Revision: 1.12 $ $Date: 2004/03/15 14:47:53 $
*/
public class CatchInstrumentor extends AbstractInstrumentor {
private static Category log =
Runtime.getLogCategory(CatchInstrumentor.class);
private Rule[] rules;
private boolean reverseMatch = false;
private String[] resolutions;
/**
* Empty constructor.
*/
public CatchInstrumentor() {
}
/**
* Scans current method for catch blocks.
*
* @param il InstructionList to scan
*/
public void instrument(InstructionList il) {
ArrayList al = new ArrayList();
JiapiMethod m = il.getDeclaringMethod();
Instrumentation instrumentation = getInstrumentation();
InstructionList methodInstructions = m.getInstructionList();
// TryBlock[] tryBlocks = m.getTryBlocks();
// for (int i = 0; i < tryBlocks.length; i++) {
// ExceptionHandler[] eh = tryBlocks[i].getExceptionHandlers();
// for (int j = 0; j < eh.length; j++) {
// String targetName = eh[j].getName();
// if (match(targetName)) { // Resolution
// Instruction catchStart = eh[j].getHandlerStart();
// int idx = methodInstructions.indexOf(catchStart);
// InstructionList catchInstructions =
// methodInstructions.createView(idx);
// // eh[j].getInstructionList();
// instrumentation.setTargetName(targetName);
// analyze(catchInstructions, instrumentation);
// // Folowing line forwards catch block without its first
// // instruction, which byt default is ASTORE(_X)
// // If that is not the case, should we forward view from
// // offset 0.
// forward(catchInstructions.createView(1));
// }
// }
// }
throw new RuntimeException("NOT IMPLEMENTED");
}
// Analyzes Catch instructions and tries to determine
// set of instructions, that is needed to get target
// (Exception in this case). Subsequent Instrumentors
// might need this piece of code.
// Other analyzations may be added later.
private boolean analyze(InstructionList il,
Instrumentation instrumentation) {
InstructionList targetCode = null;
int index = 0;
if (il.size() > 0) {
index = il.indexOf(OpcodeGroups.REFERENCE_STORE_INSTRUCTIONS,0);
log.debug("First instruction during analyze is " + il.get(0));
if (index == 0) {
InstructionFactory factory =
il.getInstructionFactory();
// First instruction should be the one that stores
// Exception instance into local variable<n>.
// If it is not, we might have already instrumented this part
// of the code.
// targetCode = il.createEmptyList();
if (true)
throw new RuntimeException("NOT IMPLEMENTED");
Instruction i = il.get(0);
int lvIdx = -1;
switch(i.getOpcode()) {
case Opcodes.ASTORE:
// throws NullPointerException
//lvIdx = Integer.parseInt(i.getOperand().toString());
lvIdx = -1; // Force failure
break;
case Opcodes.ASTORE_0:
lvIdx = 0;
break;
case Opcodes.ASTORE_1:
lvIdx = 1;
break;
case Opcodes.ASTORE_2:
lvIdx = 2;
break;
case Opcodes.ASTORE_3:
lvIdx = 3;
break;
default:
// Not possible
}
if (lvIdx >= 0) {
if (true)
throw new RuntimeException("NOT IMPLEMENTED");
// targetCode.add(factory.getLocalVariable(lvIdx, "java.lang.Object"));
log.debug("Analyze succeeded. Target code is " +
targetCode + ", local variable is at index " +
lvIdx);
}
}
}
if (targetCode == null) {
log.debug("Analyze failed, setting target code to null");
}
instrumentation.setTargetCode(targetCode);
return targetCode != null;
}
public void setResolutions(String[] resolutions) {
this.resolutions = resolutions;
createRules(resolutions);
}
/**
* Compares given String to resolutions of this Instrumentor.
*
* @return true, if match is found in any of the resolutions.
*/
protected boolean match(String name) {
if (name == null || rules == null) {
return false;
}
boolean b = false;
for (int i = 0; i < rules.length; i++) {
if (rules[i].match(name)) {
b = true;
break;
}
}
// If reverseMatch, toggle b
b = b ^ reverseMatch;
return b;
}
// Converts resolutions to rules.
private void createRules(String[] resolutions) {
if(resolutions == null) {
return;
}
this.rules = new Rule[resolutions.length];
for (int i = 0; i < resolutions.length; i++) {
try {
rules[i] = new Rule(resolutions[i]);
}
catch(Exception e) {
log.error(e.getMessage());
}
}
}
}