Skip to content

Commit

Permalink
Skip LineNumberNode and LabelNode silently in InstrumentMethod.
Browse files Browse the repository at this point in the history
  • Loading branch information
gsimard committed Oct 9, 2016
1 parent 62a2199 commit 5ace1d6
Showing 1 changed file with 69 additions and 63 deletions.
132 changes: 69 additions & 63 deletions src/main/java/cz/advel/stack/instrument/InstrumentMethod.java
Expand Up @@ -4,11 +4,11 @@
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
Expand Down Expand Up @@ -37,25 +37,25 @@
* @author jezek2
*/
class InstrumentMethod extends MethodNode {

private static String STACK_NAME = Type.getInternalName(Stack.class);
private static String STACK_ALLOC_CLASS_DESC = Type.getMethodDescriptor(Type.getType(Object.class), new Type[] { Type.getType(Class.class) } );
private static String STACK_ALLOC_OBJECT_DESC = Type.getMethodDescriptor(Type.getType(Object.class), new Type[] { Type.getType(Object.class) } );
private static String STATIC_ALLOC_DESC = Type.getDescriptor(StaticAlloc.class);

// Matthias Mann's Continuations library, see: http://www.matthiasmann.de/content/view/24/26/
private static String CONTINUATIONS_SUSPEND_EXECUTION_NAME = "de/matthiasmann/continuations/SuspendExecution";

private Instrumenter instr;
private InstrumentClass inscls;
private String className;
private ClassVisitor cv;

private List<Frame> frames;

private boolean disableAllocation;
private boolean staticAllocation = false;

boolean emitMethod = true;

public InstrumentMethod(int access, String name, String desc, String signature, String[] exceptions, Instrumenter instr, InstrumentClass inscls, String className, ClassVisitor cv) {
Expand All @@ -64,7 +64,7 @@ public InstrumentMethod(int access, String name, String desc, String signature,
this.inscls = inscls;
this.className = className;
this.cv = cv;

disableAllocation = instr.isDisabled();
}

Expand All @@ -78,7 +78,7 @@ public void visitEnd() {
disableAllocation = true;
}
}

// check for StaticAlloc annotation, if present set staticAllocation to true and remove it:
if (invisibleAnnotations != null) {
for (int i=0; i<invisibleAnnotations.size(); i++) {
Expand All @@ -92,43 +92,49 @@ public void visitEnd() {
}
}
}

int stackVar = maxLocals;

Analyzer analyzer = new Analyzer(new SimpleVerifier());
analyzer.analyze(className, this);
frames = new ArrayList<Frame>(Arrays.asList(analyzer.getFrames()));

Set<String> usedTypes = new HashSet<String>();
boolean createStack = false;

AbstractInsnNode insn = instructions.getFirst();

while (insn != null) {
if (insn instanceof MethodInsnNode) {
MethodInsnNode min = (MethodInsnNode)insn;

// check for Stack.alloc(Class):
if (min.owner.equals(STACK_NAME) && min.name.equals("alloc") && min.desc.equals(STACK_ALLOC_CLASS_DESC)) {
AbstractInsnNode insnBefore = min.getPrevious();
Type type = null;


// GS: Java 8's compiler introduces LineNumberNode and LabelNode between LdcInsnNode and MethodInsnNode, skip them
if (insnBefore instanceof LineNumberNode)
insnBefore = insnBefore.getPrevious();
if (insnBefore instanceof LabelNode)
insnBefore = insnBefore.getPrevious();

if (insnBefore instanceof LdcInsnNode && ((LdcInsnNode)insnBefore).cst instanceof Type) {
type = (Type)((LdcInsnNode)insnBefore).cst;
removeInsn(insnBefore);
}
else {
logError("first parameter of Stack.alloc(Class) must be constant");
}

if (!staticAllocation) {
usedTypes.add(type.getInternalName());
instr.addStackType(type.getInternalName());
}

insn = replaceAllocClass(insn, type, stackVar).getNext();
removeInsn(min);

// remove redudant checkcast:
if (insn instanceof TypeInsnNode) {
TypeInsnNode tin = (TypeInsnNode)insn;
Expand All @@ -137,24 +143,24 @@ public void visitEnd() {
removeInsn(tin);
}
}

continue;
}

// check for Stack.alloc(Object):
if (min.owner.equals(STACK_NAME) && min.name.equals("alloc") && min.desc.equals(STACK_ALLOC_OBJECT_DESC)) {
Frame frame = frames.get(instructions.indexOf(insn));
BasicValue value = (BasicValue)frame.getStack(frame.getStackSize() - 1);
Type type = value.getType();

if (!staticAllocation) {
usedTypes.add(type.getInternalName());
instr.addStackType(type.getInternalName());
}

insn = replaceAllocObject(insn, type, stackVar).getNext();
removeInsn(min);

// remove redudant checkcast:
if (insn instanceof TypeInsnNode) {
TypeInsnNode tin = (TypeInsnNode)insn;
Expand All @@ -163,10 +169,10 @@ public void visitEnd() {
removeInsn(tin);
}
}

continue;
}

// check for Stack.libraryCleanCurrentThread():
if (min.owner.equals(STACK_NAME) && min.name.equals("libraryCleanCurrentThread") && min.desc.equals("()V")) {
if (instr.isDisabled() || instr.isSingleThread()) {
Expand All @@ -182,7 +188,7 @@ public void visitEnd() {
}
}
}

insn = insn.getNext();
}

Expand All @@ -198,7 +204,7 @@ public void visitEnd() {
if (usedTypes.size() > 0) {
String[] typesArray = usedTypes.toArray(new String[usedTypes.size()]);
insertPush(insn, typesArray, stackVar);

while (insn != null) {
if (insn instanceof InsnNode && isReturnOpcode(insn.getOpcode())) {
insertPop(insn, true, typesArray, stackVar);
Expand All @@ -215,7 +221,7 @@ public void visitEnd() {
tryCatchBlocks.add(new TryCatchBlockNode(startLabel, endLabel, endLabel, null));
}
}

if (emitMethod) {
accept(cv);
}
Expand All @@ -224,61 +230,61 @@ public void visitEnd() {
throw new IllegalStateException(e);
}
}

////////////////////////////////////////////////////////////////////////////

private void removeInsn(AbstractInsnNode insn) {
int idx = instructions.indexOf(insn);
instructions.remove(insn);
frames.remove(idx);
}

private AbstractInsnNode insertInsn(AbstractInsnNode insn, InsnList list) {
if (list.size() == 0) {
return insn;
}

int idx = instructions.indexOf(insn);
for (int i=0; i<list.size(); i++) {
frames.add(idx+1, null);
}

AbstractInsnNode last = list.getLast();
instructions.insert(insn, list);
return last;
}

private void insertInsnBefore(AbstractInsnNode insn, InsnList list) {
if (list.size() == 0) {
return;
}

int idx = instructions.indexOf(insn);
for (int i=0; i<list.size(); i++) {
frames.add(idx, null);
}

instructions.insertBefore(insn, list);
}

private AbstractInsnNode insertInsn(AbstractInsnNode pos, AbstractInsnNode insn) {
int idx = instructions.indexOf(pos);
frames.add(idx+1, null);

instructions.insert(pos, insn);
return insn;
}

private AbstractInsnNode insertInsnBefore(AbstractInsnNode pos, AbstractInsnNode insn) {
int idx = instructions.indexOf(pos);
frames.add(idx, null);

instructions.insertBefore(pos, insn);
return insn;
}

////////////////////////////////////////////////////////////////////////////

private boolean isReturnOpcode(int opcode) {
switch (opcode) {
case Opcodes.IRETURN:
Expand All @@ -294,7 +300,7 @@ private boolean isReturnOpcode(int opcode) {

private void insertStackVarBefore(AbstractInsnNode pos, int stackVar) {
InsnList list = new InsnList();

if (instr.isSingleThread()) {
list.add(new FieldInsnNode(Opcodes.GETSTATIC, instr.getStackInternalName(), "INSTANCE", "L"+instr.getStackInternalName()+";"));
list.add(new VarInsnNode(Opcodes.ASTORE, stackVar));
Expand All @@ -304,41 +310,41 @@ private void insertStackVarBefore(AbstractInsnNode pos, int stackVar) {
list.add(new MethodInsnNode(Opcodes.INVOKESTATIC, instr.getStackInternalName(), "get", getDesc));
list.add(new VarInsnNode(Opcodes.ASTORE, stackVar));
}

insertInsnBefore(pos, list);
}

private void insertPush(AbstractInsnNode pos, String[] types, int stackVar) {
InsnList list = new InsnList();

list.add(new VarInsnNode(Opcodes.ALOAD, stackVar));
for (int i=0; i<types.length; i++) {
if (i < types.length-1) {
list.add(new InsnNode(Opcodes.DUP));
}

list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, instr.getStackInternalName(),
"push$"+Instrumenter.mangleInternalName(types[i]),
"()V"));
}

insertInsnBefore(pos, list);
}

private AbstractInsnNode insertPop(AbstractInsnNode pos, boolean before, String[] types, int stackVar) {
InsnList list = new InsnList();

list.add(new VarInsnNode(Opcodes.ALOAD, stackVar));
for (int i=0; i<types.length; i++) {
if (i < types.length-1) {
list.add(new InsnNode(Opcodes.DUP));
}

list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, instr.getStackInternalName(),
"pop$"+Instrumenter.mangleInternalName(types[i]),
"()V"));
}

if (before) {
insertInsnBefore(pos, list);
return null;
Expand All @@ -347,10 +353,10 @@ private AbstractInsnNode insertPop(AbstractInsnNode pos, boolean before, String[
return insertInsn(pos, list);
}
}

private AbstractInsnNode replaceAllocClass(AbstractInsnNode pos, Type type, int stackVar) {
InsnList list = new InsnList();

if (disableAllocation) {
list.add(new TypeInsnNode(Opcodes.NEW, type.getInternalName()));
list.add(new InsnNode(Opcodes.DUP));
Expand All @@ -366,21 +372,21 @@ else if (staticAllocation) {
"get$"+Instrumenter.mangleInternalName(type.getInternalName()),
"()"+type.getDescriptor()));
}

return insertInsn(pos, list);
}

private AbstractInsnNode replaceAllocObject(AbstractInsnNode pos, Type type, int stackVar) {
InsnList list = new InsnList();

if (disableAllocation) {
list.add(new TypeInsnNode(Opcodes.NEW, type.getInternalName()));
list.add(new InsnNode(Opcodes.DUP));
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, type.getInternalName(), "<init>", "()V"));

list.add(new InsnNode(Opcodes.DUP_X1));
list.add(new InsnNode(Opcodes.SWAP));

Method m = StackGenerator.findGetMethodType(type.getInternalName());
list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, type.getInternalName(),
"set",
Expand All @@ -389,10 +395,10 @@ private AbstractInsnNode replaceAllocObject(AbstractInsnNode pos, Type type, int
else if (staticAllocation) {
int num = inscls.registerStaticAlloc(type.getInternalName());
list.add(new FieldInsnNode(Opcodes.GETSTATIC, className, "$stackTemp"+num, type.getDescriptor()));

list.add(new InsnNode(Opcodes.DUP_X1));
list.add(new InsnNode(Opcodes.SWAP));

Method m = StackGenerator.findGetMethodType(type.getInternalName());
list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, type.getInternalName(),
"set",
Expand All @@ -405,10 +411,10 @@ else if (staticAllocation) {
"get$"+Instrumenter.mangleInternalName(type.getInternalName()),
"("+type.getDescriptor()+")"+type.getDescriptor()));
}

return insertInsn(pos, list);
}

private void logError(String msg) {
throw new IllegalStateException(msg+" (in class "+className.replace('/', '.')+", method "+name+")");
}
Expand Down

0 comments on commit 5ace1d6

Please sign in to comment.