Commit b703ccfa authored by Lukáš Marek's avatar Lukáš Marek

Merge only methods that are instrumented

parent 1f7c8e57
......@@ -160,6 +160,14 @@ public class DiSL {
if ((methodNode.access & Opcodes.ACC_NATIVE) != 0) {
return false;
}
// TODO jb ! document
// skip finalize method in java.lang.Object
final String METHOD_FINALIZE = "finalize";
if (methodNode.name.equals(METHOD_FINALIZE) &&
classNode.name.equals(Type.getInternalName(Object.class))) {
return false;
}
// *** match snippet scope ***
......@@ -265,27 +273,55 @@ public class DiSL {
return selectedMarking;
}
private static class InstrumentedClass {
private ClassNode classNode;
private Set<MethodNode> changedMethods;
public InstrumentedClass(ClassNode classNode,
Set<MethodNode> changedMethods) {
super();
this.classNode = classNode;
this.changedMethods = changedMethods;
}
public ClassNode getClassNode() {
return classNode;
}
public Set<MethodNode> getChangedMethods() {
return changedMethods;
}
}
// this method is thread safe after initialization
private ClassNode instrument(ClassNode classNode) throws DiSLException {
private InstrumentedClass instrument(ClassNode classNode)
throws DiSLException {
// report DiSL exception within our code
try {
// NOTE that class can be changed without changing any method
// - adding thread local fields
boolean classChanged = false;
// track changed methods for code merging
Set<MethodNode> changedMethods = new HashSet<MethodNode>();
// instrument all methods in a class
for (MethodNode methodNode : classNode.methods) {
boolean methodChanged = instrumentMethod(classNode, methodNode);
classChanged = classChanged || methodChanged;
// add method to the set of changed methods
if(methodChanged) {
changedMethods.add(methodNode);
classChanged = true;
}
}
// instrument thread local fields
String threadInternalName =
Type.getType(Thread.class).getInternalName();
if (threadInternalName.equals(classNode.name)) {
if (Type.getInternalName(Thread.class).equals(classNode.name)) {
Set<ThreadLocalVar> insertTLVs = new HashSet<ThreadLocalVar>();
......@@ -316,8 +352,9 @@ public class DiSL {
}
}
// we have changed some methods
if(classChanged) {
return classNode;
return new InstrumentedClass(classNode, changedMethods);
}
return null;
......@@ -358,12 +395,14 @@ public class DiSL {
classReader.accept(classNode, ClassReader.SKIP_DEBUG
| ClassReader.EXPAND_FRAMES);
ClassNode instrCN = instrument(classNode);
InstrumentedClass instrClass = instrument(classNode);
if(instrCN == null) {
if(instrClass == null) {
return null;
}
ClassNode instrCN = instrClass.getClassNode();
// if dynamic bypass is enabled use code merger
if(useDynamicBypass) {
......@@ -374,8 +413,9 @@ public class DiSL {
origCR.accept(origCN, ClassReader.SKIP_DEBUG
| ClassReader.EXPAND_FRAMES);
// output of the merge is automatically in instrCN
CodeMerger.mergeClasses(origCN, instrCN);
// origCN and instrCN are destroyed during the merging
instrCN = CodeMerger.mergeClasses(origCN, instrCN,
instrClass.getChangedMethods());
}
// DiSL uses some instructions available only in higher versions
......
package ch.usi.dag.disl.utilinstr.codemerger;
import java.util.Set;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
......@@ -10,37 +12,41 @@ import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import ch.usi.dag.disl.dynamicbypass.DynamicBypassCheck;
import ch.usi.dag.disl.exception.DiSLFatalException;
public abstract class CodeMerger {
private static final String METHOD_FINALIZE = "finalize";
private static final String DBCHECK_CLASS = Type.getInternalName(
DynamicBypassCheck.class);
private static final String DBCHECK_METHOD = "executeUninstrumented";
private static final String DBCHECK_DESC = "()Z";
// NOTE: the instrumented class node will serve as an output
public static void mergeClasses(ClassNode originalCN,
ClassNode instrumentedCN) {
// do not merge interfaces
if ((originalCN.access & Opcodes.ACC_INTERFACE) != 0) {
return;
// NOTE: the originalCN and instrumentedCN will be destroyed in the process
// NOTE: abstract or native methods should not be included in the
// changedMethods list
public static ClassNode mergeClasses(ClassNode originalCN,
ClassNode instrumentedCN, Set<MethodNode> changedMethods) {
// NOTE: that instrumentedCN can contain added fields
// - has to be returned
if(changedMethods == null) {
throw new DiSLFatalException(
"Set of changed methods cannot be null");
}
for (MethodNode instrMN : instrumentedCN.methods) {
// evaluation is done always but is more visible then in single if
boolean methodAbstract = (instrMN.access & Opcodes.ACC_ABSTRACT) != 0;
boolean methodNative = (instrMN.access & Opcodes.ACC_NATIVE) != 0;
boolean methodFinalizeInObject = instrumentedCN.name.equals(Type
.getInternalName(Object.class))
&& instrMN.name.equals(METHOD_FINALIZE);
// no changed method - no merging
if(changedMethods.isEmpty()) {
return instrumentedCN;
}
// skip methods that should not be merged
if (methodAbstract | methodNative | methodFinalizeInObject) {
for (MethodNode instrMN : instrumentedCN.methods) {
// We will construct the merged method node in the instrumented
// class node
// skip unchanged methods
if(! changedMethods.contains(instrMN)) {
continue;
}
......@@ -49,8 +55,6 @@ public abstract class CodeMerger {
InsnList ilist = instrMN.instructions;
// TODO jb - check for similarity of the instructions
// add reference to the original code
LabelNode origCodeL = new LabelNode();
ilist.add(origCodeL);
......@@ -66,6 +70,8 @@ public abstract class CodeMerger {
ilist.insert(new MethodInsnNode(Opcodes.INVOKESTATIC,
DBCHECK_CLASS, DBCHECK_METHOD, DBCHECK_DESC));
}
return instrumentedCN;
}
private static MethodNode getMethodNode(ClassNode cnToSearch,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment