Commit 664f2e0e authored by Yudi Zheng's avatar Yudi Zheng
Browse files

Add weaver support for ProcessorContext.getReceiver.

parent 08c1f905
......@@ -3,83 +3,24 @@ package ch.usi.dag.disl.marker;
import java.util.LinkedList;
import java.util.List;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.AdviceAdapter;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodNode;
import ch.usi.dag.disl.util.Constants;
import ch.usi.dag.disl.util.AsmHelper;
public class AfterInitBodyMarker extends AbstractMarker {
// empty visitor for new AdviceAdapter
private static class EmptyMethodVisitor extends MethodVisitor {
public EmptyMethodVisitor() {
super(Opcodes.ASM4);
}
}
// Get the first valid mark of a method.
// For a constructor, the return value will be the instruction after
// the object initialization.
public AbstractInsnNode findFirstValidMark(MethodNode method) {
AbstractInsnNode first = method.instructions.getFirst();
// This is not a constructor. Just return the first instruction
if (!method.name.equals(Constants.CONSTRUCTOR_NAME)) {
return first;
}
// AdviceAdapter will help us with identifying the proper place where
// the constructor to super is called
// just need an object that will hold a value
// - we need access to the changeable boolean via reference
class DataHolder {
boolean trigger = false;
}
final DataHolder dh = new DataHolder();
AdviceAdapter adapter = new AdviceAdapter(Opcodes.ASM4,
new EmptyMethodVisitor(), method.access, method.name,
method.desc) {
public void onMethodEnter() {
dh.trigger = true;
}
};
// Iterate instruction list till the instruction right after the
// object initialization
adapter.visitCode();
for (AbstractInsnNode iterator : method.instructions.toArray()) {
iterator.accept(adapter);
// first instruction will be instruction after constructor call
if (dh.trigger) {
first = iterator.getNext();
break;
}
}
return first;
}
@Override
public List<MarkedRegion> mark(MethodNode method) {
List<MarkedRegion> regions = new LinkedList<MarkedRegion>();
MarkedRegion region =
new MarkedRegion(findFirstValidMark(method));
MarkedRegion region = new MarkedRegion(
AsmHelper.findFirstValidMark(method));
for (AbstractInsnNode instr : method.instructions.toArray()) {
int opcode = instr.getOpcode();
if (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) {
......
......@@ -10,7 +10,6 @@ public interface ProcessorContext {
*/
public void apply(Class<?> processorClass, ProcessorMode mode);
// TODO ! processor - add support
/**
* Returns the object on which is the processed method (arguments of that
* method) called.
......
......@@ -6,8 +6,10 @@ import java.util.List;
import java.util.Map;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.AdviceAdapter;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.IincInsnNode;
......@@ -523,4 +525,61 @@ public abstract class AsmHelper {
}
}
// empty visitor for new AdviceAdapter
private static class EmptyMethodVisitor extends MethodVisitor {
public EmptyMethodVisitor() {
super(Opcodes.ASM4);
}
}
// Get the first valid mark of a method.
// For a constructor, the return value will be the instruction after
// the object initialization.
public static AbstractInsnNode findFirstValidMark(MethodNode method) {
AbstractInsnNode first = method.instructions.getFirst();
// This is not a constructor. Just return the first instruction
if (!method.name.equals(Constants.CONSTRUCTOR_NAME)) {
return first;
}
// AdviceAdapter will help us with identifying the proper place where
// the constructor to super is called
// just need an object that will hold a value
// - we need access to the changeable boolean via reference
class DataHolder {
boolean trigger = false;
}
final DataHolder dh = new DataHolder();
AdviceAdapter adapter = new AdviceAdapter(Opcodes.ASM4,
new EmptyMethodVisitor(), method.access, method.name,
method.desc) {
public void onMethodEnter() {
dh.trigger = true;
}
};
// Iterate instruction list till the instruction right after the
// object initialization
adapter.visitCode();
for (AbstractInsnNode iterator : method.instructions.toArray()) {
iterator.accept(adapter);
// first instruction will be instruction after constructor call
if (dh.trigger) {
first = iterator.getNext();
break;
}
}
return first;
}
}
......@@ -220,7 +220,7 @@ public class Weaver {
snippetMarkings);
for (Snippet snippet : info.getSortedSnippets()) {
List<Shadow> regions = snippetMarkings.get(snippet);
List<Shadow> shadows = snippetMarkings.get(snippet);
SnippetCode code = snippet.getCode();
// skip snippet with empty code
......@@ -232,12 +232,12 @@ public class Weaver {
// For @Before, instrument the snippet just before the
// entrance of a region.
if (snippet.getAnnotationClass().equals(Before.class)) {
for (Shadow region : regions) {
for (Shadow shadow : shadows) {
AbstractInsnNode loc = info.getWeavingStart().get(
region.getRegionStart());
shadow.getRegionStart());
int index = info.getStackStart().get(
region.getRegionStart());
shadow.getRegionStart());
// exception handler will discard the stack and push the
// exception object. Thus, before entering this snippet,
......@@ -258,8 +258,8 @@ public class Weaver {
loc = temp;
}
WeavingCode wCode = new WeavingCode(info, code, methodNode,
snippet, region, index);
WeavingCode wCode = new WeavingCode(info, methodNode, code,
loc, snippet, shadow, index);
wCode.transform(staticInfoHolder, piResolver);
methodNode.instructions.insertBefore(loc, wCode.getiList());
......@@ -272,7 +272,7 @@ public class Weaver {
// after each adjusted exit of a region.
if (snippet.getAnnotationClass().equals(AfterReturning.class)
|| snippet.getAnnotationClass().equals(After.class)) {
for (Shadow region : regions) {
for (Shadow region : shadows) {
for (AbstractInsnNode exit : region.getRegionEnds()) {
......@@ -297,8 +297,8 @@ public class Weaver {
loc = temp;
}
WeavingCode wCode = new WeavingCode(info, code,
methodNode, snippet, region, index);
WeavingCode wCode = new WeavingCode(info, methodNode,
code, loc.getNext(), snippet, region, index);
wCode.transform(staticInfoHolder, piResolver);
methodNode.instructions.insert(loc, wCode.getiList());
......@@ -313,7 +313,7 @@ public class Weaver {
if (snippet.getAnnotationClass().equals(AfterThrowing.class)
|| snippet.getAnnotationClass().equals(After.class)) {
for (Shadow region : regions) {
for (Shadow region : shadows) {
// after-throwing inserts the snippet once, and marks
// the start and the very end as the scope
AbstractInsnNode last = info.getWeavingThrow().get(region);
......@@ -333,8 +333,9 @@ public class Weaver {
last_index = info.getStackEnd().get(last);
}
WeavingCode wCode = new WeavingCode(info, code, methodNode,
snippet, region, last_index);
WeavingCode wCode = new WeavingCode(info, methodNode, code,
region.getRegionStart(), snippet, region,
last_index);
wCode.transform(staticInfoHolder, piResolver);
// Create a try-catch clause
......
......@@ -44,28 +44,29 @@ public class WeavingCode {
private WeavingInfo info;
private MethodNode method;
private SnippetCode code;
private AbstractInsnNode weavingLocation;
private InsnList iList;
private AbstractInsnNode[] iArray;
private Snippet snippet;
private Shadow region;
private Shadow shadow;
private int index;
private int maxLocals;
public WeavingCode(WeavingInfo weavingInfo, SnippetCode src,
MethodNode method, Snippet snippet, Shadow region, int index) {
info = weavingInfo;
code = src.clone();
iList = code.getInstructions();
iArray = iList.toArray();
public WeavingCode(WeavingInfo weavingInfo, MethodNode method,
SnippetCode src, AbstractInsnNode loc, Snippet snippet,
Shadow shadow, int index) {
this.info = weavingInfo;
this.method = method;
this.code = src.clone();
this.weavingLocation = loc;
this.snippet = snippet;
this.region = region;
this.shadow = shadow;
this.index = index;
this.iList = code.getInstructions();
this.iArray = iList.toArray();
maxLocals = MaxCalculator
.getMaxLocal(iList, method.desc, method.access);
}
......@@ -86,10 +87,10 @@ public class WeavingCode {
MethodInsnNode invocation = (MethodInsnNode) instr;
if (staticInfoHolder.contains(region, invocation.owner,
if (staticInfoHolder.contains(shadow, invocation.owner,
invocation.name)) {
Object const_var = staticInfoHolder.get(region,
Object const_var = staticInfoHolder.get(shadow,
invocation.owner, invocation.name);
if (const_var != null) {
......@@ -474,7 +475,7 @@ public class WeavingCode {
for (int i : code.getInvokedProcessors().keySet()) {
AbstractInsnNode instr = iArray[i];
ProcInstance processor = piResolver.get(region, i);
ProcInstance processor = piResolver.get(shadow, i);
if (processor != null) {
if (processor.getProcApplyType() == ProcessorMode.METHOD_ARGS) {
......@@ -492,7 +493,7 @@ public class WeavingCode {
}
}
public InsnList createGetArgsCode(String methodDescriptor) {
private InsnList createGetArgsCode(String methodDescriptor) {
InsnList insnList = new InsnList();
......@@ -551,16 +552,17 @@ public class WeavingCode {
continue;
}
if (invoke.name.equals("getArgs")) {
AbstractInsnNode prev = instr.getPrevious();
AbstractInsnNode prev = instr.getPrevious();
if (prev.getOpcode() != Opcodes.GETSTATIC) {
throw new DiSLFatalException("Unknown processor mode");
}
ProcessorMode procApplyType = ProcessorMode
.valueOf(((FieldInsnNode) prev).name);
if (invoke.name.equals("getArgs")) {
if (prev.getOpcode() != Opcodes.GETSTATIC) {
throw new DiSLFatalException("Unknown processor mode");
}
ProcessorMode procApplyType = ProcessorMode
.valueOf(((FieldInsnNode) prev).name);
InsnList args = null;
if (procApplyType == ProcessorMode.METHOD_ARGS) {
......@@ -572,7 +574,7 @@ public class WeavingCode {
} else {
AbstractInsnNode callee = AsmHelper.skipVirualInsns(
region.getRegionStart(), true);
shadow.getRegionStart(), true);
if (!(callee instanceof MethodInsnNode)) {
throw new DiSLFatalException("Unexpected instruction");
......@@ -583,6 +585,10 @@ public class WeavingCode {
Frame<SourceValue> frame = info.getSourceFrame(callee);
if (frame == null) {
throw new DiSLFatalException("Unknown target");
}
int argIndex = 0;
for (int i = 0; i < argTypes.length; i++) {
......@@ -600,8 +606,6 @@ public class WeavingCode {
method.instructions.insert(itr,
new InsnNode(type.getSize() == 2 ? Opcodes.DUP2
: Opcodes.DUP));
method.instructions.insert(itr,
new InsnNode(Opcodes.NOP));
}
argIndex += type.getSize();
......@@ -613,6 +617,58 @@ public class WeavingCode {
}
iList.insert(instr, args);
} else if (invoke.name.equals("getReceiver")) {
if (procApplyType == ProcessorMode.METHOD_ARGS) {
if ((method.access & Opcodes.ACC_STATIC) != 0) {
iList.insert(instr, new InsnNode(Opcodes.ACONST_NULL));
} else if (method.name.equals("<init>")
&& AsmHelper.before(weavingLocation,
AsmHelper.findFirstValidMark(method))) {
// TODO warn user that fetching object before initialization will violate the verifying
iList.insert(instr, new InsnNode(Opcodes.ACONST_NULL));
} else {
iList.insert(instr, new VarInsnNode(Opcodes.ALOAD,
-method.maxLocals));
}
} else {
AbstractInsnNode callee = AsmHelper.skipVirualInsns(
shadow.getRegionStart(), true);
if (!(callee instanceof MethodInsnNode)) {
throw new DiSLFatalException("Unexpected instruction");
}
Frame<SourceValue> frame = info.getSourceFrame(callee);
if (frame == null) {
throw new DiSLFatalException("Unknown target");
}
if (callee.getOpcode() == Opcodes.INVOKESTATIC) {
iList.insert(instr, new InsnNode(Opcodes.ACONST_NULL));
} else {
String desc = ((MethodInsnNode) callee).desc;
SourceValue source = StackUtil.getStackByIndex(frame,
Type.getArgumentTypes(desc).length);
for (AbstractInsnNode itr : source.insns) {
method.instructions.insert(itr, new VarInsnNode(
Opcodes.ASTORE,
// TRICK: the value has to be set properly because
// method code will be not adjusted by fixLocalIndex
method.maxLocals + maxLocals));
method.instructions.insert(itr, new InsnNode(
Opcodes.DUP));
}
iList.insert(instr, new VarInsnNode(Opcodes.ALOAD,
method.maxLocals + maxLocals));
maxLocals++;
}
}
}
iList.remove(instr.getPrevious());
......
......@@ -45,8 +45,11 @@ public class MaxCalculator {
public static int getMaxLocal(InsnList ilist, String desc, int access) {
int maxLocals = ((access & Opcodes.ACC_STATIC) == 0 ? 1 : 0)
+ (Type.getArgumentsAndReturnSizes(desc) >> 2);
int maxLocals = (Type.getArgumentsAndReturnSizes(desc) >> 2);
if ((access & Opcodes.ACC_STATIC) != 0) {
--maxLocals;
}
for (AbstractInsnNode instr : ilist.toArray()) {
......
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