package alt.jiapi.event;
import java.lang.reflect.Modifier;
import alt.jiapi.InstrumentationException;
import alt.jiapi.Instrumentor;
import alt.jiapi.reflect.FieldExistsException;
import alt.jiapi.reflect.Instruction;
import alt.jiapi.reflect.InstructionFactory;
import alt.jiapi.reflect.InstructionList;
import alt.jiapi.reflect.JiapiClass;
import alt.jiapi.reflect.JiapiField;
import alt.jiapi.reflect.JiapiMethod;
import alt.jiapi.reflect.Loader;
import alt.jiapi.reflect.MethodExistsException;
import alt.jiapi.reflect.Signature;
/**
* Class EventInstrumentor.
*
* @author Mika Riekkinen
*/
public abstract class EventInstrumentor implements Instrumentor {
private EventProducer ep;
private JiapiField eventProducerField;
private JiapiClass currentClass;
protected EventInstrumentor(EventProducer ep) {
this.ep = ep;
}
/**
* Matches given String to resolutions set to event-producer.
*/
public boolean match(String s) {
return ep.match(s);
}
/**
* Called by Jiapi insturmentation process.
*/
public void instrument(JiapiClass jc) {
this.currentClass = jc;
if (jc.isInterface()) {
return;
}
// Instrument all the methods
JiapiMethod[] dMethods = jc.getDeclaredMethods();
for (int i = 0; i < dMethods.length; i++) {
// Do not instrument methods syntesized by jiapi
if (!dMethods[i].isSynthetic()) {
// Abstract methods do not have instruction list
if (dMethods[i].getInstructionList() != null) {
int su1 = dMethods[i].getInstructionList().stackUsage();
instrument(dMethods[i]);
int su2 = dMethods[i].getInstructionList().stackUsage();
if (su1 != su2) {
System.out.println("ERROR: " + "Instrumentation of " + jc.getName() + ": " + dMethods[i] + " changes stack usage from " + su1 + " to " + su2);
//throw new InstrumentationException("Instrumentation of " + jc.getName() + ": " + dMethods[i] + " changes stack usage from " + su1 + " to " + su2);
}
}
}
}
}
protected JiapiClass getEventProducer() {
JiapiClass jc = null;
try {
jc = new Loader().loadClass(ep.getClass().getName());
}
catch(Exception e) {
System.out.println("ERROR: " + e);
}
return jc;
}
protected JiapiField getEventProducerField() {
String fieldName = "__jiapi_field_" +
EventRuntime.nextFieldNameIndex();
// Store EventProducer in EventRuntime,
// so that it can be retrieved later by instrumented class
// when they are instantiated.
EventRuntime.setFieldValue(fieldName, ep);
// First add a field to hold event producer
eventProducerField = null;
try {
eventProducerField =
currentClass.addField(Modifier.PRIVATE +Modifier.STATIC,
ep.getClass().getName(), fieldName);
}
catch(FieldExistsException fee) {
// ERROR
}
// Next, create static initializer, that initializes
// field created above.
JiapiMethod clinit = null;
try {
clinit = currentClass.getDeclaredMethod("<clinit>",new String[]{});
}
catch(NoSuchMethodException nsme) {
// It did not exists, so create one
try {
clinit =
currentClass.addMethod(Modifier.STATIC, "<clinit>",
new Signature("void",
new String[0]));
// create 'return' from <clinit>
clinit.getInstructionList().add(clinit.getInstructionList().getInstructionFactory().returnMethod(clinit));
}
catch(MethodExistsException mee) {
mee.printStackTrace();
}
}
InstructionList il = clinit.getInstructionList();
InstructionFactory factory = il.getInstructionFactory();
InstructionList initializer = il.createEmptyList();
try {
JiapiClass er = currentClass.getLoader().loadClass("alt.jiapi.event.EventRuntime");
JiapiMethod gfv =
er.getDeclaredMethod("getFieldValue",
new String[] {"java.lang.String"});
// Get the field value from runtime
initializer.add(factory.pushConstant(fieldName));
initializer.add(factory.invoke(gfv));
// put the returned event producer to __jiapi_field
initializer.add(factory.cast(ep.getClass().getName()));
initializer.add(factory.setField(eventProducerField));
}
catch(NoSuchMethodException nsme) {
nsme.printStackTrace();
}
catch(ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
catch(java.io.IOException ioe) {
ioe.printStackTrace();
}
// Insert initializer code before 'return'
il.insert(0, initializer);
return eventProducerField;
}
public JiapiClass getCurrentClass() {
return currentClass;
}
public abstract void instrument(JiapiMethod jm);
}