package com.onpositive.instrumentation.tasks;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.EmptyVisitor;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import com.onpositive.instrumentation.processors.ClassProcessingParticipant;
import com.onpositive.instrumentation.processors.ClassProcessor;
import com.onpositive.instrumentation.processors.InstrumentationContributor;
public class Instrumentor {
private final class Checker extends EmptyVisitor {
boolean instrumented = false;
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
if (name.equals("ON_POSITIVE_INSTRUMENTED")) {
instrumented = true;
}
return super.visitField(access, name, desc, signature, value);
}
}
private final class MC extends ClassProcessingParticipant {
private final HashSet<String> notSkip;
private MC(HashSet<String> notSkip) {
this.notSkip = notSkip;
}
public boolean isInterestedIn(ClassReader reader) {
return true;
}
public void visitField(int access, String name, String desc,
String signature, Object value) {
if (name.equals("PROFILER_INSTRUMENTED")) {
}
super.visitField(access, name, desc, signature, value);
}
public InstrumentationContributor getInstrumentationContributor(
int access, String name, String desc, String signature,
String[] exceptions, GeneratorAdapter adapter) {
final String mn = name + "." + desc;
if (name.equals("<init>")) {
notSkip.add(mn);
}
if (name.equals("<clinit>")) {
notSkip.add(mn);
}
return new InstrumentationContributor(adapter) {
public void visitJumpInsn(int opcode, Label label) {
notSkip.add(mn);
super.visitJumpInsn(opcode, label);
}
public void visitInsn(int opcode) {
if (opcode == Opcodes.ATHROW) {
notSkip.add(mn);
}
super.visitInsn(opcode);
}
public void visitMethodInsn(int opcode, String owner,
String name, String desc) {
notSkip.add(mn);
super.visitMethodInsn(opcode, owner, name, desc);
}
public void visitTryCatchBlock(Label start, Label end,
Label handler, String type) {
notSkip.add(mn);
super.visitTryCatchBlock(start, end, handler, type);
}
};
}
}
public static final String D_TEMP_CD = "D:/tempCd";
CallDictionary dict;
IJavaProject jprj;
HashMap<String, IType> types = new HashMap<String, IType>();
public boolean isBinary(String type) {
IType iType = types.get(type);
if (iType != null) {
return iType.isBinary();
}
try {
iType = jprj.findType(type.replace('/', '.').replace('$', '.'));
if (iType != null) {
types.put(type, iType);
return iType.isBinary();
}
} catch (JavaModelException e) {
}
int indexOf = type.indexOf('$');
if (indexOf != -1) {
return isBinary(type.substring(0, indexOf));
}
return false;
}
public Instrumentor(CallDictionary dict, IJavaProject project) {
this.dict = dict;
jprj = project;
}
public Instrumentor() {
this.dict = new CallDictionary();
}
static Type methodTrap = Type
.getObjectType("com/onpositive/traps/Profiler");
static Method enterMethod = Method.getMethod("void enterBinaryCall(int)");
static Method exitMethod = Method.getMethod("void exitBinaryCall(int)");
public void instrumentClass1(IFile f) throws IOException, CoreException {
if (!f.exists()) {
return;
}
BufferedInputStream bufferedInputStream = new BufferedInputStream(
f.getContents());
ByteArrayOutputStream stream = new ByteArrayOutputStream((int) 10000);
try {
while (bufferedInputStream.available() >= 0) {
int k = bufferedInputStream.read();
if (k == -1) {
break;
} else {
stream.write(k);
}
}
} finally {
bufferedInputStream.close();
}
byte[] originalBytes = stream.toByteArray();
ClassReader classReader = new ClassReader(originalBytes);
int access = classReader.getAccess();
if( (access & Opcodes.ACC_INTERFACE) != 0){
return;
}
Checker classVisitor = new Checker();
classReader.accept(classVisitor, 0);
if (classVisitor.instrumented) {
// System.out.println("Instrumented:"+f.getName());
return;
}
String className = classReader.getClassName();
if (className.contains("client")) {
return;
}
if (className.startsWith("com/onpositive/gae")) {
return;
}
if (className.startsWith("com/onpositive/traps")) {
return;
}
// HashSet<IMethod> rootMethods = new HashSet<IMethod>();
// try {
// IType findType = jprj.findType(className.replace('/', '.'));
// determineRoots(rootMethods, findType);
// } catch (JavaModelException e) {
// return;
// }
// if (className.contains("client")) {
// return;
// }
byte[] processClass = null;
ClassProcessor p = new ClassProcessor();
final HashSet<String> notSkip = new HashSet<String>();
MC participant = new MC(notSkip);
p.addParticipant(participant);
HashSet<String> pr = new HashSet<String>();
pr.add("java/");
p.addParticipant(new CallTracerParticipant(this, pr));
// ClassTransformer pa = new
// MethodEnterExitHookTransformer(this,notSkip);
processClass = p.processClass(originalBytes);
if (processClass == null) {
processClass = originalBytes;
}
if (true) {
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES
| ClassWriter.COMPUTE_MAXS);
// pa.setTarget(writer);
ClassReader reader = new ClassReader(processClass);
CustomClassInstrumentator pa = new CustomClassInstrumentator(this,writer,className);
reader.accept(pa, ClassReader.SKIP_FRAMES);
processClass = writer.toByteArray();
}
if (processClass != null) {
f.setContents(new ByteArrayInputStream(processClass), true, false,
new NullProgressMonitor());
}
}
}