Commit 7a6819fa authored by Yudi Zheng's avatar Yudi Zheng

bugfix: long method is now handled when the dynamic bypass is disabled

parent 15e7de68
......@@ -173,6 +173,11 @@ def server_parser(parser):
default=False,
help="does not instrument exception handler (improves performance but does not protect from errors within instrumentation)")
group.add_argument("-s_nodynamicbypass",
action="store_true",
default=False,
help="does not apply dynamic bypass")
group.add_argument("-s_exclusionlist",
default=None,
metavar="PATH",
......@@ -333,6 +338,8 @@ def parse_arguments(parser):
args.s_opts+= ["-Ddislserver.port="+args.s_port]
if args.s_noexcepthandler is True:
args.s_opts+= ["-Ddisl.noexcepthandler=true"]
if args.s_nodynamicbypass is True:
args.s_opts+= ["-Ddislserver.disablebypass=true"]
if args.s_exclusionlist is not None:
args.s_opts+= ["-Ddisl.exclusionList="+args.s_exclusionlist]
if args.s_instrumented is not None:
......
......@@ -18,140 +18,150 @@ import ch.usi.dag.disl.dynamicbypass.BypassCheck;
import ch.usi.dag.disl.exception.DiSLFatalException;
import ch.usi.dag.disl.util.AsmHelper.ClonedCode;
abstract class CodeMerger {
private static final String BPC_CLASS = Type.getInternalName (BypassCheck.class);
private static final String BPC_METHOD = "executeUninstrumented";
private static final String BPC_DESC = "()Z";
private static final int ALLOWED_SIZE = 64 * 1024; // 64KB limit
// 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<String> changedMethods,
boolean splitLongMethods) {
// NOTE: that instrumentedCN can contain added fields
// - has to be returned
if(changedMethods == null) {
throw new DiSLFatalException(
"Set of changed methods cannot be null");
}
// no changed method - no merging
if (changedMethods.isEmpty()) {
return instrumentedCN;
}
// merge methods one by one
for (MethodNode instrMN : instrumentedCN.methods) {
// We will construct the merged method node in the instrumented
// class node
// skip unchanged methods
if(! changedMethods.contains(instrMN.name + instrMN.desc)) {
continue;
}
MethodNode origMN = getMethodNode(originalCN, instrMN.name,
instrMN.desc);
InsnList ilist = instrMN.instructions;
List<TryCatchBlockNode> tcblist = instrMN.tryCatchBlocks;
// crate copy of the original instruction list
// this copy will be destroyed during merging
// we need the original code if the method is too long
ClonedCode origCodeCopy = ClonedCode.create (
origMN.instructions, origMN.tryCatchBlocks
);
// create copy of the lists for splitting
ClonedCode splitCopy = null;
if (splitLongMethods) {
splitCopy = ClonedCode.create (ilist, tcblist);
}
// add reference to the original code
LabelNode origCodeL = new LabelNode();
ilist.add(origCodeL);
// add original code
ilist.add(origCodeCopy.getInstructions());
// add exception handlers of the original code
tcblist.addAll(origCodeCopy.getTryCatchBlocks());
// if the dynamic bypass is activated (non-zero value returned)
// then jump to original code
ilist.insert(new JumpInsnNode(Opcodes.IFNE, origCodeL));
ilist.insert(new MethodInsnNode(Opcodes.INVOKESTATIC,
BPC_CLASS, BPC_METHOD, BPC_DESC));
// calculate the code size and if it is larger then allowed size,
// skip it
CodeSizeEvaluator cse = new CodeSizeEvaluator(null);
instrMN.accept(cse);
if (cse.getMaxSize() > ALLOWED_SIZE) {
if(splitLongMethods) {
// return originally instrumented code back to the instrMN
instrMN.instructions = splitCopy.getInstructions();
instrMN.tryCatchBlocks = splitCopy.getTryCatchBlocks();
// split methods
splitLongMethods(instrumentedCN, origMN, instrMN);
// next method
continue;
}
// insert original code into the instrumented method node
instrMN.instructions = origMN.instructions;
instrMN.tryCatchBlocks = origMN.tryCatchBlocks;
// print error msg
System.err.println("WARNING: code of the method "
+ instrumentedCN.name + "." + instrMN.name
+ " is larger ("
+ cse.getMaxSize()
+ ") then allowed size (" +
+ ALLOWED_SIZE
+ ") - skipping");
}
}
return instrumentedCN;
}
private static void splitLongMethods(ClassNode instrumentedCN,
MethodNode origMN, MethodNode instrMN) {
// TODO jb ! add splitting for to long methods
// - ignore clinit - output warning
// - output warning if splitted is to large and ignore
// check the code size of the instrumented method
// add if to the original method that jumps to the renamed instrumented method
// add original method to the instrumented code
// rename instrumented method
}
private static MethodNode getMethodNode(ClassNode cnToSearch,
String methodName, String methodDesc) {
for (MethodNode mn : cnToSearch.methods) {
if (methodName.equals(mn.name) && methodDesc.equals(mn.desc)) {
return mn;
}
}
throw new RuntimeException(
"Code merger fatal error: method for merge not found");
}
private static final String BPC_CLASS = Type.getInternalName (BypassCheck.class);
private static final String BPC_METHOD = "executeUninstrumented";
private static final String BPC_DESC = "()Z";
private static final int ALLOWED_SIZE = 64 * 1024; // 64KB limit
// 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 (final ClassNode originalCN,
final ClassNode instrumentedCN, final Set <String> 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");
}
// no changed method - no merging
if (changedMethods.isEmpty ()) {
return instrumentedCN;
}
// merge methods one by one
for (final MethodNode instrMN : instrumentedCN.methods) {
// We will construct the merged method node in the instrumented
// class node
// skip unchanged methods
if (!changedMethods.contains (instrMN.name + instrMN.desc)) {
continue;
}
final MethodNode origMN = getMethodNode (originalCN, instrMN.name,
instrMN.desc);
final InsnList ilist = instrMN.instructions;
final List <TryCatchBlockNode> tcblist = instrMN.tryCatchBlocks;
// crate copy of the original instruction list
// this copy will be destroyed during merging
// we need the original code if the method is too long
final ClonedCode origCodeCopy = ClonedCode.create (
origMN.instructions, origMN.tryCatchBlocks
);
// add reference to the original code
final LabelNode origCodeL = new LabelNode ();
ilist.add (origCodeL);
// add original code
ilist.add (origCodeCopy.getInstructions ());
// add exception handlers of the original code
tcblist.addAll (origCodeCopy.getTryCatchBlocks ());
// if the dynamic bypass is activated (non-zero value returned)
// then jump to original code
ilist.insert (new JumpInsnNode (Opcodes.IFNE, origCodeL));
ilist.insert (new MethodInsnNode (Opcodes.INVOKESTATIC,
BPC_CLASS, BPC_METHOD, BPC_DESC));
}
return instrumentedCN;
}
// 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 handleLongMethod (final ClassNode originalCN,
final ClassNode instrumentedCN, final boolean splitLongMethods) {
// merge methods one by one
for (final MethodNode instrMN : instrumentedCN.methods) {
// calculate the code size and if it is larger then allowed size,
// skip it
final CodeSizeEvaluator cse = new CodeSizeEvaluator (null);
instrMN.accept (cse);
if (cse.getMaxSize () > ALLOWED_SIZE) {
final MethodNode origMN = getMethodNode (originalCN, instrMN.name,
instrMN.desc);
if (splitLongMethods) {
// split methods
splitLongMethods (instrumentedCN, origMN, instrMN);
} else {
// insert original code into the instrumented method node
instrMN.instructions = origMN.instructions;
instrMN.tryCatchBlocks = origMN.tryCatchBlocks;
// print error msg
System.err.println ("WARNING: code of the method "
+ instrumentedCN.name + "." + instrMN.name
+ " is larger ("
+ cse.getMaxSize ()
+ ") then allowed size (" +
+ALLOWED_SIZE
+ ") - skipping");
}
}
}
return instrumentedCN;
}
private static void splitLongMethods (final ClassNode instrumentedCN,
final MethodNode origMN, final MethodNode instrMN) {
// TODO jb ! add splitting for to long methods
// - ignore clinit - output warning
// - output warning if splitted is to large and ignore
// check the code size of the instrumented method
// add if to the original method that jumps to the renamed instrumented
// method
// add original method to the instrumented code
// rename instrumented method
}
private static MethodNode getMethodNode (final ClassNode cnToSearch,
final String methodName, final String methodDesc) {
for (final MethodNode mn : cnToSearch.methods) {
if (methodName.equals (mn.name) && methodDesc.equals (mn.desc)) {
return mn;
}
}
throw new RuntimeException (
"Code merger fatal error: method for merge not found");
}
}
......@@ -518,20 +518,23 @@ public final class DiSL {
return null;
}
// TODO long method generated by Transformer is still not covered
ClassNode instrCN = instrClass.getClassNode();
// if dynamic bypass is enabled use code merger
if (useDynamicBypass) {
final ClassReader origCR = new ClassReader(classAsBytes);
final ClassNode origCN = new ClassNode();
final ClassReader origCR = new ClassReader(classAsBytes);
final ClassNode origCN = new ClassNode();
origCR.accept(origCN, ClassReader.EXPAND_FRAMES);
origCR.accept(origCN, ClassReader.EXPAND_FRAMES);
// if dynamic bypass is enabled use code merger
if (useDynamicBypass) {
// origCN and instrCN are destroyed during the merging
instrCN = CodeMerger.mergeClasses(origCN, instrCN,
instrClass.getChangedMethods(), splitLongMethods);
instrClass.getChangedMethods());
}
instrCN = CodeMerger.handleLongMethod (origCN, instrCN, splitLongMethods);
// DiSL uses some instructions available only in higher versions
final int REQUIRED_VERSION = Opcodes.V1_5;
final int MAJOR_V_MASK = 0xFFFF;
......
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