Commit 50561463 authored by Lubomir Bulej's avatar Lubomir Bulej

AsmHelper: added cloneMethod() to phase out the ClonedCode class.

CodeMerger: use cloneMethod() to create a clone of a MethodNode.
CodeMerger: cleaned up to make the structure of the bypass check and merged code more obvious.
parent ec5b7a4a
......@@ -16,7 +16,7 @@ import org.objectweb.asm.tree.TryCatchBlockNode;
import ch.usi.dag.disl.dynamicbypass.BypassCheck;
import ch.usi.dag.disl.exception.DiSLFatalException;
import ch.usi.dag.disl.util.AsmHelper.ClonedCode;
import ch.usi.dag.disl.util.AsmHelper;
abstract class CodeMerger {
......@@ -33,8 +33,8 @@ abstract class CodeMerger {
// 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) {
public static ClassNode mergeClasses (final ClassNode origCN,
final ClassNode instCN, final Set <String> changedMethods) {
// NOTE: that instrumentedCN can contain added fields
// - has to be returned
......@@ -46,54 +46,59 @@ abstract class CodeMerger {
// no changed method - no merging
if (changedMethods.isEmpty ()) {
return instrumentedCN;
return instCN;
}
// 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)) {
for (final MethodNode instMN : instCN.methods) {
if (!changedMethods.contains (instMN.name + instMN.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));
//
// Merge original method code into the instrumented method code.
// Duplicate the original method code to preserve it for the case
// where the resulting method is too long.
//
final MethodNode cloneMN = AsmHelper.cloneMethod (getMethodNode (
origCN, instMN.name, instMN.desc
));
__createBypassCheck (
instMN.instructions, instMN.tryCatchBlocks,
cloneMN.instructions, cloneMN.tryCatchBlocks
);
}
return instrumentedCN;
return instCN;
}
private static void __createBypassCheck (
final InsnList instCode, final List <TryCatchBlockNode> instTcbs,
final InsnList origCode, final List <TryCatchBlockNode> origTcbs
) {
// The bypass check code has the following layout:
//
// if (!BypassCheck.executeUninstrumented ()) {
// <instrumented code>
// } else {
// <original code>
// }
//
final MethodInsnNode checkNode = new MethodInsnNode (
Opcodes.INVOKESTATIC, BPC_CLASS, BPC_METHOD, BPC_DESC, false
);
instCode.insert (checkNode);
final LabelNode origLabel = new LabelNode ();
instCode.insert (checkNode, new JumpInsnNode (Opcodes.IFNE, origLabel));
instCode.add (origLabel);
instCode.add (origCode);
instTcbs.addAll (origTcbs);
}
// NOTE: the originalCN and instrumentedCN will be destroyed in the process
// NOTE: abstract or native methods should not be included in the
// changedMethods list
......
......@@ -438,6 +438,27 @@ public abstract class AsmHelper {
//
/**
* Clones a method node, including all code, try-catch blocks, and
* annotations. This is actually faster than just cloning the code and the
* try-catch blocks by hand.
*
* @param method
* {@link MethodNode} to clone
* @return a new instance of {@link MethodNode}
*/
public static MethodNode cloneMethod (final MethodNode method) {
final MethodNode result = new MethodNode (
Opcodes.ASM5, method.access, method.name, method.desc,
method.signature, method.exceptions.toArray (
new String [method.exceptions.size ()]
)
);
method.accept (result);
return result;
}
public static final class ClonedCode {
private final InsnList __instructions;
private final List <TryCatchBlockNode> __tryCatchBlocks;
......
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